ipfw3: shorten func show_filter and MACRO
[dragonfly.git] / sbin / ipfw3 / ipfw3.c
blobcad8f5d0e6e10b1da265c1a80cbc730f82626fd0
1 /*
2 * Copyright (c) 2002 Luigi Rizzo
3 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
4 * Copyright (c) 1994 Ugen J.S.Antsilevich
6 * Idea and grammar partially left from:
7 * Copyright (c) 1993 Daniel Boulet
9 * Redistribution and use in source forms, with and without modification,
10 * are permitted provided that this entire comment appears intact.
12 * Redistribution in binary form may occur without any restrictions.
13 * Obviously, it would be nice if you gave credit where credit is due
14 * but requiring it would be too onerous.
16 * This software is provided ``AS IS'' without any warranties of any kind.
18 * NEW command line interface for IP firewall facility
20 * $FreeBSD: src/sbin/ipfw/ipfw2.c,v 1.4.2.13 2003/05/27 22:21:11 gshapiro 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 <arpa/inet.h>
32 #include <ctype.h>
33 #include <dlfcn.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <grp.h>
37 #include <limits.h>
38 #include <netdb.h>
39 #include <pwd.h>
40 #include <sysexits.h>
41 #include <signal.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stdarg.h>
45 #include <string.h>
46 #include <timeconv.h>
47 #include <unistd.h>
49 #include <netinet/in.h>
50 #include <netinet/in_systm.h>
51 #include <netinet/ip.h>
52 #include <netinet/ip_icmp.h>
53 #include <netinet/tcp.h>
54 #include <net/if.h>
55 #include <net/if_dl.h>
56 #include <net/route.h>
57 #include <net/ethernet.h>
60 #include "../../sys/net/ipfw3/ip_fw3.h"
61 #include "../../sys/net/ipfw3/ip_fw3_table.h"
62 #include "../../sys/net/dummynet3/ip_dummynet3.h"
63 #include "../../sys/net/libalias/alias.h"
64 #include "../../sys/net/ipfw3_basic/ip_fw3_basic.h"
65 #include "../../sys/net/ipfw3_nat/ip_fw3_nat.h"
66 #include "ipfw.h"
69 #define KEYWORD_SIZE 256
70 #define MAPPING_SIZE 256
72 #define MAX_KEYWORD_LEN 20
73 #define MAX_ARGS 32
74 #define WHITESP " \t\f\v\n\r"
75 #define IPFW_LIB_PATH "/usr/lib/libipfw3%s.so"
76 #define IP_MASK_ALL 0xffffffff
77 #define NAT_BUF_LEN 1024
79 * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
80 * This is only used in this code.
82 #define IPPROTO_ETHERTYPE 0x1000
85 * This macro returns the size of a struct sockaddr when passed
86 * through a routing socket. Basically we round up sa_len to
87 * a multiple of sizeof(long), with a minimum of sizeof(long).
88 * The check for a NULL pointer is just a convenience, probably never used.
89 * The case sa_len == 0 should only apply to empty structures.
91 #define SA_SIZE(sa) \
92 ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
93 sizeof(long) : \
94 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
97 * show_rules() prints the body of an ipfw rule.
98 * Because the standard rule has at least proto src_ip dst_ip, we use
99 * a helper function to produce these entries if not provided explicitly.
100 * The first argument is the list of fields we have, the second is
101 * the list of fields we want to be printed.
103 * Special cases if we have provided a MAC header:
104 * + if the rule does not contain IP addresses/ports, do not print them;
105 * + if the rule does not contain an IP proto, print "all" instead of "ip";
108 #define HAVE_PROTO 0x0001
109 #define HAVE_SRCIP 0x0002
110 #define HAVE_DSTIP 0x0004
111 #define HAVE_MAC 0x0008
112 #define HAVE_MACTYPE 0x0010
113 #define HAVE_OPTIONS 0x8000
115 #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
118 * Definition of a port range, and macros to deal with values.
119 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
120 * LO 16-bits == number of ports in range
121 * NOTES: - Port values are not stored in network byte order.
124 #define port_range u_long
126 #define GETLOPORT(x) ((x) >> 0x10)
127 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
128 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
130 /* Set y to be the low-port value in port_range variable x. */
131 #define SETLOPORT(x, y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
133 /* Set y to be the number of ports in port_range variable x. */
134 #define SETNUMPORTS(x, y) ((x) = ((x) & 0xffff0000) | (y))
136 #define INC_ARGCV() do { \
137 (*_av)++; \
138 (*_ac)--; \
139 av = *_av; \
140 ac = *_ac; \
141 } while (0)
144 int ipfw_socket = -1; /* main RAW socket */
145 int do_resolv, /* Would try to resolve all */
146 do_acct, /* Show packet/byte count */
147 do_time, /* Show time stamps */
148 do_quiet = 1, /* Be quiet , default is quiet*/
149 do_force, /* Don't ask for confirmation */
150 do_pipe, /* this cmd refers to a pipe */
151 do_nat, /* Nat configuration. */
152 do_sort, /* field to sort results (0 = no) */
153 do_dynamic, /* display dynamic rules */
154 do_expired, /* display expired dynamic rules */
155 do_compact, /* show rules in compact mode */
156 show_sets, /* display rule sets */
157 verbose;
159 enum tokens {
160 TOK_NULL=0,
162 TOK_IP,
163 TOK_IF,
164 TOK_ALOG,
165 TOK_DENY_INC,
166 TOK_SAME_PORTS,
167 TOK_UNREG_ONLY,
168 TOK_RESET_ADDR,
169 TOK_ALIAS_REV,
170 TOK_PROXY_ONLY,
171 TOK_REDIR_ADDR,
172 TOK_REDIR_PORT,
173 TOK_REDIR_PROTO,
175 TOK_PIPE,
176 TOK_QUEUE,
177 TOK_PLR,
178 TOK_NOERROR,
179 TOK_BUCKETS,
180 TOK_DSTIP,
181 TOK_SRCIP,
182 TOK_DSTPORT,
183 TOK_SRCPORT,
184 TOK_ALL,
185 TOK_MASK,
186 TOK_BW,
187 TOK_DELAY,
188 TOK_RED,
189 TOK_GRED,
190 TOK_DROPTAIL,
191 TOK_PROTO,
192 TOK_WEIGHT,
195 struct char_int_map dummynet_params[] = {
196 { "plr", TOK_PLR },
197 { "noerror", TOK_NOERROR },
198 { "buckets", TOK_BUCKETS },
199 { "dst-ip", TOK_DSTIP },
200 { "src-ip", TOK_SRCIP },
201 { "dst-port", TOK_DSTPORT },
202 { "src-port", TOK_SRCPORT },
203 { "proto", TOK_PROTO },
204 { "weight", TOK_WEIGHT },
205 { "all", TOK_ALL },
206 { "mask", TOK_MASK },
207 { "droptail", TOK_DROPTAIL },
208 { "red", TOK_RED },
209 { "gred", TOK_GRED },
210 { "bw", TOK_BW },
211 { "bandwidth", TOK_BW },
212 { "delay", TOK_DELAY },
213 { "pipe", TOK_PIPE },
214 { "queue", TOK_QUEUE },
215 { "dummynet-params", TOK_NULL },
216 { NULL, 0 }
219 struct char_int_map nat_params[] = {
220 { "ip", TOK_IP },
221 { "if", TOK_IF },
222 { "log", TOK_ALOG },
223 { "deny_in", TOK_DENY_INC },
224 { "same_ports", TOK_SAME_PORTS },
225 { "unreg_only", TOK_UNREG_ONLY },
226 { "reset", TOK_RESET_ADDR },
227 { "reverse", TOK_ALIAS_REV },
228 { "proxy_only", TOK_PROXY_ONLY },
229 { "redirect_addr", TOK_REDIR_ADDR },
230 { "redirect_port", TOK_REDIR_PORT },
231 { "redirect_proto", TOK_REDIR_PROTO },
232 { NULL, 0 },
235 struct ipfw_keyword {
236 int type;
237 char word[MAX_KEYWORD_LEN];
238 int module;
239 int opcode;
242 struct ipfw_mapping {
243 int type;
244 int module;
245 int opcode;
246 parser_func parser;
247 shower_func shower;
250 struct ipfw_keyword keywords[KEYWORD_SIZE];
251 struct ipfw_mapping mappings[MAPPING_SIZE];
253 static int
254 match_token(struct char_int_map *table, char *string)
256 while (table->key) {
257 if (strcmp(table->key, string) == 0) {
258 return table->val;
260 table++;
262 return 0;
265 static void
266 get_modules(char *modules_str, int len)
268 if (do_get_x(IP_FW_MODULE, modules_str, &len) < 0)
269 errx(EX_USAGE, "ipfw3 not loaded.");
272 static void
273 list_modules(int ac, char *av[])
275 void *module_str = NULL;
276 int len = 1024;
277 if ((module_str = realloc(module_str, len)) == NULL)
278 err(EX_OSERR, "realloc");
280 get_modules(module_str, len);
281 printf("%s", (char *)module_str);
283 void
284 parse_accept(ipfw_insn **cmd, int *ac, char **av[])
286 (*cmd)->opcode = O_BASIC_ACCEPT;
287 (*cmd)->module = MODULE_BASIC_ID;
288 (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
289 NEXT_ARG1;
292 void
293 parse_deny(ipfw_insn **cmd, int *ac, char **av[])
295 (*cmd)->opcode = O_BASIC_DENY;
296 (*cmd)->module = MODULE_BASIC_ID;
297 (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
298 NEXT_ARG1;
301 void
302 show_accept(ipfw_insn *cmd, int show_or)
304 printf(" allow");
307 void
308 show_deny(ipfw_insn *cmd, int show_or)
310 printf(" deny");
313 static void
314 load_modules(void)
316 const char *error;
317 init_module mod_init_func;
318 void *module_lib;
319 char module_lib_file[50];
320 void *module_str = NULL;
321 int len = 1024;
323 if ((module_str = realloc(module_str, len)) == NULL)
324 err(EX_OSERR, "realloc");
326 get_modules(module_str, len);
328 const char s[2] = ",";
329 char *token;
330 token = strtok(module_str, s);
331 while (token != NULL) {
332 sprintf(module_lib_file, IPFW_LIB_PATH, token);
333 token = strtok(NULL, s);
334 module_lib = dlopen(module_lib_file, RTLD_LAZY);
335 if (!module_lib) {
336 fprintf(stderr, "Couldn't open %s: %s\n",
337 module_lib_file, dlerror());
338 exit(EX_SOFTWARE);
340 mod_init_func = dlsym(module_lib, "load_module");
341 if ((error = dlerror()))
343 fprintf(stderr, "Couldn't find init function: %s\n", error);
344 exit(EX_SOFTWARE);
346 (*mod_init_func)((register_func)register_ipfw_func,
347 (register_keyword)register_ipfw_keyword);
351 void
352 prepare_default_funcs(void)
354 /* register allow*/
355 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "allow", ACTION);
356 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "accept", ACTION);
357 register_ipfw_func(MODULE_BASIC_ID, O_BASIC_ACCEPT,
358 (parser_func)parse_accept, (shower_func)show_accept);
359 /* register deny*/
360 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "deny", ACTION);
361 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "reject", ACTION);
362 register_ipfw_func(MODULE_BASIC_ID, O_BASIC_DENY,
363 (parser_func)parse_deny, (shower_func)show_deny);
366 void
367 register_ipfw_keyword(int module, int opcode, char *word, int type)
369 struct ipfw_keyword *tmp;
371 tmp=keywords;
372 for(;;) {
373 if (tmp->type == NONE) {
374 strcpy(tmp->word, word);
375 tmp->module = module;
376 tmp->opcode = opcode;
377 tmp->type = type;
378 break;
379 } else {
380 if (strcmp(tmp->word, word) == 0)
381 errx(EX_USAGE, "keyword `%s' exists", word);
382 else
383 tmp++;
388 void
389 register_ipfw_func(int module, int opcode, parser_func parser, shower_func shower)
391 struct ipfw_mapping *tmp;
393 tmp = mappings;
394 while (1) {
395 if (tmp->type == NONE) {
396 tmp->module = module;
397 tmp->opcode = opcode;
398 tmp->parser = parser;
399 tmp->shower = shower;
400 tmp->type = IN_USE;
401 break;
402 } else {
403 if (tmp->opcode == opcode && tmp->module == module) {
404 errx(EX_USAGE, "func `%d' of module `%d' exists",
405 opcode, module);
406 break;
407 } else {
408 tmp++;
415 * this func need to check whether 'or' need to be printed,
416 * when the filter is the first filter with 'or' when dont print
417 * when not first and same as previous, then print or and no filter name
418 * when not first but different from previous, print name without 'or'
419 * show_or = 1: show or and ignore filter name
420 * show_or = 0: show filter name ignore or
422 void prev_show_chk(ipfw_insn *cmd, uint8_t *prev_module, uint8_t *prev_opcode,
423 int *show_or)
425 if (cmd->len & F_OR) {
426 if (*prev_module == 0 && *prev_opcode == 0) {
427 /* first cmd with 'or' flag */
428 *show_or = 0;
429 *prev_module = cmd->module;
430 *prev_opcode = cmd->opcode;
431 } else if (cmd->module == *prev_module &&
432 cmd->opcode == *prev_opcode) {
433 /* cmd same as previous, same module and opcode */
434 *show_or = 1;
435 } else {
436 /* cmd different from prev*/
437 *show_or = 0;
438 *prev_module = cmd->module;
439 *prev_opcode = cmd->opcode;
442 } else {
443 *show_or = 0;
444 *prev_module = 0;
445 *prev_opcode = 0;
450 * word can be: proto from to other
451 * proto show proto
452 * from show from
453 * to show to
454 * other show all other filters
456 int show_filter(ipfw_insn *cmd, char *word, int type)
458 struct ipfw_keyword *k;
459 struct ipfw_mapping *m;
460 shower_func fn;
461 int i, j, show_or;
462 uint8_t prev_module, prev_opcode;
464 k = keywords;
465 m = mappings;
466 for (i = 1; i < KEYWORD_SIZE; i++, k++) {
467 if (k->type == type) {
468 if (k->module == cmd->module &&
469 k->opcode == cmd->opcode) {
470 for (j = 1; j < MAPPING_SIZE; j++, m++) {
471 if (m->type == IN_USE &&
472 k->module == m->module &&
473 k->opcode == m->opcode) {
474 prev_show_chk(cmd, &prev_module,
475 &prev_opcode, &show_or);
476 if (cmd->len & F_NOT)
477 printf(" not");
479 fn = m->shower;
480 (*fn)(cmd, show_or);
481 return 1;
487 return 0;
490 static void
491 show_rules(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth)
493 static int twidth = 0;
494 ipfw_insn *cmd;
495 int l;
497 u_int32_t set_disable = rule->set_disable;
499 if (set_disable & (1 << rule->set)) { /* disabled */
500 if (!show_sets)
501 return;
502 else
503 printf("# DISABLED ");
505 printf("%05u ", rule->rulenum);
507 if (do_acct)
508 printf("%*ju %*ju ", pcwidth, (uintmax_t)rule->pcnt, bcwidth,
509 (uintmax_t)rule->bcnt);
511 if (do_time == 1) {
512 char timestr[30];
514 if (twidth == 0) {
515 strcpy(timestr, ctime((time_t *)&twidth));
516 *strchr(timestr, '\n') = '\0';
517 twidth = strlen(timestr);
519 if (rule->timestamp) {
520 time_t t = _long_to_time(rule->timestamp);
522 strcpy(timestr, ctime(&t));
523 *strchr(timestr, '\n') = '\0';
524 printf("%s ", timestr);
525 } else {
526 printf("%*s ", twidth, " ");
528 } else if (do_time == 2) {
529 printf( "%10u ", rule->timestamp);
532 if (show_sets)
533 printf("set %d ", rule->set);
536 struct ipfw_keyword *k;
537 struct ipfw_mapping *m;
538 shower_func fn, comment_fn = NULL;
539 ipfw_insn *comment_cmd;
540 int i, j, changed;
543 * show others and actions
545 for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule);
546 l > 0; l -= F_LEN(cmd),
547 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
548 k = keywords;
549 m = mappings;
550 for (i = 1; i< KEYWORD_SIZE; i++, k++) {
551 if ( k->module == cmd->module && k->opcode == cmd->opcode ) {
552 for (j = 1; j< MAPPING_SIZE; j++, m++) {
553 if (m->type == IN_USE &&
554 m->module == cmd->module &&
555 m->opcode == cmd->opcode) {
556 if (cmd->module == MODULE_BASIC_ID &&
557 cmd->opcode == O_BASIC_COMMENT) {
558 comment_fn = m->shower;
559 comment_cmd = cmd;
560 } else {
561 fn = m->shower;
562 (*fn)(cmd, 0);
564 if (cmd->module == MODULE_BASIC_ID &&
565 cmd->opcode ==
566 O_BASIC_CHECK_STATE) {
567 goto done;
569 break;
572 break;
578 * show proto
580 changed=0;
581 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
582 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
583 changed = show_filter(cmd, "proto", PROTO);
585 if (!changed && !do_quiet)
586 printf(" ip");
589 * show from
591 changed = 0;
592 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
593 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
594 changed = show_filter(cmd, "from", FROM);
596 if (!changed && !do_quiet)
597 printf(" from any");
600 * show to
602 changed = 0;
603 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
604 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
605 changed = show_filter(cmd, "to", TO);
607 if (!changed && !do_quiet)
608 printf(" to any");
611 * show other filters
613 for (l = rule->act_ofs, cmd = rule->cmd, m = mappings;
614 l > 0; l -= F_LEN(cmd),
615 cmd=(ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
616 show_filter(cmd, "other", FILTER);
619 /* show the comment in the end */
620 if (comment_fn != NULL) {
621 (*comment_fn)(comment_cmd, 0);
623 done:
624 printf("\n");
627 static void
628 show_states(struct ipfw_ioc_state *d, int pcwidth, int bcwidth)
630 struct protoent *pe;
631 struct in_addr a;
633 printf("%05u ", d->rulenum);
634 if (do_acct) {
635 printf("%*ju %*ju ", pcwidth, (uintmax_t)d->pcnt,
636 bcwidth, (uintmax_t)d->bcnt);
639 if (do_time == 1) {
640 /* state->timestamp */
641 char timestr[30];
642 time_t t = _long_to_time(d->timestamp);
643 strcpy(timestr, ctime(&t));
644 *strchr(timestr, '\n') = '\0';
645 printf(" (%s", timestr);
647 /* state->lifetime */
648 printf(" %ds", d->lifetime);
650 /* state->expiry */
651 if (d->expiry !=0) {
652 t = _long_to_time(d->expiry);
653 strcpy(timestr, ctime(&t));
654 *strchr(timestr, '\n') = '\0';
655 printf(" %s)", timestr);
656 } else {
657 printf(" 0)");
660 } else if (do_time == 2) {
661 printf("(%u %ds %u) ", d->timestamp, d->lifetime, d->expiry);
664 if ((pe = getprotobynumber(d->flow_id.proto)) != NULL)
665 printf(" %s", pe->p_name);
666 else
667 printf(" proto %u", d->flow_id.proto);
669 a.s_addr = htonl(d->flow_id.src_ip);
670 printf(" %s %d", inet_ntoa(a), d->flow_id.src_port);
672 a.s_addr = htonl(d->flow_id.dst_ip);
673 printf(" <-> %s %d", inet_ntoa(a), d->flow_id.dst_port);
674 printf(" CPU %d", d->cpuid);
675 printf("\n");
679 sort_q(const void *pa, const void *pb)
681 int rev = (do_sort < 0);
682 int field = rev ? -do_sort : do_sort;
683 long long res = 0;
684 const struct dn_ioc_flowqueue *a = pa;
685 const struct dn_ioc_flowqueue *b = pb;
687 switch(field) {
688 case 1: /* pkts */
689 res = a->len - b->len;
690 break;
691 case 2: /* bytes */
692 res = a->len_bytes - b->len_bytes;
693 break;
695 case 3: /* tot pkts */
696 res = a->tot_pkts - b->tot_pkts;
697 break;
699 case 4: /* tot bytes */
700 res = a->tot_bytes - b->tot_bytes;
701 break;
703 if (res < 0)
704 res = -1;
705 if (res > 0)
706 res = 1;
707 return (int)(rev ? res : -res);
710 static void
711 show_queues(struct dn_ioc_flowset *fs, struct dn_ioc_flowqueue *q)
713 int l;
715 printf("mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
716 fs->flow_mask.u.ip.proto,
717 fs->flow_mask.u.ip.src_ip, fs->flow_mask.u.ip.src_port,
718 fs->flow_mask.u.ip.dst_ip, fs->flow_mask.u.ip.dst_port);
719 if (fs->rq_elements == 0)
720 return;
722 printf("BKT Prot ___Source IP/port____ "
723 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
724 if (do_sort != 0)
725 heapsort(q, fs->rq_elements, sizeof(*q), sort_q);
726 for (l = 0; l < fs->rq_elements; l++) {
727 struct in_addr ina;
728 struct protoent *pe;
730 ina.s_addr = htonl(q[l].id.u.ip.src_ip);
731 printf("%3d ", q[l].hash_slot);
732 pe = getprotobynumber(q[l].id.u.ip.proto);
733 if (pe)
734 printf("%-4s ", pe->p_name);
735 else
736 printf("%4u ", q[l].id.u.ip.proto);
737 printf("%15s/%-5d ",
738 inet_ntoa(ina), q[l].id.u.ip.src_port);
739 ina.s_addr = htonl(q[l].id.u.ip.dst_ip);
740 printf("%15s/%-5d ",
741 inet_ntoa(ina), q[l].id.u.ip.dst_port);
742 printf("%4ju %8ju %2u %4u %3u\n",
743 (uintmax_t)q[l].tot_pkts, (uintmax_t)q[l].tot_bytes,
744 q[l].len, q[l].len_bytes, q[l].drops);
745 if (verbose)
746 printf(" S %20ju F %20ju\n",
747 (uintmax_t)q[l].S, (uintmax_t)q[l].F);
751 static void
752 show_flowset_parms(struct dn_ioc_flowset *fs, char *prefix)
754 char qs[30];
755 char plr[30];
756 char red[90]; /* Display RED parameters */
757 int l;
759 l = fs->qsize;
760 if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
761 if (l >= 8192)
762 sprintf(qs, "%d KB", l / 1024);
763 else
764 sprintf(qs, "%d B", l);
765 } else
766 sprintf(qs, "%3d sl.", l);
767 if (fs->plr)
768 sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
769 else
770 plr[0] = '\0';
771 if (fs->flags_fs & DN_IS_RED) /* RED parameters */
772 sprintf(red,
773 "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
774 (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
775 1.0 * fs->w_q / (double)(1 << SCALE_RED),
776 SCALE_VAL(fs->min_th),
777 SCALE_VAL(fs->max_th),
778 1.0 * fs->max_p / (double)(1 << SCALE_RED));
779 else
780 sprintf(red, "droptail");
782 printf("%s %s%s %d queues (%d buckets) %s\n",
783 prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
786 static void
787 show_pipes(void *data, int nbytes, int ac, char *av[])
789 u_long rulenum;
790 void *next = data;
791 struct dn_ioc_pipe *p = (struct dn_ioc_pipe *)data;
792 struct dn_ioc_flowset *fs;
793 struct dn_ioc_flowqueue *q;
794 int l;
796 if (ac > 0)
797 rulenum = strtoul(*av++, NULL, 10);
798 else
799 rulenum = 0;
800 for (; nbytes >= sizeof(*p); p = (struct dn_ioc_pipe *)next) {
801 double b = p->bandwidth;
802 char buf[30];
803 char prefix[80];
805 if (p->fs.fs_type != DN_IS_PIPE)
806 break; /* done with pipes, now queues */
809 * compute length, as pipe have variable size
811 l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
812 next = (void *)p + l;
813 nbytes -= l;
815 if (rulenum != 0 && rulenum != p->pipe_nr)
816 continue;
819 * Print rate
821 if (b == 0)
822 sprintf(buf, "unlimited");
823 else if (b >= 1000000)
824 sprintf(buf, "%7.3f Mbit/s", b/1000000);
825 else if (b >= 1000)
826 sprintf(buf, "%7.3f Kbit/s", b/1000);
827 else
828 sprintf(buf, "%7.3f bit/s ", b);
830 sprintf(prefix, "%05d: %s %4d ms ",
831 p->pipe_nr, buf, p->delay);
832 show_flowset_parms(&p->fs, prefix);
833 if (verbose)
834 printf(" V %20ju\n", (uintmax_t)p->V >> MY_M);
836 q = (struct dn_ioc_flowqueue *)(p+1);
837 show_queues(&p->fs, q);
840 for (fs = next; nbytes >= sizeof(*fs); fs = next) {
841 char prefix[80];
843 if (fs->fs_type != DN_IS_QUEUE)
844 break;
845 l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
846 next = (void *)fs + l;
847 nbytes -= l;
848 q = (struct dn_ioc_flowqueue *)(fs+1);
849 sprintf(prefix, "q%05d: weight %d pipe %d ",
850 fs->fs_nr, fs->weight, fs->parent_nr);
851 show_flowset_parms(fs, prefix);
852 show_queues(fs, q);
857 * This one handles all set-related commands
858 * ipfw set { show | enable | disable }
859 * ipfw set swap X Y
860 * ipfw set move X to Y
861 * ipfw set move rule X to Y
863 static void
864 sets_handler(int ac, char *av[])
866 u_int32_t set_disable, masks[2];
867 u_int16_t rulenum;
868 u_int8_t cmd, new_set;
869 int i, nbytes;
871 NEXT_ARG;
872 if (!ac)
873 errx(EX_USAGE, "set needs command");
874 if (!strncmp(*av, "show", strlen(*av)) ) {
875 void *data = NULL;
876 char *msg;
877 int nalloc=1000;
878 nbytes = nalloc;
880 while (nbytes >= nalloc) {
881 nalloc = nalloc * 2+321;
882 nbytes = nalloc;
883 if (data == NULL) {
884 if ((data = malloc(nbytes)) == NULL) {
885 err(EX_OSERR, "malloc");
887 } else if ((data = realloc(data, nbytes)) == NULL) {
888 err(EX_OSERR, "realloc");
890 if (do_get_x(IP_FW_GET, data, &nbytes) < 0) {
891 err(EX_OSERR, "getsockopt(IP_FW_GET)");
894 set_disable = ((struct ipfw_ioc_rule *)data)->set_disable;
895 for (i = 0, msg = "disable" ; i < 31; i++)
896 if ( (set_disable & (1<<i))) {
897 printf("%s %d", msg, i);
898 msg = "";
900 msg = (set_disable) ? " enable" : "enable";
901 for (i = 0; i < 31; i++)
902 if ( !(set_disable & (1<<i))) {
903 printf("%s %d", msg, i);
904 msg = "";
906 printf("\n");
907 } else if (!strncmp(*av, "swap", strlen(*av))) {
908 NEXT_ARG;
909 if (ac != 2)
910 errx(EX_USAGE, "set swap needs 2 set numbers\n");
911 rulenum = atoi(av[0]);
912 new_set = atoi(av[1]);
913 if (!isdigit(*(av[0])) || rulenum > 30)
914 errx(EX_DATAERR, "invalid set number %s\n", av[0]);
915 if (!isdigit(*(av[1])) || new_set > 30)
916 errx(EX_DATAERR, "invalid set number %s\n", av[1]);
917 masks[0] = (4 << 24) | (new_set << 16) | (rulenum);
918 i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t));
919 } else if (!strncmp(*av, "move", strlen(*av))) {
920 NEXT_ARG;
921 if (ac && !strncmp(*av, "rule", strlen(*av))) {
922 cmd = 2;
923 NEXT_ARG;
924 } else
925 cmd = 3;
926 if (ac != 3 || strncmp(av[1], "to", strlen(*av)))
927 errx(EX_USAGE, "syntax: set move [rule] X to Y\n");
928 rulenum = atoi(av[0]);
929 new_set = atoi(av[2]);
930 if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > 30) ||
931 (cmd == 2 && rulenum == 65535) )
932 errx(EX_DATAERR, "invalid source number %s\n", av[0]);
933 if (!isdigit(*(av[2])) || new_set > 30)
934 errx(EX_DATAERR, "invalid dest. set %s\n", av[1]);
935 masks[0] = (cmd << 24) | (new_set << 16) | (rulenum);
936 i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t));
937 } else if (!strncmp(*av, "disable", strlen(*av)) ||
938 !strncmp(*av, "enable", strlen(*av)) ) {
939 int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0;
941 NEXT_ARG;
942 masks[0] = masks[1] = 0;
944 while (ac) {
945 if (isdigit(**av)) {
946 i = atoi(*av);
947 if (i < 0 || i > 30)
948 errx(EX_DATAERR, "invalid set number %d\n", i);
949 masks[which] |= (1<<i);
950 } else if (!strncmp(*av, "disable", strlen(*av)))
951 which = 0;
952 else if (!strncmp(*av, "enable", strlen(*av)))
953 which = 1;
954 else
955 errx(EX_DATAERR, "invalid set command %s\n", *av);
956 NEXT_ARG;
958 if ( (masks[0] & masks[1]) != 0 )
959 errx(EX_DATAERR, "cannot enable and disable the same set\n");
960 i = do_set_x(IP_FW_DEL, masks, sizeof(masks));
961 if (i)
962 warn("set enable/disable: setsockopt(IP_FW_DEL)");
963 } else
964 errx(EX_USAGE, "invalid set command %s\n", *av);
967 static void
968 add_state(int ac, char *av[])
970 struct ipfw_ioc_state ioc_state;
971 ioc_state.expiry = 0;
972 ioc_state.lifetime = 0;
973 NEXT_ARG;
974 if (strcmp(*av, "rulenum") == 0) {
975 NEXT_ARG;
976 ioc_state.rulenum = atoi(*av);
977 } else {
978 errx(EX_USAGE, "ipfw state add rule");
980 NEXT_ARG;
981 struct protoent *pe;
982 pe = getprotobyname(*av);
983 ioc_state.flow_id.proto = pe->p_proto;
985 NEXT_ARG;
986 ioc_state.flow_id.src_ip = inet_addr(*av);
988 NEXT_ARG;
989 ioc_state.flow_id.src_port = atoi(*av);
991 NEXT_ARG;
992 ioc_state.flow_id.dst_ip = inet_addr(*av);
994 NEXT_ARG;
995 ioc_state.flow_id.dst_port = atoi(*av);
997 NEXT_ARG;
998 if (strcmp(*av, "live") == 0) {
999 NEXT_ARG;
1000 ioc_state.lifetime = atoi(*av);
1001 NEXT_ARG;
1004 if (strcmp(*av, "expiry") == 0) {
1005 NEXT_ARG;
1006 ioc_state.expiry = strtoul(*av, NULL, 10);
1007 printf("ioc_state.expiry=%d\n", ioc_state.expiry);
1010 if (do_set_x(IP_FW_STATE_ADD, &ioc_state, sizeof(struct ipfw_ioc_state)) < 0 ) {
1011 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_ADD)");
1013 if (!do_quiet) {
1014 printf("Flushed all states.\n");
1018 static void
1019 delete_state(int ac, char *av[])
1021 int rulenum;
1022 NEXT_ARG;
1023 if (ac == 1 && isdigit(**av))
1024 rulenum = atoi(*av);
1025 if (do_set_x(IP_FW_STATE_DEL, &rulenum, sizeof(int)) < 0 )
1026 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_DEL)");
1027 if (!do_quiet)
1028 printf("Flushed all states.\n");
1031 static void
1032 flush_state(int ac, char *av[])
1034 if (!do_force) {
1035 int c;
1037 printf("Are you sure? [yn] ");
1038 fflush(stdout);
1039 do {
1040 c = toupper(getc(stdin));
1041 while (c != '\n' && getc(stdin) != '\n')
1042 if (feof(stdin))
1043 return; /* and do not flush */
1044 } while (c != 'Y' && c != 'N');
1045 if (c == 'N') /* user said no */
1046 return;
1048 if (do_set_x(IP_FW_STATE_FLUSH, NULL, 0) < 0 )
1049 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_FLUSH)");
1050 if (!do_quiet)
1051 printf("Flushed all states.\n");
1054 static int
1055 lookup_host (char *host, struct in_addr *ipaddr)
1057 struct hostent *he;
1059 if (!inet_aton(host, ipaddr)) {
1060 if ((he = gethostbyname(host)) == NULL)
1061 return(-1);
1062 *ipaddr = *(struct in_addr *)he->h_addr_list[0];
1064 return(0);
1067 static void
1068 table_append(int ac, char *av[])
1070 struct ipfw_ioc_table tbl;
1071 char *p;
1072 int size;
1074 NEXT_ARG;
1075 if (isdigit(**av))
1076 tbl.id = atoi(*av);
1077 else
1078 errx(EX_USAGE, "table id `%s' invalid", *av);
1080 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1081 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1083 NEXT_ARG;
1084 if (strcmp(*av, "ip") == 0)
1085 tbl.type = 1;
1086 else if (strcmp(*av, "mac") == 0)
1087 tbl.type = 2;
1088 else
1089 errx(EX_USAGE, "table type `%s' not supported", *av);
1091 NEXT_ARG;
1092 if (tbl.type == 1) { /* table type ipv4 */
1093 struct ipfw_ioc_table_ip_entry ip_ent;
1094 if (!ac)
1095 errx(EX_USAGE, "IP address required");
1097 p = strchr(*av, '/');
1098 if (p) {
1099 *p++ = '\0';
1100 ip_ent.masklen = atoi(p);
1101 if (ip_ent.masklen > 32)
1102 errx(EX_DATAERR, "bad width ``%s''", p);
1103 } else {
1104 ip_ent.masklen = 32;
1107 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1108 errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1110 tbl.ip_ent[0] = ip_ent;
1111 size = sizeof(tbl) + sizeof(ip_ent);
1112 } else if (tbl.type == 2) { /* table type mac */
1113 struct ipfw_ioc_table_mac_entry mac_ent;
1114 if (!ac)
1115 errx(EX_USAGE, "MAC address required");
1117 mac_ent.addr = *ether_aton(*av);
1118 tbl.mac_ent[0] = mac_ent;
1119 size = sizeof(tbl) + sizeof(mac_ent);
1121 if (do_set_x(IP_FW_TABLE_APPEND, &tbl, size) < 0 )
1122 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_APPEND) "
1123 "table `%d' append `%s' failed", tbl.id, *av);
1126 static void
1127 table_remove(int ac, char *av[])
1129 struct ipfw_ioc_table tbl;
1130 struct ipfw_ioc_table_ip_entry ip_ent;
1131 char *p;
1132 int size;
1134 NEXT_ARG;
1135 if (isdigit(**av))
1136 tbl.id = atoi(*av);
1137 else
1138 errx(EX_USAGE, "table id `%s' invalid", *av);
1140 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1141 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1143 NEXT_ARG;
1144 if (strcmp(*av, "ip") == 0)
1145 tbl.type = 1;
1146 else if (strcmp(*av, "mac") == 0)
1147 tbl.type = 2;
1148 else
1149 errx(EX_USAGE, "table type `%s' not supported", *av);
1151 NEXT_ARG;
1152 if (!ac)
1153 errx(EX_USAGE, "IP address required");
1154 p = strchr(*av, '/');
1155 if (p) {
1156 *p++ = '\0';
1157 ip_ent.masklen = atoi(p);
1158 if (ip_ent.masklen > 32)
1159 errx(EX_DATAERR, "bad width ``%s''", p);
1160 } else {
1161 ip_ent.masklen = 32;
1164 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1165 errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1167 tbl.ip_ent[0] = ip_ent;
1168 size = sizeof(tbl) + sizeof(ip_ent);
1169 if (do_set_x(IP_FW_TABLE_REMOVE, &tbl, size) < 0 ) {
1170 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_REMOVE) "
1171 "table `%d' append `%s' failed", tbl.id, *av);
1175 static void
1176 table_flush(int ac, char *av[])
1178 struct ipfw_ioc_table ioc_table;
1179 struct ipfw_ioc_table *t = &ioc_table;
1181 NEXT_ARG;
1182 if (isdigit(**av)) {
1183 t->id = atoi(*av);
1184 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1185 errx(EX_USAGE, "table id `%d' invalid", t->id);
1186 } else {
1187 errx(EX_USAGE, "table id `%s' invalid", *av);
1189 if (do_set_x(IP_FW_TABLE_FLUSH, t, sizeof(struct ipfw_ioc_table)) < 0 )
1190 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_FLUSH) "
1191 "table `%s' flush failed", *av);
1194 static void
1195 table_list(int ac, char *av[])
1197 struct ipfw_ioc_table *ioc_table;
1198 int i, count, nbytes, nalloc = 1024;
1199 void *data = NULL;
1200 NEXT_ARG;
1201 if (strcmp(*av, "list") == 0) {
1202 nbytes = nalloc;
1203 while (nbytes >= nalloc) {
1204 nalloc = nalloc * 2 ;
1205 nbytes = nalloc;
1206 if ((data = realloc(data, nbytes)) == NULL)
1207 err(EX_OSERR, "realloc");
1208 if (do_get_x(IP_FW_TABLE_LIST, data, &nbytes) < 0)
1209 err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
1211 ioc_table = (struct ipfw_ioc_table *)data;
1212 count = nbytes / sizeof(struct ipfw_ioc_table);
1213 for (i = 0; i < count; i++, ioc_table++) {
1214 if (ioc_table->type > 0) {
1215 printf("table %d",ioc_table->id);
1216 if (ioc_table->type == 1)
1217 printf(" type ip");
1218 else if (ioc_table->type == 2)
1219 printf(" type mac");
1220 printf(" count %d",ioc_table->count);
1221 if (strlen(ioc_table->name) > 0)
1222 printf(" name %s",ioc_table->name);
1223 printf("\n");
1227 } else {
1228 errx(EX_USAGE, "ipfw3 table `%s' delete invalid", *av);
1232 void
1233 print_table(struct ipfw_ioc_table * tbl)
1235 int i;
1236 if (tbl->type == 0)
1237 errx(EX_USAGE, "table %d is not in use", tbl->id);
1239 printf("table %d", tbl->id);
1240 if (tbl->type == 1)
1241 printf(" type ip");
1242 else if (tbl->type == 2)
1243 printf(" type mac");
1245 printf(" count %d", tbl->count);
1246 if (strlen(tbl->name) > 0)
1247 printf(" name %s", tbl->name);
1249 printf("\n");
1251 if (tbl->type == 1) {
1252 struct ipfw_ioc_table_ip_entry *ip_ent;
1253 ip_ent = tbl->ip_ent;
1254 for (i = 0; i < tbl->count; i++) {
1255 printf("%s", inet_ntoa(*(struct in_addr *)&ip_ent->addr));
1256 printf("/%d ", ip_ent->masklen);
1257 printf("\n");
1258 ip_ent++;
1260 } else if (tbl->type == 2) {
1261 struct ipfw_ioc_table_mac_entry *mac_ent;
1262 mac_ent = tbl->mac_ent;
1263 for (i = 0; i < tbl->count; i++) {
1264 printf("%s", ether_ntoa(&mac_ent->addr));
1265 printf("\n");
1266 mac_ent++;
1271 static void
1272 table_show(int ac, char *av[])
1274 int nbytes, nalloc = 1024;
1275 void *data = NULL;
1276 NEXT_ARG;
1277 if (isdigit(**av)) {
1278 nbytes = nalloc;
1279 while (nbytes >= nalloc) {
1280 nalloc = nalloc * 2 + 256;
1281 nbytes = nalloc;
1282 if (data == NULL) {
1283 if ((data = malloc(nbytes)) == NULL) {
1284 err(EX_OSERR, "malloc");
1286 } else if ((data = realloc(data, nbytes)) == NULL) {
1287 err(EX_OSERR, "realloc");
1289 /* store table id in the header of data */
1290 int *head = (int *)data;
1291 *head = atoi(*av);
1292 if (*head < 0 || *head > IPFW_TABLES_MAX - 1)
1293 errx(EX_USAGE, "table id `%d' invalid", *head);
1294 if (do_get_x(IP_FW_TABLE_SHOW, data, &nbytes) < 0)
1295 err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
1296 struct ipfw_ioc_table *tbl;
1297 tbl = (struct ipfw_ioc_table *)data;
1298 print_table(tbl);
1300 } else {
1301 errx(EX_USAGE, "ipfw3 table `%s' show invalid", *av);
1305 static void
1306 table_create(int ac, char *av[])
1308 struct ipfw_ioc_table ioc_table;
1309 struct ipfw_ioc_table *t = &ioc_table;
1311 NEXT_ARG;
1312 if (ac < 2)
1313 errx(EX_USAGE, "table parameters invalid");
1314 if (isdigit(**av)) {
1315 t->id = atoi(*av);
1316 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1317 errx(EX_USAGE, "table id `%d' invalid", t->id);
1318 } else {
1319 errx(EX_USAGE, "table id `%s' invalid", *av);
1321 NEXT_ARG;
1322 if (strcmp(*av, "ip") == 0)
1323 t->type = 1;
1324 else if (strcmp(*av, "mac") == 0)
1325 t->type = 2;
1326 else
1327 errx(EX_USAGE, "table type `%s' not supported", *av);
1329 NEXT_ARG;
1330 memset(t->name, 0, IPFW_TABLE_NAME_LEN);
1331 if (ac == 2 && strcmp(*av, "name") == 0) {
1332 NEXT_ARG;
1333 if (strlen(*av) < IPFW_TABLE_NAME_LEN) {
1334 strncpy(t->name, *av, strlen(*av));
1335 } else {
1336 errx(EX_USAGE, "table name `%s' too long", *av);
1338 } else if (ac == 1) {
1339 errx(EX_USAGE, "table `%s' invalid", *av);
1342 if (do_set_x(IP_FW_TABLE_CREATE, t, sizeof(struct ipfw_ioc_table)) < 0)
1343 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_CREATE) "
1344 "table `%d' in use", t->id);
1347 static void
1348 table_delete(int ac, char *av[])
1350 struct ipfw_ioc_table ioc_table;
1351 struct ipfw_ioc_table *t = &ioc_table;
1353 NEXT_ARG;
1354 if (isdigit(**av)) {
1355 t->id = atoi(*av);
1356 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1357 errx(EX_USAGE, "table id `%d' invalid", t->id);
1358 } else {
1359 errx(EX_USAGE, "table id `%s' invalid", *av);
1361 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1362 errx(EX_USAGE, "table id `%d' invalid", t->id);
1364 if (do_set_x(IP_FW_TABLE_DELETE, t, sizeof(struct ipfw_ioc_table)) < 0)
1365 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_DELETE) "
1366 "table `%s' delete failed", *av);
1369 static void
1370 table_test(int ac, char *av[])
1372 struct ipfw_ioc_table tbl;
1373 int size;
1375 NEXT_ARG;
1376 if (isdigit(**av))
1377 tbl.id = atoi(*av);
1378 else
1379 errx(EX_USAGE, "table id `%s' invalid", *av);
1381 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1382 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1384 NEXT_ARG;
1385 if (strcmp(*av, "ip") == 0)
1386 tbl.type = 1;
1387 else if (strcmp(*av, "mac") == 0)
1388 tbl.type = 2;
1389 else
1390 errx(EX_USAGE, "table type `%s' not supported", *av);
1392 NEXT_ARG;
1393 if (tbl.type == 1) { /* table type ipv4 */
1394 struct ipfw_ioc_table_ip_entry ip_ent;
1395 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1396 errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1398 tbl.ip_ent[0] = ip_ent;
1399 size = sizeof(tbl) + sizeof(ip_ent);
1400 } else if (tbl.type == 2) { /* table type mac */
1401 struct ipfw_ioc_table_mac_entry mac_ent;
1402 if (!ac)
1403 errx(EX_USAGE, "MAC address required");
1405 mac_ent.addr = *ether_aton(*av);
1406 tbl.mac_ent[0] = mac_ent;
1407 size = sizeof(tbl) + sizeof(mac_ent);
1409 if (do_set_x(IP_FW_TABLE_TEST, &tbl, size) < 0 ) {
1410 printf("NO, %s not exists in table %d\n", *av, tbl.id);
1411 } else {
1412 printf("YES, %s exists in table %d\n", *av, tbl.id);
1416 static void
1417 table_rename(int ac, char *av[])
1419 struct ipfw_ioc_table tbl;
1420 int size;
1422 bzero(&tbl, sizeof(tbl));
1423 NEXT_ARG;
1424 if (isdigit(**av))
1425 tbl.id = atoi(*av);
1426 else
1427 errx(EX_USAGE, "table id `%s' invalid", *av);
1429 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1430 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1432 NEXT_ARG;
1433 strlcpy(tbl.name, *av, IPFW_TABLE_NAME_LEN);
1434 size = sizeof(tbl);
1435 if (do_set_x(IP_FW_TABLE_RENAME, &tbl, size) < 0 )
1436 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_RENAME) "
1437 "table `%d' not in use", tbl.id);
1440 static void
1441 list(int ac, char *av[])
1443 struct ipfw_ioc_state *dynrules, *d;
1444 struct ipfw_ioc_rule *r;
1446 u_long rnum;
1447 void *data = NULL;
1448 int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;
1449 int exitval = EX_OK, lac;
1450 char **lav, *endptr;
1451 int seen = 0;
1452 int nalloc = 1024;
1454 NEXT_ARG;
1456 /* get rules or pipes from kernel, resizing array as necessary */
1457 nbytes = nalloc;
1459 while (nbytes >= nalloc) {
1460 nalloc = nalloc * 2 ;
1461 nbytes = nalloc;
1462 if ((data = realloc(data, nbytes)) == NULL)
1463 err(EX_OSERR, "realloc");
1464 if (do_get_x(IP_FW_GET, data, &nbytes) < 0)
1465 err(EX_OSERR, "do_get_x(IP_FW_GET)");
1469 * Count static rules.
1471 r = data;
1472 nstat = r->static_count;
1475 * Count dynamic rules. This is easier as they have
1476 * fixed size.
1478 dynrules = (struct ipfw_ioc_state *)((void *)r + r->static_len);
1479 ndyn = (nbytes - r->static_len) / sizeof(*dynrules);
1481 /* if showing stats, figure out column widths ahead of time */
1482 bcwidth = pcwidth = 0;
1483 if (do_acct) {
1484 for (n = 0, r = data; n < nstat;
1485 n++, r = (void *)r + IOC_RULESIZE(r)) {
1486 /* packet counter */
1487 width = snprintf(NULL, 0, "%ju", (uintmax_t)r->pcnt);
1488 if (width > pcwidth)
1489 pcwidth = width;
1491 /* byte counter */
1492 width = snprintf(NULL, 0, "%ju", (uintmax_t)r->bcnt);
1493 if (width > bcwidth)
1494 bcwidth = width;
1497 if (do_dynamic && ndyn) {
1498 for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1499 width = snprintf(NULL, 0, "%ju", (uintmax_t)d->pcnt);
1500 if (width > pcwidth)
1501 pcwidth = width;
1503 width = snprintf(NULL, 0, "%ju", (uintmax_t)d->bcnt);
1504 if (width > bcwidth)
1505 bcwidth = width;
1509 /* if no rule numbers were specified, list all rules */
1510 if (ac == 0) {
1511 if (do_dynamic != 2) {
1512 for (n = 0, r = data; n < nstat; n++,
1513 r = (void *)r + IOC_RULESIZE(r)) {
1514 show_rules(r, pcwidth, bcwidth);
1517 if (do_dynamic && ndyn) {
1518 if (do_dynamic != 2) {
1519 printf("## States (%d):\n", ndyn);
1521 for (n = 0, d = dynrules; n < ndyn; n++, d++)
1522 show_states(d, pcwidth, bcwidth);
1524 goto done;
1527 /* display specific rules requested on command line */
1529 if (do_dynamic != 2) {
1530 for (lac = ac, lav = av; lac != 0; lac--) {
1531 /* convert command line rule # */
1532 rnum = strtoul(*lav++, &endptr, 10);
1533 if (*endptr) {
1534 exitval = EX_USAGE;
1535 warnx("invalid rule number: %s", *(lav - 1));
1536 continue;
1538 for (n = seen = 0, r = data; n < nstat;
1539 n++, r = (void *)r + IOC_RULESIZE(r) ) {
1540 if (r->rulenum > rnum)
1541 break;
1542 if (r->rulenum == rnum) {
1543 show_rules(r, pcwidth, bcwidth);
1544 seen = 1;
1547 if (!seen) {
1548 /* give precedence to other error(s) */
1549 if (exitval == EX_OK)
1550 exitval = EX_UNAVAILABLE;
1551 warnx("rule %lu does not exist", rnum);
1556 if (do_dynamic && ndyn) {
1557 if (do_dynamic != 2) {
1558 printf("## States (%d):\n", ndyn);
1560 for (lac = ac, lav = av; lac != 0; lac--) {
1561 rnum = strtoul(*lav++, &endptr, 10);
1562 if (*endptr)
1563 /* already warned */
1564 continue;
1565 for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1566 if (d->rulenum > rnum)
1567 break;
1568 if (d->rulenum == rnum)
1569 show_states(d, pcwidth, bcwidth);
1574 ac = 0;
1576 done:
1577 free(data);
1579 if (exitval != EX_OK)
1580 exit(exitval);
1583 static void
1584 show_dummynet(int ac, char *av[])
1586 void *data = NULL;
1587 int nbytes;
1588 int nalloc = 1024; /* start somewhere... */
1590 NEXT_ARG;
1592 nbytes = nalloc;
1593 while (nbytes >= nalloc) {
1594 nalloc = nalloc * 2 + 200;
1595 nbytes = nalloc;
1596 if ((data = realloc(data, nbytes)) == NULL)
1597 err(EX_OSERR, "realloc");
1598 if (do_get_x(IP_DUMMYNET_GET, data, &nbytes) < 0) {
1599 err(EX_OSERR, "do_get_x(IP_%s_GET)",
1600 do_pipe ? "DUMMYNET" : "FW");
1604 show_pipes(data, nbytes, ac, av);
1605 free(data);
1608 static void
1609 help(void)
1611 fprintf(stderr, "usage: ipfw [options]\n"
1612 " ipfw add [rulenum] [set id] action filters\n"
1613 " ipfw delete [rulenum]\n"
1614 " ipfw flush\n"
1615 " ipfw list [rulenum]\n"
1616 " ipfw show [rulenum]\n"
1617 " ipfw zero [rulenum]\n"
1618 " ipfw set [show|enable|disable]\n"
1619 " ipfw module\n"
1620 " ipfw [enable|disable]\n"
1621 " ipfw log [reset|off|on]\n"
1622 " ipfw nat [config|show|delete]\n"
1623 " ipfw pipe [config|show|delete]\n"
1624 " ipfw state [add|delete|list|show]"
1625 "\nsee ipfw manpage for details\n");
1626 exit(EX_USAGE);
1629 static void
1630 delete_nat_config(int ac, char *av[])
1632 NEXT_ARG;
1633 int i = 0;
1634 if (ac > 0) {
1635 i = atoi(*av);
1637 if (do_set_x(IP_FW_NAT_DEL, &i, sizeof(i)) == -1)
1638 errx(EX_USAGE, "NAT %d in use or not exists", i);
1641 static void
1642 delete_rules(int ac, char *av[])
1644 struct dn_ioc_pipe pipe;
1645 u_int32_t rulenum;
1646 int exitval = EX_OK;
1647 int do_set = 0;
1648 int i;
1650 memset(&pipe, 0, sizeof pipe);
1652 NEXT_ARG;
1653 if (ac > 0 && !strncmp(*av, "set", strlen(*av))) {
1654 do_set = 1; /* delete set */
1655 NEXT_ARG;
1658 /* Rule number */
1659 while (ac && isdigit(**av)) {
1660 i = atoi(*av);
1661 NEXT_ARG;
1662 if (do_pipe) {
1663 if (do_pipe == 1)
1664 pipe.pipe_nr = i;
1665 else
1666 pipe.fs.fs_nr = i;
1668 i = do_set_x(IP_DUMMYNET_DEL, &pipe, sizeof pipe);
1669 if (i) {
1670 exitval = 1;
1671 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
1672 do_pipe == 1 ? pipe.pipe_nr : pipe.fs.fs_nr);
1674 } else {
1675 rulenum = (i & 0xffff) | (do_set << 24);
1676 i = do_set_x(IP_FW_DEL, &rulenum, sizeof rulenum);
1677 if (i) {
1678 exitval = EX_UNAVAILABLE;
1679 warn("rule %u: setsockopt(IP_FW_DEL)",
1680 rulenum);
1684 if (exitval != EX_OK)
1685 exit(exitval);
1689 static unsigned long
1690 getbw(const char *str, u_short *flags, int kb)
1692 unsigned long val;
1693 int inbytes = 0;
1694 char *end;
1696 val = strtoul(str, &end, 0);
1697 if (*end == 'k' || *end == 'K') {
1698 ++end;
1699 val *= kb;
1700 } else if (*end == 'm' || *end == 'M') {
1701 ++end;
1702 val *= kb * kb;
1706 * Deal with bits or bytes or b(bits) or B(bytes). If there is no
1707 * trailer assume bits.
1709 if (strncasecmp(end, "bit", 3) == 0) {
1711 } else if (strncasecmp(end, "byte", 4) == 0) {
1712 inbytes = 1;
1713 } else if (*end == 'b') {
1715 } else if (*end == 'B') {
1716 inbytes = 1;
1720 * Return in bits if flags is NULL, else flag bits
1721 * or bytes in flags and return the unconverted value.
1723 if (inbytes && flags)
1724 *flags |= DN_QSIZE_IS_BYTES;
1725 else if (inbytes && flags == NULL)
1726 val *= 8;
1728 return(val);
1732 * config dummynet pipe/queue
1734 static void
1735 config_dummynet(int ac, char **av)
1737 struct dn_ioc_pipe pipe;
1738 u_int32_t a;
1739 void *par = NULL;
1740 int i;
1741 char *end;
1743 NEXT_ARG;
1744 memset(&pipe, 0, sizeof pipe);
1745 /* Pipe number */
1746 if (ac && isdigit(**av)) {
1747 i = atoi(*av);
1748 NEXT_ARG;
1749 if (do_pipe == 1)
1750 pipe.pipe_nr = i;
1751 else
1752 pipe.fs.fs_nr = i;
1755 while (ac > 0) {
1756 double d;
1758 int tok = match_token(dummynet_params, *av);
1759 NEXT_ARG;
1761 switch(tok) {
1762 case TOK_NOERROR:
1763 pipe.fs.flags_fs |= DN_NOERROR;
1764 break;
1766 case TOK_PLR:
1767 NEED1("plr needs argument 0..1\n");
1768 d = strtod(av[0], NULL);
1769 if (d > 1)
1770 d = 1;
1771 else if (d < 0)
1772 d = 0;
1773 pipe.fs.plr = (int)(d*0x7fffffff);
1774 NEXT_ARG;
1775 break;
1777 case TOK_QUEUE:
1778 NEED1("queue needs queue size\n");
1779 end = NULL;
1780 pipe.fs.qsize = getbw(av[0], &pipe.fs.flags_fs, 1024);
1781 NEXT_ARG;
1782 break;
1784 case TOK_BUCKETS:
1785 NEED1("buckets needs argument\n");
1786 pipe.fs.rq_size = strtoul(av[0], NULL, 0);
1787 NEXT_ARG;
1788 break;
1790 case TOK_MASK:
1791 NEED1("mask needs mask specifier\n");
1793 * per-flow queue, mask is dst_ip, dst_port,
1794 * src_ip, src_port, proto measured in bits
1796 par = NULL;
1798 pipe.fs.flow_mask.type = ETHERTYPE_IP;
1799 pipe.fs.flow_mask.u.ip.dst_ip = 0;
1800 pipe.fs.flow_mask.u.ip.src_ip = 0;
1801 pipe.fs.flow_mask.u.ip.dst_port = 0;
1802 pipe.fs.flow_mask.u.ip.src_port = 0;
1803 pipe.fs.flow_mask.u.ip.proto = 0;
1804 end = NULL;
1806 while (ac >= 1) {
1807 u_int32_t *p32 = NULL;
1808 u_int16_t *p16 = NULL;
1810 tok = match_token(dummynet_params, *av);
1811 NEXT_ARG;
1812 switch(tok) {
1813 case TOK_ALL:
1815 * special case, all bits significant
1817 pipe.fs.flow_mask.u.ip.dst_ip = ~0;
1818 pipe.fs.flow_mask.u.ip.src_ip = ~0;
1819 pipe.fs.flow_mask.u.ip.dst_port = ~0;
1820 pipe.fs.flow_mask.u.ip.src_port = ~0;
1821 pipe.fs.flow_mask.u.ip.proto = ~0;
1822 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1823 goto end_mask;
1825 case TOK_DSTIP:
1826 p32 = &pipe.fs.flow_mask.u.ip.dst_ip;
1827 break;
1829 case TOK_SRCIP:
1830 p32 = &pipe.fs.flow_mask.u.ip.src_ip;
1831 break;
1833 case TOK_DSTPORT:
1834 p16 = &pipe.fs.flow_mask.u.ip.dst_port;
1835 break;
1837 case TOK_SRCPORT:
1838 p16 = &pipe.fs.flow_mask.u.ip.src_port;
1839 break;
1841 case TOK_PROTO:
1842 break;
1844 default:
1845 NEXT_ARG;
1846 goto end_mask;
1848 if (ac < 1)
1849 errx(EX_USAGE, "mask: value missing");
1850 if (*av[0] == '/') {
1851 a = strtoul(av[0]+1, &end, 0);
1852 a = (a == 32) ? ~0 : (1 << a) - 1;
1853 } else
1854 a = strtoul(av[0], &end, 0);
1855 if (p32 != NULL)
1856 *p32 = a;
1857 else if (p16 != NULL) {
1858 if (a > 65535)
1859 errx(EX_DATAERR,
1860 "mask: must be 16 bit");
1861 *p16 = (u_int16_t)a;
1862 } else {
1863 if (a > 255)
1864 errx(EX_DATAERR,
1865 "mask: must be 8 bit");
1866 pipe.fs.flow_mask.u.ip.proto = (uint8_t)a;
1868 if (a != 0)
1869 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1870 NEXT_ARG;
1871 } /* end while, config masks */
1873 end_mask:
1874 break;
1876 case TOK_RED:
1877 case TOK_GRED:
1878 NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
1879 pipe.fs.flags_fs |= DN_IS_RED;
1880 if (tok == TOK_GRED)
1881 pipe.fs.flags_fs |= DN_IS_GENTLE_RED;
1883 * the format for parameters is w_q/min_th/max_th/max_p
1885 if ((end = strsep(&av[0], "/"))) {
1886 double w_q = strtod(end, NULL);
1887 if (w_q > 1 || w_q <= 0)
1888 errx(EX_DATAERR, "0 < w_q <= 1");
1889 pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED));
1891 if ((end = strsep(&av[0], "/"))) {
1892 pipe.fs.min_th = strtoul(end, &end, 0);
1893 if (*end == 'K' || *end == 'k')
1894 pipe.fs.min_th *= 1024;
1896 if ((end = strsep(&av[0], "/"))) {
1897 pipe.fs.max_th = strtoul(end, &end, 0);
1898 if (*end == 'K' || *end == 'k')
1899 pipe.fs.max_th *= 1024;
1901 if ((end = strsep(&av[0], "/"))) {
1902 double max_p = strtod(end, NULL);
1903 if (max_p > 1 || max_p <= 0)
1904 errx(EX_DATAERR, "0 < max_p <= 1");
1905 pipe.fs.max_p = (int)(max_p * (1 << SCALE_RED));
1907 NEXT_ARG;
1908 break;
1910 case TOK_DROPTAIL:
1911 pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
1912 break;
1914 case TOK_BW:
1915 NEED1("bw needs bandwidth\n");
1916 if (do_pipe != 1)
1917 errx(EX_DATAERR, "bandwidth only valid for pipes");
1919 * set bandwidth value
1921 pipe.bandwidth = getbw(av[0], NULL, 1000);
1922 if (pipe.bandwidth < 0)
1923 errx(EX_DATAERR, "bandwidth too large");
1924 NEXT_ARG;
1925 break;
1927 case TOK_DELAY:
1928 if (do_pipe != 1)
1929 errx(EX_DATAERR, "delay only valid for pipes");
1930 NEED1("delay needs argument 0..10000ms\n");
1931 pipe.delay = strtoul(av[0], NULL, 0);
1932 NEXT_ARG;
1933 break;
1935 case TOK_WEIGHT:
1936 if (do_pipe == 1)
1937 errx(EX_DATAERR, "weight only valid for queues");
1938 NEED1("weight needs argument 0..100\n");
1939 pipe.fs.weight = strtoul(av[0], &end, 0);
1940 NEXT_ARG;
1941 break;
1943 case TOK_PIPE:
1944 if (do_pipe == 1)
1945 errx(EX_DATAERR, "pipe only valid for queues");
1946 NEED1("pipe needs pipe_number\n");
1947 pipe.fs.parent_nr = strtoul(av[0], &end, 0);
1948 NEXT_ARG;
1949 break;
1951 default:
1952 errx(EX_DATAERR, "unrecognised option ``%s''", *av);
1955 if (do_pipe == 1) {
1956 if (pipe.pipe_nr == 0)
1957 errx(EX_DATAERR, "pipe_nr must be > 0");
1958 if (pipe.delay > 10000)
1959 errx(EX_DATAERR, "delay must be < 10000");
1960 } else { /* do_pipe == 2, queue */
1961 if (pipe.fs.parent_nr == 0)
1962 errx(EX_DATAERR, "pipe must be > 0");
1963 if (pipe.fs.weight >100)
1964 errx(EX_DATAERR, "weight must be <= 100");
1966 if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) {
1967 if (pipe.fs.qsize > 1024*1024)
1968 errx(EX_DATAERR, "queue size must be < 1MB");
1969 } else {
1970 if (pipe.fs.qsize > 100)
1971 errx(EX_DATAERR, "2 <= queue size <= 100");
1973 if (pipe.fs.flags_fs & DN_IS_RED) {
1974 size_t len;
1975 int lookup_depth, avg_pkt_size;
1976 double s, idle, weight, w_q;
1977 int clock_hz;
1978 int t;
1980 if (pipe.fs.min_th >= pipe.fs.max_th)
1981 errx(EX_DATAERR, "min_th %d must be < than max_th %d",
1982 pipe.fs.min_th, pipe.fs.max_th);
1983 if (pipe.fs.max_th == 0)
1984 errx(EX_DATAERR, "max_th must be > 0");
1986 len = sizeof(int);
1987 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
1988 &lookup_depth, &len, NULL, 0) == -1)
1990 errx(1, "sysctlbyname(\"%s\")",
1991 "net.inet.ip.dummynet.red_lookup_depth");
1992 if (lookup_depth == 0)
1993 errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
1994 " must be greater than zero");
1996 len = sizeof(int);
1997 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
1998 &avg_pkt_size, &len, NULL, 0) == -1)
2000 errx(1, "sysctlbyname(\"%s\")",
2001 "net.inet.ip.dummynet.red_avg_pkt_size");
2002 if (avg_pkt_size == 0)
2003 errx(EX_DATAERR,
2004 "net.inet.ip.dummynet.red_avg_pkt_size must"
2005 " be greater than zero");
2007 len = sizeof(clock_hz);
2008 if (sysctlbyname("net.inet.ip.dummynet.hz", &clock_hz, &len,
2009 NULL, 0) == -1) {
2010 errx(1, "sysctlbyname(\"%s\")",
2011 "net.inet.ip.dummynet.hz");
2015 * Ticks needed for sending a medium-sized packet.
2016 * Unfortunately, when we are configuring a WF2Q+ queue, we
2017 * do not have bandwidth information, because that is stored
2018 * in the parent pipe, and also we have multiple queues
2019 * competing for it. So we set s=0, which is not very
2020 * correct. But on the other hand, why do we want RED with
2021 * WF2Q+ ?
2023 if (pipe.bandwidth == 0) /* this is a WF2Q+ queue */
2024 s = 0;
2025 else
2026 s = clock_hz * avg_pkt_size * 8 / pipe.bandwidth;
2029 * max idle time (in ticks) before avg queue size becomes 0.
2030 * NOTA: (3/w_q) is approx the value x so that
2031 * (1-w_q)^x < 10^-3.
2033 w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED);
2034 idle = s * 3. / w_q;
2035 pipe.fs.lookup_step = (int)idle / lookup_depth;
2036 if (!pipe.fs.lookup_step)
2037 pipe.fs.lookup_step = 1;
2038 weight = 1 - w_q;
2039 for (t = pipe.fs.lookup_step; t > 0; --t)
2040 weight *= weight;
2041 pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
2043 i = do_set_x(IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe);
2044 if (i)
2045 err(1, "do_set_x(%s)", "IP_DUMMYNET_CONFIGURE");
2049 * helper function, updates the pointer to cmd with the length
2050 * of the current command, and also cleans up the first word of
2051 * the new command in case it has been clobbered before.
2053 static ipfw_insn*
2054 next_cmd(ipfw_insn *cmd)
2056 cmd += F_LEN(cmd);
2057 bzero(cmd, sizeof(*cmd));
2058 return cmd;
2062 * Parse arguments and assemble the microinstructions which make up a rule.
2063 * Rules are added into the 'rulebuf' and then copied in the correct order
2064 * into the actual rule.
2068 static void
2069 add(int ac, char *av[])
2072 * rules are added into the 'rulebuf' and then copied in
2073 * the correct order into the actual rule.
2074 * Some things that need to go out of order (prob, action etc.)
2075 * go into actbuf[].
2077 static uint32_t rulebuf[IPFW_RULE_SIZE_MAX];
2078 static uint32_t actbuf[IPFW_RULE_SIZE_MAX];
2079 static uint32_t othbuf[IPFW_RULE_SIZE_MAX];
2080 static uint32_t cmdbuf[IPFW_RULE_SIZE_MAX];
2082 ipfw_insn *src, *dst, *cmd, *action, *other;
2083 ipfw_insn *prev;
2084 char *prev_av;
2085 ipfw_insn *the_comment = NULL;
2086 struct ipfw_ioc_rule *rule;
2087 struct ipfw_keyword *key;
2088 struct ipfw_mapping *map;
2089 parser_func fn;
2090 int i, j;
2092 bzero(actbuf, sizeof(actbuf)); /* actions go here */
2093 bzero(othbuf, sizeof(actbuf)); /* others */
2094 bzero(cmdbuf, sizeof(cmdbuf)); /* filters */
2095 bzero(rulebuf, sizeof(rulebuf));
2097 rule = (struct ipfw_ioc_rule *)rulebuf;
2098 cmd = (ipfw_insn *)cmdbuf;
2099 action = (ipfw_insn *)actbuf;
2100 other = (ipfw_insn *)othbuf;
2102 NEED2("need more parameters");
2103 NEXT_ARG;
2105 /* [rule N] -- Rule number optional */
2106 if (ac && isdigit(**av)) {
2107 rule->rulenum = atoi(*av);
2108 NEXT_ARG;
2111 /* [set N] -- set number (0..30), optional */
2112 if (ac > 1 && !strncmp(*av, "set", strlen(*av))) {
2113 int set = strtoul(av[1], NULL, 10);
2114 if (set < 0 || set > 30)
2115 errx(EX_DATAERR, "illegal set %s", av[1]);
2116 rule->set = set;
2117 av += 2; ac -= 2;
2121 * parse before
2123 for (;;) {
2124 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2125 if (key->type == BEFORE &&
2126 strcmp(key->word, *av) == 0) {
2127 for (j = 0, map = mappings;
2128 j < MAPPING_SIZE; j++, map++) {
2129 if (map->type == IN_USE &&
2130 map->module == key->module &&
2131 map->opcode == key->opcode ) {
2132 fn = map->parser;
2133 (*fn)(&other, &ac, &av);
2134 break;
2137 break;
2140 if (i >= KEYWORD_SIZE) {
2141 break;
2142 } else if (F_LEN(other) > 0) {
2143 if (other->module == MODULE_BASIC_ID &&
2144 other->opcode == O_BASIC_CHECK_STATE) {
2145 other = next_cmd(other);
2146 goto done;
2148 other = next_cmd(other);
2153 * parse actions
2155 * only accept 1 action
2157 NEED1("missing action");
2158 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2159 if (ac > 0 && key->type == ACTION &&
2160 strcmp(key->word, *av) == 0) {
2161 for (j = 0, map = mappings; j<MAPPING_SIZE; j++, map++) {
2162 if (map->type == IN_USE &&
2163 map->module == key->module &&
2164 map->opcode == key->opcode) {
2165 fn = map->parser;
2166 (*fn)(&action, &ac, &av);
2167 break;
2170 break;
2173 if (F_LEN(action) > 0)
2174 action = next_cmd(action);
2177 * parse protocol
2179 if (strcmp(*av, "proto") == 0){
2180 NEXT_ARG;
2183 NEED1("missing protocol");
2184 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2185 if (key->type == PROTO &&
2186 strcmp(key->word, "proto") == 0) {
2187 for (j = 0, map = mappings; j<MAPPING_SIZE; j++, map++) {
2188 if (map->type == IN_USE &&
2189 map->module == key->module &&
2190 map->opcode == key->opcode ) {
2191 fn = map->parser;
2192 (*fn)(&cmd, &ac, &av);
2193 break;
2196 break;
2199 if (F_LEN(cmd) > 0)
2200 cmd = next_cmd(cmd);
2203 * other filters
2205 while (ac > 0) {
2206 char *s, *cur; /* current filter */
2207 ipfw_insn_u32 *cmd32; /* alias for cmd */
2209 s = *av;
2210 cmd32 = (ipfw_insn_u32 *)cmd;
2211 if (strcmp(*av, "or") == 0) {
2212 if (prev == NULL)
2213 errx(EX_USAGE, "'or' should"
2214 "between two filters\n");
2215 prev->len |= F_OR;
2216 cmd->len = F_OR;
2217 *av = prev_av;
2219 if (strcmp(*av, "not") == 0) {
2220 if (cmd->len & F_NOT)
2221 errx(EX_USAGE, "double \"not\" not allowed\n");
2222 cmd->len = F_NOT;
2223 NEXT_ARG;
2224 continue;
2226 cur = *av;
2227 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2228 if ((key->type == FILTER ||
2229 key->type == AFTER ||
2230 key->type == FROM ||
2231 key->type == TO) &&
2232 strcmp(key->word, cur) == 0) {
2233 for (j = 0, map = mappings;
2234 j< MAPPING_SIZE; j++, map++) {
2235 if (map->type == IN_USE &&
2236 map->module == key->module &&
2237 map->opcode == key->opcode ) {
2238 fn = map->parser;
2239 (*fn)(&cmd, &ac, &av);
2240 break;
2243 break;
2244 } else if (i == KEYWORD_SIZE - 1) {
2245 errx(EX_USAGE, "bad command `%s'", cur);
2248 if (i >= KEYWORD_SIZE) {
2249 break;
2250 } else if (F_LEN(cmd) > 0) {
2251 prev = cmd;
2252 prev_av = cur;
2253 cmd = next_cmd(cmd);
2257 done:
2258 if (ac>0)
2259 errx(EX_USAGE, "bad command `%s'", *av);
2262 * Now copy stuff into the rule.
2263 * [filters][others][action][comment]
2265 dst = (ipfw_insn *)rule->cmd;
2267 * copy all filters, except comment
2269 src = (ipfw_insn *)cmdbuf;
2270 for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
2271 /* pick comment out */
2272 i = F_LEN(src);
2273 if (src->module == MODULE_BASIC_ID && src->opcode == O_BASIC_COMMENT) {
2274 the_comment=src;
2275 } else {
2276 bcopy(src, dst, i * sizeof(u_int32_t));
2277 dst = (ipfw_insn *)((uint32_t *)dst + i);
2282 * start action section, it begin with others
2284 rule->act_ofs = (uint32_t *)dst - (uint32_t *)(rule->cmd);
2287 * copy all other others
2289 for (src = (ipfw_insn *)othbuf; src != other; src += i) {
2290 i = F_LEN(src);
2291 bcopy(src, dst, i * sizeof(u_int32_t));
2292 dst = (ipfw_insn *)((uint32_t *)dst + i);
2295 /* copy the action to the end of rule */
2296 src = (ipfw_insn *)actbuf;
2297 i = F_LEN(src);
2298 bcopy(src, dst, i * sizeof(u_int32_t));
2299 dst = (ipfw_insn *)((uint32_t *)dst + i);
2302 * comment place behind the action
2304 if (the_comment != NULL) {
2305 i = F_LEN(the_comment);
2306 bcopy(the_comment, dst, i * sizeof(u_int32_t));
2307 dst = (ipfw_insn *)((uint32_t *)dst + i);
2310 rule->cmd_len = (u_int32_t *)dst - (u_int32_t *)(rule->cmd);
2311 i = (void *)dst - (void *)rule;
2312 if (do_set_x(IP_FW_ADD, (void *)rule, i) == -1) {
2313 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
2315 if (!do_quiet)
2316 show_rules(rule, 10, 10);
2319 static void
2320 zero(int ac, char *av[])
2322 int rulenum;
2323 int failed = EX_OK;
2325 NEXT_ARG;
2327 if (!ac) {
2328 /* clear all entries */
2329 if (do_set_x(IP_FW_ZERO, NULL, 0) < 0)
2330 err(EX_UNAVAILABLE, "do_set_x(IP_FW_ZERO)");
2331 if (!do_quiet)
2332 printf("Accounting cleared.\n");
2333 return;
2336 while (ac) {
2337 /* Rule number */
2338 if (isdigit(**av)) {
2339 rulenum = atoi(*av);
2340 NEXT_ARG;
2341 if (do_set_x(IP_FW_ZERO, &rulenum, sizeof rulenum)) {
2342 warn("rule %u: do_set_x(IP_FW_ZERO)", rulenum);
2343 failed = EX_UNAVAILABLE;
2344 } else if (!do_quiet)
2345 printf("Entry %d cleared\n", rulenum);
2346 } else {
2347 errx(EX_USAGE, "invalid rule number ``%s''", *av);
2350 if (failed != EX_OK)
2351 exit(failed);
2354 static void
2355 resetlog(int ac, char *av[])
2357 int rulenum;
2358 int failed = EX_OK;
2360 NEXT_ARG;
2362 if (!ac) {
2363 /* clear all entries */
2364 if (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_RESETLOG, NULL, 0) < 0)
2365 err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)");
2366 if (!do_quiet)
2367 printf("Logging counts reset.\n");
2369 return;
2372 while (ac) {
2373 /* Rule number */
2374 if (isdigit(**av)) {
2375 rulenum = atoi(*av);
2376 NEXT_ARG;
2377 if (setsockopt(ipfw_socket, IPPROTO_IP,
2378 IP_FW_RESETLOG, &rulenum, sizeof rulenum)) {
2379 warn("rule %u: setsockopt(IP_FW_RESETLOG)", rulenum);
2380 failed = EX_UNAVAILABLE;
2381 } else if (!do_quiet)
2382 printf("Entry %d logging count reset\n", rulenum);
2383 } else {
2384 errx(EX_DATAERR, "invalid rule number ``%s''", *av);
2387 if (failed != EX_OK)
2388 exit(failed);
2391 static void
2392 flush(void)
2394 int cmd = IP_FW_FLUSH;
2395 if (do_pipe) {
2396 cmd = IP_DUMMYNET_FLUSH;
2397 } else if (do_nat) {
2398 cmd = IP_FW_NAT_FLUSH;
2400 if (!do_force) {
2401 int c;
2403 printf("Are you sure? [yn] ");
2404 fflush(stdout);
2405 do {
2406 c = toupper(getc(stdin));
2407 while (c != '\n' && getc(stdin) != '\n')
2408 if (feof(stdin))
2409 return; /* and do not flush */
2410 } while (c != 'Y' && c != 'N');
2411 if (c == 'N') /* user said no */
2412 return;
2414 if (do_set_x(cmd, NULL, 0) < 0 ) {
2415 if (do_pipe)
2416 errx(EX_USAGE, "pipe/queue in use");
2417 else if (do_nat)
2418 errx(EX_USAGE, "NAT configuration in use");
2419 else
2420 errx(EX_USAGE, "do_set_x(IP_FWFLUSH) failed");
2422 if (!do_quiet) {
2423 printf("Flushed all %s.\n", do_pipe ? "pipes":
2424 (do_nat?"nat configurations":"rules"));
2428 static void
2429 str2addr(const char* str, struct in_addr* addr)
2431 struct hostent* hp;
2433 if (inet_aton (str, addr))
2434 return;
2436 hp = gethostbyname (str);
2437 if (!hp)
2438 errx (1, "unknown host %s", str);
2440 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
2443 static int
2444 str2portrange(const char* str, const char* proto, port_range *portRange)
2446 struct servent* sp;
2447 char* sep;
2448 char* end;
2449 u_short loPort, hiPort;
2451 /* First see if this is a service, return corresponding port if so. */
2452 sp = getservbyname (str, proto);
2453 if (sp) {
2454 SETLOPORT(*portRange, ntohs(sp->s_port));
2455 SETNUMPORTS(*portRange, 1);
2456 return 0;
2459 /* Not a service, see if it's a single port or port range. */
2460 sep = strchr (str, '-');
2461 if (sep == NULL) {
2462 SETLOPORT(*portRange, strtol(str, &end, 10));
2463 if (end != str) {
2464 /* Single port. */
2465 SETNUMPORTS(*portRange, 1);
2466 return 0;
2469 /* Error in port range field. */
2470 errx (EX_DATAERR, "%s/%s: unknown service", str, proto);
2473 /* Port range, get the values and sanity check. */
2474 sscanf (str, "%hu-%hu", &loPort, &hiPort);
2475 SETLOPORT(*portRange, loPort);
2476 SETNUMPORTS(*portRange, 0); /* Error by default */
2477 if (loPort <= hiPort)
2478 SETNUMPORTS(*portRange, hiPort - loPort + 1);
2480 if (GETNUMPORTS(*portRange) == 0)
2481 errx (EX_DATAERR, "invalid port range %s", str);
2483 return 0;
2486 static int
2487 str2proto(const char* str)
2489 if (!strcmp (str, "tcp"))
2490 return IPPROTO_TCP;
2491 if (!strcmp (str, "udp"))
2492 return IPPROTO_UDP;
2493 errx (EX_DATAERR, "unknown protocol %s. Expected tcp or udp", str);
2496 static int
2497 str2addr_portrange (const char* str, struct in_addr* addr,
2498 char* proto, port_range *portRange)
2500 char* ptr;
2502 ptr = strchr (str, ':');
2503 if (!ptr)
2504 errx (EX_DATAERR, "%s is missing port number", str);
2506 *ptr = '\0';
2507 ++ptr;
2509 str2addr (str, addr);
2510 return str2portrange (ptr, proto, portRange);
2514 * Search for interface with name "ifn", and fill n accordingly:
2516 * n->ip ip address of interface "ifn"
2517 * n->if_name copy of interface name "ifn"
2519 static void
2520 set_addr_dynamic(const char *ifn, struct cfg_nat *n)
2522 struct if_msghdr *ifm;
2523 struct ifa_msghdr *ifam;
2524 struct sockaddr_dl *sdl;
2525 struct sockaddr_in *sin;
2526 char *buf, *lim, *next;
2527 size_t needed;
2528 int mib[6];
2529 int ifIndex, ifMTU;
2531 mib[0] = CTL_NET;
2532 mib[1] = PF_ROUTE;
2533 mib[2] = 0;
2534 mib[3] = AF_INET;
2535 mib[4] = NET_RT_IFLIST;
2536 mib[5] = 0;
2539 * Get interface data.
2541 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
2542 err(1, "iflist-sysctl-estimate");
2543 if ((buf = malloc(needed)) == NULL)
2544 errx(1, "malloc failed");
2545 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
2546 err(1, "iflist-sysctl-get");
2547 lim = buf + needed;
2549 * Loop through interfaces until one with
2550 * given name is found. This is done to
2551 * find correct interface index for routing
2552 * message processing.
2554 ifIndex = 0;
2555 next = buf;
2556 while (next < lim) {
2557 ifm = (struct if_msghdr *)next;
2558 next += ifm->ifm_msglen;
2559 if (ifm->ifm_version != RTM_VERSION) {
2560 if (verbose)
2561 warnx("routing message version %d "
2562 "not understood", ifm->ifm_version);
2563 continue;
2565 if (ifm->ifm_type == RTM_IFINFO) {
2566 sdl = (struct sockaddr_dl *)(ifm + 1);
2567 if (strlen(ifn) == sdl->sdl_nlen &&
2568 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
2569 ifIndex = ifm->ifm_index;
2570 ifMTU = ifm->ifm_data.ifi_mtu;
2571 break;
2575 if (!ifIndex)
2576 errx(1, "unknown interface name %s", ifn);
2578 * Get interface address.
2580 sin = NULL;
2581 while (next < lim) {
2582 ifam = (struct ifa_msghdr *)next;
2583 next += ifam->ifam_msglen;
2584 if (ifam->ifam_version != RTM_VERSION) {
2585 if (verbose)
2586 warnx("routing message version %d "
2587 "not understood", ifam->ifam_version);
2588 continue;
2590 if (ifam->ifam_type != RTM_NEWADDR)
2591 break;
2592 if (ifam->ifam_addrs & RTA_IFA) {
2593 int i;
2594 char *cp = (char *)(ifam + 1);
2596 for (i = 1; i < RTA_IFA; i <<= 1) {
2597 if (ifam->ifam_addrs & i)
2598 cp += SA_SIZE((struct sockaddr *)cp);
2600 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
2601 sin = (struct sockaddr_in *)cp;
2602 break;
2606 if (sin == NULL)
2607 errx(1, "%s: cannot get interface address", ifn);
2609 n->ip = sin->sin_addr;
2610 strncpy(n->if_name, ifn, IF_NAMESIZE);
2612 free(buf);
2615 static int
2616 setup_redir_addr(char *spool_buf, int len, int *_ac, char ***_av)
2618 struct cfg_redir *r;
2619 struct cfg_spool *tmp;
2620 char **av, *sep;
2621 char tmp_spool_buf[NAT_BUF_LEN];
2622 int ac, i, space, lsnat;
2624 i=0;
2625 av = *_av;
2626 ac = *_ac;
2627 space = 0;
2628 lsnat = 0;
2629 if (len >= SOF_REDIR) {
2630 r = (struct cfg_redir *)spool_buf;
2631 /* Skip cfg_redir at beginning of buf. */
2632 spool_buf = &spool_buf[SOF_REDIR];
2633 space = SOF_REDIR;
2634 len -= SOF_REDIR;
2635 } else {
2636 goto nospace;
2639 r->mode = REDIR_ADDR;
2640 /* Extract local address. */
2641 if (ac == 0)
2642 errx(EX_DATAERR, "redirect_addr: missing local address");
2644 sep = strchr(*av, ',');
2645 if (sep) { /* LSNAT redirection syntax. */
2646 r->laddr.s_addr = INADDR_NONE;
2647 /* Preserve av, copy spool servers to tmp_spool_buf. */
2648 strncpy(tmp_spool_buf, *av, strlen(*av)+1);
2649 lsnat = 1;
2650 } else {
2651 str2addr(*av, &r->laddr);
2653 INC_ARGCV();
2655 /* Extract public address. */
2656 if (ac == 0)
2657 errx(EX_DATAERR, "redirect_addr: missing public address");
2659 str2addr(*av, &r->paddr);
2660 INC_ARGCV();
2662 /* Setup LSNAT server pool. */
2663 if (sep) {
2664 sep = strtok(tmp_spool_buf, ", ");
2665 while (sep != NULL) {
2666 tmp = (struct cfg_spool *)spool_buf;
2667 if (len < SOF_SPOOL)
2668 goto nospace;
2670 len -= SOF_SPOOL;
2671 space += SOF_SPOOL;
2672 str2addr(sep, &tmp->addr);
2673 tmp->port = ~0;
2674 r->spool_cnt++;
2675 /* Point to the next possible cfg_spool. */
2676 spool_buf = &spool_buf[SOF_SPOOL];
2677 sep = strtok(NULL, ", ");
2680 return(space);
2682 nospace:
2683 errx(EX_DATAERR, "redirect_addr: buf is too small\n");
2686 static int
2687 setup_redir_port(char *spool_buf, int len, int *_ac, char ***_av)
2689 char **av, *sep, *protoName;
2690 char tmp_spool_buf[NAT_BUF_LEN];
2691 int ac, space, lsnat;
2692 struct cfg_redir *r;
2693 struct cfg_spool *tmp;
2694 u_short numLocalPorts;
2695 port_range portRange;
2697 av = *_av;
2698 ac = *_ac;
2699 space = 0;
2700 lsnat = 0;
2701 numLocalPorts = 0;
2703 if (len >= SOF_REDIR) {
2704 r = (struct cfg_redir *)spool_buf;
2705 /* Skip cfg_redir at beginning of buf. */
2706 spool_buf = &spool_buf[SOF_REDIR];
2707 space = SOF_REDIR;
2708 len -= SOF_REDIR;
2709 } else {
2710 goto nospace;
2713 r->mode = REDIR_PORT;
2715 * Extract protocol.
2717 if (ac == 0)
2718 errx (EX_DATAERR, "redirect_port: missing protocol");
2720 r->proto = str2proto(*av);
2721 protoName = *av;
2722 INC_ARGCV();
2725 * Extract local address.
2727 if (ac == 0)
2728 errx (EX_DATAERR, "redirect_port: missing local address");
2730 sep = strchr(*av, ',');
2731 /* LSNAT redirection syntax. */
2732 if (sep) {
2733 r->laddr.s_addr = INADDR_NONE;
2734 r->lport = ~0;
2735 numLocalPorts = 1;
2736 /* Preserve av, copy spool servers to tmp_spool_buf. */
2737 strncpy(tmp_spool_buf, *av, strlen(*av)+1);
2738 lsnat = 1;
2739 } else {
2740 if (str2addr_portrange (*av, &r->laddr, protoName, &portRange) != 0)
2741 errx(EX_DATAERR, "redirect_port:"
2742 "invalid local port range");
2744 r->lport = GETLOPORT(portRange);
2745 numLocalPorts = GETNUMPORTS(portRange);
2747 INC_ARGCV();
2750 * Extract public port and optionally address.
2752 if (ac == 0)
2753 errx (EX_DATAERR, "redirect_port: missing public port");
2755 sep = strchr (*av, ':');
2756 if (sep) {
2757 if (str2addr_portrange (*av, &r->paddr, protoName, &portRange) != 0)
2758 errx(EX_DATAERR, "redirect_port:"
2759 "invalid public port range");
2760 } else {
2761 r->paddr.s_addr = INADDR_ANY;
2762 if (str2portrange(*av, protoName, &portRange) != 0)
2763 errx(EX_DATAERR, "redirect_port:"
2764 "invalid public port range");
2767 r->pport = GETLOPORT(portRange);
2768 r->pport_cnt = GETNUMPORTS(portRange);
2769 INC_ARGCV();
2772 * Extract remote address and optionally port.
2775 * NB: isalpha(**av) => we've to check that next parameter is really an
2776 * option for this redirect entry, else stop here processing arg[cv].
2778 if (ac != 0 && !isalpha(**av)) {
2779 sep = strchr (*av, ':');
2780 if (sep) {
2781 if (str2addr_portrange (*av, &r->raddr,
2782 protoName, &portRange) != 0)
2783 errx(EX_DATAERR, "redirect_port:"
2784 "invalid remote port range");
2785 } else {
2786 SETLOPORT(portRange, 0);
2787 SETNUMPORTS(portRange, 1);
2788 str2addr (*av, &r->raddr);
2790 INC_ARGCV();
2791 } else {
2792 SETLOPORT(portRange, 0);
2793 SETNUMPORTS(portRange, 1);
2794 r->raddr.s_addr = INADDR_ANY;
2796 r->rport = GETLOPORT(portRange);
2797 r->rport_cnt = GETNUMPORTS(portRange);
2800 * Make sure port ranges match up, then add the redirect ports.
2802 if (numLocalPorts != r->pport_cnt)
2803 errx(EX_DATAERR, "redirect_port:"
2804 "port ranges must be equal in size");
2806 /* Remote port range is allowed to be '0' which means all ports. */
2807 if (r->rport_cnt != numLocalPorts &&
2808 (r->rport_cnt != 1 || r->rport != 0))
2809 errx(EX_DATAERR, "redirect_port: remote port must"
2810 "be 0 or equal to local port range in size");
2813 * Setup LSNAT server pool.
2815 if (lsnat) {
2816 sep = strtok(tmp_spool_buf, ", ");
2817 while (sep != NULL) {
2818 tmp = (struct cfg_spool *)spool_buf;
2819 if (len < SOF_SPOOL)
2820 goto nospace;
2822 len -= SOF_SPOOL;
2823 space += SOF_SPOOL;
2824 if (str2addr_portrange(sep,
2825 &tmp->addr, protoName, &portRange) != 0)
2826 errx(EX_DATAERR, "redirect_port:"
2827 "invalid local port range");
2828 if (GETNUMPORTS(portRange) != 1)
2829 errx(EX_DATAERR, "redirect_port: local port"
2830 "must be single in this context");
2831 tmp->port = GETLOPORT(portRange);
2832 r->spool_cnt++;
2833 /* Point to the next possible cfg_spool. */
2834 spool_buf = &spool_buf[SOF_SPOOL];
2835 sep = strtok(NULL, ", ");
2838 return (space);
2840 nospace:
2841 errx(EX_DATAERR, "redirect_port: buf is too small\n");
2844 static int
2845 setup_redir_proto(char *spool_buf, int len, int *_ac, char ***_av)
2847 struct protoent *protoent;
2848 struct cfg_redir *r;
2849 int ac, i, space;
2850 char **av;
2852 i=0;
2853 av = *_av;
2854 ac = *_ac;
2855 if (len >= SOF_REDIR) {
2856 r = (struct cfg_redir *)spool_buf;
2857 /* Skip cfg_redir at beginning of buf. */
2858 spool_buf = &spool_buf[SOF_REDIR];
2859 space = SOF_REDIR;
2860 len -= SOF_REDIR;
2861 } else {
2862 goto nospace;
2864 r->mode = REDIR_PROTO;
2866 * Extract protocol.
2868 if (ac == 0)
2869 errx(EX_DATAERR, "redirect_proto: missing protocol");
2871 protoent = getprotobyname(*av);
2872 if (protoent == NULL)
2873 errx(EX_DATAERR, "redirect_proto: unknown protocol %s", *av);
2874 else
2875 r->proto = protoent->p_proto;
2877 INC_ARGCV();
2880 * Extract local address.
2882 if (ac == 0)
2883 errx(EX_DATAERR, "redirect_proto: missing local address");
2884 else
2885 str2addr(*av, &r->laddr);
2886 INC_ARGCV();
2889 * Extract optional public address.
2891 if (ac == 0) {
2892 r->paddr.s_addr = INADDR_ANY;
2893 r->raddr.s_addr = INADDR_ANY;
2894 } else {
2895 /* see above in setup_redir_port() */
2896 if (!isalpha(**av)) {
2897 str2addr(*av, &r->paddr);
2898 INC_ARGCV();
2901 * Extract optional remote address.
2903 /* see above in setup_redir_port() */
2904 if (ac != 0 && !isalpha(**av)) {
2905 str2addr(*av, &r->raddr);
2906 INC_ARGCV();
2910 return (space);
2912 nospace:
2913 errx(EX_DATAERR, "redirect_proto: buf is too small\n");
2916 static void
2917 show_nat_config(char *buf) {
2918 struct cfg_nat *n;
2919 struct cfg_redir *t;
2920 struct cfg_spool *s;
2921 struct protoent *p;
2922 int i, cnt, flag, off;
2924 n = (struct cfg_nat *)buf;
2925 flag = 1;
2926 off = sizeof(*n);
2927 printf("ipfw nat %u config", n->id);
2928 if (strlen(n->if_name) != 0)
2929 printf(" if %s", n->if_name);
2930 else if (n->ip.s_addr != 0)
2931 printf(" ip %s", inet_ntoa(n->ip));
2932 while (n->mode != 0) {
2933 if (n->mode & PKT_ALIAS_LOG) {
2934 printf(" log");
2935 n->mode &= ~PKT_ALIAS_LOG;
2936 } else if (n->mode & PKT_ALIAS_DENY_INCOMING) {
2937 printf(" deny_in");
2938 n->mode &= ~PKT_ALIAS_DENY_INCOMING;
2939 } else if (n->mode & PKT_ALIAS_SAME_PORTS) {
2940 printf(" same_ports");
2941 n->mode &= ~PKT_ALIAS_SAME_PORTS;
2942 } else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) {
2943 printf(" unreg_only");
2944 n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY;
2945 } else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) {
2946 printf(" reset");
2947 n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2948 } else if (n->mode & PKT_ALIAS_REVERSE) {
2949 printf(" reverse");
2950 n->mode &= ~PKT_ALIAS_REVERSE;
2951 } else if (n->mode & PKT_ALIAS_PROXY_ONLY) {
2952 printf(" proxy_only");
2953 n->mode &= ~PKT_ALIAS_PROXY_ONLY;
2956 /* Print all the redirect's data configuration. */
2957 for (cnt = 0; cnt < n->redir_cnt; cnt++) {
2958 t = (struct cfg_redir *)&buf[off];
2959 off += SOF_REDIR;
2960 switch (t->mode) {
2961 case REDIR_ADDR:
2962 printf(" redirect_addr");
2963 if (t->spool_cnt == 0)
2964 printf(" %s", inet_ntoa(t->laddr));
2965 else
2966 for (i = 0; i < t->spool_cnt; i++) {
2967 s = (struct cfg_spool *)&buf[off];
2968 if (i)
2969 printf(", ");
2970 else
2971 printf(" ");
2972 printf("%s", inet_ntoa(s->addr));
2973 off += SOF_SPOOL;
2975 printf(" %s", inet_ntoa(t->paddr));
2976 break;
2977 case REDIR_PORT:
2978 p = getprotobynumber(t->proto);
2979 printf(" redirect_port %s ", p->p_name);
2980 if (!t->spool_cnt) {
2981 printf("%s:%u", inet_ntoa(t->laddr), t->lport);
2982 if (t->pport_cnt > 1)
2983 printf("-%u", t->lport + t->pport_cnt - 1);
2984 } else
2985 for (i=0; i < t->spool_cnt; i++) {
2986 s = (struct cfg_spool *)&buf[off];
2987 if (i)
2988 printf(", ");
2989 printf("%s:%u", inet_ntoa(s->addr), s->port);
2990 off += SOF_SPOOL;
2993 printf(" ");
2994 if (t->paddr.s_addr)
2995 printf("%s:", inet_ntoa(t->paddr));
2996 printf("%u", t->pport);
2997 if (!t->spool_cnt && t->pport_cnt > 1)
2998 printf("-%u", t->pport + t->pport_cnt - 1);
3000 if (t->raddr.s_addr) {
3001 printf(" %s", inet_ntoa(t->raddr));
3002 if (t->rport) {
3003 printf(":%u", t->rport);
3004 if (!t->spool_cnt && t->rport_cnt > 1)
3005 printf("-%u", t->rport +
3006 t->rport_cnt - 1);
3009 break;
3010 case REDIR_PROTO:
3011 p = getprotobynumber(t->proto);
3012 printf(" redirect_proto %s %s", p->p_name,
3013 inet_ntoa(t->laddr));
3014 if (t->paddr.s_addr != 0) {
3015 printf(" %s", inet_ntoa(t->paddr));
3016 if (t->raddr.s_addr)
3017 printf(" %s", inet_ntoa(t->raddr));
3019 break;
3020 default:
3021 errx(EX_DATAERR, "unknown redir mode");
3022 break;
3025 printf("\n");
3029 static void
3030 show_nat(int ac, char **av) {
3031 struct cfg_nat *n;
3032 struct cfg_redir *e;
3033 int i, nbytes, nalloc, size;
3034 int nat_cnt, redir_cnt, nat_id;
3035 uint8_t *data;
3037 nalloc = 1024;
3038 size = 0;
3039 data = NULL;
3041 NEXT_ARG;
3043 if (ac == 0)
3044 nat_id = 0;
3045 else
3046 nat_id = strtoul(*av, NULL, 10);
3048 nbytes = nalloc;
3049 while (nbytes >= nalloc) {
3050 nalloc = nalloc * 2;
3051 nbytes = nalloc;
3052 if ((data = realloc(data, nbytes)) == NULL) {
3053 err(EX_OSERR, "realloc");
3055 if (do_get_x(IP_FW_NAT_GET, data, &nbytes) < 0) {
3056 err(EX_OSERR, "do_get_x(IP_FW_NAT_GET)");
3060 if (nbytes == 0) {
3061 exit(EX_OK);
3064 nat_cnt = *((int *)data);
3065 for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) {
3066 n = (struct cfg_nat *)&data[i];
3067 if (n->id >= 0 && n->id <= IPFW_DEFAULT_RULE) {
3068 if (nat_id == 0 || n->id == nat_id)
3069 show_nat_config(&data[i]);
3071 i += sizeof(struct cfg_nat);
3072 for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) {
3073 e = (struct cfg_redir *)&data[i];
3074 i += sizeof(struct cfg_redir) +
3075 e->spool_cnt * sizeof(struct cfg_spool);
3081 get_kern_boottime(void)
3083 struct timeval boottime;
3084 size_t size;
3085 int mib[2];
3086 mib[0] = CTL_KERN;
3087 mib[1] = KERN_BOOTTIME;
3088 size = sizeof(boottime);
3089 if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
3090 boottime.tv_sec != 0) {
3091 return boottime.tv_sec;
3093 return -1;
3096 void
3097 show_nat_state(int ac, char **av)
3099 int nbytes, nalloc;
3100 int nat_id;
3101 uint8_t *data;
3103 nalloc = 1024;
3104 data = NULL;
3106 NEXT_ARG;
3107 if (ac == 0)
3108 nat_id = 0;
3109 else
3110 nat_id = strtoul(*av, NULL, 10);
3112 nbytes = nalloc;
3113 while (nbytes >= nalloc) {
3114 nalloc = nalloc * 2;
3115 nbytes = nalloc;
3116 if ((data = realloc(data, nbytes)) == NULL) {
3117 err(EX_OSERR, "realloc");
3119 memcpy(data, &nat_id, sizeof(int));
3120 if (do_get_x(IP_FW_NAT_LOG, data, &nbytes) < 0) {
3121 err(EX_OSERR, "do_get_x(IP_FW_NAT_GET_STATE)");
3124 if (nbytes == 0)
3125 exit(EX_OK);
3126 struct ipfw_ioc_nat_state *nat_state;
3127 nat_state =(struct ipfw_ioc_nat_state *)data;
3128 int count = nbytes / sizeof( struct ipfw_ioc_nat_state);
3129 int i, uptime_sec;
3130 uptime_sec = get_kern_boottime();
3131 for (i = 0; i < count; i ++) {
3132 struct protoent *pe = getprotobynumber(nat_state->link_type);
3133 printf("%s ", pe->p_name);
3134 printf("%s:%hu => ",inet_ntoa(nat_state->src_addr),
3135 htons(nat_state->src_port));
3136 printf("%s:%hu",inet_ntoa(nat_state->alias_addr),
3137 htons(nat_state->alias_port));
3138 printf(" -> %s:%hu ",inet_ntoa(nat_state->dst_addr),
3139 htons(nat_state->dst_port));
3140 if (do_time == 1) {
3141 char timestr[30];
3142 time_t t = _long_to_time(uptime_sec + nat_state->timestamp);
3143 strcpy(timestr, ctime(&t));
3144 *strchr(timestr, '\n') = '\0';
3145 printf("%s ", timestr);
3146 } else if (do_time == 2) {
3147 printf( "%10u ", uptime_sec + nat_state->timestamp);
3149 printf("\n");
3150 nat_state++;
3155 * do_set_x - extended version og do_set
3156 * insert a x_header in the beginning of the rule buf
3157 * and call setsockopt() with IP_FW_X.
3160 do_set_x(int optname, void *rule, int optlen)
3162 int len, *newbuf;
3164 ip_fw_x_header *x_header;
3165 if (ipfw_socket < 0)
3166 err(EX_UNAVAILABLE, "socket not avaialble");
3167 len = optlen + sizeof(ip_fw_x_header);
3168 newbuf = malloc(len);
3169 if (newbuf == NULL)
3170 err(EX_OSERR, "malloc newbuf in do_set_x");
3171 bzero(newbuf, len);
3172 x_header = (ip_fw_x_header *)newbuf;
3173 x_header->opcode = optname;
3174 /* copy the rule into the newbuf, just after the x_header*/
3175 bcopy(rule, ++x_header, optlen);
3176 return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, len);
3180 * same as do_set_x
3183 do_get_x(int optname, void *rule, int *optlen)
3185 int len, *newbuf, retval;
3187 ip_fw_x_header *x_header;
3188 if (ipfw_socket < 0)
3189 err(EX_UNAVAILABLE, "socket not avaialble");
3190 len = *optlen + sizeof(ip_fw_x_header);
3191 newbuf = malloc(len);
3192 if (newbuf == NULL)
3193 err(EX_OSERR, "malloc newbuf in do_get_x");
3194 bzero(newbuf, len);
3195 x_header = (ip_fw_x_header *)newbuf;
3196 x_header->opcode = optname;
3197 /* copy the rule into the newbuf, just after the x_header*/
3198 bcopy(rule, ++x_header, *optlen);
3199 retval = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, &len);
3200 bcopy(newbuf, rule, len);
3201 *optlen=len;
3202 return retval;
3205 static void
3206 config_nat(int ac, char **av)
3208 struct cfg_nat *n; /* Nat instance configuration. */
3209 int i, len, off, tok;
3210 char *id, buf[NAT_BUF_LEN]; /* Buffer for serialized data. */
3212 len = NAT_BUF_LEN;
3213 /* Offset in buf: save space for n at the beginning. */
3214 off = sizeof(struct cfg_nat);
3215 memset(buf, 0, sizeof(buf));
3216 n = (struct cfg_nat *)buf;
3218 NEXT_ARG;
3219 /* Nat id. */
3220 if (ac && isdigit(**av)) {
3221 id = *av;
3222 i = atoi(*av);
3223 NEXT_ARG;
3224 n->id = i;
3225 } else
3226 errx(EX_DATAERR, "missing nat id");
3227 if (ac == 0)
3228 errx(EX_DATAERR, "missing option");
3230 while (ac > 0) {
3231 tok = match_token(nat_params, *av);
3232 NEXT_ARG;
3233 switch (tok) {
3234 case TOK_IP:
3235 if (ac == 0)
3236 errx(EX_DATAERR, "missing option");
3237 if (!inet_aton(av[0], &(n->ip)))
3238 errx(EX_DATAERR, "bad ip address ``%s''",
3239 av[0]);
3240 NEXT_ARG;
3241 break;
3242 case TOK_IF:
3243 if (ac == 0)
3244 errx(EX_DATAERR, "missing option");
3245 set_addr_dynamic(av[0], n);
3246 NEXT_ARG;
3247 break;
3248 case TOK_ALOG:
3249 n->mode |= PKT_ALIAS_LOG;
3250 break;
3251 case TOK_DENY_INC:
3252 n->mode |= PKT_ALIAS_DENY_INCOMING;
3253 break;
3254 case TOK_SAME_PORTS:
3255 n->mode |= PKT_ALIAS_SAME_PORTS;
3256 break;
3257 case TOK_UNREG_ONLY:
3258 n->mode |= PKT_ALIAS_UNREGISTERED_ONLY;
3259 break;
3260 case TOK_RESET_ADDR:
3261 n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
3262 break;
3263 case TOK_ALIAS_REV:
3264 n->mode |= PKT_ALIAS_REVERSE;
3265 break;
3266 case TOK_PROXY_ONLY:
3267 n->mode |= PKT_ALIAS_PROXY_ONLY;
3268 break;
3270 * All the setup_redir_* functions work directly in the final
3271 * buffer, see above for details.
3273 case TOK_REDIR_ADDR:
3274 case TOK_REDIR_PORT:
3275 case TOK_REDIR_PROTO:
3276 switch (tok) {
3277 case TOK_REDIR_ADDR:
3278 i = setup_redir_addr(&buf[off], len, &ac, &av);
3279 break;
3280 case TOK_REDIR_PORT:
3281 i = setup_redir_port(&buf[off], len, &ac, &av);
3282 break;
3283 case TOK_REDIR_PROTO:
3284 i = setup_redir_proto(&buf[off], len, &ac, &av);
3285 break;
3287 n->redir_cnt++;
3288 off += i;
3289 len -= i;
3290 break;
3291 default:
3292 errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
3295 i = do_set_x(IP_FW_NAT_CFG, buf, off);
3296 if (i)
3297 err(1, "do_set_x(%s)", "IP_FW_NAT_CFG");
3299 /* After every modification, we show the resultant rule. */
3300 int _ac = 2;
3301 char *_av[] = {"config", id};
3302 show_nat(_ac, _av);
3306 static int
3307 ipfw_main(int ac, char **av)
3309 int ch;
3311 if (ac == 1)
3312 help();
3314 /* Set the force flag for non-interactive processes */
3315 do_force = !isatty(STDIN_FILENO);
3317 optind = optreset = 1;
3318 while ((ch = getopt(ac, av, "hs:acdDefNStTv")) != -1)
3319 switch (ch) {
3320 case 'h': /* help */
3321 help();
3322 break; /* NOTREACHED */
3324 case 's': /* sort */
3325 do_sort = atoi(optarg);
3326 break;
3327 case 'a':
3328 do_acct = 1;
3329 break;
3330 case 'c':
3331 do_compact = 1;
3332 break;
3333 case 'd':
3334 do_dynamic = 1;
3335 break;
3336 case 'D':
3337 do_dynamic = 2;
3338 break;
3339 case 'e':
3340 do_expired = 1;
3341 break;
3342 case 'f':
3343 do_force = 1;
3344 break;
3345 case 'N':
3346 do_resolv = 1;
3347 break;
3348 case 'S':
3349 show_sets = 1;
3350 break;
3351 case 't':
3352 do_time = 1;
3353 break;
3354 case 'T':
3355 do_time = 2;
3356 break;
3357 case 'v':
3358 do_quiet = 0;
3359 verbose++;
3360 break;
3361 default:
3362 help();
3365 ac -= optind;
3366 av += optind;
3367 NEED1("bad arguments, for usage summary ``ipfw''");
3370 * optional: pipe or queue or nat
3372 do_nat = 0;
3373 do_pipe = 0;
3374 if (!strncmp(*av, "nat", strlen(*av)))
3375 do_nat = 1;
3376 else if (!strncmp(*av, "pipe", strlen(*av))) {
3377 do_pipe = 1;
3378 } else if (!strncmp(*av, "queue", strlen(*av))) {
3379 do_pipe = 2;
3381 NEED1("missing command");
3384 * for pipes and queues and nat we normally say 'pipe NN config'
3385 * but the code is easier to parse as 'pipe config NN'
3386 * so we swap the two arguments.
3388 if ((do_pipe || do_nat) && ac > 2 && isdigit(*(av[1]))) {
3389 char *p = av[1];
3390 av[1] = av[2];
3391 av[2] = p;
3394 if (!strncmp(*av, "add", strlen(*av))) {
3395 load_modules();
3396 add(ac, av);
3397 } else if (!strncmp(*av, "delete", strlen(*av))) {
3398 delete_rules(ac, av);
3399 } else if (!strncmp(*av, "flush", strlen(*av))) {
3400 flush();
3401 } else if (!strncmp(*av, "list", strlen(*av))) {
3402 load_modules();
3403 list(ac, av);
3404 } else if (!strncmp(*av, "show", strlen(*av))) {
3405 do_acct++;
3406 load_modules();
3407 list(ac, av);
3408 } else if (!strncmp(*av, "zero", strlen(*av))) {
3409 zero(ac, av);
3410 } else if (!strncmp(*av, "set", strlen(*av))) {
3411 sets_handler(ac, av);
3412 } else if (!strncmp(*av, "module", strlen(*av))) {
3413 NEXT_ARG;
3414 if (!strncmp(*av, "show", strlen(*av)) ||
3415 !strncmp(*av, "show", strlen(*av))) {
3416 list_modules(ac, av);
3417 } else {
3418 errx(EX_USAGE, "bad ipfw module command `%s'", *av);
3420 } else if (!strncmp(*av, "resetlog", strlen(*av))) {
3421 resetlog(ac, av);
3422 } else if (!strncmp(*av, "log", strlen(*av))) {
3423 NEXT_ARG;
3424 if (!strncmp(*av, "reset", strlen(*av))) {
3425 resetlog(ac, av);
3426 } else if (!strncmp(*av, "off", strlen(*av))) {
3428 } else if (!strncmp(*av, "on", strlen(*av))) {
3430 } else {
3431 errx(EX_USAGE, "bad command `%s'", *av);
3433 } else if (!strncmp(*av, "nat", strlen(*av))) {
3434 NEXT_ARG;
3435 if (!strncmp(*av, "config", strlen(*av))) {
3436 config_nat(ac, av);
3437 } else if (!strncmp(*av, "flush", strlen(*av))) {
3438 flush();
3439 } else if (!strncmp(*av, "show", strlen(*av)) ||
3440 !strncmp(*av, "list", strlen(*av))) {
3441 if (ac > 2 && isdigit(*(av[1]))) {
3442 char *p = av[1];
3443 av[1] = av[2];
3444 av[2] = p;
3446 NEXT_ARG;
3447 if (!strncmp(*av, "config", strlen(*av))) {
3448 show_nat(ac, av);
3449 } else if (!strncmp(*av, "state", strlen(*av))) {
3450 show_nat_state(ac,av);
3451 } else {
3452 errx(EX_USAGE,
3453 "bad nat show command `%s'", *av);
3455 } else if (!strncmp(*av, "delete", strlen(*av))) {
3456 delete_nat_config(ac, av);
3457 } else {
3458 errx(EX_USAGE, "bad ipfw nat command `%s'", *av);
3460 } else if (!strncmp(*av, "pipe", strlen(*av)) ||
3461 !strncmp(*av, "queue", strlen(*av))) {
3462 NEXT_ARG;
3463 if (!strncmp(*av, "config", strlen(*av))) {
3464 config_dummynet(ac, av);
3465 } else if (!strncmp(*av, "flush", strlen(*av))) {
3466 flush();
3467 } else if (!strncmp(*av, "show", strlen(*av))) {
3468 show_dummynet(ac, av);
3469 } else {
3470 errx(EX_USAGE, "bad ipfw pipe command `%s'", *av);
3472 } else if (!strncmp(*av, "state", strlen(*av))) {
3473 NEXT_ARG;
3474 if (!strncmp(*av, "add", strlen(*av))) {
3475 add_state(ac, av);
3476 } else if (!strncmp(*av, "delete", strlen(*av))) {
3477 delete_state(ac, av);
3478 } else if (!strncmp(*av, "flush", strlen(*av))) {
3479 flush_state(ac, av);
3480 } else if (!strncmp(*av, "list", strlen(*av))) {
3481 do_dynamic = 2;
3482 list(ac, av);
3483 } else if (!strncmp(*av, "show", strlen(*av))) {
3484 do_acct = 1;
3485 do_dynamic =2;
3486 list(ac, av);
3487 } else {
3488 errx(EX_USAGE, "bad ipfw state command `%s'", *av);
3490 } else if (!strncmp(*av, "table", strlen(*av))) {
3491 if (ac > 2 && isdigit(*(av[1]))) {
3492 char *p = av[1];
3493 av[1] = av[2];
3494 av[2] = p;
3496 NEXT_ARG;
3497 if (!strncmp(*av, "append", strlen(*av))) {
3498 table_append(ac, av);
3499 } else if (!strncmp(*av, "remove", strlen(*av))) {
3500 table_remove(ac, av);
3501 } else if (!strncmp(*av, "flush", strlen(*av))) {
3502 table_flush(ac, av);
3503 } else if (!strncmp(*av, "list", strlen(*av))) {
3504 table_list(ac, av);
3505 } else if (!strncmp(*av, "show", strlen(*av))) {
3506 table_show(ac, av);
3507 } else if (!strncmp(*av, "type", strlen(*av))) {
3508 table_create(ac, av);
3509 } else if (!strncmp(*av, "delete", strlen(*av))) {
3510 table_delete(ac, av);
3511 } else if (!strncmp(*av, "test", strlen(*av))) {
3512 table_test(ac,av);
3513 } else if (!strncmp(*av, "name", strlen(*av))) {
3514 table_rename(ac, av);
3515 } else {
3516 errx(EX_USAGE, "bad ipfw table command `%s'", *av);
3519 } else {
3520 errx(EX_USAGE, "bad ipfw command `%s'", *av);
3522 return 0;
3525 static void
3526 ipfw_readfile(int ac, char *av[])
3528 char buf[BUFSIZ];
3529 char *a, *p, *args[MAX_ARGS], *cmd = NULL;
3530 char linename[10];
3531 int i=0, lineno=0, qflag=0, pflag=0, status;
3532 FILE *f = NULL;
3533 pid_t preproc = 0;
3534 int c;
3536 while ((c = getopt(ac, av, "D:U:p:q")) != -1) {
3537 switch (c) {
3538 case 'D':
3539 if (!pflag)
3540 errx(EX_USAGE, "-D requires -p");
3541 if (i > MAX_ARGS - 2)
3542 errx(EX_USAGE, "too many -D or -U options");
3543 args[i++] = "-D";
3544 args[i++] = optarg;
3545 break;
3547 case 'U':
3548 if (!pflag)
3549 errx(EX_USAGE, "-U requires -p");
3550 if (i > MAX_ARGS - 2)
3551 errx(EX_USAGE, "too many -D or -U options");
3552 args[i++] = "-U";
3553 args[i++] = optarg;
3554 break;
3556 case 'p':
3557 pflag = 1;
3558 cmd = optarg;
3559 args[0] = cmd;
3560 i = 1;
3561 break;
3563 case 'q':
3564 qflag = 1;
3565 break;
3567 default:
3568 errx(EX_USAGE, "bad arguments, for usage"
3569 " summary ``ipfw''");
3573 av += optind;
3574 ac -= optind;
3575 if (ac != 1)
3576 errx(EX_USAGE, "extraneous filename arguments");
3578 if ((f = fopen(av[0], "r")) == NULL)
3579 err(EX_UNAVAILABLE, "fopen: %s", av[0]);
3581 if (pflag) {
3582 /* pipe through preprocessor (cpp or m4) */
3583 int pipedes[2];
3585 args[i] = NULL;
3587 if (pipe(pipedes) == -1)
3588 err(EX_OSERR, "cannot create pipe");
3590 switch ((preproc = fork())) {
3591 case -1:
3592 err(EX_OSERR, "cannot fork");
3594 case 0:
3595 /* child */
3596 if (dup2(fileno(f), 0) == -1 ||
3597 dup2(pipedes[1], 1) == -1) {
3598 err(EX_OSERR, "dup2()");
3600 fclose(f);
3601 close(pipedes[1]);
3602 close(pipedes[0]);
3603 execvp(cmd, args);
3604 err(EX_OSERR, "execvp(%s) failed", cmd);
3606 default:
3607 /* parent */
3608 fclose(f);
3609 close(pipedes[1]);
3610 if ((f = fdopen(pipedes[0], "r")) == NULL) {
3611 int savederrno = errno;
3613 kill(preproc, SIGTERM);
3614 errno = savederrno;
3615 err(EX_OSERR, "fdopen()");
3620 while (fgets(buf, BUFSIZ, f)) {
3621 lineno++;
3622 sprintf(linename, "Line %d", lineno);
3623 args[0] = linename;
3625 if (*buf == '#')
3626 continue;
3627 if ((p = strchr(buf, '#')) != NULL)
3628 *p = '\0';
3629 i = 1;
3630 if (qflag)
3631 args[i++] = "-q";
3632 for (a = strtok(buf, WHITESP); a && i < MAX_ARGS;
3633 a = strtok(NULL, WHITESP), i++) {
3634 args[i] = a;
3637 if (i == (qflag? 2: 1))
3638 continue;
3639 if (i == MAX_ARGS)
3640 errx(EX_USAGE, "%s: too many arguments", linename);
3642 args[i] = NULL;
3643 ipfw_main(i, args);
3645 fclose(f);
3646 if (pflag) {
3647 if (waitpid(preproc, &status, 0) == -1)
3648 errx(EX_OSERR, "waitpid()");
3649 if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
3650 errx(EX_UNAVAILABLE, "preprocessor exited with status %d",
3651 WEXITSTATUS(status));
3652 else if (WIFSIGNALED(status))
3653 errx(EX_UNAVAILABLE, "preprocessor exited with signal %d",
3654 WTERMSIG(status));
3659 main(int ac, char *av[])
3661 ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
3662 if (ipfw_socket < 0)
3663 err(EX_UNAVAILABLE, "socket");
3665 memset(keywords, 0, sizeof(struct ipfw_keyword) * KEYWORD_SIZE);
3666 memset(mappings, 0, sizeof(struct ipfw_mapping) * MAPPING_SIZE);
3668 prepare_default_funcs();
3670 if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0)
3671 ipfw_readfile(ac, av);
3672 else
3673 ipfw_main(ac, av);
3674 return EX_OK;