内核中ARP请求的回复控制

ARP收到request请求之后,首先通过路由查询确定目的IP为一个本地地址类型(RTN_LOCAL)后,是否回复arp请求,还取决于两个判断:arp_ignore与arp_filter。可通过sysctl或者proc文件系统查看二者的值,如下所有配置值都为0:

$ sudo sysctl -a | grep -w arp_ignore
net.ipv4.conf.all.arp_ignore = 0
net.ipv4.conf.default.arp_ignore = 0
net.ipv4.conf.eth0.arp_ignore = 0
$
$ sysctl -a | grep -w arp_filter
net.ipv4.conf.all.arp_filter = 0
net.ipv4.conf.default.arp_filter = 0
net.ipv4.conf.eth0.arp_filter = 0

两者都为0,意味着dont_send为0,内核将回复任何目标IP为本机的arp请求。但是,当arp_ignore或者arp_filter任何一个返回true的时候,arp请求都不会被回复。

static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
{
    if (arp->ar_op == htons(ARPOP_REQUEST) && ip_route_input_noref(skb, tip, sip, 0, dev) == 0)
        if (addr_type == RTN_LOCAL) {
            dont_send = arp_ignore(in_dev, sip, tip);
            if (!dont_send && IN_DEV_ARPFILTER(in_dev))
                dont_send = arp_filter(sip, tip, dev);
        }
}

来看一下内核文档中对这两个参数的解释,位于内核代码根目录下文件Documentation/networking/ip-sysctl.txt:


arp_ignore - INTEGER
    Define different modes for sending replies in response to
    received ARP requests that resolve local target IP addresses:
    0 - (default): reply for any local target IP address, configured on any interface
    1 - reply only if the target IP address is local address configured on the incoming interface
   2 - reply only if the target IP address is local address configured on the incoming interface and both with the sender's IP address are part from same subnet on this interface
    3 - do not reply for local addresses configured with scope host, only resolutions for global and link addresses are replied
    4-7 - reserved
    8 - do not reply for all local addresses

    The max value from conf/{all,interface}/arp_ignore is used
    when ARP request is received on the {interface}

    在收到解析本机IP地址的ARP请求后,此值定义了发送回复报文的几种不同模式:
    0 - (默认值)只要请求的目标IP地址为本机地址,不管其配置在哪个接口上,  都回复其arp reply。
    1 - 只有在请求的目标IP地址所在接口,与接收此请求报文的接口相同时回复。
    2 - 除满足1的条件外,还要求发送arp请求的源IP地址所在网段为接收接口的IP地址所在网段的子网。
    3 - 仅回复目标IP地址类型(scope)为global与link的请求,不对类型为host的请求回复。 另外,不要求目标IP位于数据包接收的接口上。
    4 - 7 保留
    8 - 不回复对本地地址的请求。
 
arp_filter - BOOLEAN
    1 - Allows you to have multiple network interfaces on the same
    subnet, and have the ARPs for each interface be answered
    based on whether or not the kernel would route a packet from
    the ARP'd IP out that interface (therefore you must use source
    based routing for this to work). In other words it allows control
    of which cards (usually 1) will respond to an arp request.

    0 - (default) The kernel can respond to arp requests with addresses
    from other interfaces. This may seem wrong but it usually makes
    sense, because it increases the chance of successful communication.
    IP addresses are owned by the complete host on Linux, not by
    particular interfaces. Only for more complex setups like load-
    balancing, does this behaviour cause problems.

    arp_filter for the interface will be enabled if at least one of
    conf/{all,interface}/arp_filter is set to TRUE,
    it will be disabled otherwise

    1 - 允许系统中多个网络接口工作在相同的网段,在回复某一接口收到的arp请求时,
        内核根据能否路由源地址为请求的目标IP的数据包,从此接口发出来,决定是
        否回复arp(通过源IP地址查询出口路由实现)。换句话说,可控制哪个网卡
        回复arp请求。
    0 - (默认值)内核接口可回复接收到的目标IP为其它接口IP地址的arp请求。看起来
        这样是错误的,但是通常还是有道理的,因为增加了正常通信的几率。在Linux看来,
        系统拥有所有配置的IP地址,而不是某个特定端口。只是在复杂的配置情况下,
        比如负载均衡,才会产生问题。
 

ARP_IGNORE的实现

同名函数arp_ignore实现以上定义的arp_ignore功能。值为0和8的时候,就是简单的返回0,1。当值为1/2/3时,变化的是sip/scope/in_dev三个变量的值,最终的处理都是交由inet_confirm_addr函数处理,其中重要的4个参数如下。

static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip)
{
    switch (IN_DEV_ARP_IGNORE(in_dev)) {
    case 1:
        sip = 0;  scope = RT_SCOPE_HOST;  break;
    case 2:
                  scope = RT_SCOPE_HOST;  break;
    case 3:
        sip = 0;  scope = RT_SCOPE_LINK;  in_dev = NULL;  break;
    }
    return !inet_confirm_addr(net, in_dev, sip, tip, scope);
}

in_dev(in_dev): 仅在in_dev指定的接口的IP地址链表中查找;若in_dev为空,查找所有接口的IP地址链表。
sip(dst)      : 查找到的IP地址必须与dst在相同的子网内;若dst为空,不做此检查。
tip(local)    : 要查找的目标IP地址;若为0将匹配任意本地地址。
scope(scope)  : 查找到的IP地址的scope值必须小于此值。

inet_confirm_addr函数处理in_dev参数,如果其为空,遍历系统中所有的接口,对每个接口调用处理函数,直到找到正确的地址即退出。主要工作在核心处理函数confirm_addr_indev完成,其遍历指定网络接口设备in_dev的IP地址链表,找到与local地址相同并且符合要求(sip/scope指定判断条件)的接口IP地址。子函数inet_ifa_match用于判读addr所处的网段是否为ifa结构中地址的一个子网。针对arp_ignore的三个取值1/2/3看一下此函数的判断过程:

1)此时sip=0(dst=0),scope = RT_SCOPE_HOST,local为目标IP地址。
    只要设备in_dev的IP列表中有等于local的IP地址并且其scope小于RT_SCOPE_HOST;另外列表中还存在一个IP地址与local在同一个子网内,此接口IP地址不需要等于local地址。返回此接口IP(即返回true),回复arp请求。

2)此时dst为源IP地址,scope = RT_SCOPE_HOST,local为目标IP地址。
    除满足1)中的要求外,还要求dst地址所在网段为接口IP地址所在网段的子网。

3)此时sip=0(dst=0),scope = RT_SCOPE_LINK,local为目标IP地址,in_dev为空。
    由于in_dev为空,遍历系统中所有的接口(inet_confirm_addr),在每个接口上调用confirm_addr_indev函数进行判断。判断过程与1)基本相同,唯一区别在于要求scope值小于RT_SCOPE_LINK,即可回复arp请求。

static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, __be32 local, int scope)
{
    int same = 0;
    __be32 addr = 0;

    for_ifa(in_dev) {
        if (!addr && (local == ifa->ifa_local || !local) && ifa->ifa_scope <= scope) {
            addr = ifa->ifa_local;
            if (same)  break;
        }
        if (!same) {
            same = (!local || inet_ifa_match(local, ifa)) && (!dst || inet_ifa_match(dst, ifa));
            if (same && addr) {
                if (local || !dst) break;
                if (inet_ifa_match(addr, ifa))  break;
                if (ifa->ifa_scope <= scope) {
                    addr = ifa->ifa_local;  break;
                }
                same = 0;
            }
        }
    } endfor_ifa(in_dev);
    return same ? addr : 0;
}

ARP_FILTER的实现

其实现主要是通过出口路由查找函数ip_route_output,在传递参数的时候,以arp请求数据包的源IP地址(sip)为参数daddr,数据包的目标IP地址(tip)作为参数saddr,进行源路由查找。当查询结果中路由的出口设备不是此arp请求的入口设备时,返回1,过滤掉此arp请求,不回复。

static inline struct rtable *ip_route_output(struct net *net, __be32 daddr, __be32 saddr, u8 tos, int oif);

static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
{
    rt = ip_route_output(net, sip, tip, 0, 0);
    if (rt->dst.dev != dev) return 1;
}

内核版本

Linux-4.15

猜你喜欢

转载自blog.csdn.net/sinat_20184565/article/details/81219703
arp