Add code to match MAC header fields (at the moment supported on
bridged packets only, soon to come also for packets on ordinary ether_input() and ether_output() paths. The syntax is ipfw add <action> MAC dst src type where dst and src can be "any" or a MAC address optionallyfollowed by a mask, e.g. 10:20:30:40:50 10:20:30:40:50/32 10:20:30:40:50&ff:ff:ff:f0:ff:0f and type can be a single ethernet type, a range, or a type followed by a mask (values are always in hexadecimal) e.g. 0800 0800-0806 0800/8 0800&03ff Note, I am still uncertain on what is the best format for inputting these values, having the values in hexadecimal is convenient in most cases but can be confusing sometimes. Suggestions welcome. Implement suggestion from PR 37778 to allow "not me" on destination and source IP. The code in the PR was slightly wrong and interfered with the normal handling of IP addresses. This version hopefully is correct. Minor cleanup of the code, in some places moving the indentation to 4 spaces because the code was becoming too deep. Eventually, in a separate commit, I will move the whole file to 4 space indent.
This commit is contained in:
parent
7110af7577
commit
201efb1913
@ -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 ;
|
||||
|
Loading…
Reference in New Issue
Block a user