arp_process为ARP输入包的核心处理流程;
若输入为ARP请求且查路由成功,则进行如下判断:输入到本地,则进行应答;否则,允许转发,则转发,本文代码不包含转发流程;
若输入为ARP应答或者查路由失败,则更新邻居项;
static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
struct in_device *in_dev = __in_dev_get_rcu(dev);
struct arphdr *arp;
unsigned char *arp_ptr;
struct rtable *rt;
unsigned char *sha;
unsigned char *tha = NULL;
__be32 sip, tip;
u16 dev_type = dev->type;
int addr_type;
struct neighbour *n;
struct dst_entry *reply_dst = NULL;
bool is_garp = false;
/\* arp\_rcv below verifies the ARP header and verifies the device
\* is ARP'able.
\*/
/\* 获取ip配置块 \*/
if (!in\_dev)
goto out\_free\_skb;
/\* 获取arp头 \*/
arp = arp\_hdr(skb);
/\* 根据设备类型做检查 \*/
switch (dev\_type) {
default:
if (arp->ar\_pro != htons(ETH\_P\_IP) ||
htons(dev\_type) != arp->ar\_hrd)
goto out\_free\_skb;
break;
case ARPHRD\_ETHER:
case ARPHRD\_FDDI:
case ARPHRD\_IEEE802:
/\*
\* ETHERNET, and Fibre Channel (which are IEEE 802
\* devices, according to RFC 2625) devices will accept ARP
\* hardware types of either 1 (Ethernet) or 6 (IEEE 802.2).
\* This is the case also of FDDI, where the RFC 1390 says that
\* FDDI devices should accept ARP hardware of (1) Ethernet,
\* however, to be more robust, we'll accept both 1 (Ethernet)
\* or 6 (IEEE 802.2)
\*/
if ((arp->ar\_hrd != htons(ARPHRD\_ETHER) &&
arp->ar\_hrd != htons(ARPHRD\_IEEE802)) ||
arp->ar\_pro != htons(ETH\_P\_IP))
goto out\_free\_skb;
break;
case ARPHRD\_AX25:
if (arp->ar\_pro != htons(AX25\_P\_IP) ||
arp->ar\_hrd != htons(ARPHRD\_AX25))
goto out\_free\_skb;
break;
case ARPHRD\_NETROM:
if (arp->ar\_pro != htons(AX25\_P\_IP) ||
arp->ar\_hrd != htons(ARPHRD\_NETROM))
goto out\_free\_skb;
break;
}
/\* Understand only these message types \*/
/\* 操作码不是应答也不是请求 \*/
if (arp->ar\_op != htons(ARPOP\_REPLY) &&
arp->ar\_op != htons(ARPOP\_REQUEST))
goto out\_free\_skb;
/*
* Extract fields
*/
/* 获取arp指针 */
arp_ptr = (unsigned char *)(arp + );
/* 源mac */
sha = arp_ptr;
/* 源ip */
arp_ptr += dev->addr_len;
memcpy(&sip, arp_ptr, );
arp_ptr += ;
/\* 设备类型 \*/
switch (dev\_type) {
#if IS_ENABLED(CONFIG_FIREWIRE_NET)
case ARPHRD_IEEE1394:
break;
#endif
default:
/* 目的mac */
tha = arp_ptr;
arp_ptr += dev->addr_len;
}
/* 目的ip */
memcpy(&tip, arp_ptr, );
/*
* Check for bad requests for 127.x.x.x and requests for multicast
* addresses. If this is one such, delete it.
*/
/* 目的ip是组播||回环地址但是没有启用route_localnet */
if (ipv4_is_multicast(tip) ||
(!IN_DEV_ROUTE_LOCALNET(in_dev) && ipv4_is_loopback(tip)))
goto out_free_skb;
/*
* 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.
*/
/* 源ip和目的ip相同,设置了免费arp丢包 */
if (sip == tip && IN_DEV_ORCONF(in_dev, DROP_GRATUITOUS_ARP))
goto out_free_skb;
/*
* Special case: We must set Frame Relay source Q.922 address
*/
/* 设备类型为q.922,则设置源地址为广播地址 */
if (dev_type == ARPHRD_DLCI)
sha = dev->broadcast;
/*
* Process entry. The idea here is we want to send a reply if it is a
* request for us or if it is a request for someone else that we hold
* a proxy for. We want to add an entry to our cache if it is a reply
* to us or if it is a request for our address.
* (The assumption for this last is that if someone is requesting our
* address, they are probably intending to talk to us, so it saves time
* if we cache their address. Their address is also probably not in
* our cache, since ours is not in their cache.)
*
* Putting this another way, we only care about replies if they are to
* us, in which case we add them to the cache. For requests, we care
* about those for us and those for our proxies. We reply to both,
* and in the case of requests for us we add the requester to the arp
* cache.
*/
if (arp->ar\_op == htons(ARPOP\_REQUEST) && skb\_metadata\_dst(skb))
reply\_dst = (struct dst\_entry \*)
iptunnel\_metadata\_reply(skb\_metadata\_dst(skb),
GFP\_ATOMIC);
/\* Special case: IPv4 duplicate address detection packet (RFC2131) \*/
/\* 源ip为0,用于检测地址冲突 \*/
if (sip == ) {
/\* ARP请求 && 地址是本地地址 && 不忽略该ARP请求,则发送ARP应答 \*/
if (arp->ar\_op == htons(ARPOP\_REQUEST) &&
inet\_addr\_type\_dev\_table(net, dev, tip) == RTN\_LOCAL &&
!arp\_ignore(in\_dev, sip, tip))
arp\_send\_dst(ARPOP\_REPLY, ETH\_P\_ARP, sip, dev, tip,
sha, dev->dev\_addr, sha, reply\_dst);
goto out\_consume\_skb;
}
/\* ARP请求 && 查路由成功 \*/
if (arp->ar\_op == htons(ARPOP\_REQUEST) &&
ip\_route\_input\_noref(skb, tip, sip, , dev) == ) {
/\* 获取路由缓存 \*/
rt = skb\_rtable(skb);
addr\_type = rt->rt\_type;
/\* 输入到本地 \*/
if (addr\_type == RTN\_LOCAL) {
int dont\_send;
/\* 忽略检查 \*/
dont\_send = arp\_ignore(in\_dev, sip, tip);
/\* 不忽略,配置了过滤,则判断过滤 \*/
if (!dont\_send && IN\_DEV\_ARPFILTER(in\_dev))
dont\_send = arp\_filter(sip, tip, dev);
/\* 允许输入 \*/
if (!dont\_send) {
/\* 查找邻居项,更新状态 \*/
n = neigh\_event\_ns(&arp\_tbl, sha, &sip, dev);
/\* 邻居项存在,则回复ARP应答 \*/
if (n) {
arp\_send\_dst(ARPOP\_REPLY, ETH\_P\_ARP,
sip, dev, tip, sha,
dev->dev\_addr, sha,
reply\_dst);
neigh\_release(n);
}
}
goto out\_consume\_skb;
} else if (IN\_DEV\_FORWARD(in\_dev)) {
/\* ARP代理 \*/
}
}
/\* ARP应答或者查路由失败 \*/
/\* Update our ARP tables \*/
/\* 查找邻居项 \*/
n = \_\_neigh\_lookup(&arp\_tbl, &sip, dev, );
addr\_type = -;
/\* 邻居项存在,或者启用了接收非请求应答 \*/
if (n || IN\_DEV\_ARP\_ACCEPT(in\_dev)) {
/\* 检查是否为免费ARP \*/
is\_garp = arp\_is\_garp(net, dev, &addr\_type, arp->ar\_op,
sip, tip, sha, tha);
}
/\* 启用了接收非请求应答 \*/
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)
\*/
/\*
邻居项不存在,免费ARP || 邻居项不存在,不是免费ARP,则类型为应答,且为单播
创建邻居项
\*/
if (!n &&
(is\_garp ||
(arp->ar\_op == htons(ARPOP\_REPLY) &&
(addr\_type == RTN\_UNICAST ||
(addr\_type < &&
/\* postpone calculation to as late as possible \*/
inet\_addr\_type\_dev\_table(net, dev, sip) ==
RTN\_UNICAST)))))
n = \_\_neigh\_lookup(&arp\_tbl, &sip, dev, );
}
/\* 存在邻居表项 \*/
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.
\*/
/\* 当前时间超过了下次更新时间 或者 为免费ARP \*/
override = time\_after(jiffies,
n->updated +
NEIGH\_VAR(n->parms, LOCKTIME)) ||
is\_garp;
/\* Broadcast replies and request packets
do not assert neighbour reachability.
\*/
/\* 不是ARP应答,或者不是本机包,设置状态为STALE \*/
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 : , );
neigh\_release(n);
}
out_consume_skb:
consume_skb(skb);
out_free_dst:
dst_release(reply_dst);
return NET_RX_SUCCESS;
out_free_skb:
kfree_skb(skb);
return NET_RX_DROP;
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章