概述

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. Django多对多

    表名小写+_set()  得到的是一个QuertSet集合,她的后面可以跟 .add()   .remove()   .update()   .clear() models.py  文件 # 学生表 ...

  2. SIP协议入门:初学者必须明白的几个重要概念

    SIP协议初学者必须明白的几个重要概念 http://blog.sina.com.cn/s/blog_60e1d7bb0100f6er.html 一. SIP协议的分层结构 SIP是一个分层结构协议, ...

  3. python计算出现错误

    用python计算39.8-0.1得出的结果是39.699999999999996 其他数字计算正确,唯独这个计算错误. 原因: 中文解释: https://docs.python.org/zh-cn ...

  4. Java秒杀实战 (六) 服务级高并发秒杀优化(RabbitMQ+接口优化)

    转自:https://blog.csdn.net/qq_41305266/article/details/81146716 一.思路:减少数据库访问 1.系统初始化,把商品库存数量加载到Redis 2 ...

  5. SpringBoot定时任务(schedule、quartz)

    Scheduled 只适合处理简单的计划任务,不能处理分布式计划任务.优势:是spring框架提供的计划任务,开发简单,执行效率比较高.且在计划任务数量太多的时候,可能出现阻塞,崩溃,延迟启动等问题. ...

  6. SpringMVC的工作原理(转)

    SpringMVC的工作原理图: SpringMVC流程 1.  用户发送请求至前端控制器DispatcherServlet. 2.  DispatcherServlet收到请求调用HandlerMa ...

  7. js 扁平化输出数组

    1.使用数组的flat方法 [1,2,[3,[4,5]]].flat(Infinity) //[1, 2, 3, 4, 5] 2.实现方式二: var arr = [[1, 2, 23], [13, ...

  8. Redis安装及前后置启动

    Redis简单介绍及在Linux上安装(这里测试用是版本:redis-3.0.0.tar.gz) 一:什么是Redis? redis就是C语言编写的一个高性能的键值存储(key-value)的非关系型 ...

  9. 微信小程序开发(八)获取手机ip地址

    // succ.wxml <view>手机IP:{{motto.query}}</view> // succ.js var app = getApp() Page({ data ...

  10. 深度排序模型概述(二)PNN/NFM/AFM

    在CTR预估中,为了解决稀疏特征的问题,学者们提出了FM模型来建模特征之间的交互关系.但是FM模型只能表达特征之间两两组合之间的关系,无法建模两个特征之间深层次的关系或者说多个特征之间的交互关系,因此 ...