regen
[dragonfly/port-amd64.git] / sbin / ipfw / ipfw.c
blobf778c0ad3c2c9596be9960c5258cf515af57f2e2
1 /*
2 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
3 * Copyright (c) 1994 Ugen J.S.Antsilevich
5 * Idea and grammar partially left from:
6 * Copyright (c) 1993 Daniel Boulet
8 * Redistribution and use in source forms, with and without modification,
9 * are permitted provided that this entire comment appears intact.
11 * Redistribution in binary form may occur without any restrictions.
12 * Obviously, it would be nice if you gave credit where credit is due
13 * but requiring it would be too onerous.
15 * This software is provided ``AS IS'' without any warranties of any kind.
17 * NEW command line interface for IP firewall facility
19 * $FreeBSD: src/sbin/ipfw/ipfw.c,v 1.80.2.26 2003/01/14 19:15:58 dillon Exp $
20 * $DragonFly: src/sbin/ipfw/ipfw.c,v 1.8 2006/06/25 11:02:37 corecode Exp $
23 #include <sys/param.h>
24 #include <sys/mbuf.h>
25 #include <sys/socket.h>
26 #include <sys/sockio.h>
27 #include <sys/sysctl.h>
28 #include <sys/time.h>
29 #include <sys/wait.h>
31 #include <ctype.h>
32 #include <err.h>
33 #include <errno.h>
34 #include <grp.h>
35 #include <limits.h>
36 #include <netdb.h>
37 #include <pwd.h>
38 #include <signal.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <stdarg.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <sysexits.h>
46 #include <net/if.h>
47 #include <netinet/in.h>
48 #include <netinet/in_systm.h>
49 #include <netinet/ip.h>
50 #include <netinet/ip_icmp.h>
51 #include <net/ipfw/ip_fw.h>
52 #include <net/route.h> /* def. of struct route */
53 #include <net/dummynet/ip_dummynet.h>
54 #include <netinet/tcp.h>
55 #include <arpa/inet.h>
57 int s, /* main RAW socket */
58 do_resolv, /* Would try to resolve all */
59 do_acct, /* Show packet/byte count */
60 do_time, /* Show time stamps */
61 do_quiet, /* Be quiet in add and flush */
62 do_force, /* Don't ask for confirmation */
63 do_pipe, /* this cmd refers to a pipe */
64 do_sort, /* field to sort results (0 = no) */
65 do_dynamic, /* display dynamic rules */
66 do_expired, /* display expired dynamic rules */
67 verbose;
69 struct icmpcode {
70 int code;
71 char *str;
74 static struct icmpcode icmpcodes[] = {
75 { ICMP_UNREACH_NET, "net" },
76 { ICMP_UNREACH_HOST, "host" },
77 { ICMP_UNREACH_PROTOCOL, "protocol" },
78 { ICMP_UNREACH_PORT, "port" },
79 { ICMP_UNREACH_NEEDFRAG, "needfrag" },
80 { ICMP_UNREACH_SRCFAIL, "srcfail" },
81 { ICMP_UNREACH_NET_UNKNOWN, "net-unknown" },
82 { ICMP_UNREACH_HOST_UNKNOWN, "host-unknown" },
83 { ICMP_UNREACH_ISOLATED, "isolated" },
84 { ICMP_UNREACH_NET_PROHIB, "net-prohib" },
85 { ICMP_UNREACH_HOST_PROHIB, "host-prohib" },
86 { ICMP_UNREACH_TOSNET, "tosnet" },
87 { ICMP_UNREACH_TOSHOST, "toshost" },
88 { ICMP_UNREACH_FILTER_PROHIB, "filter-prohib" },
89 { ICMP_UNREACH_HOST_PRECEDENCE, "host-precedence" },
90 { ICMP_UNREACH_PRECEDENCE_CUTOFF, "precedence-cutoff" },
91 { 0, NULL }
94 static void show_usage(void);
96 static int
97 mask_bits(struct in_addr m_ad)
99 int h_fnd = 0, h_num = 0, i;
100 u_long mask;
102 mask = ntohl(m_ad.s_addr);
103 for (i = 0; i < sizeof(u_long)*CHAR_BIT; i++) {
104 if (mask & 1L) {
105 h_fnd = 1;
106 h_num++;
107 } else {
108 if (h_fnd)
109 return -1;
111 mask = mask >> 1;
113 return h_num;
116 static void
117 print_port(u_char prot, u_short port, const char comma)
119 struct servent *se = NULL;
120 struct protoent *pe;
122 if (comma == ':') {
123 printf("%c0x%04x", comma, port);
124 return;
126 if (do_resolv) {
127 pe = getprotobynumber(prot);
128 se = getservbyport(htons(port), pe ? pe->p_name : NULL);
130 if (se)
131 printf("%c%s", comma, se->s_name);
132 else
133 printf("%c%d", comma, port);
136 static void
137 print_iface(char *key, union ip_fw_if *un, int byname)
139 if (byname) {
140 printf(" %s %s", key, un->fu_via_if.name);
141 } else if (un->fu_via_ip.s_addr != 0) {
142 printf(" %s %s", key, inet_ntoa(un->fu_via_ip));
143 } else
144 printf(" %s any", key);
147 static void
148 print_reject_code(int code)
150 struct icmpcode *ic;
152 for (ic = icmpcodes; ic->str; ic++)
153 if (ic->code == code) {
154 printf("%s", ic->str);
155 return;
157 printf("%u", code);
161 * _s_x holds a string-int pair for various lookups.
162 * s=NULL terminates the struct.
164 struct _s_x { char *s; int x; };
165 static struct _s_x limit_masks[] = {
166 {"src-addr", DYN_SRC_ADDR},
167 {"src-port", DYN_SRC_PORT},
168 {"dst-addr", DYN_DST_ADDR},
169 {"dst-port", DYN_DST_PORT},
170 {NULL, 0} };
172 static void
173 show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth)
175 static int twidth = 0;
176 char comma;
177 u_long adrt;
178 struct hostent *he;
179 struct protoent *pe;
180 int i, mb;
181 int nsp = IP_FW_GETNSRCP(chain);
182 int ndp = IP_FW_GETNDSTP(chain);
184 if (do_resolv)
185 setservent(1/*stay open*/);
187 printf("%05u ", chain->fw_number);
189 if (do_acct)
190 printf("%*qu %*qu ", pcwidth, chain->fw_pcnt, bcwidth, chain->fw_bcnt);
192 if (do_time) {
193 char timestr[30];
195 if (twidth == 0) {
196 time_t zerotime = 0;
198 strcpy(timestr, ctime(&zerotime));
199 *strchr(timestr, '\n') = '\0';
200 twidth = strlen(timestr);
202 if (chain->timestamp) {
203 strcpy(timestr, ctime((time_t *)&chain->timestamp));
204 *strchr(timestr, '\n') = '\0';
205 printf("%s ", timestr);
206 } else {
207 printf("%*s ", twidth, " ");
210 if (chain->fw_flg == IP_FW_F_CHECK_S) {
211 printf("check-state\n");
212 goto done;
215 if (chain->fw_flg & IP_FW_F_RND_MATCH) {
216 double d = 1.0 * chain->dont_match_prob;
217 d = 1 - (d / 0x7fffffff);
218 printf("prob %f ", d);
221 switch (chain->fw_flg & IP_FW_F_COMMAND) {
222 case IP_FW_F_ACCEPT:
223 printf("allow");
224 break;
225 case IP_FW_F_DENY:
226 printf("deny");
227 break;
228 case IP_FW_F_COUNT:
229 printf("count");
230 break;
231 case IP_FW_F_DIVERT:
232 printf("divert %u", chain->fw_divert_port);
233 break;
234 case IP_FW_F_TEE:
235 printf("tee %u", chain->fw_divert_port);
236 break;
237 case IP_FW_F_SKIPTO:
238 printf("skipto %u", chain->fw_skipto_rule);
239 break;
240 case IP_FW_F_PIPE:
241 printf("pipe %u", chain->fw_skipto_rule);
242 break;
243 case IP_FW_F_QUEUE:
244 printf("queue %u", chain->fw_skipto_rule);
245 break;
246 case IP_FW_F_REJECT:
247 if (chain->fw_reject_code == IP_FW_REJECT_RST)
248 printf("reset");
249 else {
250 printf("unreach ");
251 print_reject_code(chain->fw_reject_code);
253 break;
254 case IP_FW_F_FWD:
255 printf("fwd %s", inet_ntoa(chain->fw_fwd_ip.sin_addr));
256 if(chain->fw_fwd_ip.sin_port)
257 printf(",%d", chain->fw_fwd_ip.sin_port);
258 break;
259 default:
260 errx(EX_OSERR, "impossible");
263 if (chain->fw_flg & IP_FW_F_PRN) {
264 printf(" log");
265 if (chain->fw_logamount)
266 printf(" logamount %d", chain->fw_logamount);
269 pe = getprotobynumber(chain->fw_prot);
270 if (pe)
271 printf(" %s", pe->p_name);
272 else
273 printf(" %u", chain->fw_prot);
275 printf(" from %s", chain->fw_flg & IP_FW_F_INVSRC ? "not " : "");
277 if (chain->fw_flg & IP_FW_F_SME) {
278 printf("me");
279 } else {
281 adrt = ntohl(chain->fw_smsk.s_addr);
282 if (adrt == ULONG_MAX && do_resolv) {
283 adrt = (chain->fw_src.s_addr);
284 he = gethostbyaddr((char *)&adrt,
285 sizeof(u_long), AF_INET);
286 if (he == NULL)
287 printf("%s", inet_ntoa(chain->fw_src));
288 else
289 printf("%s", he->h_name);
290 } else if (adrt != ULONG_MAX) {
291 mb = mask_bits(chain->fw_smsk);
292 if (mb == 0) {
293 printf("any");
294 } else if (mb > 0) {
295 printf("%s", inet_ntoa(chain->fw_src));
296 printf("/%d", mb);
297 } else {
298 printf("%s", inet_ntoa(chain->fw_src));
299 printf(":");
300 printf("%s", inet_ntoa(chain->fw_smsk));
302 } else {
303 printf("%s", inet_ntoa(chain->fw_src));
307 if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
308 comma = ' ';
309 for (i = 0; i < nsp; i++) {
310 print_port(chain->fw_prot,
311 chain->fw_uar.fw_pts[i], comma);
312 if (i == 0 && (chain->fw_flg & IP_FW_F_SRNG))
313 comma = '-';
314 else if (i == 0 && (chain->fw_flg & IP_FW_F_SMSK))
315 comma = ':';
316 else
317 comma = ',';
321 printf(" to %s", chain->fw_flg & IP_FW_F_INVDST ? "not " : "");
323 if (chain->fw_flg & IP_FW_F_DME) {
324 printf("me");
325 } else {
326 adrt = ntohl(chain->fw_dmsk.s_addr);
327 if (adrt == ULONG_MAX && do_resolv) {
328 adrt = (chain->fw_dst.s_addr);
329 he = gethostbyaddr((char *)&adrt,
330 sizeof(u_long), AF_INET);
331 if (he == NULL)
332 printf("%s", inet_ntoa(chain->fw_dst));
333 else
334 printf("%s", he->h_name);
335 } else if (adrt != ULONG_MAX) {
336 mb = mask_bits(chain->fw_dmsk);
337 if (mb == 0) {
338 printf("any");
339 } else if (mb > 0) {
340 printf("%s", inet_ntoa(chain->fw_dst));
341 printf("/%d", mb);
342 } else {
343 printf("%s", inet_ntoa(chain->fw_dst));
344 printf(":");
345 printf("%s", inet_ntoa(chain->fw_dmsk));
347 } else {
348 printf("%s", inet_ntoa(chain->fw_dst));
352 if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
353 comma = ' ';
354 for (i = 0; i < ndp; i++) {
355 print_port(chain->fw_prot,
356 chain->fw_uar.fw_pts[nsp+i], comma);
357 if (i == 0 && (chain->fw_flg & IP_FW_F_DRNG))
358 comma = '-';
359 else if (i == 0 && (chain->fw_flg & IP_FW_F_DMSK))
360 comma = ':';
361 else
362 comma = ',';
366 if (chain->fw_flg & IP_FW_F_UID) {
367 struct passwd *pwd = getpwuid(chain->fw_uid);
369 if (pwd)
370 printf(" uid %s", pwd->pw_name);
371 else
372 printf(" uid %u", chain->fw_uid);
375 if (chain->fw_flg & IP_FW_F_GID) {
376 struct group *grp = getgrgid(chain->fw_gid);
378 if (grp)
379 printf(" gid %s", grp->gr_name);
380 else
381 printf(" gid %u", chain->fw_gid);
384 if (chain->fw_flg & IP_FW_F_KEEP_S) {
385 struct _s_x *p = limit_masks;
387 switch(chain->dyn_type) {
388 default:
389 printf(" *** unknown type ***");
390 break ;
391 case DYN_KEEP_STATE:
392 printf(" keep-state");
393 break;
394 case DYN_LIMIT:
395 printf(" limit");
396 for ( ; p->s != NULL ; p++)
397 if (chain->limit_mask & p->x)
398 printf(" %s", p->s);
399 printf(" %d", chain->conn_limit);
400 break ;
403 /* Direction */
404 if ((chain->fw_flg & IP_FW_F_IN) && !(chain->fw_flg & IP_FW_F_OUT))
405 printf(" in");
406 if (!(chain->fw_flg & IP_FW_F_IN) && (chain->fw_flg & IP_FW_F_OUT))
407 printf(" out");
409 /* Handle hack for "via" backwards compatibility */
410 if ((chain->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
411 print_iface("via",
412 &chain->fw_in_if, chain->fw_flg & IP_FW_F_IIFNAME);
413 } else {
414 /* Receive interface specified */
415 if (chain->fw_flg & IP_FW_F_IIFACE)
416 print_iface("recv", &chain->fw_in_if,
417 chain->fw_flg & IP_FW_F_IIFNAME);
418 /* Transmit interface specified */
419 if (chain->fw_flg & IP_FW_F_OIFACE)
420 print_iface("xmit", &chain->fw_out_if,
421 chain->fw_flg & IP_FW_F_OIFNAME);
424 if (chain->fw_flg & IP_FW_F_FRAG)
425 printf(" frag");
427 if (chain->fw_ipopt || chain->fw_ipnopt) {
428 int _opt_printed = 0;
429 #define PRINTOPT(x) {if (_opt_printed) printf(",");\
430 printf(x); _opt_printed = 1;}
432 printf(" ipopt ");
433 if (chain->fw_ipopt & IP_FW_IPOPT_SSRR)
434 PRINTOPT("ssrr");
435 if (chain->fw_ipnopt & IP_FW_IPOPT_SSRR)
436 PRINTOPT("!ssrr");
437 if (chain->fw_ipopt & IP_FW_IPOPT_LSRR)
438 PRINTOPT("lsrr");
439 if (chain->fw_ipnopt & IP_FW_IPOPT_LSRR)
440 PRINTOPT("!lsrr");
441 if (chain->fw_ipopt & IP_FW_IPOPT_RR)
442 PRINTOPT("rr");
443 if (chain->fw_ipnopt & IP_FW_IPOPT_RR)
444 PRINTOPT("!rr");
445 if (chain->fw_ipopt & IP_FW_IPOPT_TS)
446 PRINTOPT("ts");
447 if (chain->fw_ipnopt & IP_FW_IPOPT_TS)
448 PRINTOPT("!ts");
451 if (chain->fw_ipflg & IP_FW_IF_TCPEST)
452 printf(" established");
453 else if (chain->fw_tcpf == IP_FW_TCPF_SYN &&
454 chain->fw_tcpnf == IP_FW_TCPF_ACK)
455 printf(" setup");
456 else if (chain->fw_tcpf || chain->fw_tcpnf) {
457 int _flg_printed = 0;
458 #define PRINTFLG(x) {if (_flg_printed) printf(",");\
459 printf(x); _flg_printed = 1;}
461 printf(" tcpflags ");
462 if (chain->fw_tcpf & IP_FW_TCPF_FIN)
463 PRINTFLG("fin");
464 if (chain->fw_tcpnf & IP_FW_TCPF_FIN)
465 PRINTFLG("!fin");
466 if (chain->fw_tcpf & IP_FW_TCPF_SYN)
467 PRINTFLG("syn");
468 if (chain->fw_tcpnf & IP_FW_TCPF_SYN)
469 PRINTFLG("!syn");
470 if (chain->fw_tcpf & IP_FW_TCPF_RST)
471 PRINTFLG("rst");
472 if (chain->fw_tcpnf & IP_FW_TCPF_RST)
473 PRINTFLG("!rst");
474 if (chain->fw_tcpf & IP_FW_TCPF_PSH)
475 PRINTFLG("psh");
476 if (chain->fw_tcpnf & IP_FW_TCPF_PSH)
477 PRINTFLG("!psh");
478 if (chain->fw_tcpf & IP_FW_TCPF_ACK)
479 PRINTFLG("ack");
480 if (chain->fw_tcpnf & IP_FW_TCPF_ACK)
481 PRINTFLG("!ack");
482 if (chain->fw_tcpf & IP_FW_TCPF_URG)
483 PRINTFLG("urg");
484 if (chain->fw_tcpnf & IP_FW_TCPF_URG)
485 PRINTFLG("!urg");
487 if (chain->fw_tcpopt || chain->fw_tcpnopt) {
488 int _opt_printed = 0;
489 #define PRINTTOPT(x) {if (_opt_printed) printf(",");\
490 printf(x); _opt_printed = 1;}
492 printf(" tcpoptions ");
493 if (chain->fw_tcpopt & IP_FW_TCPOPT_MSS)
494 PRINTTOPT("mss");
495 if (chain->fw_tcpnopt & IP_FW_TCPOPT_MSS)
496 PRINTTOPT("!mss");
497 if (chain->fw_tcpopt & IP_FW_TCPOPT_WINDOW)
498 PRINTTOPT("window");
499 if (chain->fw_tcpnopt & IP_FW_TCPOPT_WINDOW)
500 PRINTTOPT("!window");
501 if (chain->fw_tcpopt & IP_FW_TCPOPT_SACK)
502 PRINTTOPT("sack");
503 if (chain->fw_tcpnopt & IP_FW_TCPOPT_SACK)
504 PRINTTOPT("!sack");
505 if (chain->fw_tcpopt & IP_FW_TCPOPT_TS)
506 PRINTTOPT("ts");
507 if (chain->fw_tcpnopt & IP_FW_TCPOPT_TS)
508 PRINTTOPT("!ts");
509 if (chain->fw_tcpopt & IP_FW_TCPOPT_CC)
510 PRINTTOPT("cc");
511 if (chain->fw_tcpnopt & IP_FW_TCPOPT_CC)
512 PRINTTOPT("!cc");
515 if (chain->fw_flg & IP_FW_F_ICMPBIT) {
516 int type_index;
517 int first = 1;
519 printf(" icmptype");
521 for (type_index = 0; type_index < IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8; ++type_index)
522 if (chain->fw_uar.fw_icmptypes[type_index / (sizeof(unsigned) * 8)] &
523 (1U << (type_index % (sizeof(unsigned) * 8)))) {
524 printf("%c%d", first == 1 ? ' ' : ',', type_index);
525 first = 0;
528 printf("\n");
529 done:
530 if (do_resolv)
531 endservent();
535 sort_q(const void *pa, const void *pb)
537 int rev = (do_sort < 0);
538 int field = rev ? -do_sort : do_sort;
539 long long res = 0;
540 const struct dn_flow_queue *a = pa;
541 const struct dn_flow_queue *b = pb;
543 switch (field) {
544 case 1: /* pkts */
545 res = a->len - b->len;
546 break;
547 case 2: /* bytes */
548 res = a->len_bytes - b->len_bytes;
549 break;
551 case 3: /* tot pkts */
552 res = a->tot_pkts - b->tot_pkts;
553 break;
555 case 4: /* tot bytes */
556 res = a->tot_bytes - b->tot_bytes;
557 break;
559 if (res < 0)
560 res = -1;
561 if (res > 0)
562 res = 1;
563 return (int)(rev ? res : -res);
566 static void
567 list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
569 int l;
571 printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
572 fs->flow_mask.proto,
573 fs->flow_mask.src_ip, fs->flow_mask.src_port,
574 fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
575 if (fs->rq_elements == 0)
576 return;
578 printf("BKT Prot ___Source IP/port____ "
579 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
580 if (do_sort != 0)
581 heapsort(q, fs->rq_elements, sizeof *q, sort_q);
582 for (l = 0; l < fs->rq_elements; l++) {
583 struct in_addr ina;
584 struct protoent *pe;
586 ina.s_addr = htonl(q[l].id.src_ip);
587 printf("%3d ", q[l].hash_slot);
588 pe = getprotobynumber(q[l].id.proto);
589 if (pe)
590 printf("%-4s ", pe->p_name);
591 else
592 printf("%4u ", q[l].id.proto);
593 printf("%15s/%-5d ",
594 inet_ntoa(ina), q[l].id.src_port);
595 ina.s_addr = htonl(q[l].id.dst_ip);
596 printf("%15s/%-5d ",
597 inet_ntoa(ina), q[l].id.dst_port);
598 printf("%4qu %8qu %2u %4u %3u\n",
599 q[l].tot_pkts, q[l].tot_bytes,
600 q[l].len, q[l].len_bytes, q[l].drops);
601 if (verbose)
602 printf(" S %20qd F %20qd\n",
603 q[l].S, q[l].F);
607 static void
608 print_flowset_parms(struct dn_flow_set *fs, char *prefix)
610 int l;
611 char qs[30];
612 char plr[30];
613 char red[90]; /* Display RED parameters */
615 l = fs->qsize;
616 if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
617 if (l >= 8192)
618 sprintf(qs, "%d KB", l / 1024);
619 else
620 sprintf(qs, "%d B", l);
621 } else
622 sprintf(qs, "%3d sl.", l);
623 if (fs->plr)
624 sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
625 else
626 plr[0] = '\0';
627 if (fs->flags_fs & DN_IS_RED) /* RED parameters */
628 sprintf(red,
629 "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
630 (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
631 1.0 * fs->w_q / (double)(1 << SCALE_RED),
632 SCALE_VAL(fs->min_th),
633 SCALE_VAL(fs->max_th),
634 1.0 * fs->max_p / (double)(1 << SCALE_RED));
635 else
636 sprintf(red, "droptail");
638 printf("%s %s%s %d queues (%d buckets) %s\n",
639 prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
642 static void
643 sysctl_handler(int ac, char *av[], int which)
645 ac--;
646 av++;
648 if (*av == NULL) {
649 warnx("missing keyword to enable/disable\n");
650 } else if (strncmp(*av, "firewall", strlen(*av)) == 0) {
651 sysctlbyname("net.inet.ip.fw.enable", NULL, 0,
652 &which, sizeof(which));
653 } else if (strncmp(*av, "one_pass", strlen(*av)) == 0) {
654 sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0,
655 &which, sizeof(which));
656 } else if (strncmp(*av, "debug", strlen(*av)) == 0) {
657 sysctlbyname("net.inet.ip.fw.debug", NULL, 0,
658 &which, sizeof(which));
659 } else if (strncmp(*av, "verbose", strlen(*av)) == 0) {
660 sysctlbyname("net.inet.ip.fw.verbose", NULL, 0,
661 &which, sizeof(which));
662 } else {
663 warnx("unrecognize enable/disable keyword: %s\n", *av);
667 static void
668 list(int ac, char *av[])
670 struct ip_fw *rules;
671 struct dn_pipe *pipes;
672 void *data = NULL;
673 int pcwidth = 0;
674 int bcwidth = 0;
675 int n, num = 0;
676 int nbytes;
678 /* get rules or pipes from kernel, resizing array as necessary */
680 const int unit = do_pipe ? sizeof(*pipes) : sizeof(*rules);
681 const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;
682 int nalloc = unit;
683 nbytes = nalloc;
685 while (nbytes >= nalloc) {
686 nalloc = nalloc * 2 + 200;
687 nbytes = nalloc;
688 if ((data = realloc(data, nbytes)) == NULL)
689 err(EX_OSERR, "realloc");
690 if (getsockopt(s, IPPROTO_IP, ocmd, data, &nbytes) < 0)
691 err(EX_OSERR, "getsockopt(IP_%s_GET)",
692 do_pipe ? "DUMMYNET" : "FW");
696 /* display requested pipes */
697 if (do_pipe) {
698 u_long rulenum;
699 void *next = data;
700 struct dn_pipe *p = (struct dn_pipe *) data;
701 struct dn_flow_set *fs;
702 struct dn_flow_queue *q;
703 int l;
705 if (ac > 0)
706 rulenum = strtoul(*av++, NULL, 10);
707 else
708 rulenum = 0;
709 for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) {
710 double b = p->bandwidth;
711 char buf[30];
712 char prefix[80];
714 if (p->next != (struct dn_pipe *)DN_IS_PIPE)
715 break;
716 l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
717 next = (void *)p + l;
718 nbytes -= l;
719 q = (struct dn_flow_queue *)(p+1);
721 if (rulenum != 0 && rulenum != p->pipe_nr)
722 continue;
723 if (p->if_name[0] != '\0')
724 sprintf(buf, "%s", p->if_name);
725 else if (b == 0)
726 sprintf(buf, "unlimited");
727 else if (b >= 1000000)
728 sprintf(buf, "%7.3f Mbit/s", b/1000000);
729 else if (b >= 1000)
730 sprintf(buf, "%7.3f Kbit/s", b/1000);
731 else
732 sprintf(buf, "%7.3f bit/s ", b);
734 sprintf(prefix, "%05d: %s %4d ms ",
735 p->pipe_nr, buf, p->delay);
736 print_flowset_parms(&(p->fs), prefix);
737 if (verbose)
738 printf(" V %20qd\n", p->V >> MY_M);
739 list_queues(&(p->fs), q);
741 fs = (struct dn_flow_set *) next;
742 for (; nbytes >= sizeof *fs; fs = (struct dn_flow_set *)next) {
743 char prefix[80];
745 if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE)
746 break;
747 l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
748 next = (void *)fs + l;
749 nbytes -= l;
750 q = (struct dn_flow_queue *)(fs+1);
751 sprintf(prefix, "q%05d: weight %d pipe %d ",
752 fs->fs_nr, fs->weight, fs->parent_nr);
753 print_flowset_parms(fs, prefix);
754 list_queues(fs, q);
756 free(data);
757 return;
760 rules = (struct ip_fw *)data;
761 /* determine num more accurately */
762 num = 0;
763 while (rules[num].fw_number < 65535)
764 num++;
765 num++; /* counting starts from 0 ... */
766 /* if showing stats, figure out column widths ahead of time */
767 if (do_acct) {
768 for (n = 0; n < num; n++) {
769 struct ip_fw *const r = &rules[n];
770 char temp[32];
771 int width;
773 /* packet counter */
774 width = sprintf(temp, "%qu", r->fw_pcnt);
775 if (width > pcwidth)
776 pcwidth = width;
778 /* byte counter */
779 width = sprintf(temp, "%qu", r->fw_bcnt);
780 if (width > bcwidth)
781 bcwidth = width;
784 if (ac == 0) {
785 /* display all rules */
786 for (n = 0; n < num; n++) {
787 struct ip_fw *const r = &rules[n];
789 show_ipfw(r, pcwidth, bcwidth);
791 } else {
792 /* display specific rules requested on command line */
793 int exitval = EX_OK;
795 while (ac--) {
796 u_long rnum;
797 char *endptr;
798 int seen;
800 /* convert command line rule # */
801 rnum = strtoul(*av++, &endptr, 10);
802 if (*endptr) {
803 exitval = EX_USAGE;
804 warnx("invalid rule number: %s", *(av - 1));
805 continue;
807 do_dynamic = 0;
808 for (seen = n = 0; n < num; n++) {
809 struct ip_fw *const r = &rules[n];
811 if (r->fw_number > rnum)
812 break;
813 if (r->fw_number == rnum) {
814 show_ipfw(r, pcwidth, bcwidth);
815 seen = 1;
818 if (!seen) {
819 /* give precedence to other error(s) */
820 if (exitval == EX_OK)
821 exitval = EX_UNAVAILABLE;
822 warnx("rule %lu does not exist", rnum);
825 if (exitval != EX_OK)
826 exit(exitval);
829 * show dynamic rules
831 if (do_dynamic && num * sizeof (rules[0]) != nbytes) {
832 struct ipfw_dyn_rule *d =
833 (struct ipfw_dyn_rule *)&rules[num];
834 struct in_addr a;
835 struct protoent *pe;
837 printf("## Dynamic rules:\n");
838 for (;; d++) {
839 if (d->expire == 0 && !do_expired) {
840 if (d->next == NULL)
841 break;
842 continue;
845 printf("%05d %qu %qu (T %d, slot %d)",
846 (int)(d->rule),
847 d->pcnt, d->bcnt,
848 d->expire,
849 d->bucket);
850 switch (d->dyn_type) {
851 case DYN_LIMIT_PARENT:
852 printf(" PARENT %d", d->count);
853 break;
854 case DYN_LIMIT:
855 printf(" LIMIT");
856 break;
857 case DYN_KEEP_STATE: /* bidir, no mask */
858 printf(" <->");
859 break;
862 pe = getprotobynumber(d->id.proto);
863 if (pe)
864 printf(" %s,", pe->p_name);
865 else
866 printf(" %u,", d->id.proto);
867 a.s_addr = htonl(d->id.src_ip);
868 printf(" %s %d", inet_ntoa(a), d->id.src_port);
869 a.s_addr = htonl(d->id.dst_ip);
870 printf("<-> %s %d", inet_ntoa(a), d->id.dst_port);
871 printf("\n");
872 if (d->next == NULL)
873 break;
877 free(data);
880 static void
881 show_usage(void)
883 fprintf(stderr, "usage: ipfw [options]\n"
884 " [pipe] flush\n"
885 " add [number] rule\n"
886 " [pipe] delete number ...\n"
887 " [pipe] list [number ...]\n"
888 " [pipe] show [number ...]\n"
889 " zero [number ...]\n"
890 " resetlog [number ...]\n"
891 " pipe number config [pipeconfig]\n"
892 " rule: [prob <match_probability>] action proto src dst extras...\n"
893 " action:\n"
894 " {allow|permit|accept|pass|deny|drop|reject|unreach code|\n"
895 " reset|count|skipto num|divert port|tee port|fwd ip|\n"
896 " pipe num} [log [logamount count]]\n"
897 " proto: {ip|tcp|udp|icmp|<number>}\n"
898 " src: from [not] {me|any|ip[{/bits|:mask}]} [{port[-port]}, [port], ...]\n"
899 " dst: to [not] {me|any|ip[{/bits|:mask}]} [{port[-port]}, [port], ...]\n"
900 " extras:\n"
901 " uid {user id}\n"
902 " gid {group id}\n"
903 " fragment (may not be used with ports or tcpflags)\n"
904 " in\n"
905 " out\n"
906 " {xmit|recv|via} {iface|ip|any}\n"
907 " {established|setup}\n"
908 " tcpflags [!]{syn|fin|rst|ack|psh|urg}, ...\n"
909 " ipoptions [!]{ssrr|lsrr|rr|ts}, ...\n"
910 " tcpoptions [!]{mss|window|sack|ts|cc}, ...\n"
911 " icmptypes {type[, type]}...\n"
912 " keep-state [method]\n"
913 " pipeconfig:\n"
914 " {bw|bandwidth} <number>{bit/s|Kbit/s|Mbit/s|Bytes/s|KBytes/s|MBytes/s}\n"
915 " {bw|bandwidth} interface_name\n"
916 " delay <milliseconds>\n"
917 " queue <size>{packets|Bytes|KBytes}\n"
918 " plr <fraction>\n"
919 " mask {all| [dst-ip|src-ip|dst-port|src-port|proto] <number>}\n"
920 " buckets <number>}\n"
921 " {red|gred} <fraction>/<number>/<number>/<fraction>\n"
922 " droptail\n"
925 exit(EX_USAGE);
928 static int
929 lookup_host (char *host, struct in_addr *ipaddr)
931 struct hostent *he;
933 if (!inet_aton(host, ipaddr)) {
934 if ((he = gethostbyname(host)) == NULL)
935 return(-1);
936 *ipaddr = *(struct in_addr *)he->h_addr_list[0];
938 return(0);
941 static void
942 fill_ip(struct in_addr *ipno, struct in_addr *mask, int *acp, char ***avp)
944 int ac = *acp;
945 char **av = *avp;
946 char *p = 0, md = 0;
948 if (ac && !strncmp(*av, "any", strlen(*av))) {
949 ipno->s_addr = mask->s_addr = 0; av++; ac--;
950 } else {
951 p = strchr(*av, '/');
952 if (!p)
953 p = strchr(*av, ':');
954 if (p) {
955 md = *p;
956 *p++ = '\0';
959 if (lookup_host(*av, ipno) != 0)
960 errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
961 switch (md) {
962 case ':':
963 if (!inet_aton(p, mask))
964 errx(EX_DATAERR, "bad netmask ``%s''", p);
965 break;
966 case '/':
967 if (atoi(p) == 0) {
968 mask->s_addr = 0;
969 } else if (atoi(p) > 32) {
970 errx(EX_DATAERR, "bad width ``%s''", p);
971 } else {
972 mask->s_addr =
973 htonl(~0 << (32 - atoi(p)));
975 break;
976 default:
977 mask->s_addr = htonl(~0);
978 break;
980 ipno->s_addr &= mask->s_addr;
981 av++;
982 ac--;
984 *acp = ac;
985 *avp = av;
988 static void
989 fill_reject_code(u_short *codep, char *str)
991 struct icmpcode *ic;
992 u_long val;
993 char *s;
995 if (str == '\0')
996 errx(EX_DATAERR, "missing unreachable code");
997 val = strtoul(str, &s, 0);
998 if (s != str && *s == '\0' && val < 0x100) {
999 *codep = val;
1000 return;
1002 for (ic = icmpcodes; ic->str; ic++)
1003 if (!strcasecmp(str, ic->str)) {
1004 *codep = ic->code;
1005 return;
1007 errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str);
1010 static void
1011 add_port(u_short *cnt, u_short *ptr, u_short off, u_short port)
1013 if (off + *cnt >= IP_FW_MAX_PORTS)
1014 errx(EX_USAGE, "too many ports (max is %d)", IP_FW_MAX_PORTS);
1015 ptr[off+*cnt] = port;
1016 (*cnt)++;
1019 static int
1020 lookup_port(const char *arg, int proto, int test, int nodash)
1022 int val;
1023 char *earg, buf[32];
1024 struct servent *s;
1025 char *p, *q;
1027 snprintf(buf, sizeof(buf), "%s", arg);
1029 for (p = q = buf; *p; *q++ = *p++) {
1030 if (*p == '\\') {
1031 if (*(p+1))
1032 p++;
1033 } else {
1034 if (*p == ',' || (nodash && *p == '-'))
1035 break;
1038 *q = '\0';
1040 val = (int) strtoul(buf, &earg, 0);
1041 if (!*buf || *earg) {
1042 char *protocol = NULL;
1044 if (proto != 0) {
1045 struct protoent *pe = getprotobynumber(proto);
1047 if (pe)
1048 protocol = pe->p_name;
1051 setservent(1);
1052 if ((s = getservbyname(buf, protocol))) {
1053 val = htons(s->s_port);
1054 } else {
1055 if (!test)
1056 errx(EX_DATAERR, "unknown port ``%s''", buf);
1057 val = -1;
1059 } else {
1060 if (val < 0 || val > 0xffff) {
1061 if (!test)
1062 errx(EX_DATAERR,
1063 "port ``%s'' out of range", buf);
1064 val = -1;
1067 return(val);
1071 * return: 0 normally, 1 if first pair is a range,
1072 * 2 if first pair is a port+mask
1074 static int
1075 fill_port(u_short *cnt, u_short *ptr, u_short off, char *arg, int proto)
1077 char *s;
1078 int initial_range = 0;
1080 for (s = arg; *s && *s != ',' && *s != '-' && *s != ':'; s++) {
1081 if (*s == '\\' && *(s+1))
1082 s++;
1084 if (*s == ':') {
1085 *s++ = '\0';
1086 if (strchr(arg, ','))
1087 errx(EX_USAGE, "port/mask must be first in list");
1088 add_port(cnt, ptr, off,
1089 *arg ? lookup_port(arg, proto, 0, 0) : 0x0000);
1090 arg = s;
1091 s = strchr(arg, ',');
1092 if (s)
1093 *s++ = '\0';
1094 add_port(cnt, ptr, off,
1095 *arg ? lookup_port(arg, proto, 0, 0) : 0xffff);
1096 arg = s;
1097 initial_range = 2;
1098 } else
1099 if (*s == '-') {
1100 *s++ = '\0';
1101 if (strchr(arg, ','))
1102 errx(EX_USAGE, "port range must be first in list");
1103 add_port(cnt, ptr, off,
1104 *arg ? lookup_port(arg, proto, 0, 0) : 0x0000);
1105 arg = s;
1106 s = strchr(arg, ',');
1107 if (s)
1108 *s++ = '\0';
1109 add_port(cnt, ptr, off,
1110 *arg ? lookup_port(arg, proto, 0, 0) : 0xffff);
1111 arg = s;
1112 initial_range = 1;
1114 while (arg != NULL) {
1115 s = strchr(arg, ',');
1116 if (s)
1117 *s++ = '\0';
1118 add_port(cnt, ptr, off, lookup_port(arg, proto, 0, 0));
1119 arg = s;
1121 return initial_range;
1124 static void
1125 fill_tcpflag(u_char *set, u_char *reset, char **vp)
1127 char *p = *vp, *q;
1128 u_char *d;
1130 while (p && *p) {
1131 struct tpcflags {
1132 char * name;
1133 u_char value;
1134 } flags[] = {
1135 { "syn", IP_FW_TCPF_SYN },
1136 { "fin", IP_FW_TCPF_FIN },
1137 { "ack", IP_FW_TCPF_ACK },
1138 { "psh", IP_FW_TCPF_PSH },
1139 { "rst", IP_FW_TCPF_RST },
1140 { "urg", IP_FW_TCPF_URG }
1142 int i;
1144 if (*p == '!') {
1145 p++;
1146 d = reset;
1147 } else {
1148 d = set;
1150 q = strchr(p, ',');
1151 if (q)
1152 *q++ = '\0';
1153 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i)
1154 if (!strncmp(p, flags[i].name, strlen(p))) {
1155 *d |= flags[i].value;
1156 break;
1158 if (i == sizeof(flags) / sizeof(flags[0]))
1159 errx(EX_DATAERR, "invalid tcp flag ``%s''", p);
1160 p = q;
1164 static void
1165 fill_tcpopts(u_char *set, u_char *reset, char **vp)
1167 char *p = *vp, *q;
1168 u_char *d;
1170 while (p && *p) {
1171 struct tpcopts {
1172 const char * name;
1173 u_char value;
1174 } opts[] = {
1175 { "mss", IP_FW_TCPOPT_MSS },
1176 { "window", IP_FW_TCPOPT_WINDOW },
1177 { "sack", IP_FW_TCPOPT_SACK },
1178 { "ts", IP_FW_TCPOPT_TS },
1179 { "cc", IP_FW_TCPOPT_CC },
1181 int i;
1183 if (*p == '!') {
1184 p++;
1185 d = reset;
1186 } else {
1187 d = set;
1189 q = strchr(p, ',');
1190 if (q)
1191 *q++ = '\0';
1192 for (i = 0; i < sizeof(opts) / sizeof(opts[0]); ++i)
1193 if (!strncmp(p, opts[i].name, strlen(p))) {
1194 *d |= opts[i].value;
1195 break;
1197 if (i == sizeof(opts) / sizeof(opts[0]))
1198 errx(EX_DATAERR, "invalid tcp option ``%s''", p);
1199 p = q;
1203 static void
1204 fill_ipopt(u_char *set, u_char *reset, char **vp)
1206 char *p = *vp, *q;
1207 u_char *d;
1209 while (p && *p) {
1210 if (*p == '!') {
1211 p++;
1212 d = reset;
1213 } else {
1214 d = set;
1216 q = strchr(p, ',');
1217 if (q)
1218 *q++ = '\0';
1219 if (!strncmp(p, "ssrr", strlen(p))) *d |= IP_FW_IPOPT_SSRR;
1220 if (!strncmp(p, "lsrr", strlen(p))) *d |= IP_FW_IPOPT_LSRR;
1221 if (!strncmp(p, "rr", strlen(p))) *d |= IP_FW_IPOPT_RR;
1222 if (!strncmp(p, "ts", strlen(p))) *d |= IP_FW_IPOPT_TS;
1223 p = q;
1227 static void
1228 fill_icmptypes(unsigned *types, char **vp, u_int *fw_flg)
1230 unsigned long icmptype;
1231 char *c = *vp;
1233 while (*c) {
1234 if (*c == ',')
1235 ++c;
1237 icmptype = strtoul(c, &c, 0);
1239 if (*c != ',' && *c != '\0')
1240 errx(EX_DATAERR, "invalid ICMP type");
1242 if (icmptype >= IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8)
1243 errx(EX_DATAERR, "ICMP type out of range");
1245 types[icmptype / (sizeof(unsigned) * 8)] |=
1246 1 << (icmptype % (sizeof(unsigned) * 8));
1247 *fw_flg |= IP_FW_F_ICMPBIT;
1251 static void
1252 delete(int ac, char *av[])
1254 struct ip_fw rule;
1255 struct dn_pipe pipe;
1256 int i;
1257 int exitval = EX_OK;
1259 memset(&rule, 0, sizeof rule);
1260 memset(&pipe, 0, sizeof pipe);
1262 av++; ac--;
1264 /* Rule number */
1265 while (ac && isdigit(**av)) {
1266 i = atoi(*av); av++; ac--;
1267 if (do_pipe) {
1268 if (do_pipe == 1)
1269 pipe.pipe_nr = i;
1270 else
1271 pipe.fs.fs_nr = i;
1272 i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_DEL,
1273 &pipe, sizeof pipe);
1274 if (i) {
1275 exitval = 1;
1276 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
1277 do_pipe == 1 ? pipe.pipe_nr :
1278 pipe.fs.fs_nr);
1280 } else {
1281 rule.fw_number = i;
1282 i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rule,
1283 sizeof rule);
1284 if (i) {
1285 exitval = EX_UNAVAILABLE;
1286 warn("rule %u: setsockopt(IP_FW_DEL)",
1287 rule.fw_number);
1291 if (exitval != EX_OK)
1292 exit(exitval);
1295 static void
1296 verify_interface(union ip_fw_if *ifu)
1298 struct ifreq ifr;
1300 strlcpy(ifr.ifr_name, ifu->fu_via_if.name, sizeof(ifr.ifr_name));
1302 if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
1303 warnx("warning: interface ``%s'' does not exist",
1304 ifr.ifr_name);
1307 static void
1308 fill_iface(char *which, union ip_fw_if *ifu, int *byname, int ac, char *arg)
1310 if (!ac)
1311 errx(EX_USAGE, "missing argument for ``%s''", which);
1313 /* Parse the interface or address */
1314 if (!strcmp(arg, "any")) {
1315 ifu->fu_via_ip.s_addr = 0;
1316 *byname = 0;
1317 } else if (!isdigit(*arg)) {
1318 *byname = 1;
1319 strlcpy(ifu->fu_via_if.name, arg, sizeof(ifu->fu_via_if.name));
1321 * We assume that strings containing '*', '?', or '['
1322 * are meant to be shell pattern.
1324 if (strpbrk(arg, "*?[") != NULL) {
1325 ifu->fu_via_if.glob = 1;
1326 } else {
1327 ifu->fu_via_if.glob = 0;
1328 verify_interface(ifu);
1330 } else if (!inet_aton(arg, &ifu->fu_via_ip)) {
1331 errx(EX_DATAERR, "bad ip address ``%s''", arg);
1332 } else
1333 *byname = 0;
1336 static unsigned long
1337 getbw(const char *str, u_short *flags, int kb)
1339 char *end;
1340 unsigned long val;
1341 int inbytes = 0;
1343 val = strtoul(str, &end, 0);
1344 if (*end == 'k' || *end == 'K') {
1345 ++end;
1346 val *= kb;
1347 } else if (*end == 'm' || *end == 'M') {
1348 ++end;
1349 val *= kb * kb;
1353 * Deal with bits or bytes or b(bits) or B(bytes). If there is no
1354 * trailer assume bits.
1356 if (strncasecmp(end, "bit", 3) == 0) {
1358 } else if (strncasecmp(end, "byte", 4) == 0) {
1359 inbytes = 1;
1360 } else if (*end == 'b') {
1362 } else if (*end == 'B') {
1363 inbytes = 1;
1367 * Return in bits if flags is NULL, else flag bits
1368 * or bytes in flags and return the unconverted value.
1370 if (inbytes && flags)
1371 *flags |= DN_QSIZE_IS_BYTES;
1372 else if (inbytes && flags == NULL)
1373 val *= 8;
1374 return(val);
1377 static void
1378 config_pipe(int ac, char **av)
1380 struct dn_pipe pipe;
1381 int i;
1382 char *end;
1384 memset(&pipe, 0, sizeof pipe);
1386 av++; ac--;
1387 /* Pipe number */
1388 if (ac && isdigit(**av)) {
1389 i = atoi(*av); av++; ac--;
1390 if (do_pipe == 1)
1391 pipe.pipe_nr = i;
1392 else
1393 pipe.fs.fs_nr = i;
1395 while (ac > 1) {
1396 if (!strncmp(*av, "plr", strlen(*av))) {
1398 double d = strtod(av[1], NULL);
1399 if (d > 1)
1400 d = 1;
1401 else if (d < 0)
1402 d = 0;
1403 pipe.fs.plr = (int)(d*0x7fffffff);
1404 av += 2;
1405 ac -= 2;
1406 } else if (!strncmp(*av, "queue", strlen(*av))) {
1407 pipe.fs.qsize = getbw(av[1], &pipe.fs.flags_fs, 1024);
1408 av += 2;
1409 ac -= 2;
1410 } else if (!strncmp(*av, "buckets", strlen(*av))) {
1411 pipe.fs.rq_size = strtoul(av[1], NULL, 0);
1412 av += 2;
1413 ac -= 2;
1414 } else if (!strncmp(*av, "mask", strlen(*av))) {
1415 /* per-flow queue, mask is dst_ip, dst_port,
1416 * src_ip, src_port, proto measured in bits
1418 u_int32_t a;
1419 void *par = NULL;
1421 pipe.fs.flow_mask.dst_ip = 0;
1422 pipe.fs.flow_mask.src_ip = 0;
1423 pipe.fs.flow_mask.dst_port = 0;
1424 pipe.fs.flow_mask.src_port = 0;
1425 pipe.fs.flow_mask.proto = 0;
1426 end = NULL;
1427 av++; ac--;
1428 if (ac >= 1 && !strncmp(*av, "all", strlen(*av))) {
1429 /* special case -- all bits are significant */
1430 pipe.fs.flow_mask.dst_ip = ~0;
1431 pipe.fs.flow_mask.src_ip = ~0;
1432 pipe.fs.flow_mask.dst_port = ~0;
1433 pipe.fs.flow_mask.src_port = ~0;
1434 pipe.fs.flow_mask.proto = ~0;
1435 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1436 av++;
1437 ac--;
1438 continue;
1440 while (ac >= 1) {
1441 int len = strlen(*av);
1443 if (!strncmp(*av, "dst-ip", len))
1444 par = &pipe.fs.flow_mask.dst_ip;
1445 else if (!strncmp(*av, "src-ip", len))
1446 par = &pipe.fs.flow_mask.src_ip;
1447 else if (!strncmp(*av, "dst-port", len))
1448 par = &pipe.fs.flow_mask.dst_port;
1449 else if (!strncmp(*av, "src-port", len))
1450 par = &pipe.fs.flow_mask.src_port;
1451 else if (!strncmp(*av, "proto", len))
1452 par = &pipe.fs.flow_mask.proto;
1453 else
1454 break;
1455 if (ac < 2)
1456 errx(EX_USAGE, "mask: %s value"
1457 " missing", *av);
1458 if (*av[1] == '/') {
1459 a = strtoul(av[1]+1, &end, 0);
1460 if (a == 32) /* special case... */
1461 a = ~0;
1462 else
1463 a = (1 << a) - 1;
1464 fprintf(stderr, " mask is 0x%08x\n", a);
1465 } else {
1466 a = strtoul(av[1], &end, 0);
1468 if (par == &pipe.fs.flow_mask.src_port
1469 || par == &pipe.fs.flow_mask.dst_port) {
1470 if (a >= (1 << 16))
1471 errx(EX_DATAERR, "mask: %s"
1472 " must be 16 bit, not"
1473 " 0x%08x", *av, a);
1474 *((u_int16_t *)par) = (u_int16_t)a;
1475 } else if (par == &pipe.fs.flow_mask.proto) {
1476 if (a >= (1 << 8))
1477 errx(EX_DATAERR, "mask: %s"
1478 " must be"
1479 " 8 bit, not 0x%08x",
1480 *av, a);
1481 *((u_int8_t *)par) = (u_int8_t)a;
1482 } else
1483 *((u_int32_t *)par) = a;
1484 if (a != 0)
1485 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1486 av += 2;
1487 ac -= 2;
1488 } /* end for */
1489 } else if (!strncmp(*av, "red", strlen(*av))
1490 || !strncmp(*av, "gred", strlen(*av))) {
1491 /* RED enabled */
1492 pipe.fs.flags_fs |= DN_IS_RED;
1493 if (*av[0] == 'g')
1494 pipe.fs.flags_fs |= DN_IS_GENTLE_RED;
1495 if ((end = strsep(&av[1], "/"))) {
1496 double w_q = strtod(end, NULL);
1497 if (w_q > 1 || w_q <= 0)
1498 errx(EX_DATAERR, "w_q %f must be "
1499 "0 < x <= 1", w_q);
1500 pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED));
1502 if ((end = strsep(&av[1], "/"))) {
1503 pipe.fs.min_th = strtoul(end, &end, 0);
1504 if (*end == 'K' || *end == 'k')
1505 pipe.fs.min_th *= 1024;
1507 if ((end = strsep(&av[1], "/"))) {
1508 pipe.fs.max_th = strtoul(end, &end, 0);
1509 if (*end == 'K' || *end == 'k')
1510 pipe.fs.max_th *= 1024;
1512 if ((end = strsep(&av[1], "/"))) {
1513 double max_p = strtod(end, NULL);
1514 if (max_p > 1 || max_p <= 0)
1515 errx(EX_DATAERR, "max_p %f must be "
1516 "0 < x <= 1", max_p);
1517 pipe.fs.max_p =
1518 (int)(max_p * (1 << SCALE_RED));
1520 av += 2;
1521 ac -= 2;
1522 } else if (!strncmp(*av, "droptail", strlen(*av))) {
1523 /* DROPTAIL */
1524 pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
1525 av += 1;
1526 ac -= 1;
1527 } else {
1528 int len = strlen(*av);
1529 if (do_pipe == 1) {
1530 /* some commands are only good for pipes. */
1531 if (!strncmp(*av, "bw", len)
1532 || !strncmp(*av, "bandwidth", len)) {
1533 if (av[1][0] >= 'a'
1534 && av[1][0] <= 'z') {
1535 int l = sizeof(pipe.if_name)-1;
1536 /* interface name */
1537 strncpy(pipe.if_name, av[1], l);
1538 pipe.if_name[l] = '\0';
1539 pipe.bandwidth = 0;
1540 } else {
1541 pipe.if_name[0] = '\0';
1542 pipe.bandwidth =
1543 getbw(av[1], NULL, 1000);
1545 if (pipe.bandwidth < 0)
1546 errx(EX_DATAERR,
1547 "bandwidth too large");
1548 av += 2;
1549 ac -= 2;
1550 } else if (!strncmp(*av, "delay", len)) {
1551 pipe.delay = strtoul(av[1], NULL, 0);
1552 av += 2;
1553 ac -= 2;
1554 } else {
1555 errx(EX_DATAERR, "unrecognised pipe"
1556 " option ``%s''", *av);
1558 } else { /* this refers to a queue */
1559 if (!strncmp(*av, "weight", len)) {
1560 pipe.fs.weight =
1561 strtoul(av[1], &end, 0);
1562 av += 2;
1563 ac -= 2;
1564 } else if (!strncmp(*av, "pipe", len)) {
1565 pipe.fs.parent_nr =
1566 strtoul(av[1], &end, 0);
1567 av += 2;
1568 ac -= 2;
1569 } else {
1570 errx(EX_DATAERR, "unrecognised option "
1571 "``%s''", *av);
1576 if (do_pipe == 1) {
1577 if (pipe.pipe_nr == 0)
1578 errx(EX_DATAERR, "pipe_nr %d must be > 0",
1579 pipe.pipe_nr);
1580 if (pipe.delay > 10000)
1581 errx(EX_DATAERR, "delay %d must be < 10000",
1582 pipe.delay);
1583 } else { /* do_pipe == 2, queue */
1584 if (pipe.fs.parent_nr == 0)
1585 errx(EX_DATAERR, "pipe %d must be > 0",
1586 pipe.fs.parent_nr);
1587 if (pipe.fs.weight >100)
1588 errx(EX_DATAERR, "weight %d must be <= 100",
1589 pipe.fs.weight);
1591 if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) {
1592 if (pipe.fs.qsize > 1024*1024)
1593 errx(EX_DATAERR, "queue size %d, must be < 1MB",
1594 pipe.fs.qsize);
1595 } else {
1596 if (pipe.fs.qsize > 100)
1597 errx(EX_DATAERR, "queue size %d, must be"
1598 " 2 <= x <= 100", pipe.fs.qsize);
1600 if (pipe.fs.flags_fs & DN_IS_RED) {
1601 size_t len;
1602 int lookup_depth, avg_pkt_size;
1603 double s, idle, weight, w_q;
1604 struct clockinfo clock;
1605 int t;
1607 if (pipe.fs.min_th >= pipe.fs.max_th)
1608 errx(EX_DATAERR, "min_th %d must be < than max_th %d",
1609 pipe.fs.min_th, pipe.fs.max_th);
1610 if (pipe.fs.max_th == 0)
1611 errx(EX_DATAERR, "max_th must be > 0");
1613 len = sizeof(int);
1614 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
1615 &lookup_depth, &len, NULL, 0) == -1)
1617 errx(1, "sysctlbyname(\"%s\")",
1618 "net.inet.ip.dummynet.red_lookup_depth");
1619 if (lookup_depth == 0)
1620 errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
1621 " must be greater than zero");
1623 len = sizeof(int);
1624 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
1625 &avg_pkt_size, &len, NULL, 0) == -1)
1627 errx(1, "sysctlbyname(\"%s\")",
1628 "net.inet.ip.dummynet.red_avg_pkt_size");
1629 if (avg_pkt_size == 0)
1630 errx(EX_DATAERR,
1631 "net.inet.ip.dummynet.red_avg_pkt_size must"
1632 " be greater than zero");
1634 len = sizeof(struct clockinfo);
1635 if (sysctlbyname("kern.clockrate", &clock, &len, NULL, 0) == -1)
1636 errx(1, "sysctlbyname(\"%s\")",
1637 "kern.clockrate");
1640 * Ticks needed for sending a medium-sized packet.
1641 * Unfortunately, when we are configuring a WF2Q+ queue, we
1642 * do not have bandwidth information, because that is stored
1643 * in the parent pipe, and also we have multiple queues
1644 * competing for it. So we set s=0, which is not very
1645 * correct. But on the other hand, why do we want RED with
1646 * WF2Q+ ?
1648 if (pipe.bandwidth==0) /* this is a WF2Q+ queue */
1649 s = 0;
1650 else
1651 s = clock.hz * avg_pkt_size * 8 / pipe.bandwidth;
1654 * max idle time (in ticks) before avg queue size
1655 * becomes 0.
1656 * NOTA: (3/w_q) is approx the value x so that
1657 * (1-w_q)^x < 10^-3.
1659 w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED);
1660 idle = s * 3. / w_q;
1661 pipe.fs.lookup_step = (int)idle / lookup_depth;
1662 if (!pipe.fs.lookup_step)
1663 pipe.fs.lookup_step = 1;
1664 weight = 1 - w_q;
1665 for (t = pipe.fs.lookup_step; t > 0; --t)
1666 weight *= weight;
1667 pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
1669 i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_CONFIGURE, &pipe,
1670 sizeof pipe);
1671 if (i)
1672 err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
1675 static void
1676 add(int ac, char *av[])
1678 struct ip_fw rule;
1679 int i;
1680 u_char proto;
1681 struct protoent *pe;
1682 int saw_xmrc = 0, saw_via = 0;
1684 memset(&rule, 0, sizeof rule);
1686 av++; ac--;
1688 /* Rule number */
1689 if (ac && isdigit(**av)) {
1690 rule.fw_number = atoi(*av); av++; ac--;
1693 /* Action */
1694 if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) {
1695 double d = strtod(av[1], NULL);
1696 if (d <= 0 || d > 1)
1697 errx(EX_DATAERR, "illegal match prob. %s", av[1]);
1698 if (d != 1) { /* 1 means always match */
1699 rule.fw_flg |= IP_FW_F_RND_MATCH;
1700 rule.dont_match_prob = (long)((1 - d) * 0x7fffffff);
1702 av += 2; ac -= 2;
1705 if (ac == 0)
1706 errx(EX_USAGE, "missing action");
1707 if (!strncmp(*av, "accept", strlen(*av))
1708 || !strncmp(*av, "pass", strlen(*av))
1709 || !strncmp(*av, "allow", strlen(*av))
1710 || !strncmp(*av, "permit", strlen(*av))) {
1711 rule.fw_flg |= IP_FW_F_ACCEPT; av++; ac--;
1712 } else if (!strncmp(*av, "count", strlen(*av))) {
1713 rule.fw_flg |= IP_FW_F_COUNT; av++; ac--;
1714 } else if (!strncmp(*av, "pipe", strlen(*av))) {
1715 rule.fw_flg |= IP_FW_F_PIPE; av++; ac--;
1716 if (!ac)
1717 errx(EX_USAGE, "missing pipe number");
1718 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1719 } else if (!strncmp(*av, "queue", strlen(*av))) {
1720 rule.fw_flg |= IP_FW_F_QUEUE; av++; ac--;
1721 if (!ac)
1722 errx(EX_USAGE, "missing queue number");
1723 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1724 } else if (!strncmp(*av, "divert", strlen(*av))) {
1725 rule.fw_flg |= IP_FW_F_DIVERT; av++; ac--;
1726 if (!ac)
1727 errx(EX_USAGE, "missing %s port", "divert");
1728 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1729 if (rule.fw_divert_port == 0) {
1730 struct servent *s;
1731 setservent(1);
1732 s = getservbyname(av[-1], "divert");
1733 if (s != NULL)
1734 rule.fw_divert_port = ntohs(s->s_port);
1735 else
1736 errx(EX_DATAERR, "illegal %s port", "divert");
1738 } else if (!strncmp(*av, "tee", strlen(*av))) {
1739 rule.fw_flg |= IP_FW_F_TEE; av++; ac--;
1740 if (!ac)
1741 errx(EX_USAGE, "missing %s port", "tee divert");
1742 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1743 if (rule.fw_divert_port == 0) {
1744 struct servent *s;
1745 setservent(1);
1746 s = getservbyname(av[-1], "divert");
1747 if (s != NULL)
1748 rule.fw_divert_port = ntohs(s->s_port);
1749 else
1750 errx(EX_DATAERR, "illegal %s port",
1751 "tee divert");
1753 } else if (!strncmp(*av, "fwd", strlen(*av))
1754 || !strncmp(*av, "forward", strlen(*av))) {
1755 struct in_addr dummyip;
1756 char *pp;
1757 rule.fw_flg |= IP_FW_F_FWD; av++; ac--;
1758 if (!ac)
1759 errx(EX_USAGE, "missing forwarding IP address");
1760 rule.fw_fwd_ip.sin_len = sizeof(struct sockaddr_in);
1761 rule.fw_fwd_ip.sin_family = AF_INET;
1762 rule.fw_fwd_ip.sin_port = 0;
1763 pp = strchr(*av, ':');
1764 if(pp == NULL)
1765 pp = strchr(*av, ',');
1766 if(pp != NULL)
1768 *(pp++) = '\0';
1769 i = lookup_port(pp, 0, 1, 0);
1770 if (i == -1)
1771 errx(EX_DATAERR, "illegal forwarding"
1772 " port ``%s''", pp);
1773 else
1774 rule.fw_fwd_ip.sin_port = (u_short)i;
1776 fill_ip(&(rule.fw_fwd_ip.sin_addr), &dummyip, &ac, &av);
1777 if (rule.fw_fwd_ip.sin_addr.s_addr == 0)
1778 errx(EX_DATAERR, "illegal forwarding IP address");
1780 } else if (!strncmp(*av, "skipto", strlen(*av))) {
1781 rule.fw_flg |= IP_FW_F_SKIPTO; av++; ac--;
1782 if (!ac)
1783 errx(EX_USAGE, "missing skipto rule number");
1784 rule.fw_skipto_rule = strtoul(*av, NULL, 10); av++; ac--;
1785 } else if ((!strncmp(*av, "deny", strlen(*av))
1786 || !strncmp(*av, "drop", strlen(*av)))) {
1787 rule.fw_flg |= IP_FW_F_DENY; av++; ac--;
1788 } else if (!strncmp(*av, "reject", strlen(*av))) {
1789 rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
1790 rule.fw_reject_code = ICMP_UNREACH_HOST;
1791 } else if (!strncmp(*av, "reset", strlen(*av))) {
1792 rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
1793 rule.fw_reject_code = IP_FW_REJECT_RST; /* check TCP later */
1794 } else if (!strncmp(*av, "unreach", strlen(*av))) {
1795 rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
1796 fill_reject_code(&rule.fw_reject_code, *av); av++; ac--;
1797 } else if (!strncmp(*av, "check-state", strlen(*av))) {
1798 rule.fw_flg |= IP_FW_F_CHECK_S; av++; ac--;
1799 goto done;
1800 } else {
1801 errx(EX_DATAERR, "invalid action ``%s''", *av);
1804 /* [log] */
1805 if (ac && !strncmp(*av, "log", strlen(*av))) {
1806 rule.fw_flg |= IP_FW_F_PRN; av++; ac--;
1808 if (ac && !strncmp(*av, "logamount", strlen(*av))) {
1809 if (!(rule.fw_flg & IP_FW_F_PRN))
1810 errx(EX_USAGE, "``logamount'' not valid without"
1811 " ``log''");
1812 ac--; av++;
1813 if (!ac)
1814 errx(EX_USAGE, "``logamount'' requires argument");
1815 rule.fw_logamount = atoi(*av);
1816 if (rule.fw_logamount < 0)
1817 errx(EX_DATAERR, "``logamount'' argument must be"
1818 " positive");
1819 if (rule.fw_logamount == 0)
1820 rule.fw_logamount = -1;
1821 ac--; av++;
1824 /* protocol */
1825 if (ac == 0)
1826 errx(EX_USAGE, "missing protocol");
1827 if ((proto = atoi(*av)) > 0) {
1828 rule.fw_prot = proto; av++; ac--;
1829 } else if (!strncmp(*av, "all", strlen(*av))) {
1830 rule.fw_prot = IPPROTO_IP; av++; ac--;
1831 } else if ((pe = getprotobyname(*av)) != NULL) {
1832 rule.fw_prot = pe->p_proto; av++; ac--;
1833 } else {
1834 errx(EX_DATAERR, "invalid protocol ``%s''", *av);
1837 if (rule.fw_prot != IPPROTO_TCP
1838 && (rule.fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
1839 && rule.fw_reject_code == IP_FW_REJECT_RST)
1840 errx(EX_DATAERR, "``reset'' is only valid for tcp packets");
1842 /* from */
1843 if (ac && !strncmp(*av, "from", strlen(*av))) { av++; ac--; }
1844 else
1845 errx(EX_USAGE, "missing ``from''");
1847 if (ac && !strncmp(*av, "not", strlen(*av))) {
1848 rule.fw_flg |= IP_FW_F_INVSRC;
1849 av++; ac--;
1851 if (!ac)
1852 errx(EX_USAGE, "missing arguments");
1854 if (ac && !strncmp(*av, "me", strlen(*av))) {
1855 rule.fw_flg |= IP_FW_F_SME;
1856 av++; ac--;
1857 } else {
1858 fill_ip(&rule.fw_src, &rule.fw_smsk, &ac, &av);
1861 if (ac && (isdigit(**av)
1862 || lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) {
1863 u_short nports = 0;
1864 int retval;
1866 retval = fill_port(&nports, rule.fw_uar.fw_pts,
1867 0, *av, rule.fw_prot);
1868 if (retval == 1)
1869 rule.fw_flg |= IP_FW_F_SRNG;
1870 else if (retval == 2)
1871 rule.fw_flg |= IP_FW_F_SMSK;
1872 IP_FW_SETNSRCP(&rule, nports);
1873 av++; ac--;
1876 /* to */
1877 if (ac && !strncmp(*av, "to", strlen(*av))) { av++; ac--; }
1878 else
1879 errx(EX_USAGE, "missing ``to''");
1881 if (ac && !strncmp(*av, "not", strlen(*av))) {
1882 rule.fw_flg |= IP_FW_F_INVDST;
1883 av++; ac--;
1885 if (!ac)
1886 errx(EX_USAGE, "missing arguments");
1889 if (ac && !strncmp(*av, "me", strlen(*av))) {
1890 rule.fw_flg |= IP_FW_F_DME;
1891 av++; ac--;
1892 } else {
1893 fill_ip(&rule.fw_dst, &rule.fw_dmsk, &ac, &av);
1896 if (ac && (isdigit(**av)
1897 || lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) {
1898 u_short nports = 0;
1899 int retval;
1901 retval = fill_port(&nports, rule.fw_uar.fw_pts,
1902 IP_FW_GETNSRCP(&rule), *av, rule.fw_prot);
1903 if (retval == 1)
1904 rule.fw_flg |= IP_FW_F_DRNG;
1905 else if (retval == 2)
1906 rule.fw_flg |= IP_FW_F_DMSK;
1907 IP_FW_SETNDSTP(&rule, nports);
1908 av++; ac--;
1911 if ((rule.fw_prot != IPPROTO_TCP) && (rule.fw_prot != IPPROTO_UDP)
1912 && (IP_FW_GETNSRCP(&rule) || IP_FW_GETNDSTP(&rule))) {
1913 errx(EX_USAGE, "only TCP and UDP protocols are valid"
1914 " with port specifications");
1917 while (ac) {
1918 if (!strncmp(*av, "uid", strlen(*av))) {
1919 struct passwd *pwd;
1920 char *end;
1921 uid_t uid;
1923 rule.fw_flg |= IP_FW_F_UID;
1924 ac--; av++;
1925 if (!ac)
1926 errx(EX_USAGE, "``uid'' requires argument");
1928 uid = strtoul(*av, &end, 0);
1929 if (*end == '\0')
1930 pwd = getpwuid(uid);
1931 else
1932 pwd = getpwnam(*av);
1933 if (pwd == NULL)
1934 errx(EX_DATAERR, "uid \"%s\" is"
1935 " nonexistent", *av);
1936 rule.fw_uid = pwd->pw_uid;
1937 ac--; av++;
1938 } else if (!strncmp(*av, "gid", strlen(*av))) {
1939 struct group *grp;
1940 char *end;
1941 gid_t gid;
1943 rule.fw_flg |= IP_FW_F_GID;
1944 ac--; av++;
1945 if (!ac)
1946 errx(EX_USAGE, "``gid'' requires argument");
1948 gid = strtoul(*av, &end, 0);
1949 if (*end == '\0')
1950 grp = getgrgid(gid);
1951 else
1952 grp = getgrnam(*av);
1953 if (grp == NULL)
1954 errx(EX_DATAERR, "gid \"%s\" is"
1955 " nonexistent", *av);
1956 rule.fw_gid = grp->gr_gid;
1957 ac--; av++;
1958 } else if (!strncmp(*av, "in", strlen(*av))) {
1959 rule.fw_flg |= IP_FW_F_IN;
1960 av++; ac--;
1961 } else if (!strncmp(*av,"limit",strlen(*av))) {
1962 /* dyn. rule used to limit number of connections. */
1963 rule.fw_flg |= IP_FW_F_KEEP_S;
1964 rule.dyn_type = DYN_LIMIT ;
1965 rule.limit_mask = 0 ;
1966 av++; ac--;
1967 for (; ac >1 ;) {
1968 struct _s_x *p = limit_masks;
1969 for ( ; p->s != NULL ; p++)
1970 if (!strncmp(*av, p->s, strlen(*av))) {
1971 rule.limit_mask |= p->x ;
1972 av++; ac-- ;
1973 break ;
1975 if (p->s == NULL)
1976 break ;
1978 if (ac < 1)
1979 errx(EX_USAGE,
1980 "limit needs mask and # of connections");
1981 rule.conn_limit = atoi(*av);
1982 if (rule.conn_limit == 0)
1983 errx(EX_USAGE, "limit: limit must be >0");
1984 if (rule.limit_mask == 0)
1985 errx(EX_USAGE, "missing limit mask");
1986 av++; ac--;
1987 } else if (!strncmp(*av, "keep-state", strlen(*av))) {
1988 u_long type;
1989 rule.fw_flg |= IP_FW_F_KEEP_S;
1991 av++; ac--;
1992 if (ac > 0 && (type = atoi(*av)) != 0) {
1993 rule.dyn_type = type;
1994 av++; ac--;
1996 } else if (!strncmp(*av, "out", strlen(*av))) {
1997 rule.fw_flg |= IP_FW_F_OUT;
1998 av++; ac--;
1999 } else if (ac && !strncmp(*av, "xmit", strlen(*av))) {
2000 union ip_fw_if ifu;
2001 int byname;
2003 if (saw_via) {
2004 badviacombo:
2005 errx(EX_USAGE, "``via'' is incompatible"
2006 " with ``xmit'' and ``recv''");
2008 saw_xmrc = 1;
2009 av++; ac--;
2010 fill_iface("xmit", &ifu, &byname, ac, *av);
2011 rule.fw_out_if = ifu;
2012 rule.fw_flg |= IP_FW_F_OIFACE;
2013 if (byname)
2014 rule.fw_flg |= IP_FW_F_OIFNAME;
2015 av++; ac--;
2016 } else if (ac && !strncmp(*av, "recv", strlen(*av))) {
2017 union ip_fw_if ifu;
2018 int byname;
2020 if (saw_via)
2021 goto badviacombo;
2022 saw_xmrc = 1;
2023 av++; ac--;
2024 fill_iface("recv", &ifu, &byname, ac, *av);
2025 rule.fw_in_if = ifu;
2026 rule.fw_flg |= IP_FW_F_IIFACE;
2027 if (byname)
2028 rule.fw_flg |= IP_FW_F_IIFNAME;
2029 av++; ac--;
2030 } else if (ac && !strncmp(*av, "via", strlen(*av))) {
2031 union ip_fw_if ifu;
2032 int byname = 0;
2034 if (saw_xmrc)
2035 goto badviacombo;
2036 saw_via = 1;
2037 av++; ac--;
2038 fill_iface("via", &ifu, &byname, ac, *av);
2039 rule.fw_out_if = rule.fw_in_if = ifu;
2040 if (byname)
2041 rule.fw_flg |=
2042 (IP_FW_F_IIFNAME | IP_FW_F_OIFNAME);
2043 av++; ac--;
2044 } else if (!strncmp(*av, "fragment", strlen(*av))) {
2045 rule.fw_flg |= IP_FW_F_FRAG;
2046 av++; ac--;
2047 } else if (!strncmp(*av, "ipoptions", strlen(*av))) {
2048 av++; ac--;
2049 if (!ac)
2050 errx(EX_USAGE, "missing argument"
2051 " for ``ipoptions''");
2052 fill_ipopt(&rule.fw_ipopt, &rule.fw_ipnopt, av);
2053 av++; ac--;
2054 } else if (rule.fw_prot == IPPROTO_TCP) {
2055 if (!strncmp(*av, "established", strlen(*av))) {
2056 rule.fw_ipflg |= IP_FW_IF_TCPEST;
2057 av++; ac--;
2058 } else if (!strncmp(*av, "setup", strlen(*av))) {
2059 rule.fw_tcpf |= IP_FW_TCPF_SYN;
2060 rule.fw_tcpnf |= IP_FW_TCPF_ACK;
2061 av++; ac--;
2062 } else if (!strncmp(*av, "tcpflags", strlen(*av))
2063 || !strncmp(*av, "tcpflgs", strlen(*av))) {
2064 av++; ac--;
2065 if (!ac)
2066 errx(EX_USAGE, "missing argument"
2067 " for ``tcpflags''");
2068 fill_tcpflag(&rule.fw_tcpf,
2069 &rule.fw_tcpnf, av);
2070 av++; ac--;
2071 } else if (!strncmp(*av, "tcpoptions", strlen(*av))
2072 || !strncmp(*av, "tcpopts", strlen(*av))) {
2073 av++; ac--;
2074 if (!ac)
2075 errx(EX_USAGE, "missing argument"
2076 " for ``tcpoptions''");
2077 fill_tcpopts(&rule.fw_tcpopt,
2078 &rule.fw_tcpnopt, av);
2079 av++; ac--;
2080 } else {
2081 errx(EX_USAGE, "unknown or out of order"
2082 " argument ``%s''", *av);
2084 } else if (rule.fw_prot == IPPROTO_ICMP) {
2085 if (!strncmp(*av, "icmptypes", strlen(*av))) {
2086 av++; ac--;
2087 if (!ac)
2088 errx(EX_USAGE, "missing argument"
2089 " for ``icmptypes''");
2090 fill_icmptypes(rule.fw_uar.fw_icmptypes,
2091 av, &rule.fw_flg);
2092 av++; ac--;
2093 } else {
2094 errx(EX_USAGE, "unknown or out of order"
2095 " argument ``%s''", *av);
2097 } else {
2098 errx(EX_USAGE, "unknown argument ``%s''", *av);
2102 /* No direction specified -> do both directions */
2103 if (!(rule.fw_flg & (IP_FW_F_OUT|IP_FW_F_IN)))
2104 rule.fw_flg |= (IP_FW_F_OUT|IP_FW_F_IN);
2106 /* Sanity check interface check, but handle "via" case separately */
2107 if (saw_via) {
2108 if (rule.fw_flg & IP_FW_F_IN)
2109 rule.fw_flg |= IP_FW_F_IIFACE;
2110 if (rule.fw_flg & IP_FW_F_OUT)
2111 rule.fw_flg |= IP_FW_F_OIFACE;
2112 } else if ((rule.fw_flg & IP_FW_F_OIFACE)
2113 && (rule.fw_flg & IP_FW_F_IN)) {
2114 errx(EX_DATAERR, "can't check xmit interface of incoming"
2115 " packets");
2118 /* frag may not be used in conjunction with ports or TCP flags */
2119 if (rule.fw_flg & IP_FW_F_FRAG) {
2120 if (rule.fw_tcpf || rule.fw_tcpnf)
2121 errx(EX_DATAERR, "can't mix 'frag' and tcpflags");
2123 if (rule.fw_nports)
2124 errx(EX_DATAERR, "can't mix 'frag' and port"
2125 " specifications");
2127 if (rule.fw_flg & IP_FW_F_PRN) {
2128 if (!rule.fw_logamount) {
2129 size_t len = sizeof(int);
2131 if (sysctlbyname("net.inet.ip.fw.verbose_limit",
2132 &rule.fw_logamount, &len, NULL, 0) == -1)
2133 errx(1, "sysctlbyname(\"%s\")",
2134 "net.inet.ip.fw.verbose_limit");
2135 } else if (rule.fw_logamount == -1)
2136 rule.fw_logamount = 0;
2137 rule.fw_loghighest = rule.fw_logamount;
2139 done:
2140 i = sizeof(rule);
2141 if (getsockopt(s, IPPROTO_IP, IP_FW_ADD, &rule, &i) == -1)
2142 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
2143 if (!do_quiet)
2144 show_ipfw(&rule, 10, 10);
2147 static void
2148 zero (int ac, char *av[])
2150 struct ip_fw rule;
2151 int failed = EX_OK;
2153 av++; ac--;
2155 if (!ac) {
2156 /* clear all entries */
2157 if (setsockopt(s, IPPROTO_IP, IP_FW_ZERO, NULL, 0) < 0)
2158 err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_ZERO");
2159 if (!do_quiet)
2160 printf("Accounting cleared.\n");
2162 return;
2165 memset(&rule, 0, sizeof rule);
2166 while (ac) {
2167 /* Rule number */
2168 if (isdigit(**av)) {
2169 rule.fw_number = atoi(*av); av++; ac--;
2170 if (setsockopt(s, IPPROTO_IP,
2171 IP_FW_ZERO, &rule, sizeof rule)) {
2172 warn("rule %u: setsockopt(IP_FW_ZERO)",
2173 rule.fw_number);
2174 failed = EX_UNAVAILABLE;
2175 } else if (!do_quiet)
2176 printf("Entry %d cleared\n",
2177 rule.fw_number);
2178 } else {
2179 errx(EX_USAGE, "invalid rule number ``%s''", *av);
2182 if (failed != EX_OK)
2183 exit(failed);
2186 static void
2187 resetlog (int ac, char *av[])
2189 struct ip_fw rule;
2190 int failed = EX_OK;
2192 av++; ac--;
2194 if (!ac) {
2195 /* clear all entries */
2196 if (setsockopt(s, IPPROTO_IP, IP_FW_RESETLOG, NULL, 0) < 0)
2197 err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)");
2198 if (!do_quiet)
2199 printf("Logging counts reset.\n");
2201 return;
2204 memset(&rule, 0, sizeof rule);
2205 while (ac) {
2206 /* Rule number */
2207 if (isdigit(**av)) {
2208 rule.fw_number = atoi(*av); av++; ac--;
2209 if (setsockopt(s, IPPROTO_IP,
2210 IP_FW_RESETLOG, &rule, sizeof rule)) {
2211 warn("rule %u: setsockopt(IP_FW_RESETLOG)",
2212 rule.fw_number);
2213 failed = EX_UNAVAILABLE;
2214 } else if (!do_quiet)
2215 printf("Entry %d logging count reset\n",
2216 rule.fw_number);
2217 } else {
2218 errx(EX_DATAERR, "invalid rule number ``%s''", *av);
2221 if (failed != EX_OK)
2222 exit(failed);
2225 static int
2226 ipfw_main(int ac, char **av)
2228 int ch;
2230 if (ac == 1)
2231 show_usage();
2233 /* Initialize globals. */
2234 do_resolv = do_acct = do_time = do_quiet =
2235 do_pipe = do_sort = verbose = 0;
2237 /* Set the force flag for non-interactive processes */
2238 do_force = !isatty(STDIN_FILENO);
2240 optind = optreset = 1;
2241 while ((ch = getopt(ac, av, "s:adefNqtv")) != -1)
2242 switch (ch) {
2243 case 's': /* sort */
2244 do_sort = atoi(optarg);
2245 break;
2246 case 'a':
2247 do_acct = 1;
2248 break;
2249 case 'd':
2250 do_dynamic = 1;
2251 break;
2252 case 'e':
2253 do_expired = 1;
2254 break;
2255 case 'f':
2256 do_force = 1;
2257 break;
2258 case 'N':
2259 do_resolv = 1;
2260 break;
2261 case 'q':
2262 do_quiet = 1;
2263 break;
2264 case 't':
2265 do_time = 1;
2266 break;
2267 case 'v': /* verbose */
2268 verbose++;
2269 break;
2270 default:
2271 show_usage();
2274 ac -= optind;
2275 if (*(av += optind) == NULL)
2276 errx(EX_USAGE, "bad arguments, for usage summary ``ipfw''");
2278 if (!strncmp(*av, "pipe", strlen(*av))) {
2279 do_pipe = 1;
2280 ac--;
2281 av++;
2282 } else if (!strncmp(*av, "queue", strlen(*av))) {
2283 do_pipe = 2;
2284 ac--;
2285 av++;
2287 if (!ac)
2288 errx(EX_USAGE, "pipe requires arguments");
2290 /* allow argument swapping */
2291 if (ac > 1 && *av[0] >= '0' && *av[0] <= '9') {
2292 char *p = av[0];
2293 av[0] = av[1];
2294 av[1] = p;
2296 if (!strncmp(*av, "add", strlen(*av))) {
2297 add(ac, av);
2298 } else if (do_pipe && !strncmp(*av, "config", strlen(*av))) {
2299 config_pipe(ac, av);
2300 } else if (!strncmp(*av, "delete", strlen(*av))) {
2301 delete(ac, av);
2302 } else if (!strncmp(*av, "flush", strlen(*av))) {
2303 int do_flush = 0;
2305 if (do_force || do_quiet)
2306 do_flush = 1;
2307 else {
2308 int c;
2310 /* Ask the user */
2311 printf("Are you sure? [yn] ");
2312 fflush(stdout);
2313 do {
2314 c = toupper(getc(stdin));
2315 while (c != '\n' && getc(stdin) != '\n')
2316 if (feof(stdin))
2317 return (0);
2318 } while (c != 'Y' && c != 'N');
2319 printf("\n");
2320 if (c == 'Y')
2321 do_flush = 1;
2323 if (do_flush) {
2324 if (setsockopt(s, IPPROTO_IP,
2325 do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH,
2326 NULL, 0) < 0)
2327 err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)",
2328 do_pipe ? "DUMMYNET" : "FW");
2329 if (!do_quiet)
2330 printf("Flushed all %s.\n",
2331 do_pipe ? "pipes" : "rules");
2333 } else if (!strncmp(*av, "zero", strlen(*av))) {
2334 zero(ac, av);
2335 } else if (!strncmp(*av, "resetlog", strlen(*av))) {
2336 resetlog(ac, av);
2337 } else if (!strncmp(*av, "print", strlen(*av))) {
2338 list(--ac, ++av);
2339 } else if (!strncmp(*av, "enable", strlen(*av))) {
2340 sysctl_handler(ac, av, 1);
2341 } else if (!strncmp(*av, "disable", strlen(*av))) {
2342 sysctl_handler(ac, av, 0);
2343 } else if (!strncmp(*av, "list", strlen(*av))) {
2344 list(--ac, ++av);
2345 } else if (!strncmp(*av, "show", strlen(*av))) {
2346 do_acct++;
2347 list(--ac, ++av);
2348 } else {
2349 errx(EX_USAGE, "bad arguments, for usage summary ``ipfw''");
2351 return 0;
2355 main(int ac, char *av[])
2357 #define MAX_ARGS 32
2358 #define WHITESP " \t\f\v\n\r"
2359 char buf[BUFSIZ];
2360 char *a, *p, *args[MAX_ARGS], *cmd = NULL;
2361 char linename[10];
2362 int i, c, lineno, qflag, pflag, status;
2363 FILE *f = NULL;
2364 pid_t preproc = 0;
2366 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2367 if (s < 0)
2368 err(EX_UNAVAILABLE, "socket");
2370 setbuf(stdout, 0);
2373 * Only interpret the last command line argument as a file to
2374 * be preprocessed if it is specified as an absolute pathname.
2377 if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) {
2378 qflag = pflag = i = 0;
2379 lineno = 0;
2381 while ((c = getopt(ac, av, "D:U:p:q")) != -1)
2382 switch(c) {
2383 case 'D':
2384 if (!pflag)
2385 errx(EX_USAGE, "-D requires -p");
2386 if (i > MAX_ARGS - 2)
2387 errx(EX_USAGE,
2388 "too many -D or -U options");
2389 args[i++] = "-D";
2390 args[i++] = optarg;
2391 break;
2393 case 'U':
2394 if (!pflag)
2395 errx(EX_USAGE, "-U requires -p");
2396 if (i > MAX_ARGS - 2)
2397 errx(EX_USAGE,
2398 "too many -D or -U options");
2399 args[i++] = "-U";
2400 args[i++] = optarg;
2401 break;
2403 case 'p':
2404 pflag = 1;
2405 cmd = optarg;
2406 args[0] = cmd;
2407 i = 1;
2408 break;
2410 case 'q':
2411 qflag = 1;
2412 break;
2414 default:
2415 errx(EX_USAGE, "bad arguments, for usage"
2416 " summary ``ipfw''");
2419 av += optind;
2420 ac -= optind;
2421 if (ac != 1)
2422 errx(EX_USAGE, "extraneous filename arguments");
2424 if ((f = fopen(av[0], "r")) == NULL)
2425 err(EX_UNAVAILABLE, "fopen: %s", av[0]);
2427 if (pflag) {
2428 /* pipe through preprocessor (cpp or m4) */
2429 int pipedes[2];
2431 args[i] = 0;
2433 if (pipe(pipedes) == -1)
2434 err(EX_OSERR, "cannot create pipe");
2436 switch((preproc = fork())) {
2437 case -1:
2438 err(EX_OSERR, "cannot fork");
2440 case 0:
2441 /* child */
2442 if (dup2(fileno(f), 0) == -1
2443 || dup2(pipedes[1], 1) == -1)
2444 err(EX_OSERR, "dup2()");
2445 fclose(f);
2446 close(pipedes[1]);
2447 close(pipedes[0]);
2448 execvp(cmd, args);
2449 err(EX_OSERR, "execvp(%s) failed", cmd);
2451 default:
2452 /* parent */
2453 fclose(f);
2454 close(pipedes[1]);
2455 if ((f = fdopen(pipedes[0], "r")) == NULL) {
2456 int savederrno = errno;
2458 kill(preproc, SIGTERM);
2459 errno = savederrno;
2460 err(EX_OSERR, "fdopen()");
2465 while (fgets(buf, BUFSIZ, f)) {
2466 lineno++;
2467 sprintf(linename, "Line %d", lineno);
2468 args[0] = linename;
2470 if (*buf == '#')
2471 continue;
2472 if ((p = strchr(buf, '#')) != NULL)
2473 *p = '\0';
2474 i = 1;
2475 if (qflag)
2476 args[i++] = "-q";
2477 for (a = strtok(buf, WHITESP);
2478 a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++)
2479 args[i] = a;
2480 if (i == (qflag? 2: 1))
2481 continue;
2482 if (i == MAX_ARGS)
2483 errx(EX_USAGE, "%s: too many arguments",
2484 linename);
2485 args[i] = NULL;
2487 ipfw_main(i, args);
2489 fclose(f);
2490 if (pflag) {
2491 if (waitpid(preproc, &status, 0) == -1)
2492 errx(EX_OSERR, "waitpid()");
2493 if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
2494 errx(EX_UNAVAILABLE,
2495 "preprocessor exited with status %d",
2496 WEXITSTATUS(status));
2497 else if (WIFSIGNALED(status))
2498 errx(EX_UNAVAILABLE,
2499 "preprocessor exited with signal %d",
2500 WTERMSIG(status));
2502 } else {
2503 ipfw_main(ac, av);
2505 return EX_OK;