1 /* 2 * firewall3 - 3rd OpenWrt UCI firewall implementation 3 * 4 * Copyright (C) 2013-2018 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 "redirects.h" 20 21 22 const struct fw3_option fw3_redirect_opts[] = { 23 FW3_OPT("enabled", bool, redirect, enabled), 24 25 FW3_OPT("name", string, redirect, name), 26 FW3_OPT("family", family, redirect, family), 27 28 FW3_OPT("src", device, redirect, src), 29 FW3_OPT("dest", device, redirect, dest), 30 31 FW3_OPT("ipset", setmatch, redirect, ipset), 32 FW3_OPT("helper", cthelper, redirect, helper), 33 34 FW3_LIST("proto", protocol, redirect, proto), 35 36 FW3_OPT("src_ip", network, redirect, ip_src), 37 FW3_LIST("src_mac", mac, redirect, mac_src), 38 FW3_OPT("src_port", port, redirect, port_src), 39 40 FW3_OPT("src_dip", network, redirect, ip_dest), 41 FW3_OPT("src_dport", port, redirect, port_dest), 42 43 FW3_OPT("dest_ip", network, redirect, ip_redir), 44 FW3_OPT("dest_port", port, redirect, port_redir), 45 46 FW3_OPT("extra", string, redirect, extra), 47 48 FW3_OPT("limit", limit, redirect, limit), 49 FW3_OPT("limit_burst", int, redirect, limit.burst), 50 51 FW3_OPT("utc_time", bool, redirect, time.utc), 52 FW3_OPT("start_date", date, redirect, time.datestart), 53 FW3_OPT("stop_date", date, redirect, time.datestop), 54 FW3_OPT("start_time", time, redirect, time.timestart), 55 FW3_OPT("stop_time", time, redirect, time.timestop), 56 FW3_OPT("weekdays", weekdays, redirect, time.weekdays), 57 FW3_OPT("monthdays", monthdays, redirect, time.monthdays), 58 59 FW3_OPT("mark", mark, redirect, mark), 60 61 FW3_OPT("reflection", bool, redirect, reflection), 62 FW3_OPT("reflection_src", reflection_source, 63 redirect, reflection_src), 64 FW3_LIST("reflection_zone", device, redirect, reflection_zones), 65 66 FW3_OPT("target", target, redirect, target), 67 68 { } 69 }; 70 71 72 static bool 73 check_families(struct uci_element *e, struct fw3_redirect *r) 74 { 75 if (r->family == FW3_FAMILY_ANY) 76 return true; 77 78 if (r->_src && r->_src->family && r->_src->family != r->family) 79 { 80 warn_elem(e, "refers to source zone with different family"); 81 return false; 82 } 83 84 if (r->_dest && r->_dest->family && r->_dest->family != r->family) 85 { 86 warn_elem(e, "refers to destination zone with different family"); 87 return false; 88 } 89 90 if (r->ipset.ptr && r->ipset.ptr->family && 91 r->ipset.ptr->family != r->family) 92 { 93 warn_elem(e, "refers to ipset with different family"); 94 return false; 95 } 96 97 if (r->helper.ptr && r->helper.ptr->family && 98 r->helper.ptr->family != r->family) 99 { 100 warn_elem(e, "refers to CT helper not supporting family"); 101 return false; 102 } 103 104 if (r->ip_src.family && r->ip_src.family != r->family) 105 { 106 warn_elem(e, "uses source ip with different family"); 107 return false; 108 } 109 110 if (r->ip_dest.family && r->ip_dest.family != r->family) 111 { 112 warn_elem(e, "uses destination ip with different family"); 113 return false; 114 } 115 116 if (r->ip_redir.family && r->ip_redir.family != r->family) 117 { 118 warn_elem(e, "uses redirect ip with different family"); 119 return false; 120 } 121 122 return true; 123 } 124 125 static bool 126 compare_addr(struct fw3_address *a, struct fw3_address *b) 127 { 128 if (a->family != FW3_FAMILY_V4 || b->family != FW3_FAMILY_V4) 129 return false; 130 131 return ((a->address.v4.s_addr & a->mask.v4.s_addr) == 132 (b->address.v4.s_addr & a->mask.v4.s_addr)); 133 } 134 135 static bool 136 resolve_dest(struct uci_element *e, struct fw3_redirect *redir, 137 struct fw3_state *state) 138 { 139 struct fw3_zone *zone; 140 struct fw3_address *addr; 141 struct list_head *addrs; 142 143 if (!redir->ip_redir.set) 144 return false; 145 146 list_for_each_entry(zone, &state->zones, list) 147 { 148 addrs = fw3_resolve_zone_addresses(zone, NULL); 149 150 if (!addrs) 151 continue; 152 153 list_for_each_entry(addr, addrs, list) 154 { 155 if (!compare_addr(addr, &redir->ip_redir)) 156 continue; 157 158 snprintf(redir->dest.name, sizeof(redir->dest.name), "%s", zone->name); 159 redir->dest.set = true; 160 redir->_dest = zone; 161 162 break; 163 } 164 165 fw3_free_list(addrs); 166 167 if (redir->_dest) 168 return true; 169 } 170 171 return false; 172 } 173 174 static bool 175 check_local(struct uci_element *e, struct fw3_redirect *redir, 176 struct fw3_state *state) 177 { 178 if (redir->target != FW3_FLAG_DNAT) 179 return false; 180 181 if (!redir->ip_redir.set) 182 redir->local = true; 183 184 return redir->local; 185 } 186 187 static void 188 select_helper(struct fw3_state *state, struct fw3_redirect *redir) 189 { 190 struct fw3_protocol *proto; 191 struct fw3_cthelper *helper; 192 int n_matches = 0; 193 194 if (!state->defaults.auto_helper) 195 return; 196 197 if (!redir->_src || redir->target != FW3_FLAG_DNAT) 198 return; 199 200 if (!redir->port_redir.set || redir->port_redir.invert) 201 return; 202 203 if (redir->helper.set || redir->helper.ptr) 204 return; 205 206 if (list_empty(&redir->proto)) 207 return; 208 209 list_for_each_entry(proto, &redir->proto, list) 210 { 211 helper = fw3_lookup_cthelper_by_proto_port(state, proto, &redir->port_redir); 212 213 if (helper) 214 n_matches++; 215 } 216 217 if (n_matches != 1) 218 return; 219 220 /* store pointer to auto-selected helper but set ".set" flag to false, 221 * to allow later code to decide between configured or auto-selected 222 * helpers */ 223 redir->helper.set = false; 224 redir->helper.ptr = helper; 225 226 set(redir->_src->flags, FW3_FAMILY_V4, FW3_FLAG_HELPER); 227 } 228 229 static bool 230 check_redirect(struct fw3_state *state, struct fw3_redirect *redir, struct uci_element *e) 231 { 232 bool valid; 233 234 if (!redir->enabled) 235 return false; 236 237 if (redir->src.invert) 238 { 239 warn_section("redirect", redir, e, "must not have an inverted source"); 240 return false; 241 } 242 else if (redir->src.set && !redir->src.any && 243 !(redir->_src = fw3_lookup_zone(state, redir->src.name))) 244 { 245 warn_section("redirect", redir, e, "refers to not existing zone '%s'", 246 redir->src.name); 247 return false; 248 } 249 else if (redir->dest.set && !redir->dest.any && 250 !(redir->_dest = fw3_lookup_zone(state, redir->dest.name))) 251 { 252 warn_section("redirect", redir, e, "refers to not existing zone '%s'", 253 redir->dest.name); 254 return false; 255 } 256 else if (redir->ipset.set && state->disable_ipsets) 257 { 258 warn_section("redirect", redir, e, "skipped due to disabled ipset support"); 259 return false; 260 } 261 else if (redir->ipset.set && 262 !(redir->ipset.ptr = fw3_lookup_ipset(state, redir->ipset.name))) 263 { 264 warn_section("redirect", redir, e, "refers to unknown ipset '%s'", 265 redir->ipset.name); 266 return false; 267 } 268 else if (redir->helper.set && 269 !(redir->helper.ptr = fw3_lookup_cthelper(state, redir->helper.name))) 270 { 271 warn_section("redirect", redir, e, "refers to unknown CT helper '%s'", 272 redir->helper.name); 273 return false; 274 } 275 276 if (!check_families(e, redir)) 277 return false; 278 279 if (redir->target == FW3_FLAG_UNSPEC) 280 { 281 warn_section("redirect", redir, e, "has no target specified, defaulting to DNAT"); 282 redir->target = FW3_FLAG_DNAT; 283 } 284 else if (redir->target < FW3_FLAG_DNAT || redir->target > FW3_FLAG_SNAT) 285 { 286 warn_section("redirect", redir, e, "has invalid target specified, defaulting to DNAT"); 287 redir->target = FW3_FLAG_DNAT; 288 } 289 290 valid = false; 291 292 if (redir->target == FW3_FLAG_DNAT) 293 { 294 if (redir->src.any) 295 warn_section("redirect", redir, e, "must not have source '*' for DNAT target"); 296 else if (!redir->_src) 297 warn_section("redirect", redir, e, "has no source specified"); 298 else if (redir->helper.invert) 299 warn_section("redirect", redir, e, "must not use a negated helper match"); 300 else 301 { 302 set(redir->_src->flags, FW3_FAMILY_V4, redir->target); 303 valid = true; 304 305 if (!check_local(e, redir, state) && !redir->dest.set && 306 resolve_dest(e, redir, state)) 307 { 308 warn_section("redirect", redir, e, 309 "does not specify a destination, assuming '%s'", 310 redir->dest.name); 311 } 312 313 if (redir->reflection && redir->_dest && redir->_src->masq) 314 { 315 set(redir->_dest->flags, FW3_FAMILY_V4, FW3_FLAG_ACCEPT); 316 set(redir->_dest->flags, FW3_FAMILY_V4, FW3_FLAG_DNAT); 317 set(redir->_dest->flags, FW3_FAMILY_V4, FW3_FLAG_SNAT); 318 } 319 320 if (redir->helper.ptr) 321 set(redir->_src->flags, FW3_FAMILY_V4, FW3_FLAG_HELPER); 322 } 323 } 324 else 325 { 326 if (redir->dest.any) 327 warn_section("redirect", redir, e, 328 "must not have destination '*' for SNAT target"); 329 else if (!redir->_dest) 330 warn_section("redirect", redir, e, "has no destination specified"); 331 else if (!redir->ip_dest.set) 332 warn_section("redirect", redir, e, "has no src_dip option specified"); 333 else if (!list_empty(&redir->mac_src)) 334 warn_section("redirect", redir, e, "must not use 'src_mac' option for SNAT target"); 335 else if (redir->helper.set) 336 warn_section("redirect", redir, e, "must not use 'helper' option for SNAT target"); 337 else 338 { 339 set(redir->_dest->flags, FW3_FAMILY_V4, redir->target); 340 valid = true; 341 } 342 } 343 344 if (list_empty(&redir->proto)) 345 { 346 warn_section("redirect", redir, e, "does not specify a protocol, assuming TCP+UDP"); 347 fw3_parse_protocol(&redir->proto, "tcpudp", true); 348 } 349 350 if (!valid) 351 return false; 352 353 if (redir->target == FW3_FLAG_DNAT && !redir->port_redir.set) 354 redir->port_redir = redir->port_dest; 355 356 return true; 357 } 358 359 static struct fw3_redirect * 360 fw3_alloc_redirect(struct fw3_state *state) 361 { 362 struct fw3_redirect *redir; 363 364 redir = calloc(1, sizeof(*redir)); 365 if (!redir) 366 return NULL; 367 368 INIT_LIST_HEAD(&redir->proto); 369 INIT_LIST_HEAD(&redir->mac_src); 370 INIT_LIST_HEAD(&redir->reflection_zones); 371 372 redir->enabled = true; 373 redir->reflection = true; 374 375 list_add_tail(&redir->list, &state->redirects); 376 377 return redir; 378 } 379 380 void 381 fw3_load_redirects(struct fw3_state *state, struct uci_package *p, 382 struct blob_attr *a) 383 { 384 struct uci_section *s; 385 struct uci_element *e; 386 struct fw3_redirect *redir; 387 struct blob_attr *entry; 388 unsigned rem; 389 390 INIT_LIST_HEAD(&state->redirects); 391 392 blob_for_each_attr(entry, a, rem) 393 { 394 const char *type; 395 const char *name = "ubus redirect"; 396 397 if (!fw3_attr_parse_name_type(entry, &name, &type)) 398 continue; 399 400 if (strcmp(type, "redirect")) 401 continue; 402 403 redir = fw3_alloc_redirect(state); 404 if (!redir) 405 continue; 406 407 if (!fw3_parse_blob_options(redir, fw3_redirect_opts, entry, name)) 408 { 409 warn_section("redirect", redir, NULL, "skipped due to invalid options"); 410 fw3_free_redirect(redir); 411 continue; 412 } 413 414 if (!check_redirect(state, redir, NULL)) { 415 fw3_free_redirect(redir); 416 continue; 417 } 418 419 select_helper(state, redir); 420 } 421 422 uci_foreach_element(&p->sections, e) 423 { 424 s = uci_to_section(e); 425 426 if (strcmp(s->type, "redirect")) 427 continue; 428 429 redir = fw3_alloc_redirect(state); 430 if (!redir) 431 continue; 432 433 if (!fw3_parse_options(redir, fw3_redirect_opts, s)) 434 { 435 warn_elem(e, "skipped due to invalid options"); 436 fw3_free_redirect(redir); 437 continue; 438 } 439 440 if (!check_redirect(state, redir, e)) { 441 fw3_free_redirect(redir); 442 continue; 443 } 444 445 select_helper(state, redir); 446 } 447 } 448 449 static void 450 append_chain_nat(struct fw3_ipt_rule *r, struct fw3_redirect *redir) 451 { 452 if (redir->target == FW3_FLAG_DNAT) 453 fw3_ipt_rule_append(r, "zone_%s_prerouting", redir->src.name); 454 else 455 fw3_ipt_rule_append(r, "zone_%s_postrouting", redir->dest.name); 456 } 457 458 static void 459 set_redirect(struct fw3_ipt_rule *r, struct fw3_port *port) 460 { 461 char buf[sizeof("65535-65535")]; 462 463 fw3_ipt_rule_target(r, "REDIRECT"); 464 465 if (port && port->set) 466 { 467 if (port->port_min == port->port_max) 468 snprintf(buf, sizeof(buf), "%u", port->port_min); 469 else 470 snprintf(buf, sizeof(buf), "%u-%u", port->port_min, port->port_max); 471 472 fw3_ipt_rule_addarg(r, false, "--to-ports", buf); 473 } 474 } 475 476 static void 477 set_snat_dnat(struct fw3_ipt_rule *r, enum fw3_flag target, 478 struct fw3_address *addr, struct fw3_port *port) 479 { 480 char buf[sizeof("255.255.255.255:65535-65535")] = {}; 481 char ip[INET_ADDRSTRLEN], *p = buf; 482 size_t rem = sizeof(buf); 483 int len; 484 485 if (addr && addr->set) 486 { 487 inet_ntop(AF_INET, &addr->address.v4, ip, sizeof(ip)); 488 489 len = snprintf(p, rem, "%s", ip); 490 491 if (len < 0 || len >= rem) 492 return; 493 494 rem -= len; 495 p += len; 496 } 497 498 if (port && port->set) 499 { 500 if (port->port_min == port->port_max) 501 snprintf(p, rem, ":%u", port->port_min); 502 else 503 snprintf(p, rem, ":%u-%u", port->port_min, port->port_max); 504 } 505 506 if (target == FW3_FLAG_DNAT) 507 { 508 fw3_ipt_rule_target(r, "DNAT"); 509 fw3_ipt_rule_addarg(r, false, "--to-destination", buf); 510 } 511 else 512 { 513 fw3_ipt_rule_target(r, "SNAT"); 514 fw3_ipt_rule_addarg(r, false, "--to-source", buf); 515 } 516 } 517 518 static void 519 set_target_nat(struct fw3_ipt_rule *r, struct fw3_redirect *redir) 520 { 521 if (redir->local) 522 set_redirect(r, &redir->port_redir); 523 else if (redir->target == FW3_FLAG_DNAT) 524 set_snat_dnat(r, redir->target, &redir->ip_redir, &redir->port_redir); 525 else 526 set_snat_dnat(r, redir->target, &redir->ip_dest, &redir->port_dest); 527 } 528 529 static void 530 set_comment(struct fw3_ipt_rule *r, const char *name, int num, const char *suffix) 531 { 532 if (name) 533 { 534 if (suffix) 535 fw3_ipt_rule_comment(r, "%s (%s)", name, suffix); 536 else 537 fw3_ipt_rule_comment(r, name); 538 } 539 else 540 { 541 if (suffix) 542 fw3_ipt_rule_comment(r, "@redirect[%u] (%s)", num, suffix); 543 else 544 fw3_ipt_rule_comment(r, "@redirect[%u]", num); 545 } 546 } 547 548 static void 549 print_redirect(struct fw3_ipt_handle *h, struct fw3_state *state, 550 struct fw3_redirect *redir, int num, 551 struct fw3_protocol *proto, struct fw3_mac *mac) 552 { 553 struct fw3_ipt_rule *r; 554 struct fw3_address *src, *dst; 555 struct fw3_port *spt, *dpt; 556 557 switch (h->table) 558 { 559 case FW3_TABLE_NAT: 560 src = &redir->ip_src; 561 dst = &redir->ip_dest; 562 spt = &redir->port_src; 563 dpt = &redir->port_dest; 564 565 if (redir->target == FW3_FLAG_SNAT) 566 { 567 dst = &redir->ip_redir; 568 dpt = &redir->port_redir; 569 } 570 571 r = fw3_ipt_rule_create(h, proto, NULL, NULL, src, dst); 572 fw3_ipt_rule_sport_dport(r, spt, dpt); 573 fw3_ipt_rule_mac(r, mac); 574 fw3_ipt_rule_ipset(r, &redir->ipset); 575 fw3_ipt_rule_helper(r, &redir->helper); 576 fw3_ipt_rule_limit(r, &redir->limit); 577 fw3_ipt_rule_time(r, &redir->time); 578 fw3_ipt_rule_mark(r, &redir->mark); 579 set_target_nat(r, redir); 580 fw3_ipt_rule_extra(r, redir->extra); 581 set_comment(r, redir->name, num, NULL); 582 append_chain_nat(r, redir); 583 break; 584 585 case FW3_TABLE_RAW: 586 if (redir->target == FW3_FLAG_DNAT && redir->helper.ptr) 587 { 588 if (!fw3_cthelper_check_proto(redir->helper.ptr, proto)) 589 { 590 info(" ! Skipping protocol %s since helper '%s' does not support it", 591 fw3_protoname(proto), redir->helper.ptr->name); 592 return; 593 } 594 595 if (!redir->helper.set) 596 info(" - Auto-selected conntrack helper '%s' based on proto/port", 597 redir->helper.ptr->name); 598 599 r = fw3_ipt_rule_create(h, proto, NULL, NULL, &redir->ip_src, &redir->ip_redir); 600 fw3_ipt_rule_sport_dport(r, &redir->port_src, &redir->port_redir); 601 fw3_ipt_rule_mac(r, mac); 602 fw3_ipt_rule_ipset(r, &redir->ipset); 603 fw3_ipt_rule_limit(r, &redir->limit); 604 fw3_ipt_rule_time(r, &redir->time); 605 fw3_ipt_rule_mark(r, &redir->mark); 606 fw3_ipt_rule_addarg(r, false, "-m", "conntrack"); 607 fw3_ipt_rule_addarg(r, false, "--ctstate", "DNAT"); 608 fw3_ipt_rule_target(r, "CT"); 609 fw3_ipt_rule_addarg(r, false, "--helper", redir->helper.ptr->name); 610 set_comment(r, redir->name, num, "CT helper"); 611 fw3_ipt_rule_append(r, "zone_%s_helper", redir->_src->name); 612 } 613 break; 614 615 default: 616 break; 617 } 618 } 619 620 static void 621 print_reflection(struct fw3_ipt_handle *h, struct fw3_state *state, 622 struct fw3_redirect *redir, int num, 623 struct fw3_protocol *proto, struct fw3_address *ra, 624 struct fw3_address *ia, struct fw3_address *ea, struct fw3_device *rz) 625 { 626 struct fw3_ipt_rule *r; 627 628 switch (h->table) 629 { 630 case FW3_TABLE_NAT: 631 r = fw3_ipt_rule_create(h, proto, NULL, NULL, ia, ea); 632 fw3_ipt_rule_sport_dport(r, NULL, &redir->port_dest); 633 fw3_ipt_rule_limit(r, &redir->limit); 634 fw3_ipt_rule_time(r, &redir->time); 635 set_comment(r, redir->name, num, "reflection"); 636 set_snat_dnat(r, FW3_FLAG_DNAT, &redir->ip_redir, &redir->port_redir); 637 fw3_ipt_rule_replace(r, "zone_%s_prerouting", rz->name); 638 639 r = fw3_ipt_rule_create(h, proto, NULL, NULL, ia, &redir->ip_redir); 640 fw3_ipt_rule_sport_dport(r, NULL, &redir->port_redir); 641 fw3_ipt_rule_limit(r, &redir->limit); 642 fw3_ipt_rule_time(r, &redir->time); 643 set_comment(r, redir->name, num, "reflection"); 644 set_snat_dnat(r, FW3_FLAG_SNAT, ra, NULL); 645 fw3_ipt_rule_replace(r, "zone_%s_postrouting", rz->name); 646 break; 647 648 default: 649 break; 650 } 651 } 652 653 static void 654 expand_redirect(struct fw3_ipt_handle *handle, struct fw3_state *state, 655 struct fw3_redirect *redir, int num) 656 { 657 struct list_head *ext_addrs, *int_addrs; 658 struct fw3_address *ext_addr, *int_addr, ref_addr; 659 struct fw3_protocol *proto; 660 struct fw3_mac *mac; 661 struct fw3_device *reflection_zone; 662 struct fw3_zone *zone; 663 664 if (redir->name) 665 info(" * Redirect '%s'", redir->name); 666 else 667 info(" * Redirect #%u", num); 668 669 if (!fw3_is_family(redir->_src, handle->family) || 670 !fw3_is_family(redir->_dest, handle->family)) 671 { 672 info(" ! Skipping due to different family of zone"); 673 return; 674 } 675 676 if (!fw3_is_family(&redir->ip_src, handle->family) || 677 !fw3_is_family(&redir->ip_dest, handle->family) || 678 !fw3_is_family(&redir->ip_redir, handle->family)) 679 { 680 if (!redir->ip_src.resolved || 681 !redir->ip_dest.resolved || 682 !redir->ip_redir.resolved) 683 info(" ! Skipping due to different family of ip address"); 684 685 return; 686 } 687 688 if (redir->ipset.ptr) 689 { 690 if (!fw3_is_family(redir->ipset.ptr, handle->family)) 691 { 692 info(" ! Skipping due to different family in ipset"); 693 return; 694 } 695 696 if (!fw3_check_ipset(redir->ipset.ptr)) 697 { 698 info(" ! Skipping due to missing ipset '%s'", 699 redir->ipset.ptr->external ? 700 redir->ipset.ptr->external : redir->ipset.ptr->name); 701 return; 702 } 703 704 set(redir->ipset.ptr->flags, handle->family, handle->family); 705 } 706 707 fw3_foreach(proto, &redir->proto) 708 fw3_foreach(mac, &redir->mac_src) 709 print_redirect(handle, state, redir, num, proto, mac); 710 711 /* reflection rules */ 712 if (redir->target != FW3_FLAG_DNAT || !redir->reflection || redir->local) 713 return; 714 715 if (!redir->_dest || !redir->_src->masq) 716 return; 717 718 ext_addrs = fw3_resolve_zone_addresses(redir->_src, &redir->ip_dest); 719 if (!ext_addrs) 720 return; 721 722 list_for_each_entry(ext_addr, ext_addrs, list) 723 { 724 if (!fw3_is_family(ext_addr, handle->family)) 725 continue; 726 727 for (reflection_zone = list_empty(&redir->reflection_zones) 728 ? &redir->dest 729 : list_first_entry(&redir->reflection_zones, struct fw3_device, list); 730 list_empty(&redir->reflection_zones) 731 ? (reflection_zone == &redir->dest) 732 : (&reflection_zone->list != &redir->reflection_zones); 733 reflection_zone = list_empty(&redir->reflection_zones) 734 ? NULL 735 : list_entry(reflection_zone->list.next, struct fw3_device, list)) 736 { 737 zone = fw3_lookup_zone(state, reflection_zone->name); 738 739 if (!zone) 740 continue; 741 742 int_addrs = fw3_resolve_zone_addresses(zone, NULL); 743 if (!int_addrs) 744 continue; 745 746 list_for_each_entry(int_addr, int_addrs, list) 747 { 748 if (!fw3_is_family(int_addr, handle->family)) 749 continue; 750 751 fw3_foreach(proto, &redir->proto) 752 { 753 if (!proto) 754 continue; 755 756 if (redir->reflection_src == FW3_REFLECTION_INTERNAL) 757 ref_addr = *int_addr; 758 else 759 ref_addr = *ext_addr; 760 761 ref_addr.mask.v4.s_addr = 0xFFFFFFFF; 762 ext_addr->mask.v4.s_addr = 0xFFFFFFFF; 763 764 print_reflection(handle, state, redir, num, proto, 765 &ref_addr, int_addr, ext_addr, reflection_zone); 766 } 767 } 768 769 fw3_free_list(int_addrs); 770 } 771 } 772 773 fw3_free_list(ext_addrs); 774 } 775 776 void 777 fw3_print_redirects(struct fw3_ipt_handle *handle, struct fw3_state *state) 778 { 779 int num = 0; 780 struct fw3_redirect *redir; 781 782 if (handle->family == FW3_FAMILY_V6) 783 return; 784 785 if (handle->table != FW3_TABLE_FILTER && 786 handle->table != FW3_TABLE_NAT && 787 handle->table != FW3_TABLE_RAW) 788 return; 789 790 list_for_each_entry(redir, &state->redirects, list) 791 { 792 if (handle->table == FW3_TABLE_RAW && !redir->helper.ptr) 793 continue; 794 795 expand_redirect(handle, state, redir, num++); 796 } 797 } 798
This page was automatically generated by LXR 0.3.1. • OpenWrt