1 /* 2 * firewall3 - 3rd OpenWrt UCI firewall implementation 3 * 4 * Copyright (C) 2013-2014 Jo-Philipp Wich <jo@mein.io> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <stdio.h> 20 #include <unistd.h> 21 22 #include "options.h" 23 #include "defaults.h" 24 #include "zones.h" 25 #include "rules.h" 26 #include "redirects.h" 27 #include "snats.h" 28 #include "forwards.h" 29 #include "ipsets.h" 30 #include "includes.h" 31 #include "ubus.h" 32 #include "iptables.h" 33 #include "helpers.h" 34 35 36 static enum fw3_family print_family = FW3_FAMILY_ANY; 37 38 static struct fw3_state *run_state = NULL; 39 static struct fw3_state *cfg_state = NULL; 40 41 42 static bool 43 build_state(bool runtime) 44 { 45 struct fw3_state *state = NULL; 46 struct uci_package *p = NULL; 47 FILE *sf; 48 49 state = calloc(1, sizeof(*state)); 50 if (!state) 51 error("Out of memory"); 52 53 state->uci = uci_alloc_context(); 54 55 if (!state->uci) 56 error("Out of memory"); 57 58 if (runtime) 59 { 60 sf = fopen(FW3_STATEFILE, "r"); 61 62 if (sf) 63 { 64 uci_import(state->uci, sf, "fw3_state", &p, true); 65 fclose(sf); 66 } 67 68 if (!p) 69 { 70 uci_free_context(state->uci); 71 free(state); 72 73 return false; 74 } 75 76 state->statefile = true; 77 78 run_state = state; 79 } 80 else 81 { 82 if (!fw3_ubus_connect()) 83 warn("Failed to connect to ubus"); 84 85 if (uci_load(state->uci, "firewall", &p)) 86 { 87 uci_perror(state->uci, NULL); 88 error("Failed to load /etc/config/firewall"); 89 } 90 91 if (!fw3_find_command("ipset")) 92 { 93 warn("Unable to locate ipset utility, disabling ipset support"); 94 state->disable_ipsets = true; 95 } 96 97 cfg_state = state; 98 } 99 100 101 struct blob_buf b = {NULL, NULL, 0, NULL}; 102 fw3_ubus_rules(&b); 103 104 fw3_load_defaults(state, p); 105 fw3_load_cthelpers(state, p); 106 fw3_load_ipsets(state, p, b.head); 107 fw3_load_zones(state, p); 108 fw3_load_rules(state, p, b.head); 109 fw3_load_redirects(state, p, b.head); 110 fw3_load_snats(state, p, b.head); 111 fw3_load_forwards(state, p, b.head); 112 fw3_load_includes(state, p, b.head); 113 114 return true; 115 } 116 117 static void 118 free_state(struct fw3_state *state) 119 { 120 struct list_head *cur, *tmp; 121 122 list_for_each_safe(cur, tmp, &state->zones) 123 fw3_free_zone((struct fw3_zone *)cur); 124 125 list_for_each_safe(cur, tmp, &state->rules) 126 fw3_free_rule((struct fw3_rule *)cur); 127 128 list_for_each_safe(cur, tmp, &state->redirects) 129 fw3_free_redirect((struct fw3_redirect *)cur); 130 131 list_for_each_safe(cur, tmp, &state->snats) 132 fw3_free_snat((struct fw3_snat *)cur); 133 134 list_for_each_safe(cur, tmp, &state->forwards) 135 fw3_free_forward((struct fw3_forward *)cur); 136 137 list_for_each_safe(cur, tmp, &state->ipsets) 138 fw3_free_ipset((struct fw3_ipset *)cur); 139 140 list_for_each_safe(cur, tmp, &state->includes) 141 fw3_free_include((struct fw3_include *)cur); 142 143 list_for_each_safe(cur, tmp, &state->cthelpers) 144 fw3_free_cthelper((struct fw3_cthelper *)cur); 145 146 uci_free_context(state->uci); 147 148 free(state); 149 150 fw3_ubus_disconnect(); 151 } 152 153 154 static bool 155 family_running(enum fw3_family family) 156 { 157 return (run_state && has(run_state->defaults.flags, family, family)); 158 } 159 160 static void 161 family_set(struct fw3_state *state, enum fw3_family family, bool set) 162 { 163 if (!state) 164 return; 165 166 if (set) 167 set(state->defaults.flags, family, family); 168 else 169 del(state->defaults.flags, family, family); 170 } 171 172 static int 173 stop(bool complete) 174 { 175 int rv = 1; 176 enum fw3_family family; 177 enum fw3_table table; 178 struct fw3_ipt_handle *handle; 179 180 if (!complete && !run_state) 181 { 182 warn("The firewall appears to be stopped. " 183 "Use the 'flush' command to forcefully purge all rules."); 184 185 return rv; 186 } 187 188 if (!print_family && run_state) 189 fw3_hotplug_zones(run_state, false); 190 191 for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++) 192 { 193 if (!complete && !family_running(family)) 194 continue; 195 196 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++) 197 { 198 if (!(handle = fw3_ipt_open(family, table))) 199 continue; 200 201 info(" * %sing %s %s table", complete ? "Flush" : "Clear", 202 fw3_flag_names[family], fw3_flag_names[table]); 203 204 if (complete) 205 { 206 fw3_flush_all(handle); 207 } 208 else if (run_state) 209 { 210 fw3_flush_rules(handle, run_state, false); 211 fw3_flush_zones(handle, run_state, false); 212 } 213 214 fw3_ipt_commit(handle); 215 fw3_ipt_close(handle); 216 } 217 218 family_set(run_state, family, false); 219 family_set(cfg_state, family, false); 220 221 rv = 0; 222 } 223 224 if (run_state) { 225 for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++) 226 fw3_destroy_ipsets(run_state, family, false); 227 } 228 229 if (complete) 230 fw3_flush_conntrack(NULL); 231 232 if (!rv && run_state) 233 fw3_write_statefile(run_state); 234 235 return rv; 236 } 237 238 static int 239 start(void) 240 { 241 int rv = 1; 242 enum fw3_family family; 243 enum fw3_table table; 244 struct fw3_ipt_handle *handle; 245 246 for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++) 247 { 248 if (!print_family) 249 fw3_create_ipsets(cfg_state, family, false); 250 251 if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6) 252 continue; 253 254 if (print_family && family != print_family) 255 continue; 256 257 if (!print_family && family_running(family)) 258 { 259 warn("The %s firewall appears to be started already. " 260 "If it is indeed empty, remove the %s file and retry.", 261 fw3_flag_names[family], FW3_STATEFILE); 262 263 continue; 264 } 265 266 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++) 267 { 268 if (!(handle = fw3_ipt_open(family, table))) 269 continue; 270 271 info(" * Populating %s %s table", 272 fw3_flag_names[family], fw3_flag_names[table]); 273 274 fw3_print_default_chains(handle, cfg_state, false); 275 fw3_print_zone_chains(handle, cfg_state, false); 276 fw3_print_default_head_rules(handle, cfg_state, false); 277 fw3_print_rules(handle, cfg_state); 278 fw3_print_redirects(handle, cfg_state); 279 fw3_print_snats(handle, cfg_state); 280 fw3_print_forwards(handle, cfg_state); 281 fw3_print_zone_rules(handle, cfg_state, false); 282 fw3_print_default_tail_rules(handle, cfg_state, false); 283 284 if (!print_family) 285 fw3_ipt_commit(handle); 286 287 fw3_ipt_close(handle); 288 } 289 290 if (!print_family) 291 fw3_print_includes(cfg_state, family, false); 292 293 family_set(run_state, family, true); 294 family_set(cfg_state, family, true); 295 296 rv = 0; 297 } 298 299 if (!rv) 300 { 301 fw3_flush_conntrack(run_state); 302 fw3_set_defaults(cfg_state); 303 304 if (!print_family) 305 { 306 fw3_run_includes(cfg_state, false); 307 fw3_hotplug_zones(cfg_state, true); 308 fw3_write_statefile(cfg_state); 309 } 310 } 311 312 return rv; 313 } 314 315 316 static int 317 reload(void) 318 { 319 int rv = 1; 320 enum fw3_family family; 321 enum fw3_table table; 322 struct fw3_ipt_handle *handle; 323 324 if (!run_state) 325 return start(); 326 327 fw3_hotplug_zones(run_state, false); 328 329 for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++) 330 { 331 if (!family_running(family)) 332 goto start; 333 334 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++) 335 { 336 if (!(handle = fw3_ipt_open(family, table))) 337 continue; 338 339 info(" * Clearing %s %s table", 340 fw3_flag_names[family], fw3_flag_names[table]); 341 342 fw3_flush_rules(handle, run_state, true); 343 fw3_flush_zones(handle, run_state, true); 344 fw3_ipt_commit(handle); 345 fw3_ipt_close(handle); 346 } 347 348 fw3_ipsets_update_run_state(family, run_state, cfg_state); 349 fw3_destroy_ipsets(run_state, family, true); 350 351 family_set(run_state, family, false); 352 family_set(cfg_state, family, false); 353 354 start: 355 if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6) 356 continue; 357 358 fw3_create_ipsets(cfg_state, family, true); 359 360 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++) 361 { 362 if (!(handle = fw3_ipt_open(family, table))) 363 continue; 364 365 info(" * Populating %s %s table", 366 fw3_flag_names[family], fw3_flag_names[table]); 367 368 fw3_print_default_chains(handle, cfg_state, true); 369 fw3_print_zone_chains(handle, cfg_state, true); 370 fw3_print_default_head_rules(handle, cfg_state, true); 371 fw3_print_rules(handle, cfg_state); 372 fw3_print_redirects(handle, cfg_state); 373 fw3_print_snats(handle, cfg_state); 374 fw3_print_forwards(handle, cfg_state); 375 fw3_print_zone_rules(handle, cfg_state, true); 376 fw3_print_default_tail_rules(handle, cfg_state, true); 377 378 fw3_ipt_commit(handle); 379 fw3_ipt_close(handle); 380 } 381 382 fw3_print_includes(cfg_state, family, true); 383 384 family_set(run_state, family, true); 385 family_set(cfg_state, family, true); 386 387 rv = 0; 388 } 389 390 if (!rv) 391 { 392 fw3_flush_conntrack(run_state); 393 394 fw3_set_defaults(cfg_state); 395 fw3_run_includes(cfg_state, true); 396 fw3_hotplug_zones(cfg_state, true); 397 fw3_write_statefile(cfg_state); 398 } 399 400 return rv; 401 } 402 403 static int 404 gc(void) 405 { 406 enum fw3_family family; 407 enum fw3_table table; 408 struct fw3_ipt_handle *handle; 409 410 for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++) 411 { 412 if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6) 413 continue; 414 415 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++) 416 { 417 if (!(handle = fw3_ipt_open(family, table))) 418 continue; 419 420 fw3_ipt_gc(handle); 421 fw3_ipt_commit(handle); 422 fw3_ipt_close(handle); 423 } 424 } 425 426 return 0; 427 } 428 429 static int 430 lookup_network(const char *net) 431 { 432 struct fw3_zone *z; 433 struct fw3_device *d; 434 435 list_for_each_entry(z, &cfg_state->zones, list) 436 { 437 list_for_each_entry(d, &z->networks, list) 438 { 439 if (!strcmp(d->name, net)) 440 { 441 printf("%s\n", z->name); 442 return 0; 443 } 444 } 445 } 446 447 return 1; 448 } 449 450 static int 451 lookup_device(const char *dev) 452 { 453 struct fw3_zone *z; 454 struct fw3_device *d; 455 456 list_for_each_entry(z, &cfg_state->zones, list) 457 { 458 list_for_each_entry(d, &z->devices, list) 459 { 460 if (!strcmp(d->name, dev)) 461 { 462 printf("%s\n", z->name); 463 return 0; 464 } 465 } 466 } 467 468 return 1; 469 } 470 471 static int 472 lookup_zone(const char *zone, const char *device) 473 { 474 struct fw3_zone *z; 475 struct fw3_device *d; 476 477 list_for_each_entry(z, &cfg_state->zones, list) 478 { 479 if (strcmp(z->name, zone)) 480 continue; 481 482 list_for_each_entry(d, &z->devices, list) 483 { 484 if (device && strcmp(device, d->name)) 485 continue; 486 487 printf("%s\n", d->name); 488 489 if (device) 490 return 0; 491 } 492 493 if (!device) 494 return 0; 495 } 496 497 return 1; 498 } 499 500 static int 501 usage(void) 502 { 503 fprintf(stderr, "fw3 [-4] [-6] [-q] print\n"); 504 fprintf(stderr, "fw3 [-q] {start|stop|flush|reload|restart}\n"); 505 fprintf(stderr, "fw3 [-q] network {net}\n"); 506 fprintf(stderr, "fw3 [-q] device {dev}\n"); 507 fprintf(stderr, "fw3 [-q] zone {zone} [dev]\n"); 508 509 return 1; 510 } 511 512 513 int main(int argc, char **argv) 514 { 515 int ch, rv = 1; 516 enum fw3_family family = FW3_FAMILY_ANY; 517 struct fw3_defaults *defs = NULL; 518 519 while ((ch = getopt(argc, argv, "46dqh")) != -1) 520 { 521 switch (ch) 522 { 523 case '4': 524 family = FW3_FAMILY_V4; 525 break; 526 527 case '6': 528 family = FW3_FAMILY_V6; 529 break; 530 531 case 'd': 532 fw3_pr_debug = true; 533 break; 534 535 case 'q': 536 if (freopen("/dev/null", "w", stderr)) {} 537 break; 538 539 case 'h': 540 rv = usage(); 541 goto out; 542 } 543 } 544 545 build_state(false); 546 defs = &cfg_state->defaults; 547 548 if (optind >= argc) 549 { 550 rv = usage(); 551 goto out; 552 } 553 554 if (!strcmp(argv[optind], "print")) 555 { 556 if (family == FW3_FAMILY_ANY) 557 { 558 family = FW3_FAMILY_V4; 559 } 560 else if (family == FW3_FAMILY_V6) 561 { 562 if (defs->disable_ipv6) 563 warn("IPv6 rules globally disabled in configuration"); 564 #ifdef DISABLE_IPV6 565 else 566 warn("IPv6 support is not compiled in"); 567 #endif 568 } 569 570 if (freopen("/dev/null", "w", stderr)) {}; 571 572 cfg_state->disable_ipsets = true; 573 print_family = family; 574 fw3_pr_debug = true; 575 576 if (fw3_lock()) 577 { 578 build_state(true); 579 rv = start(); 580 fw3_unlock(); 581 } 582 } 583 else if (!strcmp(argv[optind], "start")) 584 { 585 if (fw3_lock()) 586 { 587 build_state(true); 588 rv = start(); 589 fw3_unlock(); 590 } 591 } 592 else if (!strcmp(argv[optind], "stop")) 593 { 594 if (fw3_lock()) 595 { 596 build_state(true); 597 rv = stop(false); 598 fw3_unlock(); 599 } 600 } 601 else if (!strcmp(argv[optind], "flush")) 602 { 603 if (fw3_lock()) 604 { 605 build_state(true); 606 rv = stop(true); 607 fw3_unlock(); 608 } 609 } 610 else if (!strcmp(argv[optind], "restart")) 611 { 612 if (fw3_lock()) 613 { 614 build_state(true); 615 stop(true); 616 rv = start(); 617 fw3_unlock(); 618 } 619 } 620 else if (!strcmp(argv[optind], "reload")) 621 { 622 if (fw3_lock()) 623 { 624 build_state(true); 625 rv = reload(); 626 fw3_unlock(); 627 } 628 } 629 else if (!strcmp(argv[optind], "gc")) 630 { 631 if (fw3_lock()) 632 { 633 rv = gc(); 634 fw3_unlock(); 635 } 636 } 637 else if (!strcmp(argv[optind], "network") && (optind + 1) < argc) 638 { 639 rv = lookup_network(argv[optind + 1]); 640 } 641 else if (!strcmp(argv[optind], "device") && (optind + 1) < argc) 642 { 643 rv = lookup_device(argv[optind + 1]); 644 } 645 else if (!strcmp(argv[optind], "zone") && (optind + 1) < argc) 646 { 647 rv = lookup_zone(argv[optind + 1], argv[optind + 2]); 648 } 649 else 650 { 651 rv = usage(); 652 } 653 654 out: 655 if (cfg_state) 656 free_state(cfg_state); 657 658 if (run_state) 659 free_state(run_state); 660 661 return rv; 662 } 663
This page was automatically generated by LXR 0.3.1. • OpenWrt