xref: /dragonfly/sbin/ipfw3/ipfw3table.c (revision 6b47f3ea)
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 <sys/param.h>
36 #include <sys/mbuf.h>
37 #include <sys/socket.h>
38 #include <sys/sockio.h>
39 #include <sys/sysctl.h>
40 #include <sys/time.h>
41 #include <sys/wait.h>
42 
43 #include <arpa/inet.h>
44 #include <ctype.h>
45 #include <dlfcn.h>
46 #include <err.h>
47 #include <errno.h>
48 #include <grp.h>
49 #include <limits.h>
50 #include <netdb.h>
51 #include <pwd.h>
52 #include <sysexits.h>
53 #include <signal.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <stdarg.h>
57 #include <string.h>
58 #include <timeconv.h>
59 #include <unistd.h>
60 
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/ip.h>
64 #include <netinet/ip_icmp.h>
65 #include <netinet/tcp.h>
66 #include <net/if.h>
67 #include <net/if_dl.h>
68 #include <net/route.h>
69 #include <net/ethernet.h>
70 
71 #include <net/ipfw3/ip_fw3.h>
72 #include <net/ipfw3_basic/ip_fw3_table.h>
73 #include <net/ipfw3_basic/ip_fw3_sync.h>
74 #include <net/ipfw3_basic/ip_fw3_basic.h>
75 #include <net/ipfw3_nat/ip_fw3_nat.h>
76 #include <net/dummynet3/ip_dummynet3.h>
77 
78 #include "ipfw3.h"
79 #include "ipfw3table.h"
80 
81 int
82 lookup_host (char *host, struct in_addr *ipaddr)
83 {
84 	struct hostent *he;
85 
86 	if (!inet_aton(host, ipaddr)) {
87 		if ((he = gethostbyname(host)) == NULL)
88 			return(-1);
89 		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
90 	}
91 	return(0);
92 }
93 
94 
95 void
96 table_append(int ac, char *av[])
97 {
98 	struct ipfw_ioc_table tbl;
99 	char *p;
100 	int size;
101 
102 	NEXT_ARG;
103 	if (isdigit(**av))
104 		tbl.id = atoi(*av);
105 	else
106 		errx(EX_USAGE, "table id `%s' invalid", *av);
107 
108 	if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
109 		errx(EX_USAGE, "table id `%d' invalid", tbl.id);
110 
111 	NEXT_ARG;
112 	if (strcmp(*av, "ip") == 0)
113 		tbl.type = 1;
114 	else if (strcmp(*av, "mac") == 0)
115 		tbl.type = 2;
116 	else
117 		errx(EX_USAGE, "table type `%s' not supported", *av);
118 
119 	NEXT_ARG;
120         if (tbl.type == 1) { /* table type ipv4 */
121                 struct ipfw_ioc_table_ip_entry ip_ent;
122                 if (!ac)
123                         errx(EX_USAGE, "IP address required");
124 
125                 p = strchr(*av, '/');
126                 if (p) {
127                         *p++ = '\0';
128                         ip_ent.masklen = atoi(p);
129                         if (ip_ent.masklen > 32)
130                                 errx(EX_DATAERR, "bad width ``%s''", p);
131                 } else {
132                         ip_ent.masklen = 32;
133                 }
134 
135                 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
136                         errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
137 
138                 tbl.ip_ent[0] = ip_ent;
139                 size = sizeof(tbl) + sizeof(ip_ent);
140         } else if (tbl.type == 2) { /* table type mac */
141                 struct ipfw_ioc_table_mac_entry mac_ent;
142                 if (!ac)
143                         errx(EX_USAGE, "MAC address required");
144 
145                 mac_ent.addr = *ether_aton(*av);
146                 tbl.mac_ent[0] = mac_ent;
147                 size = sizeof(tbl) + sizeof(mac_ent);
148         }
149 	if (do_set_x(IP_FW_TABLE_APPEND, &tbl, size) < 0 )
150 		errx(EX_USAGE, "do_set_x(IP_FW_TABLE_APPEND) "
151 			"table `%d' append `%s' failed", tbl.id, *av);
152 }
153 
154 void
155 table_remove(int ac, char *av[])
156 {
157 	struct ipfw_ioc_table tbl;
158 	struct ipfw_ioc_table_ip_entry ip_ent;
159 	char *p;
160 	int size;
161 
162 	NEXT_ARG;
163 	if (isdigit(**av))
164 		tbl.id = atoi(*av);
165 	else
166 		errx(EX_USAGE, "table id `%s' invalid", *av);
167 
168 	if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
169 		errx(EX_USAGE, "table id `%d' invalid", tbl.id);
170 
171 	NEXT_ARG;
172 	if (strcmp(*av, "ip") == 0)
173 		tbl.type = 1;
174 	else if (strcmp(*av, "mac") == 0)
175 		tbl.type = 2;
176 	else
177 		errx(EX_USAGE, "table type `%s' not supported", *av);
178 
179 	NEXT_ARG;
180 	if (!ac)
181 		errx(EX_USAGE, "IP address required");
182 	p = strchr(*av, '/');
183 	if (p) {
184 		*p++ = '\0';
185 		ip_ent.masklen = atoi(p);
186 		if (ip_ent.masklen > 32)
187 			errx(EX_DATAERR, "bad width ``%s''", p);
188 	} else {
189 		ip_ent.masklen = 32;
190 	}
191 
192 	if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
193 		errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
194 
195 	tbl.ip_ent[0] = ip_ent;
196 	size = sizeof(tbl) + sizeof(ip_ent);
197 	if (do_set_x(IP_FW_TABLE_REMOVE, &tbl, size) < 0 ) {
198 		errx(EX_USAGE, "do_set_x(IP_FW_TABLE_REMOVE) "
199 			"table `%d' append `%s' failed", tbl.id, *av);
200 	}
201 }
202 
203 void
204 table_flush(int ac, char *av[])
205 {
206 	struct ipfw_ioc_table ioc_table;
207 	struct ipfw_ioc_table *t = &ioc_table;
208 
209 	NEXT_ARG;
210 	if (isdigit(**av)) {
211 		t->id = atoi(*av);
212 		if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
213 			errx(EX_USAGE, "table id `%d' invalid", t->id);
214 	} else {
215 		errx(EX_USAGE, "table id `%s' invalid", *av);
216 	}
217 	if (do_set_x(IP_FW_TABLE_FLUSH, t, sizeof(struct ipfw_ioc_table)) < 0 )
218 		errx(EX_USAGE, "do_set_x(IP_FW_TABLE_FLUSH) "
219 					"table `%s' flush failed", *av);
220 }
221 
222 void
223 table_list(int ac, char *av[])
224 {
225 	struct ipfw_ioc_table *ioc_table;
226 	int i, count, nbytes, nalloc = 1024;
227 	void *data = NULL;
228 	NEXT_ARG;
229 	if (strcmp(*av, "list") == 0) {
230 		nbytes = nalloc;
231 		while (nbytes >= nalloc) {
232 			nalloc = nalloc * 2 ;
233 			nbytes = nalloc;
234 			if ((data = realloc(data, nbytes)) == NULL)
235 				err(EX_OSERR, "realloc");
236 			if (do_get_x(IP_FW_TABLE_LIST, data, &nbytes) < 0)
237 				err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
238 		}
239 		ioc_table = (struct ipfw_ioc_table *)data;
240 		count = nbytes / sizeof(struct ipfw_ioc_table);
241 		for (i = 0; i < count; i++, ioc_table++) {
242 			if (ioc_table->type > 0) {
243 				printf("table %d",ioc_table->id);
244 				if (ioc_table->type == 1)
245 					printf(" type ip");
246 				else if (ioc_table->type == 2)
247 					printf(" type mac");
248 				printf(" count %d",ioc_table->count);
249 				if (strlen(ioc_table->name) > 0)
250 					printf(" name %s",ioc_table->name);
251 				printf("\n");
252 
253 			}
254 		}
255 	} else {
256 		errx(EX_USAGE, "ipfw3 table `%s' delete invalid", *av);
257 	}
258 }
259 
260 void
261 table_print(struct ipfw_ioc_table * tbl)
262 {
263 	int i;
264         if (tbl->type == 0)
265                 errx(EX_USAGE, "table %d is not in use", tbl->id);
266 
267         printf("table %d", tbl->id);
268         if (tbl->type == 1)
269                 printf(" type ip");
270         else if (tbl->type == 2)
271                 printf(" type mac");
272 
273         printf(" count %d", tbl->count);
274 	if (strlen(tbl->name) > 0)
275 		printf(" name %s", tbl->name);
276 
277 	printf("\n");
278 
279         if (tbl->type == 1) {
280                 struct ipfw_ioc_table_ip_entry *ip_ent;
281                 ip_ent = tbl->ip_ent;
282                 for (i = 0; i < tbl->count; i++) {
283                         printf("%s", inet_ntoa(*(struct in_addr *)&ip_ent->addr));
284                         printf("/%d ", ip_ent->masklen);
285                         printf("\n");
286                         ip_ent++;
287                 }
288         } else if (tbl->type == 2) {
289                 struct ipfw_ioc_table_mac_entry *mac_ent;
290                 mac_ent = tbl->mac_ent;
291                 for (i = 0; i < tbl->count; i++) {
292                         printf("%s", ether_ntoa(&mac_ent->addr));
293                         printf("\n");
294                         mac_ent++;
295                 }
296         }
297 }
298 
299 void
300 table_show(int ac, char *av[])
301 {
302 	int nbytes, nalloc = 1024;
303 	void *data = NULL;
304 	NEXT_ARG;
305 	if (isdigit(**av)) {
306 		nbytes = nalloc;
307 		while (nbytes >= nalloc) {
308 			nalloc = nalloc * 2 + 256;
309 			nbytes = nalloc;
310 			if (data == NULL) {
311 				if ((data = malloc(nbytes)) == NULL) {
312 					err(EX_OSERR, "malloc");
313 				}
314 			} else if ((data = realloc(data, nbytes)) == NULL) {
315 				err(EX_OSERR, "realloc");
316 			}
317 			/* store table id in the header of data */
318 			int *head = (int *)data;
319 			*head = atoi(*av);
320 			if (*head < 0 || *head > IPFW_TABLES_MAX - 1)
321 				errx(EX_USAGE, "table id `%d' invalid", *head);
322 			if (do_get_x(IP_FW_TABLE_SHOW, data, &nbytes) < 0)
323 				err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
324 			struct ipfw_ioc_table *tbl;
325 			tbl = (struct ipfw_ioc_table *)data;
326 			table_print(tbl);
327 		}
328 	} else {
329 		errx(EX_USAGE, "ipfw3 table `%s' show invalid", *av);
330 	}
331 }
332 
333 void
334 table_create(int ac, char *av[])
335 {
336 	struct ipfw_ioc_table ioc_table;
337 	struct ipfw_ioc_table *t = &ioc_table;
338 
339 	NEXT_ARG;
340 	if (ac < 2)
341 		errx(EX_USAGE, "table parameters invalid");
342 	if (isdigit(**av)) {
343 		t->id = atoi(*av);
344 		if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
345 			errx(EX_USAGE, "table id `%d' invalid", t->id);
346 	} else {
347 		errx(EX_USAGE, "table id `%s' invalid", *av);
348 	}
349 	NEXT_ARG;
350 	if (strcmp(*av, "ip") == 0)
351 		t->type = 1;
352 	else if (strcmp(*av, "mac") == 0)
353 		t->type = 2;
354 	else
355 		errx(EX_USAGE, "table type `%s' not supported", *av);
356 
357 	NEXT_ARG;
358 	memset(t->name, 0, IPFW_TABLE_NAME_LEN);
359 	if (ac == 2 && strcmp(*av, "name") == 0) {
360 		NEXT_ARG;
361 		if (strlen(*av) < IPFW_TABLE_NAME_LEN) {
362 			strncpy(t->name, *av, strlen(*av));
363 		} else {
364 			errx(EX_USAGE, "table name `%s' too long", *av);
365 		}
366 	} else if (ac == 1) {
367 		errx(EX_USAGE, "table `%s' invalid", *av);
368 	}
369 
370 	if (do_set_x(IP_FW_TABLE_CREATE, t, sizeof(struct ipfw_ioc_table)) < 0)
371 		errx(EX_USAGE, "do_set_x(IP_FW_TABLE_CREATE) "
372 					"table `%d' in use", t->id);
373 }
374 
375 void
376 table_delete(int ac, char *av[])
377 {
378 	struct ipfw_ioc_table ioc_table;
379 	struct ipfw_ioc_table *t = &ioc_table;
380 
381 	NEXT_ARG;
382 	if (isdigit(**av)) {
383 		t->id = atoi(*av);
384 		if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
385 			errx(EX_USAGE, "table id `%d' invalid", t->id);
386 	} else {
387 		errx(EX_USAGE, "table id `%s' invalid", *av);
388 	}
389 	if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
390 		errx(EX_USAGE, "table id `%d' invalid", t->id);
391 
392 	if (do_set_x(IP_FW_TABLE_DELETE, t, sizeof(struct ipfw_ioc_table)) < 0)
393 		errx(EX_USAGE, "do_set_x(IP_FW_TABLE_DELETE) "
394 					"table `%s' delete failed", *av);
395 }
396 
397 void
398 table_test(int ac, char *av[])
399 {
400 	struct ipfw_ioc_table tbl;
401 	int size;
402 
403 	NEXT_ARG;
404 	if (isdigit(**av))
405 		tbl.id = atoi(*av);
406 	else
407 		errx(EX_USAGE, "table id `%s' invalid", *av);
408 
409 	if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
410 		errx(EX_USAGE, "table id `%d' invalid", tbl.id);
411 
412 	NEXT_ARG;
413 	if (strcmp(*av, "ip") == 0)
414 		tbl.type = 1;
415 	else if (strcmp(*av, "mac") == 0)
416 		tbl.type = 2;
417 	else
418 		errx(EX_USAGE, "table type `%s' not supported", *av);
419 
420 	NEXT_ARG;
421         if (tbl.type == 1) { /* table type ipv4 */
422                 struct ipfw_ioc_table_ip_entry ip_ent;
423                 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
424                         errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
425 
426                 tbl.ip_ent[0] = ip_ent;
427                 size = sizeof(tbl) + sizeof(ip_ent);
428         } else if (tbl.type == 2) { /* table type mac */
429                 struct ipfw_ioc_table_mac_entry mac_ent;
430                 if (!ac)
431                         errx(EX_USAGE, "MAC address required");
432 
433                 mac_ent.addr = *ether_aton(*av);
434                 tbl.mac_ent[0] = mac_ent;
435                 size = sizeof(tbl) + sizeof(mac_ent);
436         }
437 	if (do_set_x(IP_FW_TABLE_TEST, &tbl, size) < 0 ) {
438 		printf("NO, %s not exists in table %d\n", *av, tbl.id);
439 	} else {
440 		printf("YES, %s exists in table %d\n", *av, tbl.id);
441 	}
442 }
443 
444 static void
445 table_rename(int ac, char *av[])
446 {
447 	struct ipfw_ioc_table tbl;
448 	int size;
449 
450 	bzero(&tbl, sizeof(tbl));
451 	NEXT_ARG;
452 	if (isdigit(**av))
453 		tbl.id = atoi(*av);
454 	else
455 		errx(EX_USAGE, "table id `%s' invalid", *av);
456 
457 	if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
458 		errx(EX_USAGE, "table id `%d' invalid", tbl.id);
459 
460 	NEXT_ARG;
461 	strlcpy(tbl.name, *av, IPFW_TABLE_NAME_LEN);
462 	size = sizeof(tbl);
463 	if (do_set_x(IP_FW_TABLE_RENAME, &tbl, size) < 0 )
464 		errx(EX_USAGE, "do_set_x(IP_FW_TABLE_RENAME) "
465 					"table `%d' not in use", tbl.id);
466 }
467 
468 void
469 table_main(int ac, char **av)
470 {
471 	if (!strncmp(*av, "append", strlen(*av))) {
472 		table_append(ac, av);
473 	} else if (!strncmp(*av, "add", strlen(*av))) {
474 		table_append(ac, av);
475 	} else if (!strncmp(*av, "remove", strlen(*av))) {
476 		table_remove(ac, av);
477 	} else if (!strncmp(*av, "flush", strlen(*av))) {
478 		table_flush(ac, av);
479 	} else if (!strncmp(*av, "list", strlen(*av))) {
480 		table_list(ac, av);
481 	} else if (!strncmp(*av, "show", strlen(*av))) {
482 		table_show(ac, av);
483 	} else if (!strncmp(*av, "type", strlen(*av))) {
484 		table_create(ac, av);
485 	} else if (!strncmp(*av, "delete", strlen(*av))) {
486 		table_delete(ac, av);
487 	} else if (!strncmp(*av, "test", strlen(*av))) {
488 		table_test(ac,av);
489 	} else if (!strncmp(*av, "name", strlen(*av))) {
490 		table_rename(ac, av);
491 	} else {
492 		errx(EX_USAGE, "bad ipfw table command `%s'", *av);
493 	}
494 }
495