xref: /dragonfly/lib/libipfw3/basic/ipfw3_basic.c (revision 10f846f51bac6e64af644ef98faf46f72d181f51)
1 /*
2  * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Bill Yuan <bycn82@dragonflybsd.org>
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 <net/ipfw3/ip_fw3.h>
59 #include "../../../sbin/ipfw3/ipfw3.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 int
match_token(struct char_int_map * table,char * string)101 match_token(struct char_int_map *table, char *string)
102 {
103           while (table->key) {
104                     if (strcmp(table->key, string) == 0) {
105                               return table->val;
106                     }
107                     table++;
108           }
109           return 0;
110 }
111 
112 static char *
match_token2(struct char_int_map * table,int val)113 match_token2(struct char_int_map *table, int val)
114 {
115           while (table->val) {
116                     if (table->val == val)
117                               return table->key;
118 
119                     table++;
120           }
121           return NULL;
122 };
123 
124 static void
fill_iface(ipfw_insn_if * cmd,char * arg)125 fill_iface(ipfw_insn_if *cmd, char *arg)
126 {
127           cmd->name[0] = '\0';
128           cmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
129 
130           /* Parse the interface or address */
131           if (!strcmp(arg, "any")){
132                     cmd->o.len = 0;
133           } else if (!isdigit(*arg)) {
134                     strlcpy(cmd->name, arg, sizeof(cmd->name));
135                     cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0;
136           } else if (!inet_aton(arg, &cmd->p.ip))
137                     errx(EX_DATAERR, "bad ip address ``%s''", arg);
138 }
139 
140 static int
lookup_host(char * host,struct in_addr * ipaddr)141 lookup_host (char *host, struct in_addr *ipaddr)
142 {
143           struct hostent *he;
144 
145           if (!inet_aton(host, ipaddr)) {
146                     if ((he = gethostbyname(host)) == NULL)
147                               return -1;
148                     *ipaddr = *(struct in_addr *)he->h_addr_list[0];
149           }
150           return 0;
151 }
152 
153 /*
154  * Like strtol, but also translates service names into port numbers
155  * for some protocols.
156  * In particular:
157  *        proto == -1 disables the protocol check;
158  *        proto == IPPROTO_ETHERTYPE looks up an internal table
159  *        proto == <some value in /etc/protocols> matches the values there.
160  * Returns *end == s in case the parameter is not found.
161  */
162 static int
strtoport(char * s,char ** end,int base,int proto)163 strtoport(char *s, char **end, int base, int proto)
164 {
165           char *p, *buf;
166           char *s1;
167           int i;
168 
169           *end = s;                     /* default - not found */
170           if ( *s == '\0')
171                     return 0;           /* not found */
172 
173           if (isdigit(*s))
174                     return strtol(s, end, base);
175 
176           /*
177            * find separator. '\\' escapes the next char.
178            */
179           for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++) {
180                     if (*s1 == '\\' && s1[1] != '\0')
181                               s1++;
182           }
183 
184           buf = malloc(s1 - s + 1);
185           if (buf == NULL)
186                     return 0;
187 
188           /*
189            * copy into a buffer skipping backslashes
190            */
191           for (p = s, i = 0; p != s1 ; p++)
192                     if ( *p != '\\')
193                               buf[i++] = *p;
194           buf[i++] = '\0';
195 
196           if (proto == IPPROTO_ETHERTYPE) {
197                     i = match_token(ether_types, buf);
198                     free(buf);
199                     if (i != -1) {      /* found */
200                               *end = s1;
201                               return i;
202                     }
203           } else {
204                     struct protoent *pe = NULL;
205                     struct servent *se;
206 
207                     if (proto != 0)
208                               pe = getprotobynumber(proto);
209                     setservent(1);
210                     se = getservbyname(buf, pe ? pe->p_name : NULL);
211                     free(buf);
212                     if (se != NULL) {
213                               *end = s1;
214                               return ntohs(se->s_port);
215                     }
216           }
217           return 0;           /* not found */
218 }
219 
220 static int
contigmask(u_char * p,int len)221 contigmask(u_char *p, int len)
222 {
223           int i, n;
224           for (i=0; i<len ; i++) {
225                     if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */
226                               break;
227           }
228           for (n=i+1; n < len; n++) {
229                     if ( (p[n/8] & (1 << (7 - (n%8)))) != 0)
230                               return -1; /* mask not contiguous */
231           }
232           return i;
233 }
234 
235 static ipfw_insn
add_proto(ipfw_insn * cmd,char * av)236 *add_proto(ipfw_insn *cmd, char *av)
237 {
238           struct protoent *pe;
239           u_char proto = 0;
240           if (!strncmp(av, "all", strlen(av))) {
241                     ;
242           } else if ((proto = atoi(av)) > 0) {
243                     ;
244           } else if ((pe = getprotobyname(av)) != NULL) {
245                     proto = pe->p_proto;
246           } else {
247                     errx(EX_USAGE, "protocol `%s' not recognizable\n", av);
248           }
249           if (proto != IPPROTO_IP) {
250                     cmd->opcode = O_BASIC_PROTO;
251                     cmd->module = MODULE_BASIC_ID;
252                     cmd->len |= LEN_OF_IPFWINSN;
253                     cmd->arg1 = proto;
254           }
255           return cmd;
256 }
257 
258 void
parse_count(ipfw_insn ** cmd,int * ac,char ** av[])259 parse_count(ipfw_insn **cmd, int *ac, char **av[])
260 {
261           (*cmd)->opcode = O_BASIC_COUNT;
262           (*cmd)->module = MODULE_BASIC_ID;
263           (*cmd)->len |= LEN_OF_IPFWINSN;
264           NEXT_ARG1;
265 }
266 
267 void
parse_skipto(ipfw_insn ** cmd,int * ac,char ** av[])268 parse_skipto(ipfw_insn **cmd, int *ac, char **av[])
269 {
270           NEXT_ARG1;
271           (*cmd)->opcode = O_BASIC_SKIPTO;
272           (*cmd)->module = MODULE_BASIC_ID;
273           (*cmd)->len |= LEN_OF_IPFWINSN;
274           (*cmd)->arg1 = strtoul(**av, NULL, 10);
275           NEXT_ARG1;
276 }
277 
278 /*
279  * cmd->arg3 is count of the destination
280  * cmd->arg1 is the type, random 0, round-robin 1, sticky 2
281  */
282 void
parse_forward(ipfw_insn ** cmd,int * ac,char ** av[])283 parse_forward(ipfw_insn **cmd, int *ac, char **av[])
284 {
285           ipfw_insn_sa *p = (ipfw_insn_sa *)(*cmd);
286           struct sockaddr_in *sa;
287           char *tok, *end = NULL;
288           char *str;
289           int count, port;
290 
291           (*cmd)->opcode = O_BASIC_FORWARD;
292           NEXT_ARG1;
293           /*
294            * multiple forward destinations are seperated by colon
295            * ip address and port are seperated by comma
296            * e.g. 192.168.1.1:80,192.168.1.2:8080
297            *      192.168.1.1,192.168.1.2 or keep the port the same
298            */
299           tok = strtok(**av, ",");
300           sa = &p->sa;
301           count = 0;
302           while (tok != NULL) {
303                     sa->sin_len = sizeof(struct sockaddr_in);
304                     sa->sin_family = AF_INET;
305                     sa->sin_port = 0;
306                     str = strchr(tok,':');
307                     if (str != NULL) {
308                               *(str++) = '\0';
309                               port = strtoport(str, &end, 0, 0);
310                               sa->sin_port = (u_short)port;
311                     }
312                     if (lookup_host(tok, &(sa->sin_addr)) != 0)
313                               errx(EX_DATAERR, "forward `%s' invalid dst", tok);
314                     tok = strtok (NULL, ",");
315                     sa++;
316                     count++;
317           }
318           (*cmd)->arg3 = count;
319           if (count == 0) {
320                     errx(EX_DATAERR, "forward `%s' not recognizable", **av);
321           }
322           NEXT_ARG1;
323           if (count > 1) {
324                     if (strcmp(**av, "round-robin") == 0) {
325                               NEXT_ARG1;
326                               (*cmd)->arg1 = 1;
327                     } else if (strcmp(**av, "sticky") == 0) {
328                               NEXT_ARG1;
329                               (*cmd)->arg1 = 2;
330                     } else {
331                               /* random */
332                               (*cmd)->arg1 = 0;
333                     }
334           }
335           (*cmd)->len = LEN_OF_IPFWINSN + count * sizeof(struct sockaddr_in);
336 }
337 
338 void
parse_in(ipfw_insn ** cmd,int * ac,char ** av[])339 parse_in(ipfw_insn **cmd, int *ac, char **av[])
340 {
341           (*cmd)->opcode = O_BASIC_IN;
342           (*cmd)->module = MODULE_BASIC_ID;
343           (*cmd)->len |= LEN_OF_IPFWINSN;
344           (*cmd)->arg1 = 0;
345           NEXT_ARG1;
346 }
347 
348 void
parse_out(ipfw_insn ** cmd,int * ac,char ** av[])349 parse_out(ipfw_insn **cmd, int *ac, char **av[])
350 {
351           (*cmd)->opcode = O_BASIC_OUT;
352           (*cmd)->module = MODULE_BASIC_ID;
353           (*cmd)->len |= LEN_OF_IPFWINSN;
354           (*cmd)->arg1 = 0;
355           NEXT_ARG1;
356 }
357 
358 
359 void
parse_via(ipfw_insn ** cmd,int * ac,char ** av[])360 parse_via(ipfw_insn **cmd, int *ac, char **av[])
361 {
362           (*cmd)->module = MODULE_BASIC_ID;
363           (*cmd)->len |= LEN_OF_IPFWINSN;
364           if (strcmp(*av[0], "via")==0) {
365                     (*cmd)->opcode = O_BASIC_VIA;
366           } else if (strcmp(*av[0], "xmit")==0) {
367                     (*cmd)->opcode = O_BASIC_XMIT;
368           } else if (strcmp(*av[0], "recv")==0) {
369                     (*cmd)->opcode = O_BASIC_RECV;
370           }
371           NEXT_ARG1;
372           fill_iface((ipfw_insn_if *)(*cmd), *av[0]);
373           NEXT_ARG1;
374 }
375 
376 void
parse_src_port(ipfw_insn ** cmd,int * ac,char ** av[])377 parse_src_port(ipfw_insn **cmd, int *ac, char **av[])
378 {
379           NEXT_ARG1;
380           (*cmd)->opcode = O_BASIC_IP_SRCPORT;
381           (*cmd)->module = MODULE_BASIC_ID;
382           (*cmd)->len |= LEN_OF_IPFWINSN;
383           double v = strtol(**av, NULL, 0);
384           if (v <= 0 || v >= 65535)
385                     errx(EX_NOHOST, "port `%s' invalid", **av);
386           (*cmd)->arg1 = v;
387           NEXT_ARG1;
388 }
389 
390 void
parse_dst_port(ipfw_insn ** cmd,int * ac,char ** av[])391 parse_dst_port(ipfw_insn **cmd, int *ac, char **av[])
392 {
393           NEXT_ARG1;
394           (*cmd)->opcode = O_BASIC_IP_DSTPORT;
395           (*cmd)->module = MODULE_BASIC_ID;
396           (*cmd)->len |= LEN_OF_IPFWINSN;
397           double v = strtol(**av, NULL, 0);
398           if (v <= 0 || v >= 65535)
399                     errx(EX_NOHOST, "port `%s' invalid", **av);
400           (*cmd)->arg1 = v;
401           NEXT_ARG1;
402 }
403 
404 /*
405  * Below formats are supported:
406  * from table 1               O_BASIC_IP_SRC_LOOKUP
407  * from any                   return 0 len instruction
408  * from me                    O_BASIC_IP_SRC_ME
409  * from 1.2.3.4     O_BASIC_IP_SRC
410  * from 1.2.3.4/24  O_BASIC_IP_SRC_MASK
411  */
412 void
parse_from(ipfw_insn ** cmd,int * ac,char ** av[])413 parse_from(ipfw_insn **cmd, int *ac, char **av[])
414 {
415           ipfw_insn_ip *p = (ipfw_insn_ip *)(*cmd);
416           double port;
417           int i;
418 
419           (*cmd)->module = MODULE_BASIC_ID;
420           NEXT_ARG1;
421           if (strcmp(**av, "table") == 0) {
422                     NEXT_ARG1;
423                     NEED(*ac, 1, "table id missing");
424                     (*cmd)->len |= F_INSN_SIZE(ipfw_insn);
425                     (*cmd)->opcode = O_BASIC_IP_SRC_LOOKUP;
426                     (*cmd)->arg1 = strtoul(**av, NULL, 10);
427           } else if (strcmp(**av, "any") == 0) {
428                     (*cmd)->len &= ~F_LEN_MASK;
429           } else if (strcmp(**av, "me") == 0) {
430                     (*cmd)->len |= F_INSN_SIZE(ipfw_insn);
431                     (*cmd)->opcode = O_BASIC_IP_SRC_ME;
432           } else {
433                     char *c = NULL, md = 0;
434                     c = strchr(**av, '/');
435                     if (!c)
436                               c = strchr(**av, ':');
437                     if (c) {
438                               md = *c;
439                               *c++ = '\0';
440                     }
441                     if (lookup_host(**av, &p->addr) != 0)
442                               errx(EX_NOHOST, "hostname ``%s'' unknown", **av);
443                     switch (md) {
444                               case ':':
445                                         port = strtol(c, NULL, 0);
446                                         if (port <= 0 || port >= 65535)
447                                                   errx(EX_NOHOST, "port `%s' invalid", c);
448                                         (*cmd)->arg1 = port;
449                                         (*cmd)->len |= F_INSN_SIZE(ipfw_insn_ip);
450                                         (*cmd)->opcode = O_BASIC_IP_SRC_N_PORT;
451                                         break;
452                               case '/':
453                                         i = atoi(c);
454                                         if (i == 0)
455                                                   p->mask.s_addr = htonl(0);
456                                         else if (i > 32)
457                                                   errx(EX_DATAERR, "bad width ``%s''", c);
458                                         else
459                                                   p->mask.s_addr = htonl(~0 << (32 - i));
460                                         (*cmd)->len |= F_INSN_SIZE(ipfw_insn_ip);
461                                         (*cmd)->opcode = O_BASIC_IP_SRC_MASK;
462                                         p->addr.s_addr &= p->mask.s_addr;
463                                         break;
464                               default:
465                                         p->mask.s_addr = htonl(~0);
466                                         (*cmd)->len |= F_INSN_SIZE(ipfw_insn_u32);
467                                         (*cmd)->opcode = O_BASIC_IP_SRC;
468                                         break;
469                     }
470           }
471           NEXT_ARG1;
472 }
473 
474 void
parse_to(ipfw_insn ** cmd,int * ac,char ** av[])475 parse_to(ipfw_insn **cmd, int *ac, char **av[])
476 {
477           ipfw_insn_ip *p = (ipfw_insn_ip *)(*cmd);
478           double port;
479           int i;
480 
481           (*cmd)->module = MODULE_BASIC_ID;
482           NEXT_ARG1;
483           if (strcmp(**av, "table") == 0) {
484                     NEXT_ARG1;
485                     NEED(*ac, 1, "table id missing");
486                     (*cmd)->len |= F_INSN_SIZE(ipfw_insn);
487                     (*cmd)->opcode = O_BASIC_IP_DST_LOOKUP;
488                     (*cmd)->arg1 = strtoul(**av, NULL, 10);
489           } else if (strcmp(**av, "any") == 0) {
490                     (*cmd)->len &= ~F_LEN_MASK;
491           } else if (strcmp(**av, "me") == 0) {
492                     (*cmd)->len |= F_INSN_SIZE(ipfw_insn);
493                     (*cmd)->opcode = O_BASIC_IP_DST_ME;
494           } else {
495                     char *c = NULL, md = 0;
496                     c = strchr(**av, '/');
497                     if (!c)
498                               c = strchr(**av, ':');
499                     if (c) {
500                               md = *c;
501                               *c++ = '\0';
502                     }
503                     if (lookup_host(**av, &p->addr) != 0)
504                               errx(EX_NOHOST, "hostname ``%s'' unknown", **av);
505                     switch (md) {
506                               case ':':
507                                         port = strtol(c, NULL, 0);
508                                         if (port <= 0 || port >= 65535)
509                                                   errx(EX_NOHOST, "port `%s' invalid", c);
510                                         (*cmd)->arg1 = port;
511                                         (*cmd)->len |= F_INSN_SIZE(ipfw_insn_ip);
512                                         (*cmd)->opcode = O_BASIC_IP_DST_N_PORT;
513                                         break;
514                               case '/':
515                                         i = atoi(c);
516                                         if (i == 0)
517                                                   p->mask.s_addr = htonl(0);
518                                         else if (i > 32)
519                                                   errx(EX_DATAERR, "bad width ``%s''", c);
520                                         else
521                                                   p->mask.s_addr = htonl(~0 << (32 - i));
522                                         (*cmd)->len |= F_INSN_SIZE(ipfw_insn_ip);
523                                         (*cmd)->opcode = O_BASIC_IP_DST_MASK;
524                                         p->addr.s_addr &= p->mask.s_addr;
525                                         break;
526                               default:
527                                         p->mask.s_addr = htonl(~0);
528                                         (*cmd)->len |= F_INSN_SIZE(ipfw_insn_u32);
529                                         (*cmd)->opcode = O_BASIC_IP_DST;
530                                         break;
531                     }
532           }
533           NEXT_ARG1;
534 
535 }
536 
537 void
parse_proto(ipfw_insn ** cmd,int * ac,char ** av[])538 parse_proto(ipfw_insn **cmd, int *ac, char **av[])
539 {
540           add_proto(*cmd, **av);
541           NEXT_ARG1;
542 }
543 
544 void
parse_prob(ipfw_insn ** cmd,int * ac,char ** av[])545 parse_prob(ipfw_insn **cmd, int *ac, char **av[])
546 {
547           NEXT_ARG1;
548           (*cmd)->opcode = O_BASIC_PROB;
549           (*cmd)->module = MODULE_BASIC_ID;
550           (*cmd)->len |= LEN_OF_IPFWINSN;
551           (*cmd)->arg1 = strtoul(**av, NULL, 10);
552           NEXT_ARG1;
553 }
554 
555 void
parse_keep_state(ipfw_insn ** cmd,int * ac,char ** av[])556 parse_keep_state(ipfw_insn **cmd, int *ac, char **av[])
557 {
558           NEXT_ARG1;
559           (*cmd)->opcode = O_BASIC_KEEP_STATE;
560           (*cmd)->module = MODULE_BASIC_ID;
561           (*cmd)->len |= LEN_OF_IPFWINSN;
562           if (strcmp(**av, "limit") == 0) {
563                     NEXT_ARG1;
564                     (*cmd)->arg3 = match_token(limit_types, **av);
565                     if ((*cmd)->arg3 == 0)
566                               errx(EX_DATAERR, "limit `%s' not recognizable", **av);
567 
568                     NEXT_ARG1;
569                     (*cmd)->arg1 = strtoul(**av, NULL, 10);
570                     if ((*cmd)->arg1 == 0)
571                               errx(EX_DATAERR, "bad limit `%s'", **av);
572 
573                     NEXT_ARG1;
574           }
575           if (strcmp(**av, "live") == 0) {
576                     NEXT_ARG1;
577                     (*cmd)->arg2 = strtoul(**av, NULL, 10);
578                     NEXT_ARG1;
579           }
580 }
581 
582 void
parse_check_state(ipfw_insn ** cmd,int * ac,char ** av[])583 parse_check_state(ipfw_insn **cmd, int *ac, char **av[])
584 {
585           NEXT_ARG1;
586           (*cmd)->opcode = O_BASIC_CHECK_STATE;
587           (*cmd)->module = MODULE_BASIC_ID;
588           (*cmd)->len |= LEN_OF_IPFWINSN;
589 }
590 
591 void
parse_tagged(ipfw_insn ** cmd,int * ac,char ** av[])592 parse_tagged(ipfw_insn **cmd, int *ac, char **av[])
593 {
594           NEXT_ARG1;
595           (*cmd)->opcode = O_BASIC_TAGGED;
596           (*cmd)->module = MODULE_BASIC_ID;
597           (*cmd)->len |= LEN_OF_IPFWINSN;
598           (*cmd)->arg1 = strtoul(**av, NULL, 10);
599           NEXT_ARG1;
600 }
601 
602 void
parse_comment(ipfw_insn ** cmd,int * ac,char ** av[])603 parse_comment(ipfw_insn **cmd, int *ac, char **av[])
604 {
605           int l = 0;
606           char *p = (char *)((*cmd) + 1);
607 
608           NEXT_ARG1;
609           (*cmd)->opcode = O_BASIC_COMMENT;
610           (*cmd)->module = MODULE_BASIC_ID;
611 
612           while (*ac > 0) {
613                     l += strlen(**av) + 1;
614                     if (l > 84) {
615                               errx(EX_DATAERR, "comment too long (max 80 chars)");
616                     }
617                     strcpy(p, **av);
618                     p += strlen(**av);
619                     *p++ = ' ';
620                     NEXT_ARG1;
621           }
622           l = 1 + (l + 3) / 4;
623           (*cmd)->len |= l;
624           *(--p) = '\0';
625 }
626 
627 void
parse_tag(ipfw_insn ** cmd,int * ac,char ** av[])628 parse_tag(ipfw_insn **cmd, int *ac, char **av[])
629 {
630           NEXT_ARG1;
631           (*cmd)->opcode = O_BASIC_TAG;
632           (*cmd)->module = MODULE_BASIC_ID;
633           (*cmd)->len |= LEN_OF_IPFWINSN;
634           (*cmd)->arg1 = strtoul(**av, NULL, 10);
635           NEXT_ARG1;
636 }
637 
638 void
parse_untag(ipfw_insn ** cmd,int * ac,char ** av[])639 parse_untag(ipfw_insn **cmd, int *ac, char **av[])
640 {
641           NEXT_ARG1;
642           (*cmd)->opcode = O_BASIC_UNTAG;
643           (*cmd)->module = MODULE_BASIC_ID;
644           (*cmd)->len |= LEN_OF_IPFWINSN;
645           (*cmd)->arg1 = strtoul(**av, NULL, 10);
646           NEXT_ARG1;
647 }
648 
649 void
show_count(ipfw_insn * cmd,int show_or)650 show_count(ipfw_insn *cmd, int show_or)
651 {
652           printf(" count");
653 }
654 
655 void
show_skipto(ipfw_insn * cmd,int show_or)656 show_skipto(ipfw_insn *cmd, int show_or)
657 {
658           printf(" skipto %u", cmd->arg1);
659 }
660 
661 void
show_forward(ipfw_insn * cmd,int show_or)662 show_forward(ipfw_insn *cmd, int show_or)
663 {
664           struct sockaddr_in *sa;
665           int i;
666 
667           ipfw_insn_sa *s = (ipfw_insn_sa *)cmd;
668           sa = &s->sa;
669           printf(" forward");
670           for (i = 0; i < cmd->arg3; i++){
671                     if (i > 0)
672                               printf(",");
673                     else
674                               printf(" ");
675 
676                     printf("%s", inet_ntoa(sa->sin_addr));
677                     if (sa->sin_port != 0)
678                               printf(":%d", sa->sin_port);
679 
680                     sa++;
681           }
682           if (cmd->arg1 == 1)
683                     printf(" round-robin");
684           else if (cmd->arg1 == 2)
685                     printf(" sticky");
686 
687 }
688 
689 void
show_in(ipfw_insn * cmd,int show_or)690 show_in(ipfw_insn *cmd, int show_or)
691 {
692           printf(" in");
693 }
694 
695 void
show_out(ipfw_insn * cmd,int show_or)696 show_out(ipfw_insn *cmd, int show_or)
697 {
698           printf(" out");
699 }
700 
701 void
show_via(ipfw_insn * cmd,int show_or)702 show_via(ipfw_insn *cmd, int show_or)
703 {
704           char *s;
705           ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd;
706 
707           if ((int)cmd->opcode == O_BASIC_XMIT)
708                     s = "xmit";
709           else if ((int)cmd->opcode == O_BASIC_RECV)
710                     s = "recv";
711           else if ((int)cmd->opcode == O_BASIC_VIA)
712                     s = "via";
713           else
714                     s = "?huh?";
715           if (show_or)
716                     s = "or";
717           if (cmdif->name[0] == '\0')
718                     printf(" %s %s", s, inet_ntoa(cmdif->p.ip));
719 
720           printf(" %s %s", s, cmdif->name);
721 }
722 
723 void
show_src_port(ipfw_insn * cmd,int show_or)724 show_src_port(ipfw_insn *cmd, int show_or)
725 {
726           char *word = "src-port";
727           if (show_or)
728                     word = "or";
729           printf(" %s %d", word, cmd->arg1);
730 }
731 
732 void
show_dst_port(ipfw_insn * cmd,int show_or)733 show_dst_port(ipfw_insn *cmd, int show_or)
734 {
735           char *word = "dst-port";
736           if (show_or)
737                     word = "or";
738           printf(" %s %d", word, cmd->arg1);
739 }
740 
741 void
show_from(ipfw_insn * cmd,int show_or)742 show_from(ipfw_insn *cmd, int show_or)
743 {
744           char *word = "from";
745           if (show_or)
746                     word = "or";
747           printf(" %s %s", word, inet_ntoa(((ipfw_insn_ip *)cmd)->addr));
748 }
749 
750 void
show_from_lookup(ipfw_insn * cmd,int show_or)751 show_from_lookup(ipfw_insn *cmd, int show_or)
752 {
753           char *word = "from";
754           if (show_or)
755                     word = "or";
756           printf(" %s table %d", word, cmd->arg1);
757 }
758 
759 void
show_from_me(ipfw_insn * cmd,int show_or)760 show_from_me(ipfw_insn *cmd, int show_or)
761 {
762           char *word = "from";
763           if (show_or)
764                     word = "or";
765           printf(" %s me", word);
766 }
767 
768 void
show_from_mask(ipfw_insn * cmd,int show_or)769 show_from_mask(ipfw_insn *cmd, int show_or)
770 {
771           int mask;
772           char *word = "from";
773           if (show_or)
774                     word = "or";
775           ipfw_insn_ip *p = (ipfw_insn_ip *)cmd;
776           printf(" %s %s", word, inet_ntoa(p->addr));
777 
778           mask = contigmask((u_char *)&(p->mask.s_addr), 32);
779           if (mask < 32)
780                     printf("/%d", mask);
781 }
782 
783 void
show_from_src_n_port(ipfw_insn * cmd,int show_or)784 show_from_src_n_port(ipfw_insn *cmd, int show_or)
785 {
786           char *word = "from";
787           if (show_or)
788                     word = "or";
789           ipfw_insn_ip *p = (ipfw_insn_ip *)cmd;
790           printf(" %s %s", word, inet_ntoa(p->addr));
791           printf(":%d", cmd->arg1);
792 }
793 
794 void
show_to(ipfw_insn * cmd,int show_or)795 show_to(ipfw_insn *cmd, int show_or)
796 {
797           char *word = "to";
798           if (show_or)
799                     word = "or";
800           ipfw_insn_ip *p = (ipfw_insn_ip *)cmd;
801           printf(" %s %s", word, inet_ntoa(p->addr));
802 }
803 
804 void
show_to_lookup(ipfw_insn * cmd,int show_or)805 show_to_lookup(ipfw_insn *cmd, int show_or)
806 {
807           char *word = "to";
808           if (show_or)
809                     word = "or";
810           printf(" %s table %d", word, cmd->arg1);
811 }
812 
813 void
show_to_me(ipfw_insn * cmd,int show_or)814 show_to_me(ipfw_insn *cmd, int show_or)
815 {
816           char *word = "to";
817           if (show_or)
818                     word = "or";
819           printf(" %s me", word);
820 }
821 
822 void
show_to_mask(ipfw_insn * cmd,int show_or)823 show_to_mask(ipfw_insn *cmd, int show_or)
824 {
825           int mask;
826           char *word = "to";
827           if (show_or)
828                     word = "or";
829           ipfw_insn_ip *p = (ipfw_insn_ip *)cmd;
830           printf(" %s %s", word, inet_ntoa(p->addr));
831 
832           mask = contigmask((u_char *)&(p->mask.s_addr), 32);
833           if (mask < 32)
834                     printf("/%d", mask);
835 }
836 
837 void
show_to_src_n_port(ipfw_insn * cmd,int show_or)838 show_to_src_n_port(ipfw_insn *cmd, int show_or)
839 {
840           char *word = "to";
841           if (show_or)
842                     word = "or";
843           printf(" %s %s", word, inet_ntoa(((ipfw_insn_ip *)cmd)->addr));
844           printf(":%d", cmd->arg1);
845 }
846 
847 void
show_proto(ipfw_insn * cmd,int show_or)848 show_proto(ipfw_insn *cmd, int show_or)
849 {
850           struct protoent *pe;
851           u_char proto = 0;
852           proto = cmd->arg1;
853           pe = getprotobynumber(cmd->arg1);
854           printf(" %s", pe->p_name);
855 }
856 
857 void
show_prob(ipfw_insn * cmd,int show_or)858 show_prob(ipfw_insn *cmd, int show_or)
859 {
860           char *word = "prob";
861           if (show_or)
862                     word = "or";
863           printf(" %s %d%%", word, cmd->arg1);
864 }
865 
866 void
show_keep_state(ipfw_insn * cmd,int show_or)867 show_keep_state(ipfw_insn *cmd, int show_or)
868 {
869           printf(" keep-state");
870           if (cmd->arg1 != 0) {
871                     char *type=match_token2(limit_types, cmd->arg3);
872                     printf(" limit %s %d", type, cmd->arg1);
873           }
874           if (cmd->arg2 != 0) {
875                     printf(" live %d", cmd->arg2);
876           }
877 }
878 
879 void
show_check_state(ipfw_insn * cmd,int show_or)880 show_check_state(ipfw_insn *cmd, int show_or)
881 {
882           printf(" check-state");
883 }
884 
885 void
show_tagged(ipfw_insn * cmd,int show_or)886 show_tagged(ipfw_insn *cmd, int show_or)
887 {
888           printf(" tagged %d", cmd->arg1);
889 }
890 
891 void
show_comment(ipfw_insn * cmd,int show_or)892 show_comment(ipfw_insn *cmd, int show_or)
893 {
894           printf(" // %s", (char *)(cmd + 1));
895 }
896 
897 void
show_tag(ipfw_insn * cmd,int show_or)898 show_tag(ipfw_insn *cmd, int show_or)
899 {
900           printf(" tag %d", cmd->arg1);
901 }
902 
903 void
show_untag(ipfw_insn * cmd,int show_or)904 show_untag(ipfw_insn *cmd, int show_or)
905 {
906           printf(" untag %d", cmd->arg1);
907 }
908 
909 void
load_module(register_func function,register_keyword keyword)910 load_module(register_func function, register_keyword keyword)
911 {
912           keyword(MODULE_BASIC_ID, O_BASIC_COUNT, "count", ACTION);
913           function(MODULE_BASIC_ID, O_BASIC_COUNT,
914                               (parser_func)parse_count, (shower_func)show_count);
915 
916           keyword(MODULE_BASIC_ID, O_BASIC_SKIPTO, "skipto", ACTION);
917           function(MODULE_BASIC_ID, O_BASIC_SKIPTO,
918                               (parser_func)parse_skipto, (shower_func)show_skipto);
919 
920           keyword(MODULE_BASIC_ID, O_BASIC_FORWARD, "forward", ACTION);
921           function(MODULE_BASIC_ID, O_BASIC_FORWARD,
922                               (parser_func)parse_forward, (shower_func)show_forward);
923 
924           keyword(MODULE_BASIC_ID, O_BASIC_IN, "in", FILTER);
925           function(MODULE_BASIC_ID, O_BASIC_IN,
926                               (parser_func)parse_in, (shower_func)show_in);
927 
928           keyword(MODULE_BASIC_ID, O_BASIC_OUT, "out", FILTER);
929           function(MODULE_BASIC_ID, O_BASIC_OUT,
930                               (parser_func)parse_out, (shower_func)show_out);
931 
932           keyword(MODULE_BASIC_ID, O_BASIC_VIA, "via", FILTER);
933           function(MODULE_BASIC_ID, O_BASIC_VIA,
934                               (parser_func)parse_via, (shower_func)show_via);
935 
936           keyword(MODULE_BASIC_ID, O_BASIC_XMIT, "xmit", FILTER);
937           function(MODULE_BASIC_ID, O_BASIC_XMIT,
938                               (parser_func)parse_via, (shower_func)show_via);
939 
940           keyword(MODULE_BASIC_ID, O_BASIC_RECV, "recv", FILTER);
941           function(MODULE_BASIC_ID, O_BASIC_RECV,
942                               (parser_func)parse_via, (shower_func)show_via);
943 
944           keyword(MODULE_BASIC_ID, O_BASIC_IP_SRCPORT, "src-port", FILTER);
945           function(MODULE_BASIC_ID, O_BASIC_IP_SRCPORT,
946                           (parser_func)parse_src_port, (shower_func)show_src_port);
947 
948           keyword(MODULE_BASIC_ID, O_BASIC_IP_DSTPORT, "dst-port", FILTER);
949           function(MODULE_BASIC_ID, O_BASIC_IP_DSTPORT,
950                           (parser_func)parse_dst_port, (shower_func)show_dst_port);
951 
952           keyword(MODULE_BASIC_ID, O_BASIC_IP_SRC, "from", FROM);
953           function(MODULE_BASIC_ID, O_BASIC_IP_SRC,
954                               (parser_func)parse_from, (shower_func)show_from);
955 
956           keyword(MODULE_BASIC_ID, O_BASIC_IP_SRC_LOOKUP, "from-[table]", FROM);
957           function(MODULE_BASIC_ID, O_BASIC_IP_SRC_LOOKUP,
958                               (parser_func)parse_from, (shower_func)show_from_lookup);
959 
960           keyword(MODULE_BASIC_ID, O_BASIC_IP_SRC_ME, "from-[me]", FROM);
961           function(MODULE_BASIC_ID, O_BASIC_IP_SRC_ME,
962                               (parser_func)parse_from, (shower_func)show_from_me);
963 
964           keyword(MODULE_BASIC_ID, O_BASIC_IP_SRC_MASK, "from-[mask]", FROM);
965           function(MODULE_BASIC_ID, O_BASIC_IP_SRC_MASK,
966                               (parser_func)parse_from, (shower_func)show_from_mask);
967 
968           keyword(MODULE_BASIC_ID, O_BASIC_IP_SRC_N_PORT, "from-[ip:port]", FROM);
969           function(MODULE_BASIC_ID, O_BASIC_IP_SRC_N_PORT,
970                               (parser_func)parse_from, (shower_func)show_from_src_n_port);
971 
972           keyword(MODULE_BASIC_ID, O_BASIC_IP_DST, "to", TO);
973           function(MODULE_BASIC_ID, O_BASIC_IP_DST,
974                               (parser_func)parse_to, (shower_func)show_to);
975 
976           keyword(MODULE_BASIC_ID, O_BASIC_IP_DST_LOOKUP, "to-[table]", TO);
977           function(MODULE_BASIC_ID, O_BASIC_IP_DST_LOOKUP,
978                               (parser_func)parse_to, (shower_func)show_to_lookup);
979 
980           keyword(MODULE_BASIC_ID, O_BASIC_IP_DST_ME, "to-[me]", TO);
981           function(MODULE_BASIC_ID, O_BASIC_IP_DST_ME,
982                               (parser_func)parse_to, (shower_func)show_to_me);
983 
984           keyword(MODULE_BASIC_ID, O_BASIC_IP_DST_MASK, "to-[mask]", TO);
985           function(MODULE_BASIC_ID, O_BASIC_IP_DST_MASK,
986                               (parser_func)parse_to, (shower_func)show_to_mask);
987 
988           keyword(MODULE_BASIC_ID, O_BASIC_IP_DST_N_PORT, "to-[ip:port]", FROM);
989           function(MODULE_BASIC_ID, O_BASIC_IP_DST_N_PORT,
990                               (parser_func)parse_to, (shower_func)show_to_src_n_port);
991 
992           keyword(MODULE_BASIC_ID, O_BASIC_PROTO, "proto", PROTO);
993           function(MODULE_BASIC_ID, O_BASIC_PROTO,
994                               (parser_func)parse_proto, (shower_func)show_proto);
995 
996           keyword(MODULE_BASIC_ID, O_BASIC_PROB, "prob", FILTER);
997           function(MODULE_BASIC_ID, O_BASIC_PROB,
998                               (parser_func)parse_prob, (shower_func)show_prob);
999 
1000           keyword(MODULE_BASIC_ID, O_BASIC_KEEP_STATE, "keep-state", FILTER);
1001           function(MODULE_BASIC_ID, O_BASIC_KEEP_STATE,
1002                               (parser_func)parse_keep_state,
1003                               (shower_func)show_keep_state);
1004 
1005           keyword(MODULE_BASIC_ID, O_BASIC_CHECK_STATE, "check-state", BEFORE);
1006           function(MODULE_BASIC_ID, O_BASIC_CHECK_STATE,
1007                               (parser_func)parse_check_state,
1008                               (shower_func)show_check_state);
1009 
1010           keyword(MODULE_BASIC_ID, O_BASIC_TAG, "tag", ACTION);
1011           function(MODULE_BASIC_ID, O_BASIC_TAG,
1012                               (parser_func)parse_tag, (shower_func)show_tag);
1013 
1014           keyword(MODULE_BASIC_ID, O_BASIC_UNTAG, "untag", ACTION);
1015           function(MODULE_BASIC_ID, O_BASIC_UNTAG,
1016                               (parser_func)parse_untag, (shower_func)show_untag);
1017 
1018           keyword(MODULE_BASIC_ID, O_BASIC_TAGGED, "tagged", FILTER);
1019           function(MODULE_BASIC_ID, O_BASIC_TAGGED,
1020                               (parser_func)parse_tagged, (shower_func)show_tagged);
1021 
1022           keyword(MODULE_BASIC_ID, O_BASIC_COMMENT, "//", AFTER);
1023           function(MODULE_BASIC_ID, O_BASIC_COMMENT,
1024                               (parser_func)parse_comment, (shower_func)show_comment);
1025 }
1026