linux内核不发(Router Solicit)RS报文问题

    xiaoxiao2021-04-14  31

      最近在弄IPV6时,发现一个问题,在pppoe接入时,ppp接口不发RS请求,因为ppp接入时,上级的RADVD是配置为单播的,不会发送广播RA,导致路由器无法获取前缀。   在UBUNTU主机上测试了一下,发现ifconfig down和up接口都不会发送RS请求,这着实很奇怪。百度google无果。   最后偶然发现,这是由于打开了IPV6的转发导致,即cat /proc/sys/net/ipv6/conf/all/forwarding为1。在网站http://mirrors.deepspace6.net/Linux+IPv6-HOWTO/proc-sys-net-ipv6..html看到当开启了forwarding之后,就不再往外发送RS请求。可能内核觉得开了转发表示我自己就是路由器了,那我还发什么RS来请求路由呢。   所以要解决这个问题,需要修改内核发送RS处的逻辑,如何修改可以看下addrconf.c和ndisc.c两个文件的逻辑大概就可以知道如何改了。具体修改可见最下面的差异对比。下面说下,内核何时会发送RS(下面是pppoe拨号时的逻辑)?

    内核何时会发送RS      首先ipv6cp阶段双方会确认一个UID,然后pppd进程就会根据这个uid配置链路本地地址,应用层配置地址会触发内核inet6_addr_add >> addrconf_dad_start >> addrconf_dad_completed >> ndisc_send_rs 这里就会发出第一个RS包,并设置定时器,定时器的时间和发包次数可以通过proc配置。如果收到了回复,那么就退出定时器,不再发送RS。 收RA包是在ndisc_rcv >> ndisc_router_discovery处理,里面会解析option信息,标志位,根据前缀配置地址,配置默认路由。

    vlan2接口的RS什么时候发呢,差不了太多,是在vlan2起接口配置链路本地地址时发的,只是它是走addrconf_add_linklocal函数。注意:给接口配置链路本地地址才会触发内核发送RS报文。但内核会一直正确处理收到的RA。

    修改点: addrconf.c

    root@ubuntu:ipv6# diff -u addrconf_old.c addrconf.c --- addrconf_old.c 2015-06-29 13:40:06.000000000 +0800 +++ addrconf.c 2017-03-29 11:46:10.723980700 +0800 @@ -258,6 +258,26 @@ AC_RS, }; +/* return 1, is wan dev */ +int is_wan_dev(char* ifname) +{ + char *wan_ifnames[] = {"vlan2", "eth0.2", "ppp0", "ppp1", "ppp2", "ppp3"}; + int i = 0; + + if(!ifname) + return 0; + + for(i = 0; i < sizeof(wan_ifnames)/sizeof(char*); i++) + { + if(!strcmp(ifname, wan_ifnames[i])) + return 1; + } + return 0; +} + +EXPORT_SYMBOL(is_wan_dev); + + static void addrconf_mod_timer(struct inet6_ifaddr *ifp, enum addrconf_timer_t what, unsigned long when) @@ -270,6 +290,7 @@ ifp->timer.function = addrconf_dad_timer; break; case AC_RS: + //printk(KERN_DEBUG "llm[%s](%d) %s add a rs timer\n", __FUNCTION__, __LINE__, ifp->idev->dev->name); ifp->timer.function = addrconf_rs_timer; break; default: @@ -1590,6 +1611,8 @@ int err = -1; struct inet6_ifaddr *ifp; + + //printk(KERN_DEBUG "llm[%s](%d) %s inherit eui64\n", __FUNCTION__, __LINE__, idev->dev->name); read_lock_bh(&idev->lock); list_for_each_entry(ifp, &idev->addr_list, if_list) { if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { @@ -1599,6 +1622,8 @@ } } read_unlock_bh(&idev->lock); + + //printk(KERN_DEBUG "llm[%s](%d) %s return %d\n", __FUNCTION__, __LINE__, idev->dev->name, err); return err; } @@ -1806,6 +1831,7 @@ return; } + //printk(KERN_DEBUG "llm[%s](%d) %s recv prefix\n", __FUNCTION__, __LINE__, in6_dev->dev->name); /* * Two things going on here: * 1) Add routes for on-link prefixes @@ -2128,6 +2154,8 @@ return PTR_ERR(idev); scope = ipv6_addr_scope(pfx); + + //printk(KERN_DEBUG "llm[%s](%d) %s add addr\n", __FUNCTION__, __LINE__, idev->dev->name); timeout = addrconf_timeout_fixup(valid_lft, HZ); if (addrconf_finite_timeout(timeout)) { @@ -2346,7 +2374,7 @@ addr_flags |= IFA_F_OPTIMISTIC; #endif - + //printk(KERN_DEBUG "llm[%s](%d) %s add linklocal\n", __FUNCTION__, __LINE__, idev->dev->name); ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags); if (!IS_ERR(ifp)) { addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); @@ -2789,7 +2817,8 @@ if (idev->dead || !(idev->if_flags & IF_READY)) goto out; - if (idev->cnf.forwarding) + // llm modify + if (idev->cnf.forwarding && !is_wan_dev(idev->dev->name)) goto out; /* Announcement received after solicitation was sent */ @@ -2952,7 +2981,9 @@ start sending router solicitations. */ - if (ifp->idev->cnf.forwarding == 0 && + //llm modify + if ((ifp->idev->cnf.forwarding == 0 || + is_wan_dev(dev->name)) && ifp->idev->cnf.rtr_solicits > 0 && (dev->flags&IFF_LOOPBACK) == 0 && (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { @@ -2961,6 +2992,8 @@ * [...] as part of DAD [...] there is no need * to delay again before sending the first RS */ + + //printk(KERN_DEBUG "llm[%s](%d) %s send rs\n", __FUNCTION__, __LINE__, ifp->idev->dev->name); ndisc_send_rs(ifp->idev->dev, &ifp->addr, &in6addr_linklocal_allrouters); spin_lock_bh(&ifp->lock); @@ -4100,11 +4133,15 @@ */ if (!(ifp->rt->rt6i_node)) ip6_ins_rt(ifp->rt); - if (ifp->idev->cnf.forwarding) + + // llm modify + if (ifp->idev->cnf.forwarding && !is_wan_dev(ifp->idev->dev->name)) addrconf_join_anycast(ifp); break; case RTM_DELADDR: - if (ifp->idev->cnf.forwarding) + + // llm modify + if (ifp->idev->cnf.forwarding && !is_wan_dev(ifp->idev->dev->name)) addrconf_leave_anycast(ifp); addrconf_leave_solict(ifp->idev, &ifp->addr); dst_hold(&ifp->rt->dst); root@ubuntu:ipv6#

    ndisc.c

    root@ubuntu:ipv6# diff -u ndisc_old.c ndisc.c --- ndisc_old.c 2015-06-29 13:40:06.000000000 +0800 +++ ndisc.c 2017-03-29 11:44:45.485694700 +0800 @@ -178,6 +178,8 @@ #define NDISC_OPT_SPACE(len) (((len)+2+7)&~7) +extern int is_wan_dev(char* ifname); + /* * Return the padding between the option length and the start of the * link addr. Currently only IP-over-InfiniBand needs this, although @@ -1021,7 +1023,8 @@ } /* Don't accept RS if we're not in router mode */ - if (!idev->cnf.forwarding) + // llm modify + if (!idev->cnf.forwarding || is_wan_dev(idev->dev->name)) goto out; /* @@ -1149,6 +1152,7 @@ return; } + //printk(KERN_DEBUG "llm[%s](%d) %s recv RA\n", __FUNCTION__, __LINE__, in6_dev->dev->name); if (!ndisc_parse_options(opt, optlen, &ndopts)) { in6_dev_put(in6_dev); ND_PRINTK2(KERN_WARNING @@ -1157,7 +1161,9 @@ } /* skip route and link configuration on routers */ - if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) + // llm modify + if ((in6_dev->cnf.forwarding && !is_wan_dev(in6_dev->dev->name)) + || !in6_dev->cnf.accept_ra) goto skip_linkparms; #ifdef CONFIG_IPV6_NDISC_NODETYPE @@ -1308,7 +1314,9 @@ } /* skip route and link configuration on routers */ - if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) + // llm modify + if ((in6_dev->cnf.forwarding && !is_wan_dev(in6_dev->dev->name)) + || !in6_dev->cnf.accept_ra) goto out; #ifdef CONFIG_IPV6_ROUTE_INFO @@ -1447,7 +1455,10 @@ in6_dev = in6_dev_get(skb->dev); if (!in6_dev) return; - if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) { + + // llm modify + if ((in6_dev->cnf.forwarding && !is_wan_dev(in6_dev->dev->name)) + || !in6_dev->cnf.accept_redirects) { in6_dev_put(in6_dev); return; } root@ubuntu:ipv6#
    转载请注明原文地址: https://ju.6miu.com/read-669800.html

    最新回复(0)