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