概述

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;
}

ARP输入 之 arp_process的更多相关文章

  1. ARP输入 之 arp_rcv

    概述 arp_rcv是ARP包的入口函数,ARP模块在二层注册了类型为ETH_P_ARP的数据包回调函数arp_rcv,当收到ARP包时,二层进行分发,调用arp_rcv: arp_rcv对ARP输入 ...

  2. 《TCP/IP作品详细解释2:达到》注意事项--ARP:地址解析协议

    Net/3于ARP和实施密切与路由表相关联的,下图显示了我们的叙述性说明ARP使用样品. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVE9ERDkxMQ ...

  3. UIP源码之ARP过程分析

    之前我们使用UIP实现了tcp和udp通讯今天来说说UIP的实现流程,当然,这篇文章里面只会涉及tcp和udp,暂时还没办法说DHCP,因为UIP的DHCP实现使用了协程的概念,下一章将协程之后再说D ...

  4. ARP报文发送的可视化实现

    一.安装VS2013,下载wpdpack,为VS2010配置WinpCap环境: ⑴首先在View中选择Property Manager,然后展开工程,再展开Debug|Win32 ,接着右击 Mir ...

  5. Python黑帽编程 3.1 ARP欺骗

    Python灰帽编程 3.1 ARP欺骗 ARP欺骗是一种在局域网中常用的攻击手段,目的是让局域网中指定的(或全部)的目标机器的数据包都通过攻击者主机进行转发,是实现中间人攻击的常用手段,从而实现数据 ...

  6. 常用网络工具 ipconfig arp traceroute

    如今的计算机是离不开网络的计算机了,因而我们对网络要有一基础的认识.连不上网,程序运行不正常之类的,多少都与网络有关.本文将介绍常用的工具. 网络出问题 ipconfig ping 网络连不上,首先要 ...

  7. 在浏览器中输入URL按下回车键后发生了什么

    在浏览器中输入URL按下回车键后发生了什么 [1]解析URL[2]DNS查询,解析域名,将域名解析为IP地址[3]ARP广播,根据IP地址来解析MAC地址[4]分别从应用层到传输层.网络层和数据链路层 ...

  8. 输入URL到展现页面的全过程

    最近在看一本关于网络协议的书<图解HTTP> 当我们在浏览器的地址栏输入 http://www.pwstrick.com ,然后回车,回车这一瞬间到看到页面到底发生了什么呢? 1.  域名 ...

  9. Python黑客编程ARP欺骗

    Python灰帽编程 3.1 ARP欺骗 ARP欺骗是一种在局域网中常用的攻击手段,目的是让局域网中指定的(或全部)的目标机器的数据包都通过攻击者主机进行转发,是实现中间人攻击的常用手段,从而实现数据 ...

随机推荐

  1. 多线程之thread和runnable

    Runnanle方式可以避免Thread由于单继承特性带来的缺陷. Runnable代码可以被多个线程(thread实例)共享,适用于多个线程处理同一资源的情况. 线程的生命周期:创建,就绪,阻塞,运 ...

  2. 如何对Nginx日志文件进行切割保存

    日积月累下,日志文件会越来越大,日志文件太大严重影响服务器效率,须要定时对日志文件进行切割. 切割的方式有按月切割.按天切割.按小时切割,一般都是按天切割. 那么如何进行切割呢? 思路: 创建日志文件 ...

  3. python3使用pytesseract进行验证码识别

    pytesseract介绍 1.Python-tesseract是一个基于google's Tesseract-OCR的独立封装包: 2.Python-tesseract功能是识别图片文件中文字,并作 ...

  4. 8.JSP与JavaBean

    1.<jsp:useBean> <html> <head> <title>jsp:useBean 标签的使用</title> </he ...

  5. Supervisor的使用

    版权声明:原创文章欢迎转载,不过要记得加出处哦 https://blog.csdn.net/wljk506/article/details/77146248 supervisord 是Linux/Un ...

  6. zookeeper不停的拒绝client连接

    1 自己重建了Zookeeper集群,但是之前的应用依赖的事务是前一个Zookeeper的集群的,所以无法识别,重启一下应用就好了

  7. nginx+tomcat实现负载均衡以及双机热备

    还记得那些年吗? 还记得更新代码之后,服务器起不来被领导训斥吗?还记得更新代码,需要停机过多的时间被渠道部们埋怨吗?还记得更新代码,代码出错时自己吓个半死吗?于是我们聪明勤快的程序员,看着电影待到夜深 ...

  8. F - Star SPOJ - STARSBC

    Fernando won a compass for his birthday, and now his favorite hobby is drawing stars: first, he marks ...

  9. 2019 ICPC 南昌网络赛I:Yukino With Subinterval(CDQ分治)

    Yukino With Subinterval Yukino has an array a_1, a_2 \cdots a_na1,a2⋯*a**n*. As a tsundere girl, Yuk ...

  10. Python&Selenium智能等待方法封装

    摘要:本篇博文用几行代码展示Python和Selenium做自动化测试时常见的显示等待和封装 # 用于实现智能等待页面元素的出现 # encoding = utf-8 ""&quo ...