GARP(Gratuitous ARP)

内核函数arp_is_garp判断ARP报文是否为GARP,先决条件是发送者IP和目标IP地址相同,另外,对于ARP回复(REPLAY)报文,要求如果目标硬件地址存在,需要与发送者硬件地址相等。最后,要求ARP报文的发送者IP为单播地址,否则,判定报文不是garp。

static bool arp_is_garp(struct net *net, struct net_device *dev,
            int *addr_type, __be16 ar_op,
            __be32 sip, __be32 tip,
            unsigned char *sha, unsigned char *tha)
{
    bool is_garp = tip == sip;

    /* Gratuitous ARP _replies_ also require target hwaddr to be
     * the same as source.
     */
    if (is_garp && ar_op == htons(ARPOP_REPLY))
        is_garp =
            /* IPv4 over IEEE 1394 doesn't provide target
             * hardware address field in its ARP payload.
             */
            tha &&
            !memcmp(tha, sha, dev->addr_len);

    if (is_garp) {
        *addr_type = inet_addr_type_dev_table(net, dev, sip);
        if (*addr_type != RTN_UNICAST)
            is_garp = false;
    }
    return is_garp;

如下PROC文件控制对GARP报文的接收,default目录的文件仅在初始化时使用,是否接收GARP,由另外all和网络设备ens33目录下文件确定。

# cat /proc/sys/net/ipv4/conf/all/drop_gratuitous_arp
0
# cat /proc/sys/net/ipv4/conf/default/drop_gratuitous_arp
0
# cat /proc/sys/net/ipv4/conf/ens33/drop_gratuitous_arp
0

在ARP报文处理函数arp_process中,宏IN_DEV_ORCONF对all和网络设备(ens33)设置的drop_gratuitous_arp值进行或操作,如果结果为真,对其此报文。特别是在802.11无线网络环境中,如果存在一个恶意的ARP代理,发送GARP攻击报文,需要开启drop_gratuitous_arp选项。

static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
{
    bool is_garp = false;

    /*
     * For some 802.11 wireless deployments (and possibly other networks),
     * there will be an ARP proxy and gratuitous ARP frames are attacks
     * and thus should not be accepted.
     */
    if (sip == tip && IN_DEV_ORCONF(in_dev, DROP_GRATUITOUS_ARP))
        goto out_free_skb;
	...

如下PROC文件控制对于GARP报文,是否创建邻居表项。如果arp_accept为真,创建新的表项,否则,仅对已有表项进行更新。

# cat /proc/sys/net/ipv4/conf/all/arp_accept 
0
# cat /proc/sys/net/ipv4/conf/default/arp_accept      
0
# cat /proc/sys/net/ipv4/conf/ens33/arp_accept    
0

如果邻居系统已经存在此报文发送者IP对应的邻居信息,或者arp_accept为真,调用函数arp_is_garp判断是否为GARP报文。

    /* Update our ARP tables */
    n = __neigh_lookup(&arp_tbl, &sip, dev, 0);

    addr_type = -1;
    if (n || IN_DEV_ARP_ACCEPT(in_dev)) {
        is_garp = arp_is_garp(net, dev, &addr_type, arp->ar_op,
                      sip, tip, sha, tha);
    }

如果arp_accept为真,并且确定为GARP报文(is_garp为真),将邻居查找函数__neigh_lookup的最后一个参数设置为1,找不到的情况下创建新的邻居表项。另外,对于非garp报文,如果其为回复(REPLY)报文,并且发送者IP为单播地址,而且发送者IP和目标IP不相等(addr_type<0),也创建新的邻居表项。

    if (IN_DEV_ARP_ACCEPT(in_dev)) {
        /* Unsolicited ARP is not accepted by default.
           It is possible, that this option should be enabled for some
           devices (strip is candidate)
         */
        if (!n &&
            (is_garp ||
             (arp->ar_op == htons(ARPOP_REPLY) &&
              (addr_type == RTN_UNICAST ||
               (addr_type < 0 &&
            /* postpone calculation to as late as possible */
            inet_addr_type_dev_table(net, dev, sip) == RTN_UNICAST)))))
            n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
    }

如果邻居表项已经存在,不在进行arp_accept的判断,将邻居表项更新为NUD_REACHABLE状态,但是对于ARP请求报文或者广播回复报文,表项状态设置为NUD_STALE。

    if (n) {
        int state = NUD_REACHABLE;
        int override;

        /* If several different ARP replies follows back-to-back,
           use the FIRST one. It is possible, if several proxy
           agents are active. Taking the first reply prevents
           arp trashing and chooses the fastest router.
         */
        override = time_after(jiffies,
                      n->updated + NEIGH_VAR(n->parms, LOCKTIME)) ||
                      is_garp;

        /* Broadcast replies and request packets do not assert neighbour reachability.
         */
        if (arp->ar_op != htons(ARPOP_REPLY) ||
            skb->pkt_type != PACKET_HOST)
            state = NUD_STALE;
        neigh_update(n, sha, state, override ? NEIGH_UPDATE_F_OVERRIDE : 0, 0);

内核版本 5.0

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页