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