linux内核路由模块fib_valid_source函数(反向路由检测)
来源:互联网 发布:北京生祥义网络 编辑:程序博客网 时间:2024/06/05 05:39
表示对linu内核查路由的的效率表示堪忧。
一个经过linux的报文,无论是上送本机,还是转发,都会进行大于等于2次的查路由动作。
即执行大于等于2次的fib_lookup。
外部包过来,ip_rcv->ip_rcv_finish->ip_route_input->ip_route_input_slow
ip_route_input_slow判断报文是否转发,还是上送本机即ip_forward还是ip_local_deliver
但是在执行到ip_forward/ip_local_deliver前,还是会再次查询一次路由,无论是否开启某些安全防护功能。即无条件再会查询一次路由。
如果查询结果有问题,那再判断是否开启了某些安全防护,若开启,则丢包。。。。。。。
如果是我写,那肯定先判断安全防护是否开启,如果开启我再去执行查路由操作。。。。。
废话不多说了,ip_route_input_slow判断报文上送本机,还是转发时,执行了一次fib_lookup
ip_route_input_slow中我们可以看到这话 /* * Now we are ready to route packet. */查不到路由,就goto了 if ((err = fib_lookup(net, &fl, &res)) != 0) { if (!IN_DEV_FORWARD(in_dev)) goto e_hostunreach; goto no_route; }如果查到路由,则判断包是上送本机,还是转发。 if (res.type == RTN_LOCAL) {//这是发给我自己的,即上送本机的 int result;//罪魁祸首出现了。就是这家伙,我先不分析这个函数,最后再分析,先看看转发流程在哪里也调用了fib_validate_source。 result = fib_validate_source(saddr, daddr, tos, net->loopback_dev->ifindex, dev, &spec_dst, &itag, skb->mark); if (result < 0) goto martian_source; if (result) flags |= RTCF_DIRECTSRC; spec_dst = daddr;//执行local_input goto local_input; } if (!IN_DEV_FORWARD(in_dev)) goto e_hostunreach; if (res.type != RTN_UNICAST) goto martian_destination;//如果不是上送本机,而是需要转发的,执行 ip_mkroute_input err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);ip_mkroute_input调用__mkroute_inputstatic int __mkroute_input(struct sk_buff *skb, struct fib_result *res, struct in_device *in_dev, __be32 daddr, __be32 saddr, u32 tos, struct rtable **result){.................................//再次见到它了,我们可以看到,无论是需要转发还是需要上送本机,几乎都是无条件执行fib_validate_source err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(*res), in_dev->dev, &spec_dst, &itag, skb->mark); if (err < 0) { ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr, saddr); err = -EINVAL; goto cleanup; } }是时候来看看fib_validate_source这个函数了。/* Given (packet source, input interface) and optional (dst, oif, tos): - (main) check, that source is valid i.e. not broadcast or our local address. - figure out what "logical" interface this packet arrived and calculate "specific destination" address. - check, that packet arrived from expected physical interface. */int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, struct net_device *dev, __be32 *spec_dst, u32 *itag, u32 mark){ struct in_device *in_dev;//组装查找key//注意源地址和目的地址互换,然后查路由之所以何种方式查路由,是有一定意图的。//首先valid_source顾名思义,就是看源地址是否有效,说明才是有效,看我有没有到你的路由//如果我有到你的路由,好吧,暂且认为你有效。如果没有到你的路由,而你却偏偏给我发了一个报文//那么我认为你是伪造原地址了。(该逻辑的前提是“对称路由”,即连在相同网络中的设备,都有相同的路由) struct flowi fl = { .nl_u = { .ip4_u = { .daddr = src, .saddr = dst, .tos = tos } }, .mark = mark, .iif = oif }; struct fib_result res; int no_addr, rpf; int ret; struct net *net; no_addr = rpf = 0; rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); if (in_dev) {//入接口没有ip地址 no_addr =1 no_addr = in_dev->ifa_list == NULL;//该接口开启防护,rpf = 1//纯复制而已..... rpf = IN_DEV_RPFILTER(in_dev); if (mark && !IN_DEV_SRC_VMARK(in_dev)) fl.mark = 0; } rcu_read_unlock(); if (in_dev == NULL) goto e_inval; net = dev_net(dev);//........又查了一次路由//如果没有查到,即我没有到你的路由goto last_resort;在 last_resort中判断if (rpf),即判断是否开启了防护 if (fib_lookup(net, &fl, &res)) goto last_resort;//如果查询的结果不是RTN_UNICAST,不行。你这个报文到这是RTN_UNICAST的,而我到你却不是RTN_UNICAST的,扔掉。 if (res.type != RTN_UNICAST) goto e_inval_res; *spec_dst = FIB_RES_PREFSRC(res); fib_combine_itag(itag, &res);//如果我查询的出接口,和你报文的入接口时一个,那么ok,我认为你是合法的。#ifdef CONFIG_IP_ROUTE_MULTIPATH if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)#else if (FIB_RES_DEV(res) == dev)#endif { ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; fib_res_put(&res); return ret; }//到这步了,表示查询到了我到你的路由,但是出接口和你入接口不匹配 fib_res_put(&res);//我的入接口压根没有ip地址,你怎么可能发给我的?扔了 if (no_addr) goto last_resort;//我的入接口有ip,但是我开启了攻击防护,我认为“我发给你的出接口和你发给我的入接口不匹配”这个行为,是攻击行为,扔掉 if (rpf == 1) goto e_inval;//到这表示,我没有开启安全防护,入接口有ip,而你给我的报文不是从这我查询的出接口出去的//勉强通过,不过我得看看是否可以从我查询的出接口,有到你的路由,即指定出接口查询路由。如果查询成功,就表示,//从你这个入口出去,其实也可以到达你,所以算了,放过你吧,不扔掉你了。 fl.oif = dev->ifindex; ret = 0; if (fib_lookup(net, &fl, &res) == 0) { if (res.type == RTN_UNICAST) { *spec_dst = FIB_RES_PREFSRC(res); ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; } fib_res_put(&res); } return ret;//扔掉last_resort: if (rpf) goto e_inval; *spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); *itag = 0; return 0;e_inval_res: fib_res_put(&res);e_inval: return -EINVAL;}
阅读全文
0 0
- linux内核路由模块fib_valid_source函数(反向路由检测)
- Linux路由设置 反向路由设置
- linux 内核路由技术
- linux内核路由表
- 反向路由
- 查看 Linux 内核路由表
- 查看 Linux 内核路由表
- 查看 Linux 内核路由表
- 路由模块
- linux路由内核实现分析(三)---路由查找过程
- linux路由内核实现分析(四)---路由缓存机制
- linux路由内核实现分析(三)---路由查找过程
- linux路由内核实现分析(四)---路由缓存机制(1)
- linux路由内核实现分析(四)---路由缓存机制(2)
- linux路由内核实现分析(四)---路由缓存机制(3)
- linux路由内核实现分析(四)---路由缓存机制(4)
- Linux内核工程导论——网络:路由:路由原理
- 反向代理(Reverse Proxy)及 IIS 7 应用请求路由模块
- VS关闭突出显示当前行
- 在keil仿真中遇见的一些问题
- 搭建 Linux 下 GitLab 服务器
- sql 循环
- webview跳转加载数据
- linux内核路由模块fib_valid_source函数(反向路由检测)
- js 手动计算fontsize
- 详解Windows7下使用Eclipse搭建hadoop开发环境
- Rxjava2源码分析(三)
- 使用python编写虚拟机解释器
- synchronized同步方法
- vue中传多选项数据到后台(判断数组中是否存在该项,存在则删除,不存在则添加)
- Android下使用CMake链接已有静态库.a生成新的静态库.a,以及动态库.so链接静态库生成新的动态库.so
- 今天又学习了新的函数