|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1993 Daniel Boulet ! 24: * Copyright (c) 1994 Ugen J.S.Antsilevich ! 25: * Copyright (c) 1996 Alex Nash ! 26: * ! 27: * Redistribution and use in source forms, with and without modification, ! 28: * are permitted provided that this entire comment appears intact. ! 29: * ! 30: * Redistribution in binary form may occur without any restrictions. ! 31: * Obviously, it would be nice if you gave credit where credit is due ! 32: * but requiring it would be too onerous. ! 33: * ! 34: * This software is provided ``AS IS'' without any warranties of any kind. ! 35: * ! 36: */ ! 37: ! 38: /* ! 39: * Implement IP packet firewall ! 40: */ ! 41: #if ISFB31 ! 42: #if !defined(KLD_MODULE) && !defined(IPFIREWALL_MODULE) ! 43: #include "opt_ipfw.h" ! 44: #include "opt_ipdn.h" ! 45: #include "opt_ipdivert.h" ! 46: #include "opt_inet.h" ! 47: #endif ! 48: #endif ! 49: #ifndef INET ! 50: #error IPFIREWALL requires INET. ! 51: #endif /* INET */ ! 52: ! 53: #include <sys/param.h> ! 54: #include <sys/systm.h> ! 55: #include <sys/malloc.h> ! 56: #include <sys/mbuf.h> ! 57: #include <sys/kernel.h> ! 58: #include <sys/socket.h> ! 59: #include <sys/socketvar.h> ! 60: #include <sys/sysctl.h> ! 61: #include <net/if.h> ! 62: #include <netinet/in.h> ! 63: #include <netinet/in_systm.h> ! 64: #include <netinet/ip.h> ! 65: #include <netinet/ip_var.h> ! 66: #include <netinet/ip_icmp.h> ! 67: #include <netinet/ip_fw.h> ! 68: #if DUMMYNET ! 69: #include <net/route.h> ! 70: #include <netinet/ip_dummynet.h> ! 71: #endif ! 72: #include <netinet/tcp.h> ! 73: #include <netinet/tcp_timer.h> ! 74: #include <netinet/tcp_var.h> ! 75: #include <netinet/tcpip.h> ! 76: #include <netinet/udp.h> ! 77: ! 78: #include <netinet/if_ether.h> /* XXX ethertype_ip */ ! 79: ! 80: static int fw_debug = 1; ! 81: #if IPFIREWALL_VERBOSE ! 82: static int fw_verbose = 1; ! 83: #else ! 84: static int fw_verbose = 0; ! 85: #endif ! 86: static int fw_one_pass = 0; /* XXX */ ! 87: #if IPFIREWALL_VERBOSE_LIMIT ! 88: static int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT; ! 89: #else ! 90: static int fw_verbose_limit = 0; ! 91: #endif ! 92: ! 93: #define IPFW_DEFAULT_RULE ((u_int)(u_short)~0) ! 94: ! 95: LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain; ! 96: ! 97: MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); ! 98: ! 99: SYSCTL_DECL(_net_inet_ip); ! 100: SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); ! 101: SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, ""); ! 102: SYSCTL_INT(_net_inet_ip_fw, OID_AUTO,one_pass,CTLFLAG_RW, &fw_one_pass, 0, ""); ! 103: SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, ""); ! 104: SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, ""); ! 105: ! 106: #define dprintf(a) if (!fw_debug); else kprintf a ! 107: ! 108: #define print_ip(a) kprintf("%d.%d.%d.%d", \ ! 109: (int)(ntohl(a.s_addr) >> 24) & 0xFF, \ ! 110: (int)(ntohl(a.s_addr) >> 16) & 0xFF, \ ! 111: (int)(ntohl(a.s_addr) >> 8) & 0xFF, \ ! 112: (int)(ntohl(a.s_addr)) & 0xFF); ! 113: ! 114: #define dprint_ip(a) if (!fw_debug); else print_ip(a) ! 115: ! 116: static int add_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl)); ! 117: static int del_entry __P((struct ip_fw_head *chainptr, u_short number)); ! 118: static int zero_entry __P((struct ip_fw *)); ! 119: static int check_ipfw_struct __P((struct ip_fw *m)); ! 120: static __inline int ! 121: iface_match __P((struct ifnet *ifp, union ip_fw_if *ifu, ! 122: int byname)); ! 123: static int ipopts_match __P((struct ip *ip, struct ip_fw *f)); ! 124: static __inline int ! 125: port_match __P((u_short *portptr, int nports, u_short port, ! 126: int range_flag)); ! 127: static int tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f)); ! 128: static int icmptype_match __P((struct icmp * icmp, struct ip_fw * f)); ! 129: static void ipfw_report __P((struct ip_fw *f, struct ip *ip, ! 130: struct ifnet *rif, struct ifnet *oif)); ! 131: ! 132: static void flush_rule_ptrs(void); ! 133: ! 134: static int ip_fw_chk __P((struct ip **pip, int hlen, ! 135: struct ifnet *oif, u_int16_t *cookie, struct mbuf **m, ! 136: struct ip_fw_chain **flow_id, ! 137: struct sockaddr_in **next_hop)); ! 138: static int ip_fw_ctl __P((struct sockopt *sopt)); ! 139: ! 140: static char err_prefix[] = "ip_fw_ctl:"; ! 141: ! 142: /* ! 143: * Returns 1 if the port is matched by the vector, 0 otherwise ! 144: */ ! 145: static __inline int ! 146: port_match(u_short *portptr, int nports, u_short port, int range_flag) ! 147: { ! 148: if (!nports) ! 149: return 1; ! 150: if (range_flag) { ! 151: if (portptr[0] <= port && port <= portptr[1]) { ! 152: return 1; ! 153: } ! 154: nports -= 2; ! 155: portptr += 2; ! 156: } ! 157: while (nports-- > 0) { ! 158: if (*portptr++ == port) { ! 159: return 1; ! 160: } ! 161: } ! 162: return 0; ! 163: } ! 164: ! 165: static int ! 166: tcpflg_match(struct tcphdr *tcp, struct ip_fw *f) ! 167: { ! 168: u_char flg_set, flg_clr; ! 169: ! 170: if ((f->fw_tcpf & IP_FW_TCPF_ESTAB) && ! 171: (tcp->th_flags & (IP_FW_TCPF_RST | IP_FW_TCPF_ACK))) ! 172: return 1; ! 173: ! 174: flg_set = tcp->th_flags & f->fw_tcpf; ! 175: flg_clr = tcp->th_flags & f->fw_tcpnf; ! 176: ! 177: if (flg_set != f->fw_tcpf) ! 178: return 0; ! 179: if (flg_clr) ! 180: return 0; ! 181: ! 182: return 1; ! 183: } ! 184: ! 185: static int ! 186: icmptype_match(struct icmp *icmp, struct ip_fw *f) ! 187: { ! 188: int type; ! 189: ! 190: if (!(f->fw_flg & IP_FW_F_ICMPBIT)) ! 191: return(1); ! 192: ! 193: type = icmp->icmp_type; ! 194: ! 195: /* check for matching type in the bitmap */ ! 196: if (type < IP_FW_ICMPTYPES_MAX && ! 197: (f->fw_uar.fw_icmptypes[type / (sizeof(unsigned) * 8)] & ! 198: (1U << (type % (8 * sizeof(unsigned)))))) ! 199: return(1); ! 200: ! 201: return(0); /* no match */ ! 202: } ! 203: ! 204: static int ! 205: is_icmp_query(struct ip *ip) ! 206: { ! 207: const struct icmp *icmp; ! 208: int icmp_type; ! 209: ! 210: icmp = (struct icmp *)((u_int32_t *)ip + ip->ip_hl); ! 211: icmp_type = icmp->icmp_type; ! 212: ! 213: if (icmp_type == ICMP_ECHO || icmp_type == ICMP_ROUTERSOLICIT || ! 214: icmp_type == ICMP_TSTAMP || icmp_type == ICMP_IREQ || ! 215: icmp_type == ICMP_MASKREQ) ! 216: return(1); ! 217: ! 218: return(0); ! 219: } ! 220: ! 221: static int ! 222: ipopts_match(struct ip *ip, struct ip_fw *f) ! 223: { ! 224: register u_char *cp; ! 225: int opt, optlen, cnt; ! 226: u_char opts, nopts, nopts_sve; ! 227: ! 228: cp = (u_char *)(ip + 1); ! 229: cnt = (ip->ip_hl << 2) - sizeof (struct ip); ! 230: opts = f->fw_ipopt; ! 231: nopts = nopts_sve = f->fw_ipnopt; ! 232: ! 233: for (; cnt > 0; cnt -= optlen, cp += optlen) { ! 234: opt = cp[IPOPT_OPTVAL]; ! 235: if (opt == IPOPT_EOL) ! 236: break; ! 237: if (opt == IPOPT_NOP) ! 238: optlen = 1; ! 239: else { ! 240: optlen = cp[IPOPT_OLEN]; ! 241: if (optlen <= 0 || optlen > cnt) { ! 242: return 0; /*XXX*/ ! 243: } ! 244: } ! 245: switch (opt) { ! 246: ! 247: default: ! 248: break; ! 249: ! 250: case IPOPT_LSRR: ! 251: opts &= ~IP_FW_IPOPT_LSRR; ! 252: nopts &= ~IP_FW_IPOPT_LSRR; ! 253: break; ! 254: ! 255: case IPOPT_SSRR: ! 256: opts &= ~IP_FW_IPOPT_SSRR; ! 257: nopts &= ~IP_FW_IPOPT_SSRR; ! 258: break; ! 259: ! 260: case IPOPT_RR: ! 261: opts &= ~IP_FW_IPOPT_RR; ! 262: nopts &= ~IP_FW_IPOPT_RR; ! 263: break; ! 264: case IPOPT_TS: ! 265: opts &= ~IP_FW_IPOPT_TS; ! 266: nopts &= ~IP_FW_IPOPT_TS; ! 267: break; ! 268: } ! 269: if (opts == nopts) ! 270: break; ! 271: } ! 272: if (opts == 0 && nopts == nopts_sve) ! 273: return 1; ! 274: else ! 275: return 0; ! 276: } ! 277: ! 278: static __inline int ! 279: iface_match(struct ifnet *ifp, union ip_fw_if *ifu, int byname) ! 280: { ! 281: /* Check by name or by IP address */ ! 282: if (byname) { ! 283: /* Check unit number (-1 is wildcard) */ ! 284: if (ifu->fu_via_if.unit != -1 ! 285: && ifp->if_unit != ifu->fu_via_if.unit) ! 286: return(0); ! 287: /* Check name */ ! 288: if (strncmp(ifp->if_name, ifu->fu_via_if.name, FW_IFNLEN)) ! 289: return(0); ! 290: return(1); ! 291: } else if (ifu->fu_via_ip.s_addr != 0) { /* Zero == wildcard */ ! 292: struct ifaddr *ia; ! 293: ! 294: for (ia = ifp->if_addrhead.tqh_first; ! 295: ia != NULL; ia = ia->ifa_link.tqe_next) { ! 296: if (ia->ifa_addr == NULL) ! 297: continue; ! 298: if (ia->ifa_addr->sa_family != AF_INET) ! 299: continue; ! 300: if (ifu->fu_via_ip.s_addr != ((struct sockaddr_in *) ! 301: (ia->ifa_addr))->sin_addr.s_addr) ! 302: continue; ! 303: return(1); ! 304: } ! 305: return(0); ! 306: } ! 307: return(1); ! 308: } ! 309: ! 310: static void ! 311: ipfw_report(struct ip_fw *f, struct ip *ip, ! 312: struct ifnet *rif, struct ifnet *oif) ! 313: { ! 314: if (ip) { ! 315: static u_int64_t counter; ! 316: struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *) ip+ ip->ip_hl); ! 317: struct udphdr *const udp = (struct udphdr *) ((u_int32_t *) ip+ ip->ip_hl); ! 318: struct icmp *const icmp = (struct icmp *) ((u_int32_t *) ip + ip->ip_hl); ! 319: int count; ! 320: ! 321: count = f ? f->fw_pcnt : ++counter; ! 322: if (fw_verbose_limit != 0 && count > fw_verbose_limit) ! 323: return; ! 324: ! 325: /* Print command name */ ! 326: kprintf("ipfw: %d ", f ? f->fw_number : -1); ! 327: if (!f) ! 328: kprintf("Refuse"); ! 329: else ! 330: switch (f->fw_flg & IP_FW_F_COMMAND) { ! 331: case IP_FW_F_DENY: ! 332: kprintf("Deny"); ! 333: break; ! 334: case IP_FW_F_REJECT: ! 335: if (f->fw_reject_code == IP_FW_REJECT_RST) ! 336: kprintf("Reset"); ! 337: else ! 338: kprintf("Unreach"); ! 339: break; ! 340: case IP_FW_F_ACCEPT: ! 341: kprintf("Accept"); ! 342: break; ! 343: case IP_FW_F_COUNT: ! 344: kprintf("Count"); ! 345: break; ! 346: case IP_FW_F_DIVERT: ! 347: kprintf("Divert %d", f->fw_divert_port); ! 348: break; ! 349: case IP_FW_F_TEE: ! 350: kprintf("Tee %d", f->fw_divert_port); ! 351: break; ! 352: case IP_FW_F_SKIPTO: ! 353: kprintf("SkipTo %d", f->fw_skipto_rule); ! 354: break; ! 355: #if DUMMYNET ! 356: case IP_FW_F_PIPE: ! 357: kprintf("Pipe %d", f->fw_skipto_rule); ! 358: break; ! 359: #endif ! 360: #if IPFIREWALL_FORWARD ! 361: case IP_FW_F_FWD: ! 362: kprintf("Forward to "); ! 363: print_ip(f->fw_fwd_ip.sin_addr); ! 364: if (f->fw_fwd_ip.sin_port) ! 365: kprintf(":%d", f->fw_fwd_ip.sin_port); ! 366: break; ! 367: #endif ! 368: default: ! 369: kprintf("UNKNOWN"); ! 370: break; ! 371: } ! 372: kprintf(" "); ! 373: ! 374: switch (ip->ip_p) { ! 375: case IPPROTO_TCP: ! 376: kprintf("TCP "); ! 377: print_ip(ip->ip_src); ! 378: if ((ip->ip_off & IP_OFFMASK) == 0) ! 379: kprintf(":%d ", ntohs(tcp->th_sport)); ! 380: else ! 381: kprintf(" "); ! 382: print_ip(ip->ip_dst); ! 383: if ((ip->ip_off & IP_OFFMASK) == 0) ! 384: kprintf(":%d", ntohs(tcp->th_dport)); ! 385: break; ! 386: case IPPROTO_UDP: ! 387: kprintf("UDP "); ! 388: print_ip(ip->ip_src); ! 389: if ((ip->ip_off & IP_OFFMASK) == 0) ! 390: kprintf(":%d ", ntohs(udp->uh_sport)); ! 391: else ! 392: kprintf(" "); ! 393: print_ip(ip->ip_dst); ! 394: if ((ip->ip_off & IP_OFFMASK) == 0) ! 395: kprintf(":%d", ntohs(udp->uh_dport)); ! 396: break; ! 397: case IPPROTO_ICMP: ! 398: if ((ip->ip_off & IP_OFFMASK) == 0) ! 399: kprintf("ICMP:%u.%u ", icmp->icmp_type, icmp->icmp_code); ! 400: else ! 401: kprintf("ICMP "); ! 402: print_ip(ip->ip_src); ! 403: kprintf(" "); ! 404: print_ip(ip->ip_dst); ! 405: break; ! 406: default: ! 407: kprintf("P:%d ", ip->ip_p); ! 408: print_ip(ip->ip_src); ! 409: kprintf(" "); ! 410: print_ip(ip->ip_dst); ! 411: break; ! 412: } ! 413: if (oif) ! 414: kprintf(" out via %s%d", oif->if_name, oif->if_unit); ! 415: else if (rif) ! 416: kprintf(" in via %s%d", rif->if_name, rif->if_unit); ! 417: if ((ip->ip_off & IP_OFFMASK)) ! 418: kprintf(" Fragment = %d",ip->ip_off & IP_OFFMASK); ! 419: kprintf("\n"); ! 420: if (fw_verbose_limit != 0 && count == fw_verbose_limit) ! 421: kprintf("ipfw: limit reached on rule #%d\n", ! 422: f ? f->fw_number : -1); ! 423: } ! 424: } ! 425: ! 426: /* ! 427: * given an ip_fw_chain *, lookup_next_rule will return a pointer ! 428: * of the same type to the next one. This can be either the jump ! 429: * target (for skipto instructions) or the next one in the chain (in ! 430: * all other cases including a missing jump target). ! 431: * Backward jumps are not allowed, so start looking from the next ! 432: * rule... ! 433: */ ! 434: static struct ip_fw_chain * lookup_next_rule(struct ip_fw_chain *me); ! 435: ! 436: static struct ip_fw_chain * ! 437: lookup_next_rule(struct ip_fw_chain *me) ! 438: { ! 439: struct ip_fw_chain *chain ; ! 440: int rule = me->rule->fw_skipto_rule ; /* guess... */ ! 441: ! 442: if ( (me->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_SKIPTO ) ! 443: for (chain = me->chain.le_next; chain ; chain = chain->chain.le_next ) ! 444: if (chain->rule->fw_number >= rule) ! 445: return chain ; ! 446: return me->chain.le_next ; /* failure or not a skipto */ ! 447: } ! 448: ! 449: /* ! 450: * Parameters: ! 451: * ! 452: * pip Pointer to packet header (struct ip **) ! 453: * bridge_ipfw extension: pip = NULL means a complete ethernet packet ! 454: * including ethernet header in the mbuf. Other fields ! 455: * are ignored/invalid. ! 456: * ! 457: * hlen Packet header length ! 458: * oif Outgoing interface, or NULL if packet is incoming ! 459: * *cookie Skip up to the first rule past this rule number; ! 460: * *m The packet; we set to NULL when/if we nuke it. ! 461: * *flow_id pointer to the last matching rule (in/out) ! 462: * *next_hop socket we are forwarding to (in/out). ! 463: * ! 464: * Return value: ! 465: * ! 466: * 0 The packet is to be accepted and routed normally OR ! 467: * the packet was denied/rejected and has been dropped; ! 468: * in the latter case, *m is equal to NULL upon return. ! 469: * port Divert the packet to port. ! 470: */ ! 471: ! 472: static int ! 473: ip_fw_chk(struct ip **pip, int hlen, ! 474: struct ifnet *oif, u_int16_t *cookie, struct mbuf **m, ! 475: struct ip_fw_chain **flow_id, ! 476: struct sockaddr_in **next_hop) ! 477: { ! 478: struct ip_fw_chain *chain; ! 479: struct ip_fw *rule = NULL; ! 480: struct ip *ip = NULL ; ! 481: struct ifnet *const rif = (*m)->m_pkthdr.rcvif; ! 482: u_short offset = 0 ; ! 483: u_short src_port, dst_port; ! 484: u_int16_t skipto = *cookie; ! 485: ! 486: if (pip) { /* normal ip packet */ ! 487: ip = *pip; ! 488: offset = (ip->ip_off & IP_OFFMASK); ! 489: } else { /* bridged or non-ip packet */ ! 490: struct ether_header *eh = mtod(*m, struct ether_header *); ! 491: switch (ntohs(eh->ether_type)) { ! 492: case ETHERTYPE_IP : ! 493: if ((*m)->m_len<sizeof(struct ether_header) + sizeof(struct ip)) ! 494: goto non_ip ; ! 495: ip = (struct ip *)(eh + 1 ); ! 496: if (ip->ip_v != IPVERSION) ! 497: goto non_ip ; ! 498: hlen = ip->ip_hl << 2; ! 499: if (hlen < sizeof(struct ip)) /* minimum header length */ ! 500: goto non_ip ; ! 501: if ((*m)->m_len < 14 + hlen + 14) { ! 502: kprintf("-- m_len %d, need more...\n", (*m)->m_len); ! 503: goto non_ip ; ! 504: } ! 505: offset = (ip->ip_off & IP_OFFMASK); ! 506: break ; ! 507: default : ! 508: non_ip: ip = NULL ; ! 509: break ; ! 510: } ! 511: } ! 512: ! 513: if (*flow_id) { ! 514: if (fw_one_pass) ! 515: return 0 ; /* accept if passed first test */ ! 516: /* ! 517: * pkt has already been tagged. Look for the next rule ! 518: * to restart processing ! 519: */ ! 520: chain = LIST_NEXT( *flow_id, chain); ! 521: ! 522: if ( (chain = (*flow_id)->rule->next_rule_ptr) == NULL ) ! 523: chain = (*flow_id)->rule->next_rule_ptr = ! 524: lookup_next_rule(*flow_id) ; ! 525: if (! chain) goto dropit; ! 526: } else { ! 527: /* ! 528: * Go down the chain, looking for enlightment ! 529: * If we've been asked to start at a given rule immediatly, do so. ! 530: */ ! 531: chain = LIST_FIRST(&ip_fw_chain); ! 532: if ( skipto ) { ! 533: if (skipto >= IPFW_DEFAULT_RULE) ! 534: goto dropit; ! 535: while (chain && (chain->rule->fw_number <= skipto)) { ! 536: chain = LIST_NEXT(chain, chain); ! 537: } ! 538: if (! chain) goto dropit; ! 539: } ! 540: } ! 541: *cookie = 0; ! 542: for (; chain; chain = LIST_NEXT(chain, chain)) { ! 543: register struct ip_fw * f ; ! 544: again: ! 545: f = chain->rule; ! 546: ! 547: if (oif) { ! 548: /* Check direction outbound */ ! 549: if (!(f->fw_flg & IP_FW_F_OUT)) ! 550: continue; ! 551: } else { ! 552: /* Check direction inbound */ ! 553: if (!(f->fw_flg & IP_FW_F_IN)) ! 554: continue; ! 555: } ! 556: if (ip == NULL ) { ! 557: /* ! 558: * do relevant checks for non-ip packets: ! 559: * after this, only goto got_match or continue ! 560: */ ! 561: struct ether_header *eh = mtod(*m, struct ether_header *); ! 562: ! 563: /* ! 564: * make default rule always match or we have a panic ! 565: */ ! 566: if (f->fw_number == IPFW_DEFAULT_RULE) ! 567: goto got_match ; ! 568: /* ! 569: * temporary hack: ! 570: * udp from 0.0.0.0 means this rule applies. ! 571: * 1 src port is match ether type ! 572: * 2 src ports (interval) is match ether type ! 573: * 3 src ports is match ether address ! 574: */ ! 575: if ( f->fw_src.s_addr != 0 || f->fw_prot != IPPROTO_UDP ! 576: || f->fw_smsk.s_addr != 0xffffffff ) ! 577: continue; ! 578: switch (IP_FW_GETNSRCP(f)) { ! 579: case 1: /* match one type */ ! 580: if ( /* ( (f->fw_flg & IP_FW_F_INVSRC) != 0) ^ */ ! 581: ( f->fw_uar.fw_pts[0] == ntohs(eh->ether_type) ) ) { ! 582: goto got_match ; ! 583: } ! 584: break ; ! 585: default: ! 586: break ; ! 587: } ! 588: continue ; ! 589: } ! 590: ! 591: /* Fragments */ ! 592: if ((f->fw_flg & IP_FW_F_FRAG) && offset == 0 ) ! 593: continue; ! 594: ! 595: /* If src-addr doesn't match, not this rule. */ ! 596: if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((ip->ip_src.s_addr ! 597: & f->fw_smsk.s_addr) != f->fw_src.s_addr)) ! 598: continue; ! 599: ! 600: /* If dest-addr doesn't match, not this rule. */ ! 601: if (((f->fw_flg & IP_FW_F_INVDST) != 0) ^ ((ip->ip_dst.s_addr ! 602: & f->fw_dmsk.s_addr) != f->fw_dst.s_addr)) ! 603: continue; ! 604: ! 605: /* Interface check */ ! 606: if ((f->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) { ! 607: struct ifnet *const iface = oif ? oif : rif; ! 608: ! 609: /* Backwards compatibility hack for "via" */ ! 610: if (!iface || !iface_match(iface, ! 611: &f->fw_in_if, f->fw_flg & IP_FW_F_OIFNAME)) ! 612: continue; ! 613: } else { ! 614: /* Check receive interface */ ! 615: if ((f->fw_flg & IP_FW_F_IIFACE) ! 616: && (!rif || !iface_match(rif, ! 617: &f->fw_in_if, f->fw_flg & IP_FW_F_IIFNAME))) ! 618: continue; ! 619: /* Check outgoing interface */ ! 620: if ((f->fw_flg & IP_FW_F_OIFACE) ! 621: && (!oif || !iface_match(oif, ! 622: &f->fw_out_if, f->fw_flg & IP_FW_F_OIFNAME))) ! 623: continue; ! 624: } ! 625: ! 626: /* Check IP options */ ! 627: if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f)) ! 628: continue; ! 629: ! 630: /* Check protocol; if wildcard, match */ ! 631: if (f->fw_prot == IPPROTO_IP) ! 632: goto got_match; ! 633: ! 634: /* If different, don't match */ ! 635: if (ip->ip_p != f->fw_prot) ! 636: continue; ! 637: ! 638: /* ! 639: * here, pip==NULL for bridged pkts -- they include the ethernet ! 640: * header so i have to adjust lengths accordingly ! 641: */ ! 642: #define PULLUP_TO(l) do { \ ! 643: int len = (pip ? l : l + 14 ) ; \ ! 644: if ((*m)->m_len < (len) ) { \ ! 645: if ( (*m = m_pullup(*m, (len))) == 0) \ ! 646: goto bogusfrag; \ ! 647: ip = mtod(*m, struct ip *); \ ! 648: if (pip) \ ! 649: *pip = ip ; \ ! 650: else \ ! 651: ip = (struct ip *)((int)ip + 14); \ ! 652: offset = (ip->ip_off & IP_OFFMASK); \ ! 653: } \ ! 654: } while (0) ! 655: ! 656: /* Protocol specific checks */ ! 657: switch (ip->ip_p) { ! 658: case IPPROTO_TCP: ! 659: { ! 660: struct tcphdr *tcp; ! 661: ! 662: if (offset == 1) /* cf. RFC 1858 */ ! 663: goto bogusfrag; ! 664: if (offset != 0) { ! 665: /* ! 666: * TCP flags and ports aren't available in this ! 667: * packet -- if this rule specified either one, ! 668: * we consider the rule a non-match. ! 669: */ ! 670: if (f->fw_nports != 0 || ! 671: f->fw_tcpf != f->fw_tcpnf) ! 672: continue; ! 673: ! 674: break; ! 675: } ! 676: PULLUP_TO(hlen + 14); ! 677: tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl); ! 678: if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f)) ! 679: continue; ! 680: src_port = ntohs(tcp->th_sport); ! 681: dst_port = ntohs(tcp->th_dport); ! 682: goto check_ports; ! 683: } ! 684: ! 685: case IPPROTO_UDP: ! 686: { ! 687: struct udphdr *udp; ! 688: ! 689: if (offset != 0) { ! 690: /* ! 691: * Port specification is unavailable -- if this ! 692: * rule specifies a port, we consider the rule ! 693: * a non-match. ! 694: */ ! 695: if (f->fw_nports != 0) ! 696: continue; ! 697: ! 698: break; ! 699: } ! 700: PULLUP_TO(hlen + 4); ! 701: udp = (struct udphdr *) ((u_int32_t *)ip + ip->ip_hl); ! 702: src_port = ntohs(udp->uh_sport); ! 703: dst_port = ntohs(udp->uh_dport); ! 704: check_ports: ! 705: if (!port_match(&f->fw_uar.fw_pts[0], ! 706: IP_FW_GETNSRCP(f), src_port, ! 707: f->fw_flg & IP_FW_F_SRNG)) ! 708: continue; ! 709: if (!port_match(&f->fw_uar.fw_pts[IP_FW_GETNSRCP(f)], ! 710: IP_FW_GETNDSTP(f), dst_port, ! 711: f->fw_flg & IP_FW_F_DRNG)) ! 712: continue; ! 713: break; ! 714: } ! 715: ! 716: case IPPROTO_ICMP: ! 717: { ! 718: struct icmp *icmp; ! 719: ! 720: if (offset != 0) /* Type isn't valid */ ! 721: break; ! 722: PULLUP_TO(hlen + 2); ! 723: icmp = (struct icmp *) ((u_int32_t *)ip + ip->ip_hl); ! 724: if (!icmptype_match(icmp, f)) ! 725: continue; ! 726: break; ! 727: } ! 728: #undef PULLUP_TO ! 729: ! 730: bogusfrag: ! 731: if (fw_verbose) ! 732: ipfw_report(NULL, ip, rif, oif); ! 733: goto dropit; ! 734: } ! 735: ! 736: got_match: ! 737: *flow_id = chain ; /* XXX set flow id */ ! 738: /* Update statistics */ ! 739: f->fw_pcnt += 1; ! 740: if (ip) { ! 741: f->fw_bcnt += ip->ip_len; ! 742: } ! 743: f->timestamp = time_second; ! 744: ! 745: /* Log to console if desired */ ! 746: if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose) ! 747: ipfw_report(f, ip, rif, oif); ! 748: ! 749: /* Take appropriate action */ ! 750: switch (f->fw_flg & IP_FW_F_COMMAND) { ! 751: case IP_FW_F_ACCEPT: ! 752: return(0); ! 753: case IP_FW_F_COUNT: ! 754: continue; ! 755: #if IPDIVERT ! 756: case IP_FW_F_DIVERT: ! 757: *cookie = f->fw_number; ! 758: return(f->fw_divert_port); ! 759: #endif ! 760: case IP_FW_F_TEE: ! 761: /* ! 762: * XXX someday tee packet here, but beware that you ! 763: * can't use m_copym() or m_copypacket() because ! 764: * the divert input routine modifies the mbuf ! 765: * (and these routines only increment reference ! 766: * counts in the case of mbuf clusters), so need ! 767: * to write custom routine. ! 768: */ ! 769: continue; ! 770: case IP_FW_F_SKIPTO: /* XXX check */ ! 771: if ( f->next_rule_ptr ) ! 772: chain = f->next_rule_ptr ; ! 773: else ! 774: chain = lookup_next_rule(chain) ; ! 775: if (! chain) goto dropit; ! 776: goto again ; ! 777: #if DUMMYNET ! 778: case IP_FW_F_PIPE: ! 779: return(f->fw_pipe_nr | 0x10000 ); ! 780: #endif ! 781: #if IPFIREWALL_FORWARD ! 782: case IP_FW_F_FWD: ! 783: /* Change the next-hop address for this packet. ! 784: * Initially we'll only worry about directly ! 785: * reachable next-hop's, but ultimately ! 786: * we will work out for next-hops that aren't ! 787: * direct the route we would take for it. We ! 788: * [cs]ould leave this latter problem to ! 789: * ip_output.c. We hope to high [name the abode of ! 790: * your favourite deity] that ip_output doesn't modify ! 791: * the new value of next_hop (which is dst there) ! 792: */ ! 793: if (next_hop != NULL) /* Make sure, first... */ ! 794: *next_hop = &(f->fw_fwd_ip); ! 795: return(0); /* Allow the packet */ ! 796: #endif ! 797: } ! 798: ! 799: /* Deny/reject this packet using this rule */ ! 800: rule = f; ! 801: break; ! 802: ! 803: } ! 804: ! 805: #if DIAGNOSTIC ! 806: /* Rule IPFW_DEFAULT_RULE should always be there and should always match */ ! 807: if (!chain) ! 808: panic("ip_fw: chain"); ! 809: #endif ! 810: ! 811: /* ! 812: * At this point, we're going to drop the packet. ! 813: * Send a reject notice if all of the following are true: ! 814: * ! 815: * - The packet matched a reject rule ! 816: * - The packet is not an ICMP packet, or is an ICMP query packet ! 817: * - The packet is not a multicast or broadcast packet ! 818: */ ! 819: if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT ! 820: && ip ! 821: && (ip->ip_p != IPPROTO_ICMP || is_icmp_query(ip)) ! 822: && !((*m)->m_flags & (M_BCAST|M_MCAST)) ! 823: && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { ! 824: switch (rule->fw_reject_code) { ! 825: case IP_FW_REJECT_RST: ! 826: { ! 827: struct tcphdr *const tcp = ! 828: (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl); ! 829: struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip; ! 830: ! 831: if (offset != 0 || (tcp->th_flags & TH_RST)) ! 832: break; ! 833: ti.ti_i = *((struct ipovly *) ip); ! 834: ti.ti_t = *tcp; ! 835: bcopy(&ti, ip, sizeof(ti)); ! 836: NTOHL(tip->ti_seq); ! 837: NTOHL(tip->ti_ack); ! 838: tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2); ! 839: if (tcp->th_flags & TH_ACK) { ! 840: tcp_respond(NULL, tip, *m, ! 841: (tcp_seq)0, ntohl(tcp->th_ack), TH_RST); ! 842: } else { ! 843: if (tcp->th_flags & TH_SYN) ! 844: tip->ti_len++; ! 845: tcp_respond(NULL, tip, *m, tip->ti_seq ! 846: + tip->ti_len, (tcp_seq)0, TH_RST|TH_ACK); ! 847: } ! 848: *m = NULL; ! 849: break; ! 850: } ! 851: default: /* Send an ICMP unreachable using code */ ! 852: icmp_error(*m, ICMP_UNREACH, ! 853: rule->fw_reject_code, 0L, 0); ! 854: *m = NULL; ! 855: break; ! 856: } ! 857: } ! 858: ! 859: dropit: ! 860: /* ! 861: * Finally, drop the packet. ! 862: */ ! 863: /* *cookie = 0; */ /* XXX is this necessary ? */ ! 864: if (*m) { ! 865: m_freem(*m); ! 866: *m = NULL; ! 867: } ! 868: return(0); ! 869: } ! 870: ! 871: /* ! 872: * when a rule is added/deleted, zero the direct pointers within ! 873: * all firewall rules. These will be reconstructed on the fly ! 874: * as packets are matched. ! 875: * Must be called at splnet(). ! 876: */ ! 877: static void ! 878: flush_rule_ptrs() ! 879: { ! 880: struct ip_fw_chain *fcp ; ! 881: ! 882: for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next) { ! 883: fcp->rule->next_rule_ptr = NULL ; ! 884: } ! 885: } ! 886: ! 887: static int ! 888: add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl) ! 889: { ! 890: struct ip_fw *ftmp = 0; ! 891: struct ip_fw_chain *fwc = 0, *fcp, *fcpl = 0; ! 892: u_short nbr = 0; ! 893: int s; ! 894: ! 895: fwc = _MALLOC(sizeof *fwc, M_IPFW, M_DONTWAIT); ! 896: ftmp = _MALLOC(sizeof *ftmp, M_IPFW, M_DONTWAIT); ! 897: if (!fwc || !ftmp) { ! 898: dprintf(("%s MALLOC said no\n", err_prefix)); ! 899: if (fwc) FREE(fwc, M_IPFW); ! 900: if (ftmp) FREE(ftmp, M_IPFW); ! 901: return (ENOSPC); ! 902: } ! 903: ! 904: bcopy(frwl, ftmp, sizeof(struct ip_fw)); ! 905: ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0'; ! 906: ftmp->fw_pcnt = 0L; ! 907: ftmp->fw_bcnt = 0L; ! 908: ftmp->next_rule_ptr = NULL ; ! 909: ftmp->pipe_ptr = NULL ; ! 910: fwc->rule = ftmp; ! 911: ! 912: s = splnet(); ! 913: ! 914: if (chainptr->lh_first == 0) { ! 915: LIST_INSERT_HEAD(chainptr, fwc, chain); ! 916: splx(s); ! 917: return(0); ! 918: } ! 919: ! 920: /* If entry number is 0, find highest numbered rule and add 100 */ ! 921: if (ftmp->fw_number == 0) { ! 922: for (fcp = LIST_FIRST(chainptr); fcp; fcp = LIST_NEXT(fcp, chain)) { ! 923: if (fcp->rule->fw_number != (u_short)-1) ! 924: nbr = fcp->rule->fw_number; ! 925: else ! 926: break; ! 927: } ! 928: if (nbr < IPFW_DEFAULT_RULE - 100) ! 929: nbr += 100; ! 930: ftmp->fw_number = nbr; ! 931: } ! 932: ! 933: /* Got a valid number; now insert it, keeping the list ordered */ ! 934: for (fcp = LIST_FIRST(chainptr); fcp; fcp = LIST_NEXT(fcp, chain)) { ! 935: if (fcp->rule->fw_number > ftmp->fw_number) { ! 936: if (fcpl) { ! 937: LIST_INSERT_AFTER(fcpl, fwc, chain); ! 938: } else { ! 939: LIST_INSERT_HEAD(chainptr, fwc, chain); ! 940: } ! 941: break; ! 942: } else { ! 943: fcpl = fcp; ! 944: } ! 945: } ! 946: flush_rule_ptrs(); ! 947: ! 948: splx(s); ! 949: return (0); ! 950: } ! 951: ! 952: static int ! 953: del_entry(struct ip_fw_head *chainptr, u_short number) ! 954: { ! 955: struct ip_fw_chain *fcp; ! 956: ! 957: fcp = LIST_FIRST(chainptr); ! 958: if (number != (u_short)-1) { ! 959: for (; fcp; fcp = LIST_NEXT(fcp, chain)) { ! 960: if (fcp->rule->fw_number == number) { ! 961: int s; ! 962: ! 963: /* prevent access to rules while removing them */ ! 964: s = splnet(); ! 965: while (fcp && fcp->rule->fw_number == number) { ! 966: struct ip_fw_chain *next; ! 967: ! 968: next = LIST_NEXT(fcp, chain); ! 969: LIST_REMOVE(fcp, chain); ! 970: #if DUMMYNET ! 971: dn_rule_delete(fcp) ; ! 972: #endif ! 973: flush_rule_ptrs(); ! 974: FREE(fcp->rule, M_IPFW); ! 975: FREE(fcp, M_IPFW); ! 976: fcp = next; ! 977: } ! 978: splx(s); ! 979: return 0; ! 980: } ! 981: } ! 982: } ! 983: ! 984: return (EINVAL); ! 985: } ! 986: ! 987: static int ! 988: zero_entry(struct ip_fw *frwl) ! 989: { ! 990: struct ip_fw_chain *fcp; ! 991: int s, cleared; ! 992: ! 993: if (frwl == 0) { ! 994: s = splnet(); ! 995: for (fcp = LIST_FIRST(&ip_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain)) { ! 996: fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0; ! 997: fcp->rule->timestamp = 0; ! 998: } ! 999: splx(s); ! 1000: } ! 1001: else { ! 1002: cleared = 0; ! 1003: ! 1004: /* ! 1005: * It's possible to insert multiple chain entries with the ! 1006: * same number, so we don't stop after finding the first ! 1007: * match if zeroing a specific entry. ! 1008: */ ! 1009: for (fcp = LIST_FIRST(&ip_fw_chain); fcp; fcp = LIST_NEXT(fcp, chain)) ! 1010: if (frwl->fw_number == fcp->rule->fw_number) { ! 1011: s = splnet(); ! 1012: while (fcp && frwl->fw_number == fcp->rule->fw_number) { ! 1013: fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0; ! 1014: fcp->rule->timestamp = 0; ! 1015: fcp = LIST_NEXT(fcp, chain); ! 1016: } ! 1017: splx(s); ! 1018: cleared = 1; ! 1019: break; ! 1020: } ! 1021: if (!cleared) /* we didn't find any matching rules */ ! 1022: return (EINVAL); ! 1023: } ! 1024: ! 1025: if (fw_verbose) { ! 1026: if (frwl) ! 1027: kprintf("ipfw: Entry %d cleared.\n", frwl->fw_number); ! 1028: else ! 1029: kprintf("ipfw: Accounting cleared.\n"); ! 1030: } ! 1031: ! 1032: return (0); ! 1033: } ! 1034: ! 1035: static int ! 1036: check_ipfw_struct(struct ip_fw *frwl) ! 1037: { ! 1038: /* Check for invalid flag bits */ ! 1039: if ((frwl->fw_flg & ~IP_FW_F_MASK) != 0) { ! 1040: dprintf(("%s undefined flag bits set (flags=%x)\n", ! 1041: err_prefix, frwl->fw_flg)); ! 1042: return (EINVAL); ! 1043: } ! 1044: /* Must apply to incoming or outgoing (or both) */ ! 1045: if (!(frwl->fw_flg & (IP_FW_F_IN | IP_FW_F_OUT))) { ! 1046: dprintf(("%s neither in nor out\n", err_prefix)); ! 1047: return (EINVAL); ! 1048: } ! 1049: /* Empty interface name is no good */ ! 1050: if (((frwl->fw_flg & IP_FW_F_IIFNAME) ! 1051: && !*frwl->fw_in_if.fu_via_if.name) ! 1052: || ((frwl->fw_flg & IP_FW_F_OIFNAME) ! 1053: && !*frwl->fw_out_if.fu_via_if.name)) { ! 1054: dprintf(("%s empty interface name\n", err_prefix)); ! 1055: return (EINVAL); ! 1056: } ! 1057: /* Sanity check interface matching */ ! 1058: if ((frwl->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) { ! 1059: ; /* allow "via" backwards compatibility */ ! 1060: } else if ((frwl->fw_flg & IP_FW_F_IN) ! 1061: && (frwl->fw_flg & IP_FW_F_OIFACE)) { ! 1062: dprintf(("%s outgoing interface check on incoming\n", ! 1063: err_prefix)); ! 1064: return (EINVAL); ! 1065: } ! 1066: /* Sanity check port ranges */ ! 1067: if ((frwl->fw_flg & IP_FW_F_SRNG) && IP_FW_GETNSRCP(frwl) < 2) { ! 1068: dprintf(("%s src range set but n_src_p=%d\n", ! 1069: err_prefix, IP_FW_GETNSRCP(frwl))); ! 1070: return (EINVAL); ! 1071: } ! 1072: if ((frwl->fw_flg & IP_FW_F_DRNG) && IP_FW_GETNDSTP(frwl) < 2) { ! 1073: dprintf(("%s dst range set but n_dst_p=%d\n", ! 1074: err_prefix, IP_FW_GETNDSTP(frwl))); ! 1075: return (EINVAL); ! 1076: } ! 1077: if (IP_FW_GETNSRCP(frwl) + IP_FW_GETNDSTP(frwl) > IP_FW_MAX_PORTS) { ! 1078: dprintf(("%s too many ports (%d+%d)\n", ! 1079: err_prefix, IP_FW_GETNSRCP(frwl), IP_FW_GETNDSTP(frwl))); ! 1080: return (EINVAL); ! 1081: } ! 1082: /* ! 1083: * Protocols other than TCP/UDP don't use port range ! 1084: */ ! 1085: if ((frwl->fw_prot != IPPROTO_TCP) && ! 1086: (frwl->fw_prot != IPPROTO_UDP) && ! 1087: (IP_FW_GETNSRCP(frwl) || IP_FW_GETNDSTP(frwl))) { ! 1088: dprintf(("%s port(s) specified for non TCP/UDP rule\n", ! 1089: err_prefix)); ! 1090: return (EINVAL); ! 1091: } ! 1092: ! 1093: /* ! 1094: * Rather than modify the entry to make such entries work, ! 1095: * we reject this rule and require user level utilities ! 1096: * to enforce whatever policy they deem appropriate. ! 1097: */ ! 1098: if ((frwl->fw_src.s_addr & (~frwl->fw_smsk.s_addr)) || ! 1099: (frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) { ! 1100: dprintf(("%s rule never matches\n", err_prefix)); ! 1101: return (EINVAL); ! 1102: } ! 1103: ! 1104: if ((frwl->fw_flg & IP_FW_F_FRAG) && ! 1105: (frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) { ! 1106: if (frwl->fw_nports) { ! 1107: dprintf(("%s cannot mix 'frag' and ports\n", err_prefix)); ! 1108: return (EINVAL); ! 1109: } ! 1110: if (frwl->fw_prot == IPPROTO_TCP && ! 1111: frwl->fw_tcpf != frwl->fw_tcpnf) { ! 1112: dprintf(("%s cannot mix 'frag' and TCP flags\n", err_prefix)); ! 1113: return (EINVAL); ! 1114: } ! 1115: } ! 1116: ! 1117: /* Check command specific stuff */ ! 1118: switch (frwl->fw_flg & IP_FW_F_COMMAND) ! 1119: { ! 1120: case IP_FW_F_REJECT: ! 1121: if (frwl->fw_reject_code >= 0x100 ! 1122: && !(frwl->fw_prot == IPPROTO_TCP ! 1123: && frwl->fw_reject_code == IP_FW_REJECT_RST)) { ! 1124: dprintf(("%s unknown reject code\n", err_prefix)); ! 1125: return (EINVAL); ! 1126: } ! 1127: break; ! 1128: case IP_FW_F_DIVERT: /* Diverting to port zero is invalid */ ! 1129: case IP_FW_F_PIPE: /* piping through 0 is invalid */ ! 1130: case IP_FW_F_TEE: ! 1131: if (frwl->fw_divert_port == 0) { ! 1132: dprintf(("%s can't divert to port 0\n", err_prefix)); ! 1133: return (EINVAL); ! 1134: } ! 1135: break; ! 1136: case IP_FW_F_DENY: ! 1137: case IP_FW_F_ACCEPT: ! 1138: case IP_FW_F_COUNT: ! 1139: case IP_FW_F_SKIPTO: ! 1140: #if IPFIREWALL_FORWARD ! 1141: case IP_FW_F_FWD: ! 1142: #endif ! 1143: break; ! 1144: default: ! 1145: dprintf(("%s invalid command\n", err_prefix)); ! 1146: return (EINVAL); ! 1147: } ! 1148: ! 1149: return 0; ! 1150: } ! 1151: ! 1152: static int ! 1153: ip_fw_ctl(struct sockopt *sopt) ! 1154: { ! 1155: int error, s; ! 1156: size_t size; ! 1157: char *buf, *bp; ! 1158: struct ip_fw_chain *fcp; ! 1159: struct ip_fw frwl; ! 1160: ! 1161: /* Disallow sets in really-really secure mode. */ ! 1162: if (sopt->sopt_dir == SOPT_SET && securelevel >= 3) ! 1163: return (EPERM); ! 1164: error = 0; ! 1165: ! 1166: switch (sopt->sopt_name) { ! 1167: case IP_FW_GET: ! 1168: for (fcp = LIST_FIRST(&ip_fw_chain), size = 0; fcp; ! 1169: fcp = LIST_NEXT(fcp, chain)) ! 1170: size += sizeof *fcp->rule; ! 1171: buf = _MALLOC(size, M_TEMP, M_WAITOK); ! 1172: if (buf == 0) { ! 1173: error = ENOBUFS; ! 1174: break; ! 1175: } ! 1176: ! 1177: for (fcp = LIST_FIRST(&ip_fw_chain), bp = buf; fcp; ! 1178: fcp = LIST_NEXT(fcp, chain)) { ! 1179: bcopy(fcp->rule, bp, sizeof *fcp->rule); ! 1180: bp += sizeof *fcp->rule; ! 1181: } ! 1182: error = sooptcopyout(sopt, buf, size); ! 1183: FREE(buf, M_TEMP); ! 1184: break; ! 1185: ! 1186: case IP_FW_FLUSH: ! 1187: for (fcp = ip_fw_chain.lh_first; ! 1188: fcp != 0 && fcp->rule->fw_number != IPFW_DEFAULT_RULE; ! 1189: fcp = ip_fw_chain.lh_first) { ! 1190: s = splnet(); ! 1191: LIST_REMOVE(fcp, chain); ! 1192: FREE(fcp->rule, M_IPFW); ! 1193: FREE(fcp, M_IPFW); ! 1194: splx(s); ! 1195: } ! 1196: break; ! 1197: ! 1198: case IP_FW_ZERO: ! 1199: if (sopt->sopt_val != 0) { ! 1200: error = sooptcopyin(sopt, &frwl, sizeof frwl, ! 1201: sizeof frwl); ! 1202: if (error || (error = zero_entry(&frwl))) ! 1203: break; ! 1204: } else { ! 1205: error = zero_entry(0); ! 1206: } ! 1207: break; ! 1208: ! 1209: case IP_FW_ADD: ! 1210: error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl); ! 1211: if (error || (error = check_ipfw_struct(&frwl))) ! 1212: break; ! 1213: ! 1214: if (frwl.fw_number == IPFW_DEFAULT_RULE) { ! 1215: dprintf(("%s can't add rule %u\n", err_prefix, ! 1216: (unsigned)IPFW_DEFAULT_RULE)); ! 1217: error = EINVAL; ! 1218: } else { ! 1219: error = add_entry(&ip_fw_chain, &frwl); ! 1220: } ! 1221: break; ! 1222: ! 1223: case IP_FW_DEL: ! 1224: error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl); ! 1225: if (error) ! 1226: break; ! 1227: ! 1228: if (frwl.fw_number == IPFW_DEFAULT_RULE) { ! 1229: dprintf(("%s can't delete rule %u\n", err_prefix, ! 1230: (unsigned)IPFW_DEFAULT_RULE)); ! 1231: error = EINVAL; ! 1232: } else { ! 1233: error = del_entry(&ip_fw_chain, frwl.fw_number); ! 1234: } ! 1235: break; ! 1236: ! 1237: default: ! 1238: kprintf("ip_fw_ctl invalid option %d\n", sopt->sopt_name); ! 1239: error = EINVAL ; ! 1240: } ! 1241: ! 1242: return (error); ! 1243: } ! 1244: ! 1245: struct ip_fw_chain *ip_fw_default_rule ; ! 1246: ! 1247: void ! 1248: ip_fw_init(void) ! 1249: { ! 1250: struct ip_fw default_rule; ! 1251: ! 1252: ip_fw_chk_ptr = ip_fw_chk; ! 1253: ip_fw_ctl_ptr = ip_fw_ctl; ! 1254: LIST_INIT(&ip_fw_chain); ! 1255: ! 1256: bzero(&default_rule, sizeof default_rule); ! 1257: default_rule.fw_prot = IPPROTO_IP; ! 1258: default_rule.fw_number = IPFW_DEFAULT_RULE; ! 1259: #if IPFIREWALL_DEFAULT_TO_ACCEPT ! 1260: default_rule.fw_flg |= IP_FW_F_ACCEPT; ! 1261: #else ! 1262: default_rule.fw_flg |= IP_FW_F_DENY; ! 1263: #endif ! 1264: default_rule.fw_flg |= IP_FW_F_IN | IP_FW_F_OUT; ! 1265: if (check_ipfw_struct(&default_rule) != 0 || ! 1266: add_entry(&ip_fw_chain, &default_rule)) ! 1267: panic("ip_fw_init"); ! 1268: ! 1269: ip_fw_default_rule = ip_fw_chain.lh_first ; ! 1270: kprintf("IP packet filtering initialized, " ! 1271: #if IPDIVERT ! 1272: "divert enabled, "); ! 1273: #else ! 1274: "divert disabled, "); ! 1275: #endif ! 1276: #if IPFIREWALL_FORWARD ! 1277: kprintf("rule-based forwarding enabled, "); ! 1278: #else ! 1279: kprintf("rule-based forwarding disabled, "); ! 1280: #endif ! 1281: #if IPFIREWALL_DEFAULT_TO_ACCEPT ! 1282: kprintf("default to accept, "); ! 1283: #endif ! 1284: #ifndef IPFIREWALL_VERBOSE ! 1285: kprintf("logging disabled\n"); ! 1286: #else ! 1287: if (fw_verbose_limit == 0) ! 1288: kprintf("unlimited logging\n"); ! 1289: else ! 1290: kprintf("logging limited to %d packets/entry\n", ! 1291: fw_verbose_limit); ! 1292: #endif ! 1293: } ! 1294: ! 1295: #if ISFB31 ! 1296: ! 1297: /* ! 1298: * ### LD 08/04/99: This is used if IPFIREWALL is a FreeBSD "KLD" module ! 1299: * Right now, we're linked to the kernel all the time ! 1300: * will be fixed with the use of an NKE? ! 1301: * ! 1302: * Note: ip_fw_init is called from div_init() in xnu ! 1303: */ ! 1304: ! 1305: static ip_fw_chk_t *old_chk_ptr; ! 1306: static ip_fw_ctl_t *old_ctl_ptr; ! 1307: ! 1308: #if defined(IPFIREWALL_MODULE) && !defined(KLD_MODULE) ! 1309: ! 1310: #include <sys/exec.h> ! 1311: #include <sys/sysent.h> ! 1312: #include <sys/lkm.h> ! 1313: ! 1314: MOD_MISC(ipfw); ! 1315: ! 1316: static int ! 1317: ipfw_load(struct lkm_table *lkmtp, int cmd) ! 1318: { ! 1319: int s=splnet(); ! 1320: ! 1321: old_chk_ptr = ip_fw_chk_ptr; ! 1322: old_ctl_ptr = ip_fw_ctl_ptr; ! 1323: ! 1324: ip_fw_init(); ! 1325: splx(s); ! 1326: return 0; ! 1327: } ! 1328: ! 1329: static int ! 1330: ipfw_unload(struct lkm_table *lkmtp, int cmd) ! 1331: { ! 1332: int s=splnet(); ! 1333: ! 1334: ip_fw_chk_ptr = old_chk_ptr; ! 1335: ip_fw_ctl_ptr = old_ctl_ptr; ! 1336: ! 1337: while (LIST_FIRST(&ip_fw_chain) != NULL) { ! 1338: struct ip_fw_chain *fcp = LIST_FIRST(&ip_fw_chain); ! 1339: LIST_REMOVE(LIST_FIRST(&ip_fw_chain), chain); ! 1340: FREE(fcp->rule, M_IPFW); ! 1341: FREE(fcp, M_IPFW); ! 1342: } ! 1343: ! 1344: splx(s); ! 1345: kprintf("IP firewall unloaded\n"); ! 1346: return 0; ! 1347: } ! 1348: ! 1349: int ! 1350: ipfw_mod(struct lkm_table *lkmtp, int cmd, int ver) ! 1351: { ! 1352: MOD_DISPATCH(ipfw, lkmtp, cmd, ver, ! 1353: ipfw_load, ipfw_unload, lkm_nullcmd); ! 1354: } ! 1355: #else ! 1356: static int ! 1357: ipfw_modevent(module_t mod, int type, void *unused) ! 1358: { ! 1359: int s; ! 1360: ! 1361: switch (type) { ! 1362: case MOD_LOAD: ! 1363: s = splnet(); ! 1364: ! 1365: old_chk_ptr = ip_fw_chk_ptr; ! 1366: old_ctl_ptr = ip_fw_ctl_ptr; ! 1367: ! 1368: ip_fw_init(); ! 1369: splx(s); ! 1370: return 0; ! 1371: case MOD_UNLOAD: ! 1372: s = splnet(); ! 1373: ! 1374: ip_fw_chk_ptr = old_chk_ptr; ! 1375: ip_fw_ctl_ptr = old_ctl_ptr; ! 1376: ! 1377: while (LIST_FIRST(&ip_fw_chain) != NULL) { ! 1378: struct ip_fw_chain *fcp = LIST_FIRST(&ip_fw_chain); ! 1379: LIST_REMOVE(LIST_FIRST(&ip_fw_chain), chain); ! 1380: FREE(fcp->rule, M_IPFW); ! 1381: FREE(fcp, M_IPFW); ! 1382: } ! 1383: ! 1384: splx(s); ! 1385: kprintf("IP firewall unloaded\n"); ! 1386: return 0; ! 1387: default: ! 1388: break; ! 1389: } ! 1390: return 0; ! 1391: } ! 1392: ! 1393: static moduledata_t ipfwmod = { ! 1394: "ipfw", ! 1395: ipfw_modevent, ! 1396: 0 ! 1397: }; ! 1398: DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY); ! 1399: #endif ! 1400: #endif /* ISFB31 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.