diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c index b06576abddc3..03ec6ccfc878 100644 --- a/sys/netinet/ip_fw.c +++ b/sys/netinet/ip_fw.c @@ -2,7 +2,7 @@ * Copyright (c) 1993 Daniel Boulet * Copyright (c) 1994 Ugen J.S.Antsilevich * Copyright (c) 1996 Alex Nash - * Copyright (c) 2000-2001 Luigi Rizzo + * Copyright (c) 2000-2002 Luigi Rizzo * * Redistribution and use in source forms, with and without modification, * are permitted provided that this entire comment appears intact. @@ -1109,15 +1109,14 @@ ip_fw_chk(struct mbuf **m, struct ifnet *oif, u_int16_t *cookie, #define BRIDGED (cookie == &bridgeCookie) if (cookie == NULL) { /* this is a bridged packet */ - bridgeCookie = 0; - cookie = &bridgeCookie; - eh = (struct ether_header *)next_hop; - if ( (*m)->m_pkthdr.len >= sizeof(struct ip) && - ntohs(eh->ether_type) == ETHERTYPE_IP) - hlen = ip->ip_hl << 2; - } else { + bridgeCookie = 0; + cookie = &bridgeCookie; + eh = (struct ether_header *)next_hop; + if ( (*m)->m_pkthdr.len >= sizeof(struct ip) && + ntohs(eh->ether_type) == ETHERTYPE_IP) hlen = ip->ip_hl << 2; - } + } else + hlen = ip->ip_hl << 2; /* Grab and reset cookie */ skipto = *cookie; @@ -1130,7 +1129,7 @@ ip_fw_chk(struct mbuf **m, struct ifnet *oif, u_int16_t *cookie, proto = ip->ip_p; src_ip = ip->ip_src; dst_ip = ip->ip_dst; - if (BRIDGED) { /* not yet... */ + if (BRIDGED) { /* bridged packets are as on the wire */ ip_off = ntohs(ip->ip_off); ip_len = ntohs(ip->ip_len); } else { @@ -1225,6 +1224,81 @@ ip_fw_chk(struct mbuf **m, struct ifnet *oif, u_int16_t *cookie, if (f->fw_number == IPFW_DEFAULT_RULE) goto got_match ; + /* Check if rule only valid for bridged packets */ + if ((f->fw_flg & IP_FW_BRIDGED) != 0 && !(BRIDGED)) + continue; +#undef BRIDGED + + if (oif) { + /* Check direction outbound */ + if (!(f->fw_flg & IP_FW_F_OUT)) + continue; + } else { + /* Check direction inbound */ + if (!(f->fw_flg & IP_FW_F_IN)) + continue; + } + + if (f->fw_flg & IP_FW_F_MAC) { + u_int32_t *want, *mask, *hdr; + + if (eh == NULL) /* header not available */ + continue; + + want = (void *)&(f->fw_mac_hdr); + mask = (void *)&(f->fw_mac_mask); + hdr = (void *)eh; + + if ( want[0] != (hdr[0] & mask[0]) ) + continue; + if ( want[1] != (hdr[1] & mask[1]) ) + continue; + if ( want[2] != (hdr[2] & mask[2]) ) + continue; + if (f->fw_flg & IP_FW_F_SRNG) { + u_int16_t type = ntohs(eh->ether_type); + if (type < (u_int16_t)(f->fw_mac_type) || + type > (u_int16_t)(f->fw_mac_mask_type) ) + continue; + } else { + if ((u_int16_t)(f->fw_mac_type) != (eh->ether_type & + (u_int16_t)(f->fw_mac_mask_type)) ) + continue; + } + } + + /* Interface check */ + if ((f->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) { + struct ifnet *const iface = oif ? oif : rif; + + /* Backwards compatibility hack for "via" */ + if (!iface || !iface_match(iface, + &f->fw_in_if, f->fw_flg & IP_FW_F_OIFNAME)) + continue; + } else { + /* Check receive interface */ + if ((f->fw_flg & IP_FW_F_IIFACE) + && (!rif || !iface_match(rif, + &f->fw_in_if, f->fw_flg & IP_FW_F_IIFNAME))) + continue; + /* Check outgoing interface */ + if ((f->fw_flg & IP_FW_F_OIFACE) + && (!oif || !iface_match(oif, + &f->fw_out_if, f->fw_flg & IP_FW_F_OIFNAME))) + continue; + } + + /* + * For packets which matched the MAC check, we do not need + * to continue, this is a valid match. + * For not-ip packets, the rule does not apply. + */ + if (f->fw_flg & IP_FW_F_MAC) + goto rnd_then_got_match; + + if (hlen == 0) + continue; + /* * dynamic rules are checked at the first keep-state or * check-state occurrence. @@ -1248,65 +1322,35 @@ ip_fw_chk(struct mbuf **m, struct ifnet *oif, u_int16_t *cookie, continue ; } - /* Check if rule only valid for bridged packets */ - if ((f->fw_flg & IP_FW_BRIDGED) != 0 && !(BRIDGED)) - continue; - - if (oif) { - /* Check direction outbound */ - if (!(f->fw_flg & IP_FW_F_OUT)) - continue; - } else { - /* Check direction inbound */ - if (!(f->fw_flg & IP_FW_F_IN)) - continue; - } - /* Fragments */ if ((f->fw_flg & IP_FW_F_FRAG) && offset == 0 ) continue; + /* + * For matching addresses, tif != NULL means we matched + * the address we requested (either "me" or addr/mask). + * Then the check for "xxx" or "not xxx" can be done + * with an XOR. + */ + + /* source address -- mandatory */ if (f->fw_flg & IP_FW_F_SME) { INADDR_TO_IFP(src_ip, tif); - if (tif == NULL) - continue; - } + } else + (int)tif = f->fw_src.s_addr == + (src_ip.s_addr & f->fw_smsk.s_addr); + if ( ((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ (tif == NULL) ) + continue; + + /* dst address -- mandatory */ if (f->fw_flg & IP_FW_F_DME) { INADDR_TO_IFP(dst_ip, tif); - if (tif == NULL) - continue; - } - /* If src-addr doesn't match, not this rule. */ - if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((src_ip.s_addr - & f->fw_smsk.s_addr) != f->fw_src.s_addr)) + } else + (int)tif = f->fw_dst.s_addr == + (dst_ip.s_addr & f->fw_dmsk.s_addr); + if ( ((f->fw_flg & IP_FW_F_INVDST) != 0) ^ (tif == NULL) ) continue; - - /* If dest-addr doesn't match, not this rule. */ - if (((f->fw_flg & IP_FW_F_INVDST) != 0) ^ ((dst_ip.s_addr - & f->fw_dmsk.s_addr) != f->fw_dst.s_addr)) - continue; - - /* Interface check */ - if ((f->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) { - struct ifnet *const iface = oif ? oif : rif; - - /* Backwards compatibility hack for "via" */ - if (!iface || !iface_match(iface, - &f->fw_in_if, f->fw_flg & IP_FW_F_OIFNAME)) - continue; - } else { - /* Check receive interface */ - if ((f->fw_flg & IP_FW_F_IIFACE) - && (!rif || !iface_match(rif, - &f->fw_in_if, f->fw_flg & IP_FW_F_IIFNAME))) - continue; - /* Check outgoing interface */ - if ((f->fw_flg & IP_FW_F_OIFACE) - && (!oif || !iface_match(oif, - &f->fw_out_if, f->fw_flg & IP_FW_F_OIFNAME))) - continue; - } - + /* Check IP header values */ if (f->fw_ipflg & IP_FW_IF_IPOPT && !ipopts_match(ip, f)) continue; @@ -1577,7 +1621,7 @@ ip_fw_chk(struct mbuf **m, struct ifnet *oif, u_int16_t *cookie, && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { switch (f->fw_reject_code) { case IP_FW_REJECT_RST: - { + { /* XXX warning, this code writes into the mbuf */ struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl); @@ -1603,7 +1647,7 @@ ip_fw_chk(struct mbuf **m, struct ifnet *oif, u_int16_t *cookie, } *m = NULL; break; - } + } default: /* Send an ICMP unreachable using code */ icmp_error(*m, ICMP_UNREACH, f->fw_reject_code, 0L, 0); @@ -1617,7 +1661,6 @@ ip_fw_chk(struct mbuf **m, struct ifnet *oif, u_int16_t *cookie, * Finally, drop the packet. */ return(IP_FW_PORT_DENY_FLAG); -#undef BRIDGED } /* @@ -1814,6 +1857,9 @@ check_ipfw_struct(struct ip_fw *frwl) err_prefix, frwl->fw_flg)); return (EINVAL); } + if ( (frwl->fw_flg & IP_FW_F_MAC) ) { /* match MAC address */ + return 0; + } if (frwl->fw_flg == IP_FW_F_CHECK_S) { /* check-state */ return 0 ;