Merge branch 'vendor/GCC50'
[dragonfly.git] / lib / libipfw3 / basic / ipfw3_basic.c
1 /*
2  * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Bill Yuan <bycn82@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include <ctype.h>
36 #include <err.h>
37 #include <errno.h>
38 #include <grp.h>
39 #include <limits.h>
40 #include <netdb.h>
41 #include <pwd.h>
42 #include <signal.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stdarg.h>
46 #include <string.h>
47 #include <sysexits.h>
48 #include <timeconv.h>
49 #include <unistd.h>
50
51 #include <netinet/in.h>
52
53 #include <arpa/inet.h>
54 #include <net/if.h>
55 #include <net/route.h>
56 #include <net/pfil.h>
57
58 #include "../../../sys/net/ipfw3/ip_fw3.h"
59 #include "../../../sbin/ipfw3/ipfw.h"
60 #include "ipfw3_basic.h"
61
62
63 #define IP_MASK_ALL     0xffffffff
64 /*
65  * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
66  * This is only used in this code.
67  */
68 #define IPPROTO_ETHERTYPE       0x1000
69
70
71 struct char_int_map limit_types[] = {
72         { "src-addr",   1 },
73         { "src-port",   2 },
74         { "dst-addr",   3 },
75         { "dst-port",   4 },
76         { NULL,         0 }
77 };
78
79 static struct char_int_map ether_types[] = {
80         { "ip",         0x0800 },
81         { "ipv4",       0x0800 },
82         { "ipv6",       0x86dd },
83         { "arp",        0x0806 },
84         { "rarp",       0x8035 },
85         { "vlan",       0x8100 },
86         { "loop",       0x9000 },
87         { "trail",      0x1000 },
88         { "pppoe_disc", 0x8863 },
89         { "pppoe_sess", 0x8864 },
90         { "ipx_8022",   0x00E0 },
91         { "ipx_8023",   0x0000 },
92         { "ipx_ii",     0x8137 },
93         { "ipx_snap",   0x8137 },
94         { "ipx",        0x8137 },
95         { "ns",         0x0600 },
96         { NULL,         0 }
97 };
98
99 /**
100  * match_token takes a table and a string, returns the value associated
101  * with the string (0 meaning an error in most cases)
102  */
103 static int
104 match_token(struct char_int_map *table, char *string)
105 {
106         while (table->key) {
107                 if (strcmp(table->key, string) == 0)
108                         return table->val;
109
110                 table++;
111         }
112         return 0;
113 };
114
115 static char *
116 match_token2(struct char_int_map *table, int val)
117 {
118         while (table->val) {
119                 if (table->val == val)
120                         return table->key;
121
122                 table++;
123         }
124         return NULL;
125 };
126
127 static void
128 fill_iface(ipfw_insn_if *cmd, char *arg)
129 {
130         cmd->name[0] = '\0';
131         cmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
132
133         /* Parse the interface or address */
134         if (!strcmp(arg, "any")){
135                 cmd->o.len = 0;
136         } else if (!isdigit(*arg)) {
137                 strlcpy(cmd->name, arg, sizeof(cmd->name));
138                 cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0;
139         } else if (!inet_aton(arg, &cmd->p.ip))
140                 errx(EX_DATAERR, "bad ip address ``%s''", arg);
141 }
142
143 static int
144 lookup_host (char *host, struct in_addr *ipaddr)
145 {
146         struct hostent *he;
147
148         if (!inet_aton(host, ipaddr)) {
149                 if ((he = gethostbyname(host)) == NULL)
150                         return(-1);
151                 *ipaddr = *(struct in_addr *)he->h_addr_list[0];
152         }
153         return(0);
154 }
155
156 /*
157  * Like strtol, but also translates service names into port numbers
158  * for some protocols.
159  * In particular:
160  *      proto == -1 disables the protocol check;
161  *      proto == IPPROTO_ETHERTYPE looks up an internal table
162  *      proto == <some value in /etc/protocols> matches the values there.
163  * Returns *end == s in case the parameter is not found.
164  */
165 static int
166 strtoport(char *s, char **end, int base, int proto)
167 {
168         char *p, *buf;
169         char *s1;
170         int i;
171
172         *end = s;               /* default - not found */
173         if ( *s == '\0')
174                 return 0;       /* not found */
175
176         if (isdigit(*s))
177                 return strtol(s, end, base);
178
179         /*
180          * find separator. '\\' escapes the next char.
181          */
182         for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++) {
183                 if (*s1 == '\\' && s1[1] != '\0')
184                         s1++;
185         }
186
187         buf = malloc(s1 - s + 1);
188         if (buf == NULL)
189                 return 0;
190
191         /*
192          * copy into a buffer skipping backslashes
193          */
194         for (p = s, i = 0; p != s1 ; p++)
195                 if ( *p != '\\')
196                         buf[i++] = *p;
197         buf[i++] = '\0';
198
199         if (proto == IPPROTO_ETHERTYPE) {
200                 i = match_token(ether_types, buf);
201                 free(buf);
202                 if (i != -1) {  /* found */
203                         *end = s1;
204                         return i;
205                 }
206         } else {
207                 struct protoent *pe = NULL;
208                 struct servent *se;
209
210                 if (proto != 0)
211                         pe = getprotobynumber(proto);
212                 setservent(1);
213                 se = getservbyname(buf, pe ? pe->p_name : NULL);
214                 free(buf);
215                 if (se != NULL) {
216                         *end = s1;
217                         return ntohs(se->s_port);
218                 }
219         }
220         return 0;       /* not found */
221 }
222
223 static int
224 contigmask(u_char *p, int len)
225 {
226         int i, n;
227         for (i=0; i<len ; i++) {
228                 if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */
229                         break;
230         }
231         for (n=i+1; n < len; n++) {
232                 if ( (p[n/8] & (1 << (7 - (n%8)))) != 0)
233                         return -1; /* mask not contiguous */
234         }
235         return i;
236 }
237
238 static void
239 fill_ip(ipfw_insn_ip *cmd, char *av)
240 {
241         char *p = NULL, md = 0;
242         u_int32_t i;
243
244         cmd->o.len &= ~F_LEN_MASK;      /* zero len */
245
246         if (!strncmp(av, "any", strlen(av)))
247                 return;
248
249         if (!strncmp(av, "me", strlen(av))) {
250                 cmd->o.len |= F_INSN_SIZE(ipfw_insn);
251                 return;
252         }
253
254         p = strchr(av, '/');
255         if (!p)
256                 p = strchr(av, ':');
257
258         if (p) {
259                 md = *p;
260                 *p++ = '\0';
261         }
262
263         if (lookup_host(av, &cmd->addr) != 0)
264                 errx(EX_NOHOST, "hostname ``%s'' unknown", av);
265         switch (md) {
266         case ':':
267                 if (!inet_aton(p, &cmd->mask))
268                         errx(EX_DATAERR, "bad netmask ``%s''", p);
269                 break;
270         case '/':
271                 i = atoi(p);
272                 if (i == 0)
273                         cmd->mask.s_addr = htonl(0);
274                 else if (i > 32)
275                         errx(EX_DATAERR, "bad width ``%s''", p);
276                 else
277                         cmd->mask.s_addr = htonl(~0 << (32 - i));
278                 break;
279         default:
280                 cmd->mask.s_addr = htonl(~0);
281                 break;
282         }
283         cmd->addr.s_addr &= cmd->mask.s_addr;
284
285         if (p)
286                 p = strchr(p, '{');
287         if (p) {
288                 u_int32_t *d;
289                 int low, high;
290                 int i = contigmask((u_char *)&(cmd->mask), 32);
291
292                 if (i < 24 || i > 31) {
293                         fprintf(stderr, "invalid set with mask %d\n", i);
294                         exit(0);
295                 }
296                 cmd->o.arg1 = 1<<(32-i);
297                 cmd->addr.s_addr = ntohl(cmd->addr.s_addr);
298                 d = (u_int32_t *)&cmd->mask;
299                 cmd->o.opcode = O_BASIC_IP_DST_SET;     /* default */
300                 cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32;
301                 for (i = 0; i < (cmd->o.arg1+31)/32 ; i++)
302                         d[i] = 0;       /* clear masks */
303
304                 av = p+1;
305                 low = cmd->addr.s_addr & 0xff;
306                 high = low + cmd->o.arg1 - 1;
307                 while (isdigit(*av)) {
308                         char *s;
309                         u_int16_t a = strtol(av, &s, 0);
310
311                         if (s == av) /* no parameter */
312                                 break;
313                         if (a < low || a > high) {
314                                 fprintf(stderr,
315                                         "addr %d out of range [%d-%d]\n",
316                                                 a, low, high);
317                                 exit(0);
318                         }
319                         a -= low;
320                         d[ a/32] |= 1<<(a & 31);
321                         if (*s != ',')
322                                 break;
323                         av = s+1;
324                 }
325                 return;
326         }
327
328         if (cmd->mask.s_addr == 0) {
329                 if (cmd->o.len & F_NOT)
330                         errx(EX_DATAERR, "not any never matches");
331                 else    /* useless, nuke it */
332                         return;
333         } else if (cmd->mask.s_addr == IP_MASK_ALL) {
334                 cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
335         } else {                                                /* addr/mask */
336                 cmd->o.len |= F_INSN_SIZE(ipfw_insn_ip);
337                 printf("cmd->o.len=%d\n", cmd->o.len);
338         }
339 }
340
341
342 static ipfw_insn *add_srcip(ipfw_insn *cmd, char *av)
343 {
344         fill_ip((ipfw_insn_ip *)cmd, av);
345         if ((int)cmd->opcode == O_BASIC_IP_DST_SET)             /* set */
346                 cmd->opcode = O_BASIC_IP_SRC_SET;
347         else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn))          /* me */
348                 cmd->opcode = O_BASIC_IP_SRC_ME;
349         else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32))      /* one IP */
350                 cmd->opcode = O_BASIC_IP_SRC;
351         else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_ip))       /* addr/mask */
352                 cmd->opcode = O_BASIC_IP_SRC_MASK;
353         return cmd;
354 }
355
356
357 static ipfw_insn *add_dstip(ipfw_insn *cmd, char *av)
358 {
359         fill_ip((ipfw_insn_ip *)cmd, av);
360         if ((int)cmd->opcode == O_BASIC_IP_DST_SET)
361                 cmd->opcode = O_BASIC_IP_DST_SET;
362         else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn))
363                 cmd->opcode = O_BASIC_IP_DST_ME;
364         else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32))
365                 cmd->opcode = O_BASIC_IP_DST;
366         else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_ip))
367                 cmd->opcode = O_BASIC_IP_DST_MASK;
368         return cmd;
369 }
370
371
372 static ipfw_insn *add_proto(ipfw_insn *cmd, char *av)
373 {
374         struct protoent *pe;
375         u_char proto = 0;
376         if (!strncmp(av, "all", strlen(av))) {
377                 ;
378         } else if ((proto = atoi(av)) > 0) {
379                 ;
380         } else if ((pe = getprotobyname(av)) != NULL) {
381                 proto = pe->p_proto;
382         } else {
383                 errx(EX_USAGE, "protocol `%s' not recognizable\n", av);
384         }
385         if (proto != IPPROTO_IP) {
386                 cmd->opcode = O_BASIC_PROTO;
387                 cmd->module = MODULE_BASIC_ID;
388                 cmd->len = cmd->len|LEN_OF_IPFWINSN;
389                 cmd->arg1 = proto;
390         }
391         return cmd;
392 }
393
394 void
395 parse_count(ipfw_insn **cmd, int *ac, char **av[])
396 {
397         (*cmd)->opcode = O_BASIC_COUNT;
398         (*cmd)->module = MODULE_BASIC_ID;
399         (*cmd)->len = LEN_OF_IPFWINSN;
400         NEXT_ARG1;
401 }
402
403 void
404 parse_skipto(ipfw_insn **cmd, int *ac, char **av[])
405 {
406         NEXT_ARG1;
407         (*cmd)->opcode = O_BASIC_SKIPTO;
408         (*cmd)->module = MODULE_BASIC_ID;
409         (*cmd)->len = LEN_OF_IPFWINSN;
410         (*cmd)->arg1 = strtoul(**av, NULL, 10);
411         NEXT_ARG1;
412 }
413
414 /*
415  * cmd->arg3 is count of the destination
416  * cmd->arg1 is the type, random 0, round-robin 1, sticky 2
417  */
418 void
419 parse_forward(ipfw_insn **cmd, int *ac, char **av[])
420 {
421         ipfw_insn_sa *p = (ipfw_insn_sa *)(*cmd);
422         struct sockaddr_in *sa;
423         char *tok, *end = '\0';
424         char *str;
425         int count, port;
426
427         (*cmd)->opcode = O_BASIC_FORWARD;
428         NEXT_ARG1;
429         /*
430          * multiple forward destinations are seperated by colon
431          * ip address and port are seperated by comma
432          * e.g. 192.168.1.1:80,192.168.1.2:8080
433          *      192.168.1.1,192.168.1.2 or keep the port the same
434          */
435         tok = strtok(**av, ",");
436         sa = &p->sa;
437         count = 0;
438         while (tok != NULL) {
439                 sa->sin_len = sizeof(struct sockaddr_in);
440                 sa->sin_family = AF_INET;
441                 sa->sin_port = 0;
442                 str = strchr(tok,':');
443                 if (str != NULL) {
444                         *(str++) = '\0';
445                         port = strtoport(str, &end, 0, 0);
446                         sa->sin_port = (u_short)port;
447                 }
448                 lookup_host(tok, &(sa->sin_addr));
449                 tok = strtok (NULL, ",");
450                 sa++;
451                 count++;
452         }
453         (*cmd)->arg3 = count;
454         if (count == 0) {
455                 errx(EX_DATAERR, "forward `%s' not recognizable", **av);
456         }
457         NEXT_ARG1;
458         if (count > 1) {
459                 if (strcmp(**av, "round-robin") == 0) {
460                         NEXT_ARG1;
461                         (*cmd)->arg1 = 1;
462                 } else if (strcmp(**av, "sticky") == 0) {
463                         NEXT_ARG1;
464                         (*cmd)->arg1 = 2;
465                 } else {
466                         /* random */
467                         (*cmd)->arg1 = 0;
468                 }
469         }
470         (*cmd)->len = LEN_OF_IPFWINSN + count * sizeof(struct sockaddr_in);
471 }
472
473 void
474 parse_in(ipfw_insn **cmd, int *ac, char **av[])
475 {
476         (*cmd)->opcode = O_BASIC_IN;
477         (*cmd)->module = MODULE_BASIC_ID;
478         (*cmd)->len = LEN_OF_IPFWINSN;
479         (*cmd)->arg1 = 0;
480         NEXT_ARG1;
481 }
482
483 void
484 parse_out(ipfw_insn **cmd, int *ac, char **av[])
485 {
486         (*cmd)->opcode = O_BASIC_OUT;
487         (*cmd)->module = MODULE_BASIC_ID;
488         (*cmd)->len = LEN_OF_IPFWINSN;
489         (*cmd)->arg1 = 0;
490         NEXT_ARG1;
491 }
492
493
494 void
495 parse_via(ipfw_insn **cmd, int *ac, char **av[])
496 {
497         (*cmd)->module = MODULE_BASIC_ID;
498         (*cmd)->len = LEN_OF_IPFWINSN;
499         if (strcmp(*av[0], "via")==0) {
500                 (*cmd)->opcode = O_BASIC_VIA;
501         } else if (strcmp(*av[0], "xmit")==0) {
502                 (*cmd)->opcode = O_BASIC_XMIT;
503         } else if (strcmp(*av[0], "recv")==0) {
504                 (*cmd)->opcode = O_BASIC_RECV;
505         }
506         NEXT_ARG1;
507         fill_iface((ipfw_insn_if *)(*cmd), *av[0]);
508         NEXT_ARG1;
509 }
510
511 void
512 parse_from(ipfw_insn **cmd, int *ac, char **av[])
513 {
514         (*cmd)->module = MODULE_BASIC_ID;
515         NEXT_ARG1;
516         add_srcip(*cmd, **av);
517         NEXT_ARG1;
518 }
519
520 void
521 parse_to(ipfw_insn **cmd, int *ac, char **av[])
522 {
523         (*cmd)->module = MODULE_BASIC_ID;
524         NEXT_ARG1;
525         add_dstip(*cmd, **av);
526         NEXT_ARG1;
527 }
528
529 void
530 parse_proto(ipfw_insn **cmd, int *ac, char **av[])
531 {
532         add_proto(*cmd, **av);
533         NEXT_ARG1;
534 }
535
536 void
537 parse_prob(ipfw_insn **cmd, int *ac, char **av[])
538 {
539         NEXT_ARG1;
540         (*cmd)->opcode = O_BASIC_PROB;
541         (*cmd)->module = MODULE_BASIC_ID;
542         (*cmd)->len = LEN_OF_IPFWINSN;
543         (*cmd)->arg1 = strtoul(**av, NULL, 10);
544         NEXT_ARG1;
545 }
546
547 void
548 parse_keep_state(ipfw_insn **cmd, int *ac, char **av[])
549 {
550         NEXT_ARG1;
551         (*cmd)->opcode = O_BASIC_KEEP_STATE;
552         (*cmd)->module = MODULE_BASIC_ID;
553         (*cmd)->len = LEN_OF_IPFWINSN;
554         if (strcmp(**av, "limit") == 0) {
555                 NEXT_ARG1;
556                 (*cmd)->arg3 = match_token(limit_types, **av);
557                 if ((*cmd)->arg3 == 0)
558                         errx(EX_DATAERR, "limit `%s' not recognizable", **av);
559
560                 NEXT_ARG1;
561                 (*cmd)->arg1 = strtoul(**av, NULL, 10);
562                 if ((*cmd)->arg1 == 0)
563                         errx(EX_DATAERR, "bad limit `%s'", **av);
564
565                 NEXT_ARG1;
566         }
567         if (strcmp(**av, "live") == 0) {
568                 NEXT_ARG1;
569                 (*cmd)->arg2 = strtoul(**av, NULL, 10);
570                 NEXT_ARG1;
571         }
572 }
573
574 void
575 parse_check_state(ipfw_insn **cmd, int *ac, char **av[])
576 {
577         NEXT_ARG1;
578         (*cmd)->opcode = O_BASIC_CHECK_STATE;
579         (*cmd)->module = MODULE_BASIC_ID;
580         (*cmd)->len = LEN_OF_IPFWINSN;
581 }
582
583 void
584 parse_tagged(ipfw_insn **cmd, int *ac, char **av[])
585 {
586         NEXT_ARG1;
587         (*cmd)->opcode = O_BASIC_TAGGED;
588         (*cmd)->module = MODULE_BASIC_ID;
589         (*cmd)->len = LEN_OF_IPFWINSN;
590         (*cmd)->arg1 = strtoul(**av, NULL, 10);
591         NEXT_ARG1;
592 }
593
594 void
595 parse_comment(ipfw_insn **cmd, int *ac, char **av[])
596 {
597         int l = 0;
598         char *p = (char *)((*cmd) + 1);
599
600         NEXT_ARG1;
601         (*cmd)->opcode = O_BASIC_COMMENT;
602         (*cmd)->module = MODULE_BASIC_ID;
603
604         while (*ac > 0) {
605                 l += strlen(**av) + 1;
606                 if (l > 84) {
607                         errx(EX_DATAERR, "comment too long (max 80 chars)");
608                 }
609                 strcpy(p, **av);
610                 p += strlen(**av);
611                 *p++ = ' ';
612                 NEXT_ARG1;
613         }
614         l = 1 + (l + 3) / 4;
615         (*cmd)->len = l;
616         *(--p) = '\0';
617 }
618
619 void
620 parse_tag(ipfw_insn **cmd, int *ac, char **av[])
621 {
622         NEXT_ARG1;
623         (*cmd)->opcode = O_BASIC_TAG;
624         (*cmd)->module = MODULE_BASIC_ID;
625         (*cmd)->len = LEN_OF_IPFWINSN;
626         (*cmd)->arg1 = strtoul(**av, NULL, 10);
627         NEXT_ARG1;
628 }
629
630 void
631 parse_untag(ipfw_insn **cmd, int *ac, char **av[])
632 {
633         NEXT_ARG1;
634         (*cmd)->opcode = O_BASIC_UNTAG;
635         (*cmd)->module = MODULE_BASIC_ID;
636         (*cmd)->len = LEN_OF_IPFWINSN;
637         (*cmd)->arg1 = strtoul(**av, NULL, 10);
638         NEXT_ARG1;
639 }
640
641 void
642 show_count(ipfw_insn *cmd)
643 {
644         printf(" count");
645 }
646
647 void
648 show_skipto(ipfw_insn *cmd)
649 {
650         printf(" skipto %u", cmd->arg1);
651 }
652
653 void
654 show_forward(ipfw_insn *cmd)
655 {
656         struct sockaddr_in *sa;
657         int i;
658
659         ipfw_insn_sa *s = (ipfw_insn_sa *)cmd;
660         sa = &s->sa;
661         printf(" forward");
662         for (i = 0; i < cmd->arg3; i++){
663                 if (i > 0)
664                         printf(",");
665                 else
666                         printf(" ");
667
668                 printf("%s", inet_ntoa(sa->sin_addr));
669                 if (sa->sin_port != 0)
670                         printf(":%d", sa->sin_port);
671
672                 sa++;
673         }
674         if (cmd->arg1 == 1)
675                 printf(" round-robin");
676         else if (cmd->arg1 == 2)
677                 printf(" sticky");
678
679 }
680
681 void
682 show_in(ipfw_insn *cmd)
683 {
684         printf(" in");
685 }
686
687 void
688 show_out(ipfw_insn *cmd)
689 {
690         printf(" out");
691 }
692
693 void
694 show_via(ipfw_insn *cmd)
695 {
696         char *s;
697         ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd;
698
699         if ((int)cmd->opcode == O_BASIC_XMIT)
700                 s = "xmit";
701         else if ((int)cmd->opcode == O_BASIC_RECV)
702                 s = "recv";
703         else if ((int)cmd->opcode == O_BASIC_VIA)
704                 s = "via";
705         else
706                 s = "?huh?";
707
708         if (cmdif->name[0] == '\0')
709                 printf(" %s %s", s, inet_ntoa(cmdif->p.ip));
710
711         printf(" %s %s", s, cmdif->name);
712 }
713
714 void
715 show_from(ipfw_insn *cmd)
716 {
717         printf(" from %s", inet_ntoa(((ipfw_insn_ip *)cmd)->addr));
718 }
719
720 void
721 show_to(ipfw_insn *cmd)
722 {
723         printf(" to %s", inet_ntoa(((ipfw_insn_ip *)cmd)->addr));
724 }
725
726 void
727 show_proto(ipfw_insn *cmd)
728 {
729         struct protoent *pe;
730         u_char proto = 0;
731         proto = cmd->arg1;
732         pe = getprotobynumber(cmd->arg1);
733         printf(" %s", pe->p_name);
734 }
735
736 void
737 show_prob(ipfw_insn *cmd)
738 {
739         printf(" prob %d%%", cmd->arg1);
740 }
741
742 void
743 show_keep_state(ipfw_insn *cmd)
744 {
745         printf(" keep-state");
746         if (cmd->arg1 != 0) {
747                 char *type=match_token2(limit_types, cmd->arg3);
748                 printf(" limit %s %d", type, cmd->arg1);
749         }
750         if (cmd->arg2 != 0) {
751                 printf(" live %d", cmd->arg2);
752         }
753 }
754
755 void
756 show_check_state(ipfw_insn *cmd)
757 {
758         printf(" check-state");
759 }
760
761 void
762 show_tagged(ipfw_insn *cmd)
763 {
764         printf(" tagged %d", cmd->arg1);
765 }
766
767 void
768 show_comment(ipfw_insn *cmd)
769 {
770         printf(" // %s", (char *)(cmd + 1));
771 }
772
773 void
774 show_tag(ipfw_insn *cmd)
775 {
776         printf(" tag %d", cmd->arg1);
777 }
778
779 void
780 show_untag(ipfw_insn *cmd)
781 {
782         printf(" untag %d", cmd->arg1);
783 }
784
785 void
786 load_module(register_func function, register_keyword keyword)
787 {
788         keyword(MODULE_BASIC_ID, O_BASIC_COUNT, "count",
789                         IPFW_KEYWORD_TYPE_ACTION);
790         function(MODULE_BASIC_ID, O_BASIC_COUNT,
791                         (parser_func)parse_count, (shower_func)show_count);
792
793         keyword(MODULE_BASIC_ID, O_BASIC_SKIPTO, "skipto",
794                         IPFW_KEYWORD_TYPE_ACTION);
795         function(MODULE_BASIC_ID, O_BASIC_SKIPTO,
796                         (parser_func)parse_skipto, (shower_func)show_skipto);
797
798         keyword(MODULE_BASIC_ID, O_BASIC_FORWARD, "forward",
799                         IPFW_KEYWORD_TYPE_ACTION);
800         function(MODULE_BASIC_ID, O_BASIC_FORWARD,
801                         (parser_func)parse_forward, (shower_func)show_forward);
802
803         keyword(MODULE_BASIC_ID, O_BASIC_IN, "in", IPFW_KEYWORD_TYPE_FILTER);
804         function(MODULE_BASIC_ID, O_BASIC_IN,
805                         (parser_func)parse_in, (shower_func)show_in);
806
807         keyword(MODULE_BASIC_ID, O_BASIC_OUT, "out", IPFW_KEYWORD_TYPE_FILTER);
808         function(MODULE_BASIC_ID, O_BASIC_OUT,
809                         (parser_func)parse_out, (shower_func)show_out);
810
811         keyword(MODULE_BASIC_ID, O_BASIC_VIA, "via", IPFW_KEYWORD_TYPE_FILTER);
812         function(MODULE_BASIC_ID, O_BASIC_VIA,
813                         (parser_func)parse_via, (shower_func)show_via);
814
815         keyword(MODULE_BASIC_ID, O_BASIC_XMIT, "xmit",
816                         IPFW_KEYWORD_TYPE_FILTER);
817         function(MODULE_BASIC_ID, O_BASIC_XMIT,
818                         (parser_func)parse_via, (shower_func)show_via);
819
820         keyword(MODULE_BASIC_ID, O_BASIC_RECV, "recv",
821                         IPFW_KEYWORD_TYPE_FILTER);
822         function(MODULE_BASIC_ID, O_BASIC_RECV,
823                         (parser_func)parse_via, (shower_func)show_via);
824
825         keyword(MODULE_BASIC_ID, O_BASIC_IP_SRC, "from",
826                         IPFW_KEYWORD_TYPE_FILTER);
827         function(MODULE_BASIC_ID, O_BASIC_IP_SRC,
828                         (parser_func)parse_from, (shower_func)show_from);
829
830         keyword(MODULE_BASIC_ID, O_BASIC_IP_DST, "to",
831                         IPFW_KEYWORD_TYPE_FILTER);
832         function(MODULE_BASIC_ID, O_BASIC_IP_DST,
833                         (parser_func)parse_to, (shower_func)show_to);
834
835         keyword(MODULE_BASIC_ID, O_BASIC_PROTO, "proto",
836                         IPFW_KEYWORD_TYPE_FILTER);
837         function(MODULE_BASIC_ID, O_BASIC_PROTO,
838                         (parser_func)parse_proto, (shower_func)show_proto);
839
840         keyword(MODULE_BASIC_ID, O_BASIC_PROB, "prob",
841                         IPFW_KEYWORD_TYPE_FILTER);
842         function(MODULE_BASIC_ID, O_BASIC_PROB,
843                         (parser_func)parse_prob, (shower_func)show_prob);
844
845         keyword(MODULE_BASIC_ID, O_BASIC_KEEP_STATE, "keep-state",
846                         IPFW_KEYWORD_TYPE_FILTER);
847         function(MODULE_BASIC_ID, O_BASIC_KEEP_STATE,
848                         (parser_func)parse_keep_state,
849                         (shower_func)show_keep_state);
850
851         keyword(MODULE_BASIC_ID, O_BASIC_CHECK_STATE, "check-state",
852                         IPFW_KEYWORD_TYPE_OTHERS);
853         function(MODULE_BASIC_ID, O_BASIC_CHECK_STATE,
854                         (parser_func)parse_check_state,
855                         (shower_func)show_check_state);
856
857         keyword(MODULE_BASIC_ID, O_BASIC_TAG, "tag", IPFW_KEYWORD_TYPE_OTHERS);
858         function(MODULE_BASIC_ID, O_BASIC_TAG,
859                         (parser_func)parse_tag, (shower_func)show_tag);
860
861         keyword(MODULE_BASIC_ID, O_BASIC_UNTAG, "untag",
862                         IPFW_KEYWORD_TYPE_OTHERS);
863         function(MODULE_BASIC_ID, O_BASIC_UNTAG,
864                         (parser_func)parse_untag, (shower_func)show_untag);
865
866         keyword(MODULE_BASIC_ID, O_BASIC_TAGGED, "tagged",
867                         IPFW_KEYWORD_TYPE_FILTER);
868         function(MODULE_BASIC_ID, O_BASIC_TAGGED,
869                         (parser_func)parse_tagged, (shower_func)show_tagged);
870
871         keyword(MODULE_BASIC_ID, O_BASIC_COMMENT, "//",
872                         IPFW_KEYWORD_TYPE_FILTER);
873         function(MODULE_BASIC_ID, O_BASIC_COMMENT,
874                         (parser_func)parse_comment, (shower_func)show_comment);
875 }