概述

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. DIP常用资源整理

    Deep Learning(深度学习): ufldl的2个教程(这个没得说,入门绝对的好教程,Ng的,逻辑清晰有练习):一 ufldl的2个教程(这个没得说,入门绝对的好教程,Ng的,逻辑清晰有练习) ...

  2. elementUI中的loading

    先安装引入 import ElementUI from 'element-ui' import { Loading } from 'element-ui' 在vue的原型链上定义一个打开loading ...

  3. linux 下使用 VirtualBox 搭建集群环境

    参考文章: https://www.nakivo.com/blog/virtualbox-network-setting-guide/ https://help.ubuntu.com/lts/serv ...

  4. 19.SSM整合_配置式开发

    1.定义实体类Student 2.定义Student表 3.定义index页面 4.定义处理器 5.定义Service 6.定义Dao接口 7.定义Dao的Mapper配置文件 8.定义MyBatis ...

  5. Django restfulframework 开发相关知识 整理

    目录 目录 前言 前后端分离 实现前后端分离的方法 前后端分离带来的优点 RESTful十大规范 协议规范 域名规范 版本表示规范 url使用名词 http请求动词 过滤条件 状态码 错误信息 请求方 ...

  6. 【Git】一、安装、配置和仓库创建

    之前一直使用图形界面的git,只会一些最常用的操作,并没有说深入学习git的全部功能 开发这么久了,觉得是时候学习一下指令操作,更快捷也更bigger ------------------------ ...

  7. 一篇关于ajax跨域问题的解决方案

    这几天没事,我有一个好友,让我帮他做一个机器人对话demo, 我说 看看有没有时间(其实自己一脸懵逼) 然后百度了一下,发现了一个机器人  -(连接就不弄出来了,可以私底下交流) ,,我是用这个的 好 ...

  8. Django_02_创建模型

    一:ORM简介 ORM,全拼Object-Relation Mapping,中文意为对象-关系映射,是随着面向对象的软件开发方法发展而产生的. 面向对象的开发方法是当今企业级应用开发环境中的主流开发方 ...

  9. Python 实现快递查询

    实现效果: 源代码: import urllib.request import json import msvcrt kd_dict = {1:'shentong',2:'youzhengguonei ...

  10. windows安装mysql(5.7.26版本)压缩包

    1.解压安装包,进入文件夹,并创建一个data文件夹! 2.修改 my-default.ini 文件 [mysql] default-character-set=utf8 [mysqld] port ...