⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 route.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (ZERONET(saddr)) {		if (!LOCAL_MCAST(daddr))			goto e_inval;		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);	} else if (fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, &itag) < 0)		goto e_inval;	rth = dst_alloc(&ipv4_dst_ops);	if (!rth)		goto e_nobufs;	rth->u.dst.output= ip_rt_bug;	atomic_set(&rth->u.dst.__refcnt, 1);	rth->u.dst.flags= DST_HOST;	rth->key.dst	= daddr;	rth->rt_dst	= daddr;	rth->key.tos	= tos;#ifdef CONFIG_IP_ROUTE_FWMARK	rth->key.fwmark	= skb->nfmark;#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;	dev_hold(rth->u.dst.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	in_dev_put(in_dev);	hash = rt_hash_code(daddr, saddr^(dev->ifindex<<5), tos);	return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);e_nobufs:	in_dev_put(in_dev);	return -ENOBUFS;e_inval:	in_dev_put(in_dev);	return -EINVAL;}/* *	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 net_device *dev){	struct rt_key	key;	struct fib_result res;	struct in_device *in_dev = in_dev_get(dev);	struct in_device *out_dev = NULL;	unsigned	flags = 0;	u32		itag = 0;	struct rtable * rth;	unsigned	hash;	u32		spec_dst;	int		err = -EINVAL;	int		free_res = 0;	/*	 *	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->nfmark;#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)) != 0) {		if (!IN_DEV_FORWARD(in_dev))			goto e_inval;		goto no_route;	}	free_res = 1;#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);			fib_res_put(&res);			free_res = 0;			if (fib_lookup(&key, &res))				goto e_inval;			free_res = 1;			if (res.type != RTN_UNICAST)				goto e_inval;			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))		goto e_inval;	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 = in_dev_get(FIB_RES_DEV(res));	if (out_dev == NULL) {		if (net_ratelimit())			printk(KERN_CRIT "Bug in ip_route_input_slow(). Please, report\n");		goto e_inval;	}	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))			goto e_inval;	}	rth = dst_alloc(&ipv4_dst_ops);	if (!rth)		goto e_nobufs;	atomic_set(&rth->u.dst.__refcnt, 1);	rth->u.dst.flags= DST_HOST;	rth->key.dst	= daddr;	rth->rt_dst	= daddr;	rth->key.tos	= tos;#ifdef CONFIG_IP_ROUTE_FWMARK	rth->key.fwmark	= skb->nfmark;#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;	dev_hold(rth->u.dst.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 net_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;	}#endifintern:	err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);done:	in_dev_put(in_dev);	if (out_dev)		in_dev_put(out_dev);	if (free_res)		fib_res_put(&res);	return err;brd_input:	if (skb->protocol != __constant_htons(ETH_P_IP))		goto e_inval;	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(&ipv4_dst_ops);	if (!rth)		goto e_nobufs;	rth->u.dst.output= ip_rt_bug;	atomic_set(&rth->u.dst.__refcnt, 1);	rth->u.dst.flags= DST_HOST;	rth->key.dst	= daddr;	rth->rt_dst	= daddr;	rth->key.tos	= tos;#ifdef CONFIG_IP_ROUTE_FWMARK	rth->key.fwmark	= skb->nfmark;#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;	dev_hold(rth->u.dst.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;	goto intern;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 %u.%u.%u.%u from %u.%u.%u.%u, dev %s\n",			NIPQUAD(daddr), NIPQUAD(saddr), dev->name);#endife_inval:	err = -EINVAL;	goto done;e_nobufs:	err = -ENOBUFS;	goto done;martian_source:#ifdef CONFIG_IP_ROUTE_VERBOSE	if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) {		/*		 *	RFC1812 recommendation, if source is martian,		 *	the only hint is MAC header.		 */		printk(KERN_WARNING "martian source %u.%u.%u.%u from %u.%u.%u.%u, on dev %s\n",			NIPQUAD(daddr), NIPQUAD(saddr), 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);				if(i<(dev->hard_header_len-1))					printk(":");			}			printk("\n");		}	}#endif	goto e_inval;}int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,		   u8 tos, struct net_device *dev){	struct rtable * rth;	unsigned	hash;	int iif = dev->ifindex;	tos &= IPTOS_RT_MASK;	hash = rt_hash_code(daddr, saddr^(iif<<5), tos);	read_lock(&rt_hash_table[hash].lock);	for (rth=rt_hash_table[hash].chain; 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->nfmark &&#endif		    rth->key.tos == tos) {			rth->u.dst.lastuse = jiffies;			dst_hold(&rth->u.dst);			rth->u.dst.__use++;			read_unlock(&rt_hash_table[hash].lock);			skb->dst = (struct dst_entry*)rth;			return 0;		}	}	read_unlock(&rt_hash_table[hash].lock);	/* 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)) {		struct in_device *in_dev;		read_lock(&inetdev_lock);		if ((in_dev = __in_dev_get(dev)) != NULL) {			int our = ip_check_mc(in_dev, daddr);			if (our#ifdef CONFIG_IP_MROUTE			    || (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev))#endif			    ) {				read_unlock(&inetdev_lock);				return ip_route_input_mc(skb, daddr, saddr, tos, dev, our);			}		}		read_unlock(&inetdev_lock);		return -EINVAL;	}	return ip_route_input_slow(skb, daddr, saddr, tos, dev);}/* * Major route resolver routine. */int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey){	struct rt_key key;	struct fib_result res;	unsigned flags = 0;	struct rtable *rth;	struct net_device *dev_out = NULL;	unsigned hash;	int free_res = 0;	int err;	u32 tos;	tos = oldkey->tos & (IPTOS_RT_MASK|RTO_ONLINK);	key.dst = oldkey->dst;	key.src = oldkey->src;	key.tos = tos&IPTOS_RT_MASK;	key.iif = loopback_dev.ifindex;	key.oif = oldkey->oif;#ifdef CONFIG_IP_ROUTE_FWMARK	key.fwmark = oldkey->fwmark;#endif	key.scope = (tos&RTO_ONLINK) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;	res.fi = NULL;#ifdef CONFIG_IP_MULTIPLE_TABLES	res.r = NULL;#endif	if (oldkey->src) {		if (MULTICAST(oldkey->src)		    || BADCLASS(oldkey->src)		    || ZERONET(oldkey->src))			return -EINVAL;		/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */		dev_out = ip_dev_find(oldkey->src);		if (dev_out == NULL)			return -EINVAL;		/* 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 (oldkey->oif == 0		    && (MULTICAST(oldkey->dst) || oldkey->dst == 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;		}		if (dev_out)			dev_put(dev_out);		dev_out = NULL;	}	if (oldkey->oif) {		dev_out = dev_get_by_index(oldkey->oif);		if (dev_out == NULL)			return -ENODEV;		if (__in_dev_get(dev_out) == NULL) {			dev_put(dev_out);			return -ENODEV;	/* Wrong error code */		}		if (LOCAL_MCAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF) {			if (!key.src)				key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK);			goto make_route;		}		if (!key.src) {			if (MULTICAST(oldkey->dst))				key.src = inet_select_addr(dev_out, 0, key.scope);			else if (!oldkey->dst)				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);		if (dev_out)			dev_put(dev_out);		dev_out = &loopback_dev;		dev_hold(dev_out);		key.oif = loopback_dev.ifindex;		res.type = RTN_LOCAL;		flags |= RTCF_LOCAL;		goto make_route;	}	if (fib_lookup(&key, &res)) {		res.fi = NULL;		if (oldkey->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			   addresses. When oif is specified, routing			   tables are looked up with only one purpose:			   to catch if destination is gatewayed, rather than			   direct. Moreover, if MSG_DONTROUTE is set,			   we send packet, ignoring both routing tables			   and ifaddr state. --ANK			   We could make it even if oif is unknown,			   likely IPv6, but we do not.			 */			if (key.src == 0)				key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK);			res.type = RTN_UNICAST;			goto make_route;		}		if (dev_out)			dev_put(dev_out);		return -ENETUNREACH;	}	free_res = 1;	if (res.type == RTN_NAT)		goto e_inval;	if (res.type == RTN_LOCAL) {		if (!key.src)			key.src = key.dst;		if (dev_out)			dev_put(dev_out);		dev_out = &loopback_dev;		dev_hold(dev_out);		key.oif = dev_out->ifindex;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -