arptables实现ARP报文IPMAC绑定

iptables实现的IPMAC绑定对ARP报文无效,以下使用arptables规则控制ARP报文的IPMAC绑定。在主机192.168.1.127上配置以下规则:

# arptables -A INPUT -s 192.168.1.201 --source-mac ! 00:0C:29:38:40:6B -j DROP
#
# arptables -L -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
-j DROP -i any -o any -s 192.168.1.201 ! --src-mac 00:0c:29:38:40:6b , pcnt=4 -- bcnt=184

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)

在主机192.168.1.201(MAC:00:0c:29:38:40:19,与以上配置的source-mac不相同)上使用arping测试到以上主机1.127的连通性,发送了4个报文,没有收到回应。在主机1.127上查看arptables计数,显示丢弃了4个报文,两者相吻合。

# arping 192.168.1.127
ARPING 192.168.1.127 from 192.168.1.201 eth0
^CSent 4 probes (4 broadcast(s))
Received 0 response(s)

将主机1.201的MAC地址修改为:00:0c:29:38:40:6b,其到主机1.127的arp可通。arptables显示没有匹配DROP规则的计数。

# arptables -L -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
-j DROP -i any -o any -s 192.168.1.201 ! --src-mac 00:0c:29:38:40:6b , pcnt=0 -- bcnt=0

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)

另外,关键字–source-mac和–destination-mac还可以指定内置的字符串(Unicast/Multicast/Broadcast),如下拒绝主机1.201的ARP广播流量。

# arptables -A INPUT -s 192.168.1.201 --destination-mac Broadcast -j DROP
#
# arptables -L -v --line-number
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
1 -j DROP -i any -o any -s 192.168.1.201 --dst-mac ff:ff:ff:ff:ff:ff , pcnt=0 -- bcnt=0

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)

arp报文匹配

如下arp规则处理函数arpt_do_table,其中由arp_packet_match执行报文合规则的匹配,最后一个参数为配置的规则信息。

unsigned int arpt_do_table(struct sk_buff *skb,
               const struct nf_hook_state *state, struct xt_table *table)
{
    const struct arphdr *arp;
    struct arpt_entry *e, **jumpstack;

    e = get_entry(table_base, private->hook_entry[hook]);

    acpar.state   = state;
    acpar.hotdrop = false;

    arp = arp_hdr(skb);
    do {
        const struct xt_entry_target *t;
        struct xt_counters *counter;

        if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) {
            e = arpt_next_entry(e);
            continue;
        }

首先,由ARP报文中获取发送端的硬件地址(src_devaddr),和IP地址(src_ipaddr);以及target目的端的硬件地址(tgt_devaddr)和IP地址(tgt_ipaddr),接下来,比较报文中获取的硬件地址和arptables规则(arpinfo)中配置的硬件地址是否匹配,不匹配返回0。

static inline int arp_packet_match(const struct arphdr *arphdr,
                   struct net_device *dev,
                   const char *indev, const char *outdev,
                   const struct arpt_arp *arpinfo)
{
    const char *arpptr = (char *)(arphdr + 1);
    const char *src_devaddr, *tgt_devaddr;
    ...

    src_devaddr = arpptr;
    arpptr += dev->addr_len;
    memcpy(&src_ipaddr, arpptr, sizeof(u32));
    arpptr += sizeof(u32);
    tgt_devaddr = arpptr;
    arpptr += dev->addr_len;
    memcpy(&tgt_ipaddr, arpptr, sizeof(u32));

    if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR,
            arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr,
                    dev->addr_len)) ||
        NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR,
            arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr,
                    dev->addr_len)))
        return 0;

其次,比较报文中的IP地址与规则配置的地址是否匹配,不匹配返回0。完全匹配的情况返回1,执行规则中指定的动作,以上为DROP,丢弃报文。

    if (NF_INVF(arpinfo, ARPT_INV_SRCIP,
            (src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr) ||
        NF_INVF(arpinfo, ARPT_INV_TGTIP,
            (tgt_ipaddr & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr))
        return 0;

    /* Look for ifname matches.  */
    ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask);

    if (NF_INVF(arpinfo, ARPT_INV_VIA_IN, ret != 0))
        return 0;

    ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask);

    if (NF_INVF(arpinfo, ARPT_INV_VIA_OUT, ret != 0))
        return 0;

    return 1;

内核hook点

NF_ARP_IN位于arp协议的入口函数arp_rcv中,如果没有规则将报文丢弃,最后交由arp_process进行处理。

static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
           struct packet_type *pt, struct net_device *orig_dev)
{
    const struct arphdr *arp;

    /* do not tweak dropwatch on an ARP we will ignore */
    if (dev->flags & IFF_NOARP ||
        skb->pkt_type == PACKET_OTHERHOST ||
        skb->pkt_type == PACKET_LOOPBACK)
        goto consumeskb;
    ...
    memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));

    return NF_HOOK(NFPROTO_ARP, NF_ARP_IN,
               dev_net(dev), NULL, skb, dev, NULL,
               arp_process);

内核版本 5.10

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值