• ARP输入 之 arp_process


    概述

    arp_process为ARP输入包的核心处理流程;

    若输入为ARP请求且查路由成功,则进行如下判断:输入到本地,则进行应答;否则,允许转发,则转发,本文代码不包含转发流程;

    若输入为ARP应答或者查路由失败,则更新邻居项;

    源码分析
      1 static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
      2 {
      3     struct net_device *dev = skb->dev;
      4     struct in_device *in_dev = __in_dev_get_rcu(dev);
      5     struct arphdr *arp;
      6     unsigned char *arp_ptr;
      7     struct rtable *rt;
      8     unsigned char *sha;
      9     unsigned char *tha = NULL;
     10     __be32 sip, tip;
     11     u16 dev_type = dev->type;
     12     int addr_type;
     13     struct neighbour *n;
     14     struct dst_entry *reply_dst = NULL;
     15     bool is_garp = false;
     16 
     17     /* arp_rcv below verifies the ARP header and verifies the device
     18      * is ARP'able.
     19      */
     20     /* 获取ip配置块 */
     21     if (!in_dev)
     22         goto out_free_skb;
     23 
     24     /* 获取arp头 */
     25     arp = arp_hdr(skb);
     26 
     27     /* 根据设备类型做检查 */
     28     switch (dev_type) {
     29     default:
     30         if (arp->ar_pro != htons(ETH_P_IP) ||
     31             htons(dev_type) != arp->ar_hrd)
     32             goto out_free_skb;
     33         break;
     34     case ARPHRD_ETHER:
     35     case ARPHRD_FDDI:
     36     case ARPHRD_IEEE802:
     37         /*
     38          * ETHERNET, and Fibre Channel (which are IEEE 802
     39          * devices, according to RFC 2625) devices will accept ARP
     40          * hardware types of either 1 (Ethernet) or 6 (IEEE 802.2).
     41          * This is the case also of FDDI, where the RFC 1390 says that
     42          * FDDI devices should accept ARP hardware of (1) Ethernet,
     43          * however, to be more robust, we'll accept both 1 (Ethernet)
     44          * or 6 (IEEE 802.2)
     45          */
     46         if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
     47              arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
     48             arp->ar_pro != htons(ETH_P_IP))
     49             goto out_free_skb;
     50         break;
     51     case ARPHRD_AX25:
     52         if (arp->ar_pro != htons(AX25_P_IP) ||
     53             arp->ar_hrd != htons(ARPHRD_AX25))
     54             goto out_free_skb;
     55         break;
     56     case ARPHRD_NETROM:
     57         if (arp->ar_pro != htons(AX25_P_IP) ||
     58             arp->ar_hrd != htons(ARPHRD_NETROM))
     59             goto out_free_skb;
     60         break;
     61     }
     62 
     63     /* Understand only these message types */
     64     
     65     /* 操作码不是应答也不是请求 */
     66     if (arp->ar_op != htons(ARPOP_REPLY) &&
     67         arp->ar_op != htons(ARPOP_REQUEST))
     68         goto out_free_skb;
     69 
     70 /*
     71  *    Extract fields
     72  */
     73     /* 获取arp指针 */
     74     arp_ptr = (unsigned char *)(arp + 1);
     75     /* 源mac */
     76     sha    = arp_ptr;
     77     /* 源ip */
     78     arp_ptr += dev->addr_len;
     79     memcpy(&sip, arp_ptr, 4);
     80     arp_ptr += 4;
     81 
     82     /* 设备类型 */
     83     switch (dev_type) {
     84 #if IS_ENABLED(CONFIG_FIREWIRE_NET)
     85     case ARPHRD_IEEE1394:
     86         break;
     87 #endif
     88     default:
     89         /* 目的mac */
     90         tha = arp_ptr;
     91         arp_ptr += dev->addr_len;
     92     }
     93     /* 目的ip */
     94     memcpy(&tip, arp_ptr, 4);
     95 /*
     96  *    Check for bad requests for 127.x.x.x and requests for multicast
     97  *    addresses.  If this is one such, delete it.
     98  */
     99     /* 目的ip是组播||回环地址但是没有启用route_localnet */
    100     if (ipv4_is_multicast(tip) ||
    101         (!IN_DEV_ROUTE_LOCALNET(in_dev) && ipv4_is_loopback(tip)))
    102         goto out_free_skb;
    103 
    104  /*
    105   *    For some 802.11 wireless deployments (and possibly other networks),
    106   *    there will be an ARP proxy and gratuitous ARP frames are attacks
    107   *    and thus should not be accepted.
    108   */
    109     /* 源ip和目的ip相同,设置了免费arp丢包 */
    110     if (sip == tip && IN_DEV_ORCONF(in_dev, DROP_GRATUITOUS_ARP))
    111         goto out_free_skb;
    112 
    113 /*
    114  *     Special case: We must set Frame Relay source Q.922 address
    115  */
    116     /* 设备类型为q.922,则设置源地址为广播地址 */
    117     if (dev_type == ARPHRD_DLCI)
    118         sha = dev->broadcast;
    119 
    120 /*
    121  *  Process entry.  The idea here is we want to send a reply if it is a
    122  *  request for us or if it is a request for someone else that we hold
    123  *  a proxy for.  We want to add an entry to our cache if it is a reply
    124  *  to us or if it is a request for our address.
    125  *  (The assumption for this last is that if someone is requesting our
    126  *  address, they are probably intending to talk to us, so it saves time
    127  *  if we cache their address.  Their address is also probably not in
    128  *  our cache, since ours is not in their cache.)
    129  *
    130  *  Putting this another way, we only care about replies if they are to
    131  *  us, in which case we add them to the cache.  For requests, we care
    132  *  about those for us and those for our proxies.  We reply to both,
    133  *  and in the case of requests for us we add the requester to the arp
    134  *  cache.
    135  */
    136 
    137     if (arp->ar_op == htons(ARPOP_REQUEST) && skb_metadata_dst(skb))
    138         reply_dst = (struct dst_entry *)
    139                 iptunnel_metadata_reply(skb_metadata_dst(skb),
    140                             GFP_ATOMIC);
    141 
    142     /* Special case: IPv4 duplicate address detection packet (RFC2131) */
    143     /* 源ip为0,用于检测地址冲突 */
    144     if (sip == 0) {
    145         /* ARP请求 && 地址是本地地址 && 不忽略该ARP请求,则发送ARP应答 */
    146         if (arp->ar_op == htons(ARPOP_REQUEST) &&
    147             inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL &&
    148             !arp_ignore(in_dev, sip, tip))
    149             arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip,
    150                      sha, dev->dev_addr, sha, reply_dst);
    151         goto out_consume_skb;
    152     }
    153 
    154     /* ARP请求 && 查路由成功 */
    155     if (arp->ar_op == htons(ARPOP_REQUEST) &&
    156         ip_route_input_noref(skb, tip, sip, 0, dev) == 0) {
    157 
    158         /* 获取路由缓存 */
    159         rt = skb_rtable(skb);
    160         addr_type = rt->rt_type;
    161 
    162         /* 输入到本地 */
    163         if (addr_type == RTN_LOCAL) {
    164             int dont_send;
    165 
    166             /* 忽略检查 */
    167             dont_send = arp_ignore(in_dev, sip, tip);
    168 
    169             /* 不忽略,配置了过滤,则判断过滤 */
    170             if (!dont_send && IN_DEV_ARPFILTER(in_dev))
    171                 dont_send = arp_filter(sip, tip, dev);
    172             /* 允许输入 */
    173             if (!dont_send) {
    174                 /* 查找邻居项,更新状态 */
    175                 n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
    176 
    177                 /* 邻居项存在,则回复ARP应答 */
    178                 if (n) {
    179                     arp_send_dst(ARPOP_REPLY, ETH_P_ARP,
    180                              sip, dev, tip, sha,
    181                              dev->dev_addr, sha,
    182                              reply_dst);
    183                     neigh_release(n);
    184                 }
    185             }
    186             goto out_consume_skb;
    187         } else if (IN_DEV_FORWARD(in_dev)) {
    188             /* ARP代理 */
    189         }
    190     }
    191 
    192    /* ARP应答或者查路由失败 */
    193 
    194     /* Update our ARP tables */
    195     /* 查找邻居项 */
    196     n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
    197 
    198     addr_type = -1;
    199     /* 邻居项存在,或者启用了接收非请求应答 */
    200     if (n || IN_DEV_ARP_ACCEPT(in_dev)) {
    201         /* 检查是否为免费ARP */
    202         is_garp = arp_is_garp(net, dev, &addr_type, arp->ar_op,
    203                       sip, tip, sha, tha);
    204     }
    205 
    206     /* 启用了接收非请求应答 */
    207     if (IN_DEV_ARP_ACCEPT(in_dev)) {
    208         /* Unsolicited ARP is not accepted by default.
    209            It is possible, that this option should be enabled for some
    210            devices (strip is candidate)
    211          */
    212         /*
    213           邻居项不存在,免费ARP || 邻居项不存在,不是免费ARP,则类型为应答,且为单播
    214           创建邻居项
    215         */
    216         if (!n &&
    217             (is_garp ||
    218              (arp->ar_op == htons(ARPOP_REPLY) &&
    219               (addr_type == RTN_UNICAST ||
    220                (addr_type < 0 &&
    221             /* postpone calculation to as late as possible */
    222             inet_addr_type_dev_table(net, dev, sip) ==
    223                 RTN_UNICAST)))))
    224             n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
    225     }
    226 
    227     /* 存在邻居表项 */
    228     if (n) {
    229         int state = NUD_REACHABLE;
    230         int override;
    231 
    232         /* If several different ARP replies follows back-to-back,
    233            use the FIRST one. It is possible, if several proxy
    234            agents are active. Taking the first reply prevents
    235            arp trashing and chooses the fastest router.
    236          */
    237         /* 当前时间超过了下次更新时间 或者 为免费ARP */
    238         override = time_after(jiffies,
    239                       n->updated +
    240                       NEIGH_VAR(n->parms, LOCKTIME)) ||
    241                is_garp;
    242 
    243         /* Broadcast replies and request packets
    244            do not assert neighbour reachability.
    245          */
    246         /* 不是ARP应答,或者不是本机包,设置状态为STALE */
    247         if (arp->ar_op != htons(ARPOP_REPLY) ||
    248             skb->pkt_type != PACKET_HOST)
    249             state = NUD_STALE;
    250         /* 更新邻居项 */
    251         neigh_update(n, sha, state,
    252                  override ? NEIGH_UPDATE_F_OVERRIDE : 0, 0);
    253         neigh_release(n);
    254     }
    255 
    256 out_consume_skb:
    257     consume_skb(skb);
    258 
    259 out_free_dst:
    260     dst_release(reply_dst);
    261     return NET_RX_SUCCESS;
    262 
    263 out_free_skb:
    264     kfree_skb(skb);
    265     return NET_RX_DROP;
    266 }
  • 相关阅读:
    [JSOI2016]最佳团体
    CF125E MST Company
    CF482C Game with Strings
    CF379F New Year Tree
    CF1051F The Shortest Statement
    小a和uim之大逃离
    新魔法药水
    翻硬币
    [CQOI2017]小Q的棋盘
    UVA11729突击战
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/11755428.html
Copyright © 2020-2023  润新知