HAMMER VFS - Do a better job with IO_DIRECT
[dragonfly.git] / contrib / ipfilter / ipt.c
blobf77508919e34bbf21ef30454f4d69fb572a7d033
1 /*
2 * Copyright (C) 1993-2002 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
5 */
6 #ifdef __FreeBSD__
7 # ifndef __FreeBSD_cc_version
8 # include <osreldate.h>
9 # else
10 # if __FreeBSD_cc_version < 430000
11 # include <osreldate.h>
12 # endif
13 # endif
14 #endif
15 #if defined(__sgi) && (IRIX > 602)
16 # define _KMEMUSER
17 # include <sys/ptimers.h>
18 #endif
19 #include <stdio.h>
20 #include <assert.h>
21 #include <string.h>
22 #include <sys/types.h>
23 #if !defined(__SVR4) && !defined(__svr4__) && !defined(__sgi)
24 #include <strings.h>
25 #else
26 #if !defined(__sgi)
27 #include <sys/byteorder.h>
28 #endif
29 #include <sys/file.h>
30 #endif
31 #include <sys/param.h>
32 #include <sys/time.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <stddef.h>
36 #include <sys/socket.h>
37 #include <sys/ioctl.h>
38 #include <netinet/in.h>
39 #include <netinet/in_systm.h>
40 #ifndef linux
41 #include <netinet/ip_var.h>
42 #endif
43 #include <netinet/ip.h>
44 #include <netinet/udp.h>
45 #include <netinet/tcp.h>
46 #include <netinet/ip_icmp.h>
47 #include <net/if.h>
48 #if __FreeBSD_version >= 300000
49 # include <net/if_var.h>
50 #endif
51 #include <netdb.h>
52 #include <arpa/nameser.h>
53 #include <arpa/inet.h>
54 #include <resolv.h>
55 #include <ctype.h>
56 #include "ip_compat.h"
57 #include <netinet/tcpip.h>
58 #include "ip_fil.h"
59 #include "ip_nat.h"
60 #include "ip_state.h"
61 #include "ip_frag.h"
62 #include "ipf.h"
63 #include "ipt.h"
65 #if !defined(lint)
66 static const char sccsid[] = "@(#)ipt.c 1.19 6/3/96 (C) 1993-2000 Darren Reed";
67 static const char rcsid[] = "@(#)$Id: ipt.c,v 2.6.2.26 2003/11/09 17:22:21 darrenr Exp $";
68 #endif
70 extern char *optarg;
71 extern struct frentry *ipfilter[2][2];
72 extern struct ipread snoop, etherf, tcpd, pcap, iptext, iphex;
73 extern struct ifnet *get_unit __P((char *, int));
74 extern void init_ifp __P((void));
75 extern ipnat_t *natparse __P((char *, int, int *));
76 extern int fr_running;
78 int opts = 0;
79 int rremove = 0;
80 int use_inet6 = 0;
81 int main __P((int, char *[]));
82 int loadrules __P((char *));
83 int kmemcpy __P((char *, long, int));
84 void dumpnat __P((void));
85 void dumpstate __P((void));
86 char *getifname __P((void *));
87 void drain_log __P((char *));
89 int main(argc,argv)
90 int argc;
91 char *argv[];
93 char *datain, *iface, *ifname, *packet, *logout;
94 int fd, i, dir, c, loaded, dump, hlen;
95 struct in_addr src;
96 struct ifnet *ifp;
97 struct ipread *r;
98 u_long buf[2048];
99 ip_t *ip;
101 dir = 0;
102 dump = 0;
103 loaded = 0;
104 r = &iptext;
105 iface = NULL;
106 logout = NULL;
107 src.s_addr = 0;
108 ifname = "anon0";
109 datain = NULL;
111 nat_init();
112 fr_stateinit();
113 initparse();
114 ipflog_init();
115 fr_running = 1;
117 while ((c = getopt(argc, argv, "6bdDEHi:I:l:NoPr:Rs:STvxX")) != -1)
118 switch (c)
120 case '6' :
121 #ifdef USE_INET6
122 use_inet6 = 1;
123 break;
124 #else
125 fprintf(stderr, "IPv6 not supported\n");
126 exit(1);
127 #endif
128 case 'b' :
129 opts |= OPT_BRIEF;
130 break;
131 case 'd' :
132 opts |= OPT_DEBUG;
133 break;
134 case 'D' :
135 dump = 1;
136 break;
137 case 'i' :
138 datain = optarg;
139 break;
140 case 'I' :
141 ifname = optarg;
142 break;
143 case 'l' :
144 logout = optarg;
145 break;
146 case 'o' :
147 opts |= OPT_SAVEOUT;
148 break;
149 case 'r' :
150 if (loadrules(optarg) == -1)
151 return -1;
152 loaded = 1;
153 break;
154 case 's' :
155 src.s_addr = inet_addr(optarg);
156 break;
157 case 'v' :
158 opts |= OPT_VERBOSE;
159 break;
160 case 'E' :
161 r = &etherf;
162 break;
163 case 'H' :
164 r = &iphex;
165 break;
166 case 'N' :
167 opts |= OPT_NAT;
168 break;
169 case 'P' :
170 r = &pcap;
171 break;
172 case 'R' :
173 rremove = 1;
174 break;
175 case 'S' :
176 r = &snoop;
177 break;
178 case 'T' :
179 r = &tcpd;
180 break;
181 case 'x' :
182 opts |= OPT_HEX;
183 break;
184 case 'X' :
185 r = &iptext;
186 break;
189 if (loaded == 0) {
190 (void)fprintf(stderr,"no rules loaded\n");
191 exit(-1);
194 if (opts & OPT_SAVEOUT)
195 init_ifp();
197 if (datain)
198 fd = (*r->r_open)(datain);
199 else
200 fd = (*r->r_open)("-");
202 if (fd < 0)
203 exit(-1);
205 ip = (ip_t *)buf;
206 while ((i = (*r->r_readip)((char *)buf, sizeof(buf),
207 &iface, &dir)) > 0) {
208 if (iface == NULL || *iface == '\0')
209 iface = ifname;
210 ifp = get_unit(iface, ip->ip_v);
211 hlen = 0;
212 if (!use_inet6) {
213 ip->ip_off = ntohs(ip->ip_off);
214 ip->ip_len = ntohs(ip->ip_len);
215 hlen = ip->ip_hl << 2;
216 if (src.s_addr != 0) {
217 if (src.s_addr == ip->ip_src.s_addr)
218 dir = 1;
219 else if (src.s_addr == ip->ip_dst.s_addr)
220 dir = 0;
223 #ifdef USE_INET6
224 else
225 hlen = sizeof(ip6_t);
226 #endif
227 if (opts & OPT_VERBOSE) {
228 printf("%s on [%s]: ", dir ? "out" : "in",
229 (iface && *iface) ? iface : "??");
231 packet = (char *)buf;
232 /* ipfr_slowtimer(); */
233 i = fr_check(ip, hlen, ifp, dir, (mb_t **)&packet);
234 if ((opts & OPT_NAT) == 0)
235 switch (i)
237 case -5 :
238 (void)printf("block return-icmp-as-dest");
239 break;
240 case -4 :
241 (void)printf("block return-icmp");
242 break;
243 case -3 :
244 (void)printf("block return-rst");
245 break;
246 case -2 :
247 (void)printf("auth");
248 break;
249 case -1 :
250 (void)printf("block");
251 break;
252 case 0 :
253 (void)printf("pass");
254 break;
255 case 1 :
256 (void)printf("nomatch");
257 break;
259 if (!use_inet6) {
260 ip->ip_off = htons(ip->ip_off);
261 ip->ip_len = htons(ip->ip_len);
264 if (!(opts & OPT_BRIEF)) {
265 putchar(' ');
266 printpacket((ip_t *)buf);
267 printf("--------------");
268 } else if ((opts & (OPT_BRIEF|OPT_NAT)) == (OPT_NAT|OPT_BRIEF))
269 printpacket((ip_t *)buf);
270 #ifndef linux
271 if (dir && (ifp != NULL) && ip->ip_v && (packet != NULL))
272 # if defined(__sgi) && (IRIX < 605)
273 (*ifp->if_output)(ifp, (void *)packet, NULL);
274 # else
275 (*ifp->if_output)(ifp, (void *)packet, NULL, 0);
276 # endif
277 #endif
278 if ((opts & (OPT_BRIEF|OPT_NAT)) != (OPT_NAT|OPT_BRIEF))
279 putchar('\n');
280 dir = 0;
281 if (iface != ifname) {
282 free(iface);
283 iface = ifname;
286 (*r->r_close)();
288 if (logout != NULL) {
289 drain_log(logout);
292 if (dump == 1) {
293 dumpnat();
294 dumpstate();
297 return 0;
302 * Load in either NAT or ipf rules from a file, which is treated as stdin
303 * if the name is "-". NOTE, stdin can only be used once as the file is
304 * closed after use.
306 int loadrules(file)
307 char *file;
309 char line[513], *s;
310 int linenum, i;
311 void *fr;
312 FILE *fp;
313 int parsestatus;
315 if (!strcmp(file, "-"))
316 fp = stdin;
317 else if (!(fp = fopen(file, "r"))) {
318 (void)fprintf(stderr, "couldn't open %s\n", file);
319 return (-1);
322 if (!(opts & OPT_BRIEF))
323 (void)printf("opening rule file \"%s\"\n", file);
325 linenum = 0;
327 while (fgets(line, sizeof(line) - 1, fp)) {
328 linenum++;
331 * treat both CR and LF as EOL
333 if ((s = index(line, '\n')))
334 *s = '\0';
335 if ((s = index(line, '\r')))
336 *s = '\0';
339 * # is comment marker, everything after is a ignored
341 if ((s = index(line, '#')))
342 *s = '\0';
344 if (!*line)
345 continue;
347 /* fake an `ioctl' call :) */
349 if ((opts & OPT_NAT) != 0) {
350 parsestatus = 1;
351 fr = natparse(line, linenum, &parsestatus);
352 if (parsestatus != 0) {
353 if (*line) {
354 fprintf(stderr,
355 "%d: syntax error in \"%s\"\n",
356 linenum, line);
358 fprintf(stderr, "%s: %s error (%d), quitting\n",
359 file,
360 ((parsestatus < 0)? "parse": "internal"),
361 parsestatus);
362 exit(1);
364 if (!fr)
365 continue;
367 if (rremove == 0) {
368 i = IPL_EXTERN(ioctl)(IPL_LOGNAT, SIOCADNAT,
369 (caddr_t)&fr,
370 FWRITE|FREAD);
371 if (opts & OPT_DEBUG)
372 fprintf(stderr,
373 "iplioctl(ADNAT,%p,1) = %d\n",
374 fr, i);
375 } else {
376 i = IPL_EXTERN(ioctl)(IPL_LOGNAT, SIOCRMNAT,
377 (caddr_t)&fr,
378 FWRITE|FREAD);
379 if (opts & OPT_DEBUG)
380 fprintf(stderr,
381 "iplioctl(RMNAT,%p,1) = %d\n",
382 fr, i);
384 } else {
385 fr = parse(line, linenum, &parsestatus);
387 if (parsestatus != 0) {
388 fprintf(stderr, "%s: %s error (%d), quitting\n",
389 file,
390 ((parsestatus < 0)? "parse": "internal"),
391 parsestatus);
392 exit(1);
395 if (!fr) {
396 continue;
399 if (rremove == 0) {
400 i = IPL_EXTERN(ioctl)(0, SIOCADAFR,
401 (caddr_t)&fr,
402 FWRITE|FREAD);
403 if (opts & OPT_DEBUG)
404 fprintf(stderr,
405 "iplioctl(ADAFR,%p,1) = %d\n",
406 fr, i);
407 } else {
408 i = IPL_EXTERN(ioctl)(0, SIOCRMAFR,
409 (caddr_t)&fr,
410 FWRITE|FREAD);
411 if (opts & OPT_DEBUG)
412 fprintf(stderr,
413 "iplioctl(RMAFR,%p,1) = %d\n",
414 fr, i);
418 (void)fclose(fp);
420 return 0;
424 int kmemcpy(addr, offset, size)
425 char *addr;
426 long offset;
427 int size;
429 bcopy((char *)offset, addr, size);
430 return 0;
435 * Display the built up NAT table rules and mapping entries.
437 void dumpnat()
439 ipnat_t *ipn;
440 nat_t *nat;
442 printf("List of active MAP/Redirect filters:\n");
443 for (ipn = nat_list; ipn != NULL; ipn = ipn->in_next)
444 printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
445 printf("\nList of active sessions:\n");
446 for (nat = nat_instances; nat; nat = nat->nat_next)
447 printactivenat(nat, opts);
452 * Display the built up state table rules and mapping entries.
454 void dumpstate()
456 ipstate_t *ips;
458 printf("List of active state sessions:\n");
459 for (ips = ips_list; ips != NULL; )
460 ips = printstate(ips, opts & (OPT_DEBUG|OPT_VERBOSE));
465 * Given a pointer to an interface in the kernel, return a pointer to a
466 * string which is the interface name.
468 char *getifname(ptr)
469 void *ptr;
471 #if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \
472 defined(__OpenBSD__)
473 #else
474 char buf[32], *s;
475 int len;
476 #endif
477 struct ifnet netif;
479 if (ptr == (void *)-1)
480 return "!";
481 if (ptr == NULL)
482 return "-";
484 if (kmemcpy((char *)&netif, (u_long)ptr, sizeof(netif)) == -1)
485 return "X";
486 #if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \
487 defined(__OpenBSD__) || defined(__DragonFly__)
488 return strdup(netif.if_xname);
489 #else
490 if (kmemcpy(buf, (u_long)netif.if_name, sizeof(buf)) == -1)
491 return "X";
492 if (netif.if_unit < 10)
493 len = 2;
494 else if (netif.if_unit < 1000)
495 len = 3;
496 else if (netif.if_unit < 10000)
497 len = 4;
498 else
499 len = 5;
500 buf[sizeof(buf) - len] = '\0';
501 for (s = buf; *s && !isdigit(*s); s++)
503 if (isdigit(*s))
504 *s = '\0';
505 sprintf(buf + strlen(buf), "%d", netif.if_unit % 10000);
506 return strdup(buf);
507 #endif
511 void drain_log(filename)
512 char *filename;
514 char buffer[IPLLOGSIZE];
515 struct iovec iov;
516 struct uio uio;
517 size_t resid;
518 int fd;
520 fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644);
521 if (fd == -1) {
522 perror("drain_log:open");
523 return;
526 while (1) {
527 bzero((char *)&iov, sizeof(iov));
528 iov.iov_base = buffer;
529 iov.iov_len = sizeof(buffer);
531 bzero((char *)&uio, sizeof(uio));
532 uio.uio_iov = &iov;
533 uio.uio_iovcnt = 1;
534 uio.uio_resid = iov.iov_len;
535 resid = uio.uio_resid;
537 if (ipflog_read(0, &uio) == 0) {
539 * If nothing was read then break out.
541 if (uio.uio_resid == resid)
542 break;
543 write(fd, buffer, resid - uio.uio_resid);
544 } else
545 break;
548 close(fd);