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/Attic/ipfw.c,v 1.3 2003/08/08 04:18:39 dillon Exp $
23 #include <sys/param.h>
25 #include <sys/socket.h>
26 #include <sys/sockio.h>
27 #include <sys/sysctl.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 */
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" },
94 static void show_usage(void);
97 mask_bits(struct in_addr m_ad)
99 int h_fnd = 0, h_num = 0, i;
102 mask = ntohl(m_ad.s_addr);
103 for (i = 0; i < sizeof(u_long)*CHAR_BIT; i++) {
117 print_port(u_char prot, u_short port, const char comma)
119 struct servent *se = NULL;
123 printf("%c0x%04x", comma, port);
127 pe = getprotobynumber(prot);
128 se = getservbyport(htons(port), pe ? pe->p_name : NULL);
131 printf("%c%s", comma, se->s_name);
133 printf("%c%d", comma, port);
137 print_iface(char *key, union ip_fw_if *un, int byname)
139 char ifnb[FW_IFNLEN+1];
142 strncpy(ifnb, un->fu_via_if.name, FW_IFNLEN);
143 ifnb[FW_IFNLEN] = '\0';
144 if (un->fu_via_if.unit == -1)
145 printf(" %s %s*", key, ifnb);
147 printf(" %s %s%d", key, ifnb, un->fu_via_if.unit);
148 } else if (un->fu_via_ip.s_addr != 0) {
149 printf(" %s %s", key, inet_ntoa(un->fu_via_ip));
151 printf(" %s any", key);
155 print_reject_code(int code)
159 for (ic = icmpcodes; ic->str; ic++)
160 if (ic->code == code) {
161 printf("%s", ic->str);
168 * _s_x holds a string-int pair for various lookups.
169 * s=NULL terminates the struct.
171 struct _s_x { char *s; int x; };
172 static struct _s_x limit_masks[] = {
173 {"src-addr", DYN_SRC_ADDR},
174 {"src-port", DYN_SRC_PORT},
175 {"dst-addr", DYN_DST_ADDR},
176 {"dst-port", DYN_DST_PORT},
180 show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth)
182 static int twidth = 0;
188 int nsp = IP_FW_GETNSRCP(chain);
189 int ndp = IP_FW_GETNDSTP(chain);
192 setservent(1/*stay open*/);
194 printf("%05u ", chain->fw_number);
197 printf("%*qu %*qu ", pcwidth, chain->fw_pcnt, bcwidth, chain->fw_bcnt);
203 strcpy(timestr, ctime((time_t *)&twidth));
204 *strchr(timestr, '\n') = '\0';
205 twidth = strlen(timestr);
207 if (chain->timestamp) {
208 strcpy(timestr, ctime((time_t *)&chain->timestamp));
209 *strchr(timestr, '\n') = '\0';
210 printf("%s ", timestr);
212 printf("%*s ", twidth, " ");
215 if (chain->fw_flg == IP_FW_F_CHECK_S) {
216 printf("check-state\n");
220 if (chain->fw_flg & IP_FW_F_RND_MATCH) {
221 double d = 1.0 * chain->dont_match_prob;
222 d = 1 - (d / 0x7fffffff);
223 printf("prob %f ", d);
226 switch (chain->fw_flg & IP_FW_F_COMMAND) {
237 printf("divert %u", chain->fw_divert_port);
240 printf("tee %u", chain->fw_divert_port);
243 printf("skipto %u", chain->fw_skipto_rule);
246 printf("pipe %u", chain->fw_skipto_rule);
249 printf("queue %u", chain->fw_skipto_rule);
252 if (chain->fw_reject_code == IP_FW_REJECT_RST)
256 print_reject_code(chain->fw_reject_code);
260 printf("fwd %s", inet_ntoa(chain->fw_fwd_ip.sin_addr));
261 if(chain->fw_fwd_ip.sin_port)
262 printf(",%d", chain->fw_fwd_ip.sin_port);
265 errx(EX_OSERR, "impossible");
268 if (chain->fw_flg & IP_FW_F_PRN) {
270 if (chain->fw_logamount)
271 printf(" logamount %d", chain->fw_logamount);
274 pe = getprotobynumber(chain->fw_prot);
276 printf(" %s", pe->p_name);
278 printf(" %u", chain->fw_prot);
280 printf(" from %s", chain->fw_flg & IP_FW_F_INVSRC ? "not " : "");
282 if (chain->fw_flg & IP_FW_F_SME) {
286 adrt = ntohl(chain->fw_smsk.s_addr);
287 if (adrt == ULONG_MAX && do_resolv) {
288 adrt = (chain->fw_src.s_addr);
289 he = gethostbyaddr((char *)&adrt,
290 sizeof(u_long), AF_INET);
292 printf("%s", inet_ntoa(chain->fw_src));
294 printf("%s", he->h_name);
295 } else if (adrt != ULONG_MAX) {
296 mb = mask_bits(chain->fw_smsk);
300 printf("%s", inet_ntoa(chain->fw_src));
303 printf("%s", inet_ntoa(chain->fw_src));
305 printf("%s", inet_ntoa(chain->fw_smsk));
308 printf("%s", inet_ntoa(chain->fw_src));
312 if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
314 for (i = 0; i < nsp; i++) {
315 print_port(chain->fw_prot,
316 chain->fw_uar.fw_pts[i], comma);
317 if (i == 0 && (chain->fw_flg & IP_FW_F_SRNG))
319 else if (i == 0 && (chain->fw_flg & IP_FW_F_SMSK))
326 printf(" to %s", chain->fw_flg & IP_FW_F_INVDST ? "not " : "");
328 if (chain->fw_flg & IP_FW_F_DME) {
331 adrt = ntohl(chain->fw_dmsk.s_addr);
332 if (adrt == ULONG_MAX && do_resolv) {
333 adrt = (chain->fw_dst.s_addr);
334 he = gethostbyaddr((char *)&adrt,
335 sizeof(u_long), AF_INET);
337 printf("%s", inet_ntoa(chain->fw_dst));
339 printf("%s", he->h_name);
340 } else if (adrt != ULONG_MAX) {
341 mb = mask_bits(chain->fw_dmsk);
345 printf("%s", inet_ntoa(chain->fw_dst));
348 printf("%s", inet_ntoa(chain->fw_dst));
350 printf("%s", inet_ntoa(chain->fw_dmsk));
353 printf("%s", inet_ntoa(chain->fw_dst));
357 if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
359 for (i = 0; i < ndp; i++) {
360 print_port(chain->fw_prot,
361 chain->fw_uar.fw_pts[nsp+i], comma);
362 if (i == 0 && (chain->fw_flg & IP_FW_F_DRNG))
364 else if (i == 0 && (chain->fw_flg & IP_FW_F_DMSK))
371 if (chain->fw_flg & IP_FW_F_UID) {
372 struct passwd *pwd = getpwuid(chain->fw_uid);
375 printf(" uid %s", pwd->pw_name);
377 printf(" uid %u", chain->fw_uid);
380 if (chain->fw_flg & IP_FW_F_GID) {
381 struct group *grp = getgrgid(chain->fw_gid);
384 printf(" gid %s", grp->gr_name);
386 printf(" gid %u", chain->fw_gid);
389 if (chain->fw_flg & IP_FW_F_KEEP_S) {
390 struct _s_x *p = limit_masks;
392 switch(chain->dyn_type) {
394 printf(" *** unknown type ***");
397 printf(" keep-state");
401 for ( ; p->s != NULL ; p++)
402 if (chain->limit_mask & p->x)
404 printf(" %d", chain->conn_limit);
409 if (chain->fw_flg & IP_FW_BRIDGED)
411 if ((chain->fw_flg & IP_FW_F_IN) && !(chain->fw_flg & IP_FW_F_OUT))
413 if (!(chain->fw_flg & IP_FW_F_IN) && (chain->fw_flg & IP_FW_F_OUT))
416 /* Handle hack for "via" backwards compatibility */
417 if ((chain->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
419 &chain->fw_in_if, chain->fw_flg & IP_FW_F_IIFNAME);
421 /* Receive interface specified */
422 if (chain->fw_flg & IP_FW_F_IIFACE)
423 print_iface("recv", &chain->fw_in_if,
424 chain->fw_flg & IP_FW_F_IIFNAME);
425 /* Transmit interface specified */
426 if (chain->fw_flg & IP_FW_F_OIFACE)
427 print_iface("xmit", &chain->fw_out_if,
428 chain->fw_flg & IP_FW_F_OIFNAME);
431 if (chain->fw_flg & IP_FW_F_FRAG)
434 if (chain->fw_ipopt || chain->fw_ipnopt) {
435 int _opt_printed = 0;
436 #define PRINTOPT(x) {if (_opt_printed) printf(",");\
437 printf(x); _opt_printed = 1;}
440 if (chain->fw_ipopt & IP_FW_IPOPT_SSRR)
442 if (chain->fw_ipnopt & IP_FW_IPOPT_SSRR)
444 if (chain->fw_ipopt & IP_FW_IPOPT_LSRR)
446 if (chain->fw_ipnopt & IP_FW_IPOPT_LSRR)
448 if (chain->fw_ipopt & IP_FW_IPOPT_RR)
450 if (chain->fw_ipnopt & IP_FW_IPOPT_RR)
452 if (chain->fw_ipopt & IP_FW_IPOPT_TS)
454 if (chain->fw_ipnopt & IP_FW_IPOPT_TS)
458 if (chain->fw_ipflg & IP_FW_IF_TCPEST)
459 printf(" established");
460 else if (chain->fw_tcpf == IP_FW_TCPF_SYN &&
461 chain->fw_tcpnf == IP_FW_TCPF_ACK)
463 else if (chain->fw_tcpf || chain->fw_tcpnf) {
464 int _flg_printed = 0;
465 #define PRINTFLG(x) {if (_flg_printed) printf(",");\
466 printf(x); _flg_printed = 1;}
468 printf(" tcpflags ");
469 if (chain->fw_tcpf & IP_FW_TCPF_FIN)
471 if (chain->fw_tcpnf & IP_FW_TCPF_FIN)
473 if (chain->fw_tcpf & IP_FW_TCPF_SYN)
475 if (chain->fw_tcpnf & IP_FW_TCPF_SYN)
477 if (chain->fw_tcpf & IP_FW_TCPF_RST)
479 if (chain->fw_tcpnf & IP_FW_TCPF_RST)
481 if (chain->fw_tcpf & IP_FW_TCPF_PSH)
483 if (chain->fw_tcpnf & IP_FW_TCPF_PSH)
485 if (chain->fw_tcpf & IP_FW_TCPF_ACK)
487 if (chain->fw_tcpnf & IP_FW_TCPF_ACK)
489 if (chain->fw_tcpf & IP_FW_TCPF_URG)
491 if (chain->fw_tcpnf & IP_FW_TCPF_URG)
494 if (chain->fw_tcpopt || chain->fw_tcpnopt) {
495 int _opt_printed = 0;
496 #define PRINTTOPT(x) {if (_opt_printed) printf(",");\
497 printf(x); _opt_printed = 1;}
499 printf(" tcpoptions ");
500 if (chain->fw_tcpopt & IP_FW_TCPOPT_MSS)
502 if (chain->fw_tcpnopt & IP_FW_TCPOPT_MSS)
504 if (chain->fw_tcpopt & IP_FW_TCPOPT_WINDOW)
506 if (chain->fw_tcpnopt & IP_FW_TCPOPT_WINDOW)
507 PRINTTOPT("!window");
508 if (chain->fw_tcpopt & IP_FW_TCPOPT_SACK)
510 if (chain->fw_tcpnopt & IP_FW_TCPOPT_SACK)
512 if (chain->fw_tcpopt & IP_FW_TCPOPT_TS)
514 if (chain->fw_tcpnopt & IP_FW_TCPOPT_TS)
516 if (chain->fw_tcpopt & IP_FW_TCPOPT_CC)
518 if (chain->fw_tcpnopt & IP_FW_TCPOPT_CC)
522 if (chain->fw_flg & IP_FW_F_ICMPBIT) {
528 for (type_index = 0; type_index < IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8; ++type_index)
529 if (chain->fw_uar.fw_icmptypes[type_index / (sizeof(unsigned) * 8)] &
530 (1U << (type_index % (sizeof(unsigned) * 8)))) {
531 printf("%c%d", first == 1 ? ' ' : ',', type_index);
542 sort_q(const void *pa, const void *pb)
544 int rev = (do_sort < 0);
545 int field = rev ? -do_sort : do_sort;
547 const struct dn_flow_queue *a = pa;
548 const struct dn_flow_queue *b = pb;
552 res = a->len - b->len;
555 res = a->len_bytes - b->len_bytes;
558 case 3: /* tot pkts */
559 res = a->tot_pkts - b->tot_pkts;
562 case 4: /* tot bytes */
563 res = a->tot_bytes - b->tot_bytes;
570 return (int)(rev ? res : -res);
574 list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
578 printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
580 fs->flow_mask.src_ip, fs->flow_mask.src_port,
581 fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
582 if (fs->rq_elements == 0)
585 printf("BKT Prot ___Source IP/port____ "
586 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
588 heapsort(q, fs->rq_elements, sizeof *q, sort_q);
589 for (l = 0; l < fs->rq_elements; l++) {
593 ina.s_addr = htonl(q[l].id.src_ip);
594 printf("%3d ", q[l].hash_slot);
595 pe = getprotobynumber(q[l].id.proto);
597 printf("%-4s ", pe->p_name);
599 printf("%4u ", q[l].id.proto);
601 inet_ntoa(ina), q[l].id.src_port);
602 ina.s_addr = htonl(q[l].id.dst_ip);
604 inet_ntoa(ina), q[l].id.dst_port);
605 printf("%4qu %8qu %2u %4u %3u\n",
606 q[l].tot_pkts, q[l].tot_bytes,
607 q[l].len, q[l].len_bytes, q[l].drops);
609 printf(" S %20qd F %20qd\n",
615 print_flowset_parms(struct dn_flow_set *fs, char *prefix)
620 char red[90]; /* Display RED parameters */
623 if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
625 sprintf(qs, "%d KB", l / 1024);
627 sprintf(qs, "%d B", l);
629 sprintf(qs, "%3d sl.", l);
631 sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
634 if (fs->flags_fs & DN_IS_RED) /* RED parameters */
636 "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
637 (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
638 1.0 * fs->w_q / (double)(1 << SCALE_RED),
639 SCALE_VAL(fs->min_th),
640 SCALE_VAL(fs->max_th),
641 1.0 * fs->max_p / (double)(1 << SCALE_RED));
643 sprintf(red, "droptail");
645 printf("%s %s%s %d queues (%d buckets) %s\n",
646 prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
650 sysctl_handler(int ac, char *av[], int which)
656 warnx("missing keyword to enable/disable\n");
657 } else if (strncmp(*av, "firewall", strlen(*av)) == 0) {
658 sysctlbyname("net.inet.ip.fw.enable", NULL, 0,
659 &which, sizeof(which));
660 } else if (strncmp(*av, "one_pass", strlen(*av)) == 0) {
661 sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0,
662 &which, sizeof(which));
663 } else if (strncmp(*av, "debug", strlen(*av)) == 0) {
664 sysctlbyname("net.inet.ip.fw.debug", NULL, 0,
665 &which, sizeof(which));
666 } else if (strncmp(*av, "verbose", strlen(*av)) == 0) {
667 sysctlbyname("net.inet.ip.fw.verbose", NULL, 0,
668 &which, sizeof(which));
670 warnx("unrecognize enable/disable keyword: %s\n", *av);
675 list(int ac, char *av[])
678 struct dn_pipe *pipes;
685 /* get rules or pipes from kernel, resizing array as necessary */
687 const int unit = do_pipe ? sizeof(*pipes) : sizeof(*rules);
688 const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;
692 while (nbytes >= nalloc) {
693 nalloc = nalloc * 2 + 200;
695 if ((data = realloc(data, nbytes)) == NULL)
696 err(EX_OSERR, "realloc");
697 if (getsockopt(s, IPPROTO_IP, ocmd, data, &nbytes) < 0)
698 err(EX_OSERR, "getsockopt(IP_%s_GET)",
699 do_pipe ? "DUMMYNET" : "FW");
703 /* display requested pipes */
707 struct dn_pipe *p = (struct dn_pipe *) data;
708 struct dn_flow_set *fs;
709 struct dn_flow_queue *q;
713 rulenum = strtoul(*av++, NULL, 10);
716 for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) {
717 double b = p->bandwidth;
721 if (p->next != (struct dn_pipe *)DN_IS_PIPE)
723 l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
724 next = (void *)p + l;
726 q = (struct dn_flow_queue *)(p+1);
728 if (rulenum != 0 && rulenum != p->pipe_nr)
730 if (p->if_name[0] != '\0')
731 sprintf(buf, "%s", p->if_name);
733 sprintf(buf, "unlimited");
734 else if (b >= 1000000)
735 sprintf(buf, "%7.3f Mbit/s", b/1000000);
737 sprintf(buf, "%7.3f Kbit/s", b/1000);
739 sprintf(buf, "%7.3f bit/s ", b);
741 sprintf(prefix, "%05d: %s %4d ms ",
742 p->pipe_nr, buf, p->delay);
743 print_flowset_parms(&(p->fs), prefix);
745 printf(" V %20qd\n", p->V >> MY_M);
746 list_queues(&(p->fs), q);
748 fs = (struct dn_flow_set *) next;
749 for (; nbytes >= sizeof *fs; fs = (struct dn_flow_set *)next) {
752 if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE)
754 l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
755 next = (void *)fs + l;
757 q = (struct dn_flow_queue *)(fs+1);
758 sprintf(prefix, "q%05d: weight %d pipe %d ",
759 fs->fs_nr, fs->weight, fs->parent_nr);
760 print_flowset_parms(fs, prefix);
767 rules = (struct ip_fw *)data;
768 /* determine num more accurately */
770 while (rules[num].fw_number < 65535)
772 num++; /* counting starts from 0 ... */
773 /* if showing stats, figure out column widths ahead of time */
775 for (n = 0; n < num; n++) {
776 struct ip_fw *const r = &rules[n];
781 width = sprintf(temp, "%qu", r->fw_pcnt);
786 width = sprintf(temp, "%qu", r->fw_bcnt);
792 /* display all rules */
793 for (n = 0; n < num; n++) {
794 struct ip_fw *const r = &rules[n];
796 show_ipfw(r, pcwidth, bcwidth);
799 /* display specific rules requested on command line */
807 /* convert command line rule # */
808 rnum = strtoul(*av++, &endptr, 10);
811 warnx("invalid rule number: %s", *(av - 1));
815 for (seen = n = 0; n < num; n++) {
816 struct ip_fw *const r = &rules[n];
818 if (r->fw_number > rnum)
820 if (r->fw_number == rnum) {
821 show_ipfw(r, pcwidth, bcwidth);
826 /* give precedence to other error(s) */
827 if (exitval == EX_OK)
828 exitval = EX_UNAVAILABLE;
829 warnx("rule %lu does not exist", rnum);
832 if (exitval != EX_OK)
838 if (do_dynamic && num * sizeof (rules[0]) != nbytes) {
839 struct ipfw_dyn_rule *d =
840 (struct ipfw_dyn_rule *)&rules[num];
844 printf("## Dynamic rules:\n");
846 if (d->expire == 0 && !do_expired) {
852 printf("%05d %qu %qu (T %d, slot %d)",
857 switch (d->dyn_type) {
858 case DYN_LIMIT_PARENT:
859 printf(" PARENT %d", d->count);
864 case DYN_KEEP_STATE: /* bidir, no mask */
869 pe = getprotobynumber(d->id.proto);
871 printf(" %s,", pe->p_name);
873 printf(" %u,", d->id.proto);
874 a.s_addr = htonl(d->id.src_ip);
875 printf(" %s %d", inet_ntoa(a), d->id.src_port);
876 a.s_addr = htonl(d->id.dst_ip);
877 printf("<-> %s %d", inet_ntoa(a), d->id.dst_port);
890 fprintf(stderr, "usage: ipfw [options]\n"
892 " add [number] rule\n"
893 " [pipe] delete number ...\n"
894 " [pipe] list [number ...]\n"
895 " [pipe] show [number ...]\n"
896 " zero [number ...]\n"
897 " resetlog [number ...]\n"
898 " pipe number config [pipeconfig]\n"
899 " rule: [prob <match_probability>] action proto src dst extras...\n"
901 " {allow|permit|accept|pass|deny|drop|reject|unreach code|\n"
902 " reset|count|skipto num|divert port|tee port|fwd ip|\n"
903 " pipe num} [log [logamount count]]\n"
904 " proto: {ip|tcp|udp|icmp|<number>}\n"
905 " src: from [not] {me|any|ip[{/bits|:mask}]} [{port[-port]}, [port], ...]\n"
906 " dst: to [not] {me|any|ip[{/bits|:mask}]} [{port[-port]}, [port], ...]\n"
910 " fragment (may not be used with ports or tcpflags)\n"
913 " {xmit|recv|via} {iface|ip|any}\n"
914 " {established|setup}\n"
915 " tcpflags [!]{syn|fin|rst|ack|psh|urg}, ...\n"
916 " ipoptions [!]{ssrr|lsrr|rr|ts}, ...\n"
917 " tcpoptions [!]{mss|window|sack|ts|cc}, ...\n"
918 " icmptypes {type[, type]}...\n"
919 " keep-state [method]\n"
921 " {bw|bandwidth} <number>{bit/s|Kbit/s|Mbit/s|Bytes/s|KBytes/s|MBytes/s}\n"
922 " {bw|bandwidth} interface_name\n"
923 " delay <milliseconds>\n"
924 " queue <size>{packets|Bytes|KBytes}\n"
926 " mask {all| [dst-ip|src-ip|dst-port|src-port|proto] <number>}\n"
927 " buckets <number>}\n"
928 " {red|gred} <fraction>/<number>/<number>/<fraction>\n"
936 lookup_host (char *host, struct in_addr *ipaddr)
940 if (!inet_aton(host, ipaddr)) {
941 if ((he = gethostbyname(host)) == NULL)
943 *ipaddr = *(struct in_addr *)he->h_addr_list[0];
949 fill_ip(struct in_addr *ipno, struct in_addr *mask, int *acp, char ***avp)
955 if (ac && !strncmp(*av, "any", strlen(*av))) {
956 ipno->s_addr = mask->s_addr = 0; av++; ac--;
958 p = strchr(*av, '/');
960 p = strchr(*av, ':');
966 if (lookup_host(*av, ipno) != 0)
967 errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
970 if (!inet_aton(p, mask))
971 errx(EX_DATAERR, "bad netmask ``%s''", p);
976 } else if (atoi(p) > 32) {
977 errx(EX_DATAERR, "bad width ``%s''", p);
980 htonl(~0 << (32 - atoi(p)));
984 mask->s_addr = htonl(~0);
987 ipno->s_addr &= mask->s_addr;
996 fill_reject_code(u_short *codep, char *str)
1003 errx(EX_DATAERR, "missing unreachable code");
1004 val = strtoul(str, &s, 0);
1005 if (s != str && *s == '\0' && val < 0x100) {
1009 for (ic = icmpcodes; ic->str; ic++)
1010 if (!strcasecmp(str, ic->str)) {
1014 errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str);
1018 add_port(u_short *cnt, u_short *ptr, u_short off, u_short port)
1020 if (off + *cnt >= IP_FW_MAX_PORTS)
1021 errx(EX_USAGE, "too many ports (max is %d)", IP_FW_MAX_PORTS);
1022 ptr[off+*cnt] = port;
1027 lookup_port(const char *arg, int proto, int test, int nodash)
1030 char *earg, buf[32];
1034 snprintf(buf, sizeof(buf), "%s", arg);
1036 for (p = q = buf; *p; *q++ = *p++) {
1041 if (*p == ',' || (nodash && *p == '-'))
1047 val = (int) strtoul(buf, &earg, 0);
1048 if (!*buf || *earg) {
1049 char *protocol = NULL;
1052 struct protoent *pe = getprotobynumber(proto);
1055 protocol = pe->p_name;
1059 if ((s = getservbyname(buf, protocol))) {
1060 val = htons(s->s_port);
1063 errx(EX_DATAERR, "unknown port ``%s''", buf);
1067 if (val < 0 || val > 0xffff) {
1070 "port ``%s'' out of range", buf);
1078 * return: 0 normally, 1 if first pair is a range,
1079 * 2 if first pair is a port+mask
1082 fill_port(u_short *cnt, u_short *ptr, u_short off, char *arg, int proto)
1085 int initial_range = 0;
1087 for (s = arg; *s && *s != ',' && *s != '-' && *s != ':'; s++) {
1088 if (*s == '\\' && *(s+1))
1093 if (strchr(arg, ','))
1094 errx(EX_USAGE, "port/mask must be first in list");
1095 add_port(cnt, ptr, off,
1096 *arg ? lookup_port(arg, proto, 0, 0) : 0x0000);
1098 s = strchr(arg, ',');
1101 add_port(cnt, ptr, off,
1102 *arg ? lookup_port(arg, proto, 0, 0) : 0xffff);
1108 if (strchr(arg, ','))
1109 errx(EX_USAGE, "port range must be first in list");
1110 add_port(cnt, ptr, off,
1111 *arg ? lookup_port(arg, proto, 0, 0) : 0x0000);
1113 s = strchr(arg, ',');
1116 add_port(cnt, ptr, off,
1117 *arg ? lookup_port(arg, proto, 0, 0) : 0xffff);
1121 while (arg != NULL) {
1122 s = strchr(arg, ',');
1125 add_port(cnt, ptr, off, lookup_port(arg, proto, 0, 0));
1128 return initial_range;
1132 fill_tcpflag(u_char *set, u_char *reset, char **vp)
1142 { "syn", IP_FW_TCPF_SYN },
1143 { "fin", IP_FW_TCPF_FIN },
1144 { "ack", IP_FW_TCPF_ACK },
1145 { "psh", IP_FW_TCPF_PSH },
1146 { "rst", IP_FW_TCPF_RST },
1147 { "urg", IP_FW_TCPF_URG }
1160 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i)
1161 if (!strncmp(p, flags[i].name, strlen(p))) {
1162 *d |= flags[i].value;
1165 if (i == sizeof(flags) / sizeof(flags[0]))
1166 errx(EX_DATAERR, "invalid tcp flag ``%s''", p);
1172 fill_tcpopts(u_char *set, u_char *reset, char **vp)
1182 { "mss", IP_FW_TCPOPT_MSS },
1183 { "window", IP_FW_TCPOPT_WINDOW },
1184 { "sack", IP_FW_TCPOPT_SACK },
1185 { "ts", IP_FW_TCPOPT_TS },
1186 { "cc", IP_FW_TCPOPT_CC },
1199 for (i = 0; i < sizeof(opts) / sizeof(opts[0]); ++i)
1200 if (!strncmp(p, opts[i].name, strlen(p))) {
1201 *d |= opts[i].value;
1204 if (i == sizeof(opts) / sizeof(opts[0]))
1205 errx(EX_DATAERR, "invalid tcp option ``%s''", p);
1211 fill_ipopt(u_char *set, u_char *reset, char **vp)
1226 if (!strncmp(p, "ssrr", strlen(p))) *d |= IP_FW_IPOPT_SSRR;
1227 if (!strncmp(p, "lsrr", strlen(p))) *d |= IP_FW_IPOPT_LSRR;
1228 if (!strncmp(p, "rr", strlen(p))) *d |= IP_FW_IPOPT_RR;
1229 if (!strncmp(p, "ts", strlen(p))) *d |= IP_FW_IPOPT_TS;
1235 fill_icmptypes(unsigned *types, char **vp, u_int *fw_flg)
1237 unsigned long icmptype;
1244 icmptype = strtoul(c, &c, 0);
1246 if (*c != ',' && *c != '\0')
1247 errx(EX_DATAERR, "invalid ICMP type");
1249 if (icmptype >= IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8)
1250 errx(EX_DATAERR, "ICMP type out of range");
1252 types[icmptype / (sizeof(unsigned) * 8)] |=
1253 1 << (icmptype % (sizeof(unsigned) * 8));
1254 *fw_flg |= IP_FW_F_ICMPBIT;
1259 delete(int ac, char *av[])
1262 struct dn_pipe pipe;
1264 int exitval = EX_OK;
1266 memset(&rule, 0, sizeof rule);
1267 memset(&pipe, 0, sizeof pipe);
1272 while (ac && isdigit(**av)) {
1273 i = atoi(*av); av++; ac--;
1279 i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_DEL,
1280 &pipe, sizeof pipe);
1283 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
1284 do_pipe == 1 ? pipe.pipe_nr :
1289 i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rule,
1292 exitval = EX_UNAVAILABLE;
1293 warn("rule %u: setsockopt(IP_FW_DEL)",
1298 if (exitval != EX_OK)
1303 verify_interface(union ip_fw_if *ifu)
1308 * If a unit was specified, check for that exact interface.
1309 * If a wildcard was specified, check for unit 0.
1311 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
1312 ifu->fu_via_if.name,
1313 ifu->fu_via_if.unit == -1 ? 0 : ifu->fu_via_if.unit);
1315 if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
1316 warnx("warning: interface ``%s'' does not exist",
1321 fill_iface(char *which, union ip_fw_if *ifu, int *byname, int ac, char *arg)
1324 errx(EX_USAGE, "missing argument for ``%s''", which);
1326 /* Parse the interface or address */
1327 if (!strcmp(arg, "any")) {
1328 ifu->fu_via_ip.s_addr = 0;
1330 } else if (!isdigit(*arg)) {
1334 strncpy(ifu->fu_via_if.name, arg,
1335 sizeof(ifu->fu_via_if.name));
1336 ifu->fu_via_if.name[sizeof(ifu->fu_via_if.name) - 1] = '\0';
1337 for (q = ifu->fu_via_if.name;
1338 *q && !isdigit(*q) && *q != '*'; q++)
1340 ifu->fu_via_if.unit = (*q == '*') ? -1 : atoi(q);
1342 verify_interface(ifu);
1343 } else if (!inet_aton(arg, &ifu->fu_via_ip)) {
1344 errx(EX_DATAERR, "bad ip address ``%s''", arg);
1350 config_pipe(int ac, char **av)
1352 struct dn_pipe pipe;
1356 memset(&pipe, 0, sizeof pipe);
1360 if (ac && isdigit(**av)) {
1361 i = atoi(*av); av++; ac--;
1368 if (!strncmp(*av, "plr", strlen(*av))) {
1370 double d = strtod(av[1], NULL);
1375 pipe.fs.plr = (int)(d*0x7fffffff);
1378 } else if (!strncmp(*av, "queue", strlen(*av))) {
1380 pipe.fs.qsize = strtoul(av[1], &end, 0);
1381 if (*end == 'K' || *end == 'k') {
1382 pipe.fs.flags_fs |= DN_QSIZE_IS_BYTES;
1383 pipe.fs.qsize *= 1024;
1384 } else if (*end == 'B' || !strncmp(end, "by", 2)) {
1385 pipe.fs.flags_fs |= DN_QSIZE_IS_BYTES;
1389 } else if (!strncmp(*av, "buckets", strlen(*av))) {
1390 pipe.fs.rq_size = strtoul(av[1], NULL, 0);
1393 } else if (!strncmp(*av, "mask", strlen(*av))) {
1394 /* per-flow queue, mask is dst_ip, dst_port,
1395 * src_ip, src_port, proto measured in bits
1400 pipe.fs.flow_mask.dst_ip = 0;
1401 pipe.fs.flow_mask.src_ip = 0;
1402 pipe.fs.flow_mask.dst_port = 0;
1403 pipe.fs.flow_mask.src_port = 0;
1404 pipe.fs.flow_mask.proto = 0;
1407 if (ac >= 1 && !strncmp(*av, "all", strlen(*av))) {
1408 /* special case -- all bits are significant */
1409 pipe.fs.flow_mask.dst_ip = ~0;
1410 pipe.fs.flow_mask.src_ip = ~0;
1411 pipe.fs.flow_mask.dst_port = ~0;
1412 pipe.fs.flow_mask.src_port = ~0;
1413 pipe.fs.flow_mask.proto = ~0;
1414 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1420 int len = strlen(*av);
1422 if (!strncmp(*av, "dst-ip", len))
1423 par = &pipe.fs.flow_mask.dst_ip;
1424 else if (!strncmp(*av, "src-ip", len))
1425 par = &pipe.fs.flow_mask.src_ip;
1426 else if (!strncmp(*av, "dst-port", len))
1427 par = &pipe.fs.flow_mask.dst_port;
1428 else if (!strncmp(*av, "src-port", len))
1429 par = &pipe.fs.flow_mask.src_port;
1430 else if (!strncmp(*av, "proto", len))
1431 par = &pipe.fs.flow_mask.proto;
1435 errx(EX_USAGE, "mask: %s value"
1437 if (*av[1] == '/') {
1438 a = strtoul(av[1]+1, &end, 0);
1439 if (a == 32) /* special case... */
1443 fprintf(stderr, " mask is 0x%08x\n", a);
1445 a = strtoul(av[1], &end, 0);
1447 if (par == &pipe.fs.flow_mask.src_port
1448 || par == &pipe.fs.flow_mask.dst_port) {
1450 errx(EX_DATAERR, "mask: %s"
1451 " must be 16 bit, not"
1453 *((u_int16_t *)par) = (u_int16_t)a;
1454 } else if (par == &pipe.fs.flow_mask.proto) {
1456 errx(EX_DATAERR, "mask: %s"
1458 " 8 bit, not 0x%08x",
1460 *((u_int8_t *)par) = (u_int8_t)a;
1462 *((u_int32_t *)par) = a;
1464 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1468 } else if (!strncmp(*av, "red", strlen(*av))
1469 || !strncmp(*av, "gred", strlen(*av))) {
1471 pipe.fs.flags_fs |= DN_IS_RED;
1473 pipe.fs.flags_fs |= DN_IS_GENTLE_RED;
1474 if ((end = strsep(&av[1], "/"))) {
1475 double w_q = strtod(end, NULL);
1476 if (w_q > 1 || w_q <= 0)
1477 errx(EX_DATAERR, "w_q %f must be "
1479 pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED));
1481 if ((end = strsep(&av[1], "/"))) {
1482 pipe.fs.min_th = strtoul(end, &end, 0);
1483 if (*end == 'K' || *end == 'k')
1484 pipe.fs.min_th *= 1024;
1486 if ((end = strsep(&av[1], "/"))) {
1487 pipe.fs.max_th = strtoul(end, &end, 0);
1488 if (*end == 'K' || *end == 'k')
1489 pipe.fs.max_th *= 1024;
1491 if ((end = strsep(&av[1], "/"))) {
1492 double max_p = strtod(end, NULL);
1493 if (max_p > 1 || max_p <= 0)
1494 errx(EX_DATAERR, "max_p %f must be "
1495 "0 < x <= 1", max_p);
1497 (int)(max_p * (1 << SCALE_RED));
1501 } else if (!strncmp(*av, "droptail", strlen(*av))) {
1503 pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
1507 int len = strlen(*av);
1509 /* some commands are only good for pipes. */
1510 if (!strncmp(*av, "bw", len)
1511 || !strncmp(*av, "bandwidth", len)) {
1513 && av[1][0] <= 'z') {
1514 int l = sizeof(pipe.if_name)-1;
1515 /* interface name */
1516 strncpy(pipe.if_name, av[1], l);
1517 pipe.if_name[l] = '\0';
1520 pipe.if_name[0] = '\0';
1522 strtoul(av[1], &end, 0);
1528 } else if (*end == 'M') {
1534 || !strncmp(end, "by", 2))
1535 pipe.bandwidth *= 8;
1537 if (pipe.bandwidth < 0)
1539 "bandwidth too large");
1542 } else if (!strncmp(*av, "delay", len)) {
1543 pipe.delay = strtoul(av[1], NULL, 0);
1547 errx(EX_DATAERR, "unrecognised pipe"
1548 " option ``%s''", *av);
1550 } else { /* this refers to a queue */
1551 if (!strncmp(*av, "weight", len)) {
1553 strtoul(av[1], &end, 0);
1556 } else if (!strncmp(*av, "pipe", len)) {
1558 strtoul(av[1], &end, 0);
1562 errx(EX_DATAERR, "unrecognised option "
1569 if (pipe.pipe_nr == 0)
1570 errx(EX_DATAERR, "pipe_nr %d must be > 0",
1572 if (pipe.delay > 10000)
1573 errx(EX_DATAERR, "delay %d must be < 10000",
1575 } else { /* do_pipe == 2, queue */
1576 if (pipe.fs.parent_nr == 0)
1577 errx(EX_DATAERR, "pipe %d must be > 0",
1579 if (pipe.fs.weight >100)
1580 errx(EX_DATAERR, "weight %d must be <= 100",
1583 if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) {
1584 if (pipe.fs.qsize > 1024*1024)
1585 errx(EX_DATAERR, "queue size %d, must be < 1MB",
1588 if (pipe.fs.qsize > 100)
1589 errx(EX_DATAERR, "queue size %d, must be"
1590 " 2 <= x <= 100", pipe.fs.qsize);
1592 if (pipe.fs.flags_fs & DN_IS_RED) {
1594 int lookup_depth, avg_pkt_size;
1595 double s, idle, weight, w_q;
1596 struct clockinfo clock;
1599 if (pipe.fs.min_th >= pipe.fs.max_th)
1600 errx(EX_DATAERR, "min_th %d must be < than max_th %d",
1601 pipe.fs.min_th, pipe.fs.max_th);
1602 if (pipe.fs.max_th == 0)
1603 errx(EX_DATAERR, "max_th must be > 0");
1606 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
1607 &lookup_depth, &len, NULL, 0) == -1)
1609 errx(1, "sysctlbyname(\"%s\")",
1610 "net.inet.ip.dummynet.red_lookup_depth");
1611 if (lookup_depth == 0)
1612 errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
1613 " must be greater than zero");
1616 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
1617 &avg_pkt_size, &len, NULL, 0) == -1)
1619 errx(1, "sysctlbyname(\"%s\")",
1620 "net.inet.ip.dummynet.red_avg_pkt_size");
1621 if (avg_pkt_size == 0)
1623 "net.inet.ip.dummynet.red_avg_pkt_size must"
1624 " be greater than zero");
1626 len = sizeof(struct clockinfo);
1627 if (sysctlbyname("kern.clockrate", &clock, &len, NULL, 0) == -1)
1628 errx(1, "sysctlbyname(\"%s\")",
1632 * Ticks needed for sending a medium-sized packet.
1633 * Unfortunately, when we are configuring a WF2Q+ queue, we
1634 * do not have bandwidth information, because that is stored
1635 * in the parent pipe, and also we have multiple queues
1636 * competing for it. So we set s=0, which is not very
1637 * correct. But on the other hand, why do we want RED with
1640 if (pipe.bandwidth==0) /* this is a WF2Q+ queue */
1643 s = clock.hz * avg_pkt_size * 8 / pipe.bandwidth;
1646 * max idle time (in ticks) before avg queue size
1648 * NOTA: (3/w_q) is approx the value x so that
1649 * (1-w_q)^x < 10^-3.
1651 w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED);
1652 idle = s * 3. / w_q;
1653 pipe.fs.lookup_step = (int)idle / lookup_depth;
1654 if (!pipe.fs.lookup_step)
1655 pipe.fs.lookup_step = 1;
1657 for (t = pipe.fs.lookup_step; t > 0; --t)
1659 pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
1661 i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_CONFIGURE, &pipe,
1664 err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
1668 add(int ac, char *av[])
1673 struct protoent *pe;
1674 int saw_xmrc = 0, saw_via = 0;
1676 memset(&rule, 0, sizeof rule);
1681 if (ac && isdigit(**av)) {
1682 rule.fw_number = atoi(*av); av++; ac--;
1686 if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) {
1687 double d = strtod(av[1], NULL);
1688 if (d <= 0 || d > 1)
1689 errx(EX_DATAERR, "illegal match prob. %s", av[1]);
1690 if (d != 1) { /* 1 means always match */
1691 rule.fw_flg |= IP_FW_F_RND_MATCH;
1692 rule.dont_match_prob = (long)((1 - d) * 0x7fffffff);
1698 errx(EX_USAGE, "missing action");
1699 if (!strncmp(*av, "accept", strlen(*av))
1700 || !strncmp(*av, "pass", strlen(*av))
1701 || !strncmp(*av, "allow", strlen(*av))
1702 || !strncmp(*av, "permit", strlen(*av))) {
1703 rule.fw_flg |= IP_FW_F_ACCEPT; av++; ac--;
1704 } else if (!strncmp(*av, "count", strlen(*av))) {
1705 rule.fw_flg |= IP_FW_F_COUNT; av++; ac--;
1706 } else if (!strncmp(*av, "pipe", strlen(*av))) {
1707 rule.fw_flg |= IP_FW_F_PIPE; av++; ac--;
1709 errx(EX_USAGE, "missing pipe number");
1710 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1711 } else if (!strncmp(*av, "queue", strlen(*av))) {
1712 rule.fw_flg |= IP_FW_F_QUEUE; av++; ac--;
1714 errx(EX_USAGE, "missing queue number");
1715 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1716 } else if (!strncmp(*av, "divert", strlen(*av))) {
1717 rule.fw_flg |= IP_FW_F_DIVERT; av++; ac--;
1719 errx(EX_USAGE, "missing %s port", "divert");
1720 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1721 if (rule.fw_divert_port == 0) {
1724 s = getservbyname(av[-1], "divert");
1726 rule.fw_divert_port = ntohs(s->s_port);
1728 errx(EX_DATAERR, "illegal %s port", "divert");
1730 } else if (!strncmp(*av, "tee", strlen(*av))) {
1731 rule.fw_flg |= IP_FW_F_TEE; av++; ac--;
1733 errx(EX_USAGE, "missing %s port", "tee divert");
1734 rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
1735 if (rule.fw_divert_port == 0) {
1738 s = getservbyname(av[-1], "divert");
1740 rule.fw_divert_port = ntohs(s->s_port);
1742 errx(EX_DATAERR, "illegal %s port",
1745 } else if (!strncmp(*av, "fwd", strlen(*av))
1746 || !strncmp(*av, "forward", strlen(*av))) {
1747 struct in_addr dummyip;
1749 rule.fw_flg |= IP_FW_F_FWD; av++; ac--;
1751 errx(EX_USAGE, "missing forwarding IP address");
1752 rule.fw_fwd_ip.sin_len = sizeof(struct sockaddr_in);
1753 rule.fw_fwd_ip.sin_family = AF_INET;
1754 rule.fw_fwd_ip.sin_port = 0;
1755 pp = strchr(*av, ':');
1757 pp = strchr(*av, ',');
1761 i = lookup_port(pp, 0, 1, 0);
1763 errx(EX_DATAERR, "illegal forwarding"
1764 " port ``%s''", pp);
1766 rule.fw_fwd_ip.sin_port = (u_short)i;
1768 fill_ip(&(rule.fw_fwd_ip.sin_addr), &dummyip, &ac, &av);
1769 if (rule.fw_fwd_ip.sin_addr.s_addr == 0)
1770 errx(EX_DATAERR, "illegal forwarding IP address");
1772 } else if (!strncmp(*av, "skipto", strlen(*av))) {
1773 rule.fw_flg |= IP_FW_F_SKIPTO; av++; ac--;
1775 errx(EX_USAGE, "missing skipto rule number");
1776 rule.fw_skipto_rule = strtoul(*av, NULL, 10); av++; ac--;
1777 } else if ((!strncmp(*av, "deny", strlen(*av))
1778 || !strncmp(*av, "drop", strlen(*av)))) {
1779 rule.fw_flg |= IP_FW_F_DENY; av++; ac--;
1780 } else if (!strncmp(*av, "reject", strlen(*av))) {
1781 rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
1782 rule.fw_reject_code = ICMP_UNREACH_HOST;
1783 } else if (!strncmp(*av, "reset", strlen(*av))) {
1784 rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
1785 rule.fw_reject_code = IP_FW_REJECT_RST; /* check TCP later */
1786 } else if (!strncmp(*av, "unreach", strlen(*av))) {
1787 rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
1788 fill_reject_code(&rule.fw_reject_code, *av); av++; ac--;
1789 } else if (!strncmp(*av, "check-state", strlen(*av))) {
1790 rule.fw_flg |= IP_FW_F_CHECK_S; av++; ac--;
1793 errx(EX_DATAERR, "invalid action ``%s''", *av);
1797 if (ac && !strncmp(*av, "log", strlen(*av))) {
1798 rule.fw_flg |= IP_FW_F_PRN; av++; ac--;
1800 if (ac && !strncmp(*av, "logamount", strlen(*av))) {
1801 if (!(rule.fw_flg & IP_FW_F_PRN))
1802 errx(EX_USAGE, "``logamount'' not valid without"
1806 errx(EX_USAGE, "``logamount'' requires argument");
1807 rule.fw_logamount = atoi(*av);
1808 if (rule.fw_logamount < 0)
1809 errx(EX_DATAERR, "``logamount'' argument must be"
1811 if (rule.fw_logamount == 0)
1812 rule.fw_logamount = -1;
1818 errx(EX_USAGE, "missing protocol");
1819 if ((proto = atoi(*av)) > 0) {
1820 rule.fw_prot = proto; av++; ac--;
1821 } else if (!strncmp(*av, "all", strlen(*av))) {
1822 rule.fw_prot = IPPROTO_IP; av++; ac--;
1823 } else if ((pe = getprotobyname(*av)) != NULL) {
1824 rule.fw_prot = pe->p_proto; av++; ac--;
1826 errx(EX_DATAERR, "invalid protocol ``%s''", *av);
1829 if (rule.fw_prot != IPPROTO_TCP
1830 && (rule.fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
1831 && rule.fw_reject_code == IP_FW_REJECT_RST)
1832 errx(EX_DATAERR, "``reset'' is only valid for tcp packets");
1835 if (ac && !strncmp(*av, "from", strlen(*av))) { av++; ac--; }
1837 errx(EX_USAGE, "missing ``from''");
1839 if (ac && !strncmp(*av, "not", strlen(*av))) {
1840 rule.fw_flg |= IP_FW_F_INVSRC;
1844 errx(EX_USAGE, "missing arguments");
1846 if (ac && !strncmp(*av, "me", strlen(*av))) {
1847 rule.fw_flg |= IP_FW_F_SME;
1850 fill_ip(&rule.fw_src, &rule.fw_smsk, &ac, &av);
1853 if (ac && (isdigit(**av)
1854 || lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) {
1858 retval = fill_port(&nports, rule.fw_uar.fw_pts,
1859 0, *av, rule.fw_prot);
1861 rule.fw_flg |= IP_FW_F_SRNG;
1862 else if (retval == 2)
1863 rule.fw_flg |= IP_FW_F_SMSK;
1864 IP_FW_SETNSRCP(&rule, nports);
1869 if (ac && !strncmp(*av, "to", strlen(*av))) { av++; ac--; }
1871 errx(EX_USAGE, "missing ``to''");
1873 if (ac && !strncmp(*av, "not", strlen(*av))) {
1874 rule.fw_flg |= IP_FW_F_INVDST;
1878 errx(EX_USAGE, "missing arguments");
1881 if (ac && !strncmp(*av, "me", strlen(*av))) {
1882 rule.fw_flg |= IP_FW_F_DME;
1885 fill_ip(&rule.fw_dst, &rule.fw_dmsk, &ac, &av);
1888 if (ac && (isdigit(**av)
1889 || lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) {
1893 retval = fill_port(&nports, rule.fw_uar.fw_pts,
1894 IP_FW_GETNSRCP(&rule), *av, rule.fw_prot);
1896 rule.fw_flg |= IP_FW_F_DRNG;
1897 else if (retval == 2)
1898 rule.fw_flg |= IP_FW_F_DMSK;
1899 IP_FW_SETNDSTP(&rule, nports);
1903 if ((rule.fw_prot != IPPROTO_TCP) && (rule.fw_prot != IPPROTO_UDP)
1904 && (IP_FW_GETNSRCP(&rule) || IP_FW_GETNDSTP(&rule))) {
1905 errx(EX_USAGE, "only TCP and UDP protocols are valid"
1906 " with port specifications");
1910 if (!strncmp(*av, "uid", strlen(*av))) {
1915 rule.fw_flg |= IP_FW_F_UID;
1918 errx(EX_USAGE, "``uid'' requires argument");
1920 uid = strtoul(*av, &end, 0);
1922 pwd = getpwuid(uid);
1924 pwd = getpwnam(*av);
1926 errx(EX_DATAERR, "uid \"%s\" is"
1927 " nonexistent", *av);
1928 rule.fw_uid = pwd->pw_uid;
1930 } else if (!strncmp(*av, "gid", strlen(*av))) {
1935 rule.fw_flg |= IP_FW_F_GID;
1938 errx(EX_USAGE, "``gid'' requires argument");
1940 gid = strtoul(*av, &end, 0);
1942 grp = getgrgid(gid);
1944 grp = getgrnam(*av);
1946 errx(EX_DATAERR, "gid \"%s\" is"
1947 " nonexistent", *av);
1948 rule.fw_gid = grp->gr_gid;
1950 } else if (!strncmp(*av, "in", strlen(*av))) {
1951 rule.fw_flg |= IP_FW_F_IN;
1953 } else if (!strncmp(*av,"limit",strlen(*av))) {
1954 /* dyn. rule used to limit number of connections. */
1955 rule.fw_flg |= IP_FW_F_KEEP_S;
1956 rule.dyn_type = DYN_LIMIT ;
1957 rule.limit_mask = 0 ;
1960 struct _s_x *p = limit_masks;
1961 for ( ; p->s != NULL ; p++)
1962 if (!strncmp(*av, p->s, strlen(*av))) {
1963 rule.limit_mask |= p->x ;
1972 "limit needs mask and # of connections");
1973 rule.conn_limit = atoi(*av);
1974 if (rule.conn_limit == 0)
1975 errx(EX_USAGE, "limit: limit must be >0");
1976 if (rule.limit_mask == 0)
1977 errx(EX_USAGE, "missing limit mask");
1979 } else if (!strncmp(*av, "keep-state", strlen(*av))) {
1981 rule.fw_flg |= IP_FW_F_KEEP_S;
1984 if (ac > 0 && (type = atoi(*av)) != 0) {
1985 rule.dyn_type = type;
1988 } else if (!strncmp(*av, "bridged", strlen(*av))) {
1989 rule.fw_flg |= IP_FW_BRIDGED;
1991 } else if (!strncmp(*av, "out", strlen(*av))) {
1992 rule.fw_flg |= IP_FW_F_OUT;
1994 } else if (ac && !strncmp(*av, "xmit", strlen(*av))) {
2000 errx(EX_USAGE, "``via'' is incompatible"
2001 " with ``xmit'' and ``recv''");
2005 fill_iface("xmit", &ifu, &byname, ac, *av);
2006 rule.fw_out_if = ifu;
2007 rule.fw_flg |= IP_FW_F_OIFACE;
2009 rule.fw_flg |= IP_FW_F_OIFNAME;
2011 } else if (ac && !strncmp(*av, "recv", strlen(*av))) {
2019 fill_iface("recv", &ifu, &byname, ac, *av);
2020 rule.fw_in_if = ifu;
2021 rule.fw_flg |= IP_FW_F_IIFACE;
2023 rule.fw_flg |= IP_FW_F_IIFNAME;
2025 } else if (ac && !strncmp(*av, "via", strlen(*av))) {
2033 fill_iface("via", &ifu, &byname, ac, *av);
2034 rule.fw_out_if = rule.fw_in_if = ifu;
2037 (IP_FW_F_IIFNAME | IP_FW_F_OIFNAME);
2039 } else if (!strncmp(*av, "fragment", strlen(*av))) {
2040 rule.fw_flg |= IP_FW_F_FRAG;
2042 } else if (!strncmp(*av, "ipoptions", strlen(*av))) {
2045 errx(EX_USAGE, "missing argument"
2046 " for ``ipoptions''");
2047 fill_ipopt(&rule.fw_ipopt, &rule.fw_ipnopt, av);
2049 } else if (rule.fw_prot == IPPROTO_TCP) {
2050 if (!strncmp(*av, "established", strlen(*av))) {
2051 rule.fw_ipflg |= IP_FW_IF_TCPEST;
2053 } else if (!strncmp(*av, "setup", strlen(*av))) {
2054 rule.fw_tcpf |= IP_FW_TCPF_SYN;
2055 rule.fw_tcpnf |= IP_FW_TCPF_ACK;
2057 } else if (!strncmp(*av, "tcpflags", strlen(*av))
2058 || !strncmp(*av, "tcpflgs", strlen(*av))) {
2061 errx(EX_USAGE, "missing argument"
2062 " for ``tcpflags''");
2063 fill_tcpflag(&rule.fw_tcpf,
2064 &rule.fw_tcpnf, av);
2066 } else if (!strncmp(*av, "tcpoptions", strlen(*av))
2067 || !strncmp(*av, "tcpopts", strlen(*av))) {
2070 errx(EX_USAGE, "missing argument"
2071 " for ``tcpoptions''");
2072 fill_tcpopts(&rule.fw_tcpopt,
2073 &rule.fw_tcpnopt, av);
2076 errx(EX_USAGE, "unknown or out of order"
2077 " argument ``%s''", *av);
2079 } else if (rule.fw_prot == IPPROTO_ICMP) {
2080 if (!strncmp(*av, "icmptypes", strlen(*av))) {
2083 errx(EX_USAGE, "missing argument"
2084 " for ``icmptypes''");
2085 fill_icmptypes(rule.fw_uar.fw_icmptypes,
2089 errx(EX_USAGE, "unknown or out of order"
2090 " argument ``%s''", *av);
2093 errx(EX_USAGE, "unknown argument ``%s''", *av);
2097 /* No direction specified -> do both directions */
2098 if (!(rule.fw_flg & (IP_FW_F_OUT|IP_FW_F_IN)))
2099 rule.fw_flg |= (IP_FW_F_OUT|IP_FW_F_IN);
2101 /* Sanity check interface check, but handle "via" case separately */
2103 if (rule.fw_flg & IP_FW_F_IN)
2104 rule.fw_flg |= IP_FW_F_IIFACE;
2105 if (rule.fw_flg & IP_FW_F_OUT)
2106 rule.fw_flg |= IP_FW_F_OIFACE;
2107 } else if ((rule.fw_flg & IP_FW_F_OIFACE)
2108 && (rule.fw_flg & IP_FW_F_IN)) {
2109 errx(EX_DATAERR, "can't check xmit interface of incoming"
2113 /* frag may not be used in conjunction with ports or TCP flags */
2114 if (rule.fw_flg & IP_FW_F_FRAG) {
2115 if (rule.fw_tcpf || rule.fw_tcpnf)
2116 errx(EX_DATAERR, "can't mix 'frag' and tcpflags");
2119 errx(EX_DATAERR, "can't mix 'frag' and port"
2122 if (rule.fw_flg & IP_FW_F_PRN) {
2123 if (!rule.fw_logamount) {
2124 size_t len = sizeof(int);
2126 if (sysctlbyname("net.inet.ip.fw.verbose_limit",
2127 &rule.fw_logamount, &len, NULL, 0) == -1)
2128 errx(1, "sysctlbyname(\"%s\")",
2129 "net.inet.ip.fw.verbose_limit");
2130 } else if (rule.fw_logamount == -1)
2131 rule.fw_logamount = 0;
2132 rule.fw_loghighest = rule.fw_logamount;
2136 if (getsockopt(s, IPPROTO_IP, IP_FW_ADD, &rule, &i) == -1)
2137 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
2139 show_ipfw(&rule, 10, 10);
2143 zero (int ac, char *av[])
2151 /* clear all entries */
2152 if (setsockopt(s, IPPROTO_IP, IP_FW_ZERO, NULL, 0) < 0)
2153 err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_ZERO");
2155 printf("Accounting cleared.\n");
2160 memset(&rule, 0, sizeof rule);
2163 if (isdigit(**av)) {
2164 rule.fw_number = atoi(*av); av++; ac--;
2165 if (setsockopt(s, IPPROTO_IP,
2166 IP_FW_ZERO, &rule, sizeof rule)) {
2167 warn("rule %u: setsockopt(IP_FW_ZERO)",
2169 failed = EX_UNAVAILABLE;
2170 } else if (!do_quiet)
2171 printf("Entry %d cleared\n",
2174 errx(EX_USAGE, "invalid rule number ``%s''", *av);
2177 if (failed != EX_OK)
2182 resetlog (int ac, char *av[])
2190 /* clear all entries */
2191 if (setsockopt(s, IPPROTO_IP, IP_FW_RESETLOG, NULL, 0) < 0)
2192 err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)");
2194 printf("Logging counts reset.\n");
2199 memset(&rule, 0, sizeof rule);
2202 if (isdigit(**av)) {
2203 rule.fw_number = atoi(*av); av++; ac--;
2204 if (setsockopt(s, IPPROTO_IP,
2205 IP_FW_RESETLOG, &rule, sizeof rule)) {
2206 warn("rule %u: setsockopt(IP_FW_RESETLOG)",
2208 failed = EX_UNAVAILABLE;
2209 } else if (!do_quiet)
2210 printf("Entry %d logging count reset\n",
2213 errx(EX_DATAERR, "invalid rule number ``%s''", *av);
2216 if (failed != EX_OK)
2221 ipfw_main(int ac, char **av)
2228 /* Initialize globals. */
2229 do_resolv = do_acct = do_time = do_quiet =
2230 do_pipe = do_sort = verbose = 0;
2232 /* Set the force flag for non-interactive processes */
2233 do_force = !isatty(STDIN_FILENO);
2235 optind = optreset = 1;
2236 while ((ch = getopt(ac, av, "s:adefNqtv")) != -1)
2238 case 's': /* sort */
2239 do_sort = atoi(optarg);
2262 case 'v': /* verbose */
2270 if (*(av += optind) == NULL)
2271 errx(EX_USAGE, "bad arguments, for usage summary ``ipfw''");
2273 if (!strncmp(*av, "pipe", strlen(*av))) {
2277 } else if (!strncmp(*av, "queue", strlen(*av))) {
2283 errx(EX_USAGE, "pipe requires arguments");
2285 /* allow argument swapping */
2286 if (ac > 1 && *av[0] >= '0' && *av[0] <= '9') {
2291 if (!strncmp(*av, "add", strlen(*av))) {
2293 } else if (do_pipe && !strncmp(*av, "config", strlen(*av))) {
2294 config_pipe(ac, av);
2295 } else if (!strncmp(*av, "delete", strlen(*av))) {
2297 } else if (!strncmp(*av, "flush", strlen(*av))) {
2300 if (do_force || do_quiet)
2306 printf("Are you sure? [yn] ");
2309 c = toupper(getc(stdin));
2310 while (c != '\n' && getc(stdin) != '\n')
2313 } while (c != 'Y' && c != 'N');
2319 if (setsockopt(s, IPPROTO_IP,
2320 do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH,
2322 err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)",
2323 do_pipe ? "DUMMYNET" : "FW");
2325 printf("Flushed all %s.\n",
2326 do_pipe ? "pipes" : "rules");
2328 } else if (!strncmp(*av, "zero", strlen(*av))) {
2330 } else if (!strncmp(*av, "resetlog", strlen(*av))) {
2332 } else if (!strncmp(*av, "print", strlen(*av))) {
2334 } else if (!strncmp(*av, "enable", strlen(*av))) {
2335 sysctl_handler(ac, av, 1);
2336 } else if (!strncmp(*av, "disable", strlen(*av))) {
2337 sysctl_handler(ac, av, 0);
2338 } else if (!strncmp(*av, "list", strlen(*av))) {
2340 } else if (!strncmp(*av, "show", strlen(*av))) {
2344 errx(EX_USAGE, "bad arguments, for usage summary ``ipfw''");
2350 main(int ac, char *av[])
2353 #define WHITESP " \t\f\v\n\r"
2355 char *a, *p, *args[MAX_ARGS], *cmd = NULL;
2357 int i, c, lineno, qflag, pflag, status;
2361 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2363 err(EX_UNAVAILABLE, "socket");
2368 * Only interpret the last command line argument as a file to
2369 * be preprocessed if it is specified as an absolute pathname.
2372 if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) {
2373 qflag = pflag = i = 0;
2376 while ((c = getopt(ac, av, "D:U:p:q")) != -1)
2380 errx(EX_USAGE, "-D requires -p");
2381 if (i > MAX_ARGS - 2)
2383 "too many -D or -U options");
2390 errx(EX_USAGE, "-U requires -p");
2391 if (i > MAX_ARGS - 2)
2393 "too many -D or -U options");
2410 errx(EX_USAGE, "bad arguments, for usage"
2411 " summary ``ipfw''");
2417 errx(EX_USAGE, "extraneous filename arguments");
2419 if ((f = fopen(av[0], "r")) == NULL)
2420 err(EX_UNAVAILABLE, "fopen: %s", av[0]);
2423 /* pipe through preprocessor (cpp or m4) */
2428 if (pipe(pipedes) == -1)
2429 err(EX_OSERR, "cannot create pipe");
2431 switch((preproc = fork())) {
2433 err(EX_OSERR, "cannot fork");
2437 if (dup2(fileno(f), 0) == -1
2438 || dup2(pipedes[1], 1) == -1)
2439 err(EX_OSERR, "dup2()");
2444 err(EX_OSERR, "execvp(%s) failed", cmd);
2450 if ((f = fdopen(pipedes[0], "r")) == NULL) {
2451 int savederrno = errno;
2453 (void)kill(preproc, SIGTERM);
2455 err(EX_OSERR, "fdopen()");
2460 while (fgets(buf, BUFSIZ, f)) {
2462 sprintf(linename, "Line %d", lineno);
2467 if ((p = strchr(buf, '#')) != NULL)
2472 for (a = strtok(buf, WHITESP);
2473 a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++)
2475 if (i == (qflag? 2: 1))
2478 errx(EX_USAGE, "%s: too many arguments",
2486 if (waitpid(preproc, &status, 0) == -1)
2487 errx(EX_OSERR, "waitpid()");
2488 if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
2489 errx(EX_UNAVAILABLE,
2490 "preprocessor exited with status %d",
2491 WEXITSTATUS(status));
2492 else if (WIFSIGNALED(status))
2493 errx(EX_UNAVAILABLE,
2494 "preprocessor exited with signal %d",