diff options
| author | Luigi Rizzo <luigi@FreeBSD.org> | 2002-05-12 20:43:50 +0000 |
|---|---|---|
| committer | Luigi Rizzo <luigi@FreeBSD.org> | 2002-05-12 20:43:50 +0000 |
| commit | 201efb1913e986bbb8777051dc035e4a0f5a4c02 (patch) | |
| tree | 2d37341c56c767eb3ebc3e305db97c08b7de17ce | |
| parent | 7110af7577b8a4fcd4f154bade61083c77480b39 (diff) | |
Notes
| -rw-r--r-- | sys/netinet/ip_fw.c | 170 |
1 files changed, 108 insertions, 62 deletions
diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c index b06576abddc31..03ec6ccfc878e 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,66 +1224,48 @@ again: if (f->fw_number == IPFW_DEFAULT_RULE) goto got_match ; - /* - * dynamic rules are checked at the first keep-state or - * check-state occurrence. - */ - if (f->fw_flg & (IP_FW_F_KEEP_S|IP_FW_F_CHECK_S) && - dyn_checked == 0 ) { - dyn_checked = 1 ; - q = lookup_dyn_rule(&last_pkt, &direction); - if (q != NULL) { - DEB(printf("-- dynamic match 0x%08x %d %s 0x%08x %d\n", - (q->id.src_ip), (q->id.src_port), - (direction == MATCH_FORWARD ? "-->" : "<--"), - (q->id.dst_ip), (q->id.dst_port) ); ) - f = q->rule ; - q->pcnt++ ; - q->bcnt += ip_len; - goto got_match ; /* random not allowed here */ - } - /* if this was a check-only rule, continue with next */ - if (f->fw_flg & IP_FW_F_CHECK_S) - continue ; - } - /* Check if rule only valid for bridged packets */ if ((f->fw_flg & IP_FW_BRIDGED) != 0 && !(BRIDGED)) - continue; + continue; +#undef BRIDGED if (oif) { - /* Check direction outbound */ - if (!(f->fw_flg & IP_FW_F_OUT)) - continue; + /* 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; + /* Check direction inbound */ + if (!(f->fw_flg & IP_FW_F_IN)) + continue; } - /* Fragments */ - if ((f->fw_flg & IP_FW_F_FRAG) && offset == 0 ) - continue; + if (f->fw_flg & IP_FW_F_MAC) { + u_int32_t *want, *mask, *hdr; - if (f->fw_flg & IP_FW_F_SME) { - INADDR_TO_IFP(src_ip, tif); - if (tif == NULL) - continue; - } - 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)) + if (eh == NULL) /* header not available */ 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)) + 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) { @@ -1307,6 +1288,69 @@ again: 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. + */ + if (f->fw_flg & (IP_FW_F_KEEP_S|IP_FW_F_CHECK_S) && + dyn_checked == 0 ) { + dyn_checked = 1 ; + q = lookup_dyn_rule(&last_pkt, &direction); + if (q != NULL) { + DEB(printf("-- dynamic match 0x%08x %d %s 0x%08x %d\n", + (q->id.src_ip), (q->id.src_port), + (direction == MATCH_FORWARD ? "-->" : "<--"), + (q->id.dst_ip), (q->id.dst_port) ); ) + f = q->rule ; + q->pcnt++ ; + q->bcnt += ip_len; + goto got_match ; /* random not allowed here */ + } + /* if this was a check-only rule, continue with next */ + if (f->fw_flg & IP_FW_F_CHECK_S) + 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); + } 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); + } 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; + /* Check IP header values */ if (f->fw_ipflg & IP_FW_IF_IPOPT && !ipopts_match(ip, f)) continue; @@ -1577,7 +1621,7 @@ got_match: && !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 @@ got_match: } *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 @@ dropit: * 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 ; |
