主机192.168.1.201的MAC地址如下:
$ ip address
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:38:40:6b brd ff:ff:ff:ff:ff:ff
inet 192.168.1.201/24 brd 192.168.1.255 scope global eth0
valid_lft forever preferred_lft forever
在另外一台主机上配置如下的规则,如果检测到192.168.1.201的MAC地址不等于00:0c:29:38:40:6b,表明为假冒的主机192.168.1.201,将报文丢弃。
# iptables -A INPUT -s 192.168.1.201 -m mac ! --mac-source 00:0c:29:38:40:6b -j DROP
#
# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP all -- 192.168.1.201 anywhere MAC ! 00:0C:29:38:40:6B
将第三台主机的接口IP地址设置为192.168.1.201,ping以上配置了IPMAC绑定的主机,没有响应。查看规则信息,如下丢弃了6个报文:
# iptables -L -v -n
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
6 504 DROP all -- * * 192.168.1.201 0.0.0.0/0 MAC ! 00:0C:29:38:40:6B
注意,以上规则配置于INPUT点,对于ARP请求是不生效的。另外,IPMAC绑定也可以配置在FORWARD点,用于检测转发的流量。不支持配置在OUTPUT点。
# iptables -A FORWARD -s 192.168.1.201 -m mac ! --mac-source 00:0c:29:38:40:6b -j DROP
MAC扩展
函数mac_mt_init注册了匹配结构mac_mt_reg。可知以上iptables命令中的mac选项(-m mac)可应用在PREROUTING,LOCAL_IN和FORWARD三个hook中。
static struct xt_match mac_mt_reg __read_mostly = {
.name = "mac",
.revision = 0,
.family = NFPROTO_UNSPEC,
.match = mac_mt,
.matchsize = sizeof(struct xt_mac_info),
.hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) |
(1 << NF_INET_FORWARD),
.me = THIS_MODULE,
};
static int __init mac_mt_init(void)
{
return xt_register_match(&mac_mt_reg);
}
匹配处理函数mac_mt如下,对于以太网设备,在MAC头部合法的情况下,判断其中源MAC地址是否与配置的MAC相等,考虑取反的情况(如以上的取反符号 !),返回匹配结果。
注意,不能对目的MAC地址进行匹配(路由情况下,目的MAC通常为路由器自身地址)。
static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct xt_mac_info *info = par->matchinfo;
bool ret;
if (skb->dev == NULL || skb->dev->type != ARPHRD_ETHER)
return false;
if (skb_mac_header(skb) < skb->head)
return false;
if (skb_mac_header(skb) + ETH_HLEN > skb->data)
return false;
ret = ether_addr_equal(eth_hdr(skb)->h_source, info->srcaddr);
ret ^= info->invert;
return ret;
内核版本 5.10