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