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