📄 route.c
字号:
struct rtable *rth; u32 spec_dst; struct in_device *in_dev = dev->ip_ptr; u32 itag = 0; /* Primary sanity checks. */ if (MULTICAST(saddr) || BADCLASS(saddr) || LOOPBACK(saddr) || in_dev == NULL || skb->protocol != __constant_htons(ETH_P_IP)) return -EINVAL; if (ZERONET(saddr)) { if (!LOCAL_MCAST(daddr)) return -EINVAL; spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); } else if (fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, &itag) < 0) return -EINVAL; rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops); if (!rth) return -ENOBUFS; rth->u.dst.output= ip_rt_bug; atomic_set(&rth->u.dst.use, 1); rth->key.dst = daddr; rth->rt_dst = daddr; rth->key.tos = tos;#ifdef CONFIG_IP_ROUTE_FWMARK rth->key.fwmark = skb->fwmark;#endif rth->key.src = saddr; rth->rt_src = saddr;#ifdef CONFIG_IP_ROUTE_NAT rth->rt_dst_map = daddr; rth->rt_src_map = saddr;#endif#ifdef CONFIG_NET_CLS_ROUTE rth->u.dst.tclassid = itag;#endif rth->rt_iif = rth->key.iif = dev->ifindex; rth->u.dst.dev = &loopback_dev; rth->key.oif = 0; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; rth->rt_type = RTN_MULTICAST; rth->rt_flags = RTCF_MULTICAST; if (our) { rth->u.dst.input= ip_local_deliver; rth->rt_flags |= RTCF_LOCAL; }#ifdef CONFIG_IP_MROUTE if (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev)) rth->u.dst.input = ip_mr_input;#endif hash = rt_hash_code(daddr, saddr^(dev->ifindex<<5), tos); return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);}/* * NOTE. We drop all the packets that has local source * addresses, because every properly looped back packet * must have correct destination already attached by output routine. * * Such approach solves two big problems: * 1. Not simplex devices are handled properly. * 2. IP spoofing attempts are filtered with 100% of guarantee. */int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, u8 tos, struct device *dev){ struct rt_key key; struct fib_result res; struct in_device *in_dev = dev->ip_ptr; struct in_device *out_dev; unsigned flags = 0; u32 itag = 0; struct rtable * rth; unsigned hash; u32 spec_dst; int err = -EINVAL; /* * IP on this device is disabled. */ if (!in_dev) return -EINVAL; key.dst = daddr; key.src = saddr; key.tos = tos;#ifdef CONFIG_IP_ROUTE_FWMARK key.fwmark = skb->fwmark;#endif key.iif = dev->ifindex; key.oif = 0; key.scope = RT_SCOPE_UNIVERSE; hash = rt_hash_code(daddr, saddr^(key.iif<<5), tos); /* Check for the most weird martians, which can be not detected by fib_lookup. */ if (MULTICAST(saddr) || BADCLASS(saddr) || LOOPBACK(saddr)) goto martian_source; if (daddr == 0xFFFFFFFF || (saddr == 0 && daddr == 0)) goto brd_input; /* Accept zero addresses only to limited broadcast; * I even do not know to fix it or not. Waiting for complains :-) */ if (ZERONET(saddr)) goto martian_source; if (BADCLASS(daddr) || ZERONET(daddr) || LOOPBACK(daddr)) goto martian_destination; /* * Now we are ready to route packet. */ if ((err = fib_lookup(&key, &res))) { if (!IN_DEV_FORWARD(in_dev)) return -EINVAL; goto no_route; }#ifdef CONFIG_IP_ROUTE_NAT /* Policy is applied before mapping destination, but rerouting after map should be made with old source. */ if (1) { u32 src_map = saddr; if (res.r) src_map = fib_rules_policy(saddr, &res, &flags); if (res.type == RTN_NAT) { key.dst = fib_rules_map_destination(daddr, &res); if (fib_lookup(&key, &res) || res.type != RTN_UNICAST) return -EINVAL; flags |= RTCF_DNAT; } key.src = src_map; }#endif if (res.type == RTN_BROADCAST) goto brd_input; if (res.type == RTN_LOCAL) { int result; result = fib_validate_source(saddr, daddr, tos, loopback_dev.ifindex, dev, &spec_dst, &itag); if (result < 0) goto martian_source; if (result) flags |= RTCF_DIRECTSRC; spec_dst = daddr; goto local_input; } if (!IN_DEV_FORWARD(in_dev)) return -EINVAL; if (res.type != RTN_UNICAST) goto martian_destination;#ifdef CONFIG_IP_ROUTE_MULTIPATH if (res.fi->fib_nhs > 1 && key.oif == 0) fib_select_multipath(&key, &res);#endif out_dev = FIB_RES_DEV(res)->ip_ptr; if (out_dev == NULL) { if (net_ratelimit()) printk(KERN_CRIT "Bug in ip_route_input_slow(). Please, report\n"); return -EINVAL; } err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(res), dev, &spec_dst, &itag); if (err < 0) goto martian_source; if (err) flags |= RTCF_DIRECTSRC; if (out_dev == in_dev && err && !(flags&(RTCF_NAT|RTCF_MASQ)) && (IN_DEV_SHARED_MEDIA(out_dev) || inet_addr_onlink(out_dev, saddr, FIB_RES_GW(res)))) flags |= RTCF_DOREDIRECT; if (skb->protocol != __constant_htons(ETH_P_IP)) { /* Not IP (i.e. ARP). Do not create route, if it is * invalid for proxy arp. DNAT routes are always valid. */ if (out_dev == in_dev && !(flags&RTCF_DNAT)) return -EINVAL; } rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops); if (!rth) return -ENOBUFS; atomic_set(&rth->u.dst.use, 1); rth->key.dst = daddr; rth->rt_dst = daddr; rth->key.tos = tos;#ifdef CONFIG_IP_ROUTE_FWMARK rth->key.fwmark = skb->fwmark;#endif rth->key.src = saddr; rth->rt_src = saddr; rth->rt_gateway = daddr;#ifdef CONFIG_IP_ROUTE_NAT rth->rt_src_map = key.src; rth->rt_dst_map = key.dst; if (flags&RTCF_DNAT) rth->rt_gateway = key.dst;#endif rth->rt_iif = rth->key.iif = dev->ifindex; rth->u.dst.dev = out_dev->dev; rth->key.oif = 0; rth->rt_spec_dst= spec_dst; rth->u.dst.input = ip_forward; rth->u.dst.output = ip_output; rt_set_nexthop(rth, &res, itag); rth->rt_flags = flags;#ifdef CONFIG_NET_FASTROUTE if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT))) { struct device *odev = rth->u.dst.dev; if (odev != dev && dev->accept_fastpath && odev->mtu >= dev->mtu && dev->accept_fastpath(dev, &rth->u.dst) == 0) rth->rt_flags |= RTCF_FAST; }#endif return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);brd_input: if (skb->protocol != __constant_htons(ETH_P_IP)) return -EINVAL; if (ZERONET(saddr)) { spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); } else { err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, &itag); if (err < 0) goto martian_source; if (err) flags |= RTCF_DIRECTSRC; } flags |= RTCF_BROADCAST; res.type = RTN_BROADCAST;local_input: rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops); if (!rth) return -ENOBUFS; rth->u.dst.output= ip_rt_bug; atomic_set(&rth->u.dst.use, 1); rth->key.dst = daddr; rth->rt_dst = daddr; rth->key.tos = tos;#ifdef CONFIG_IP_ROUTE_FWMARK rth->key.fwmark = skb->fwmark;#endif rth->key.src = saddr; rth->rt_src = saddr;#ifdef CONFIG_IP_ROUTE_NAT rth->rt_dst_map = key.dst; rth->rt_src_map = key.src;#endif#ifdef CONFIG_NET_CLS_ROUTE rth->u.dst.tclassid = itag;#endif rth->rt_iif = rth->key.iif = dev->ifindex; rth->u.dst.dev = &loopback_dev; rth->key.oif = 0; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; rth->u.dst.input= ip_local_deliver; rth->rt_flags = flags|RTCF_LOCAL; if (res.type == RTN_UNREACHABLE) { rth->u.dst.input= ip_error; rth->u.dst.error= -err; rth->rt_flags &= ~RTCF_LOCAL; } rth->rt_type = res.type; return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);no_route: spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); res.type = RTN_UNREACHABLE; goto local_input; /* * Do not cache martian addresses: they should be logged (RFC1812) */martian_destination:#ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) printk(KERN_WARNING "martian destination %08x from %08x, dev %s\n", daddr, saddr, dev->name);#endif return -EINVAL;martian_source:#ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) { /* * RFC1812 recommenadtion, if source is martian, * the only hint is MAC header. */ printk(KERN_WARNING "martian source %08x for %08x, dev %s\n", saddr, daddr, dev->name); if (dev->hard_header_len) { int i; unsigned char *p = skb->mac.raw; printk(KERN_WARNING "ll header:"); for (i=0; i<dev->hard_header_len; i++, p++) printk(" %02x", *p); printk("\n"); } }#endif return -EINVAL;}int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, u8 tos, struct device *dev){ struct rtable * rth; unsigned hash; int iif = dev->ifindex; tos &= IPTOS_TOS_MASK; hash = rt_hash_code(daddr, saddr^(iif<<5), tos); for (rth=rt_hash_table[hash]; rth; rth=rth->u.rt_next) { if (rth->key.dst == daddr && rth->key.src == saddr && rth->key.iif == iif && rth->key.oif == 0 &&#ifdef CONFIG_IP_ROUTE_FWMARK rth->key.fwmark == skb->fwmark &&#endif rth->key.tos == tos) { rth->u.dst.lastuse = jiffies; atomic_inc(&rth->u.dst.use); atomic_inc(&rth->u.dst.refcnt); skb->dst = (struct dst_entry*)rth; return 0; } } /* Multicast recognition logic is moved from route cache to here. The problem was that too many Ethernet cards have broken/missing hardware multicast filters :-( As result the host on multicasting network acquires a lot of useless route cache entries, sort of SDR messages from all the world. Now we try to get rid of them. Really, provided software IP multicast filter is organized reasonably (at least, hashed), it does not result in a slowdown comparing with route cache reject entries. Note, that multicast routers are not affected, because route cache entry is created eventually. */ if (MULTICAST(daddr)) { int our = ip_check_mc(dev, daddr); if (!our#ifdef CONFIG_IP_MROUTE && (LOCAL_MCAST(daddr) || !dev->ip_ptr || !IN_DEV_MFORWARD((struct in_device*)dev->ip_ptr))#endif ) return -EINVAL; return ip_route_input_mc(skb, daddr, saddr, tos, dev, our); } return ip_route_input_slow(skb, daddr, saddr, tos, dev);}/* * Major route resolver routine. */int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif){ struct rt_key key; struct fib_result res; unsigned flags = 0; struct rtable *rth; struct device *dev_out = NULL; unsigned hash;#ifdef CONFIG_IP_TRANSPARENT_PROXY u32 nochecksrc = (tos & RTO_TPROXY);#endif tos &= IPTOS_TOS_MASK|RTO_ONLINK; key.dst = daddr; key.src = saddr; key.tos = tos&IPTOS_TOS_MASK; key.iif = loopback_dev.ifindex; key.oif = oif; key.scope = (tos&RTO_ONLINK) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; res.fi = NULL;#ifdef CONFIG_IP_MULTIPLE_TABLES res.r = NULL;#endif if (saddr) { if (MULTICAST(saddr) || BADCLASS(saddr) || ZERONET(saddr)) return -EINVAL; /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ dev_out = ip_dev_find(saddr);#ifdef CONFIG_IP_TRANSPARENT_PROXY /* If address is not local, test for transparent proxy flag; if address is local --- clear the flag. */ if (dev_out == NULL) { if (nochecksrc == 0 || inet_addr_type(saddr) != RTN_UNICAST) return -EINVAL; flags |= RTCF_TPROXY; }#else if (dev_out == NULL) return -EINVAL;#endif /* I removed check for oif == dev_out->oif here. It was wrong by three reasons: 1. ip_dev_find(saddr) can return wrong iface, if saddr is assigned to multiple interfaces. 2. Moreover, we are allowed to send packets with saddr of another iface. --ANK */ if (oif == 0 &&#ifdef CONFIG_IP_TRANSPARENT_PROXY dev_out &&#endif (MULTICAST(daddr) || daddr == 0xFFFFFFFF)) { /* Special hack: user can direct multicasts and limited broadcast via necessary interface without fiddling with IP_MULTICAST_IF or IP_PKTINFO. This hack is not just for fun, it allows vic,vat and friends to work. They bind socket to loopback, set ttl to zero and expect that it will work. From the viewpoint of routing cache they are broken, because we are not allowed to build multicast path with loopback source addr (look, routing cache cannot know, that ttl is zero, so that packet will not leave this host and route is valid). Luckily, this hack is good workaround. */ key.oif = dev_out->ifindex; goto make_route; } dev_out = NULL; } if (oif) { dev_out = dev_get_by_index(oif); if (dev_out == NULL) return -ENODEV; if (dev_out->ip_ptr == NULL) return -ENODEV; /* Wrong error code */ if (LOCAL_MCAST(daddr) || daddr == 0xFFFFFFFF) { if (!key.src) key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK); goto make_route; } if (!key.src) { if (MULTICAST(daddr)) key.src = inet_select_addr(dev_out, 0, key.scope); else if (!daddr) key.src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST); } } if (!key.dst) { key.dst = key.src; if (!key.dst) key.dst = key.src = htonl(INADDR_LOOPBACK); dev_out = &loopback_dev; key.oif = loopback_dev.ifindex; res.type = RTN_LOCAL; flags |= RTCF_LOCAL; goto make_route; } if (fib_lookup(&key, &res)) { res.fi = NULL; if (oif) { /* Apparently, routing tables are wrong. Assume, that the destination is on link. WHY? DW. Because we are allowed to send to iface even if it has NO routes and NO assigned
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -