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

📄 route.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
#ifdef CONFIG_IP_MROUTE	if (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev))		rth->u.dst.input = ip_mr_input;#endif	RT_CACHE_STAT_INC(in_slow_mc);	in_dev_put(in_dev);	hash = rt_hash(daddr, saddr, dev->ifindex);	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;}static void ip_handle_martian_source(struct net_device *dev,				     struct in_device *in_dev,				     struct sk_buff *skb,				     __be32 daddr,				     __be32 saddr){	RT_CACHE_STAT_INC(in_martian_src);#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 && skb_mac_header_was_set(skb)) {			int i;			const unsigned char *p = skb_mac_header(skb);			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}static inline 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){	struct rtable *rth;	int err;	struct in_device *out_dev;	unsigned flags = 0;	__be32 spec_dst;	u32 itag;	/* get a working reference to the output device */	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");		return -EINVAL;	}	err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(*res),				  in_dev->dev, &spec_dst, &itag);	if (err < 0) {		ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr,					 saddr);		err = -EINVAL;		goto cleanup;	}	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 != 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)) {			err = -EINVAL;			goto cleanup;		}	}	rth = dst_alloc(&ipv4_dst_ops);	if (!rth) {		err = -ENOBUFS;		goto cleanup;	}	atomic_set(&rth->u.dst.__refcnt, 1);	rth->u.dst.flags= DST_HOST;	if (IN_DEV_CONF_GET(in_dev, NOPOLICY))		rth->u.dst.flags |= DST_NOPOLICY;	if (IN_DEV_CONF_GET(out_dev, NOXFRM))		rth->u.dst.flags |= DST_NOXFRM;	rth->fl.fl4_dst	= daddr;	rth->rt_dst	= daddr;	rth->fl.fl4_tos	= tos;	rth->fl.mark    = skb->mark;	rth->fl.fl4_src	= saddr;	rth->rt_src	= saddr;	rth->rt_gateway	= daddr;	rth->rt_iif 	=		rth->fl.iif	= in_dev->dev->ifindex;	rth->u.dst.dev	= (out_dev)->dev;	dev_hold(rth->u.dst.dev);	rth->idev	= in_dev_get(rth->u.dst.dev);	rth->fl.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;	*result = rth;	err = 0; cleanup:	/* release the working reference to the output device */	in_dev_put(out_dev);	return err;}static inline int ip_mkroute_input(struct sk_buff *skb,				   struct fib_result* res,				   const struct flowi *fl,				   struct in_device *in_dev,				   __be32 daddr, __be32 saddr, u32 tos){	struct rtable* rth = NULL;	int err;	unsigned hash;#ifdef CONFIG_IP_ROUTE_MULTIPATH	if (res->fi && res->fi->fib_nhs > 1 && fl->oif == 0)		fib_select_multipath(fl, res);#endif	/* create a routing cache entry */	err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth);	if (err)		return err;	/* put it into the cache */	hash = rt_hash(daddr, saddr, fl->iif);	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. */static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,			       u8 tos, struct net_device *dev){	struct fib_result res;	struct in_device *in_dev = in_dev_get(dev);	struct flowi fl = { .nl_u = { .ip4_u =				      { .daddr = daddr,					.saddr = saddr,					.tos = tos,					.scope = RT_SCOPE_UNIVERSE,				      } },			    .mark = skb->mark,			    .iif = dev->ifindex };	unsigned	flags = 0;	u32		itag = 0;	struct rtable * rth;	unsigned	hash;	__be32		spec_dst;	int		err = -EINVAL;	int		free_res = 0;	/* IP on this device is disabled. */	if (!in_dev)		goto out;	/* 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 == htonl(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(&fl, &res)) != 0) {		if (!IN_DEV_FORWARD(in_dev))			goto e_hostunreach;		goto no_route;	}	free_res = 1;	RT_CACHE_STAT_INC(in_slow_tot);	if (res.type == RTN_BROADCAST)		goto brd_input;	if (res.type == RTN_LOCAL) {		int result;		result = fib_validate_source(saddr, daddr, tos,					     init_net.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_hostunreach;	if (res.type != RTN_UNICAST)		goto martian_destination;	err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);done:	in_dev_put(in_dev);	if (free_res)		fib_res_put(&res);out:	return err;brd_input:	if (skb->protocol != 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;	RT_CACHE_STAT_INC(in_brd);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;	if (IN_DEV_CONF_GET(in_dev, NOPOLICY))		rth->u.dst.flags |= DST_NOPOLICY;	rth->fl.fl4_dst	= daddr;	rth->rt_dst	= daddr;	rth->fl.fl4_tos	= tos;	rth->fl.mark    = skb->mark;	rth->fl.fl4_src	= saddr;	rth->rt_src	= saddr;#ifdef CONFIG_NET_CLS_ROUTE	rth->u.dst.tclassid = itag;#endif	rth->rt_iif	=	rth->fl.iif	= dev->ifindex;	rth->u.dst.dev	= init_net.loopback_dev;	dev_hold(rth->u.dst.dev);	rth->idev	= in_dev_get(rth->u.dst.dev);	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;	hash = rt_hash(daddr, saddr, fl.iif);	err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);	goto done;no_route:	RT_CACHE_STAT_INC(in_no_route);	spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);	res.type = RTN_UNREACHABLE;	if (err == -ESRCH)		err = -ENETUNREACH;	goto local_input;	/*	 *	Do not cache martian addresses: they should be logged (RFC1812)	 */martian_destination:	RT_CACHE_STAT_INC(in_martian_dst);#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_hostunreach:	err = -EHOSTUNREACH;	goto done;e_inval:	err = -EINVAL;	goto done;e_nobufs:	err = -ENOBUFS;	goto done;martian_source:	ip_handle_martian_source(dev, in_dev, skb, daddr, saddr);	goto e_inval;}int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,		   u8 tos, struct net_device *dev){	struct rtable * rth;	unsigned	hash;	int iif = dev->ifindex;	tos &= IPTOS_RT_MASK;	hash = rt_hash(daddr, saddr, iif);	rcu_read_lock();	for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;	     rth = rcu_dereference(rth->u.dst.rt_next)) {		if (rth->fl.fl4_dst == daddr &&		    rth->fl.fl4_src == saddr &&		    rth->fl.iif == iif &&		    rth->fl.oif == 0 &&		    rth->fl.mark == skb->mark &&		    rth->fl.fl4_tos == tos) {			dst_use(&rth->u.dst, jiffies);			RT_CACHE_STAT_INC(in_hit);			rcu_read_unlock();			skb->dst = (struct dst_entry*)rth;			return 0;		}		RT_CACHE_STAT_INC(in_hlist_search);	}	rcu_read_unlock();	/* 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;		rcu_read_lock();		if ((in_dev = __in_dev_get_rcu(dev)) != NULL) {			int our = ip_check_mc(in_dev, daddr, saddr,				ip_hdr(skb)->protocol);			if (our#ifdef CONFIG_IP_MROUTE			    || (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev))#endif			    ) {				rcu_read_unlock();				return ip_route_input_mc(skb, daddr, saddr,							 tos, dev, our);			}		}		rcu_read_unlock();		return -EINVAL;	}	return ip_route_input_slow(skb, daddr, saddr, tos, dev);}static inline int __mkroute_output(struct rtable **result,				   struct fib_result* res,				   const struct flowi *fl,				   const struct flowi *oldflp,				   struct net_device *dev_out,				   unsigned flags){	struct rtable *rth;	struct in_device *in_dev;	u32 tos = RT_FL_TOS(oldflp);	int err = 0;	if (LOOPBACK(fl->fl4_src) && !(dev_out->flags&IFF_LOOPBACK))		return -EINVAL;	if (fl->fl4_dst == htonl(0xFFFFFFFF))		res->type = RTN_BROADCAST;	else if (MULTICAST(fl->fl4_dst))		res->type = RTN_MULTICAST;	else if (BADCLASS(fl->fl4_dst) || ZERONET(fl->fl4_dst))		return -EINVAL;	if (dev_out->flags & IFF_LOOPBACK)		flags |= RTCF_LOCAL;	/* get work reference to inet device */	in_dev = in_dev_get(dev_out);	if (!in_dev)		return -EINVAL;	if (res->type == RTN_BROADCAST) {		flags |= RTCF_BROADCAST | RTCF_LOCAL;		if (res->fi) {			fib_info_put(res->fi);			res->fi = NULL;		}	} else if (res->type == RTN_MULTICAST) {		flags |= RTCF_MULTICAST|RTCF_LOCAL;		if (!ip_check_mc(in_dev, oldflp->fl4_dst, oldflp->fl4_src,				 oldflp->proto))			flags &= ~RTCF_LOCAL;		/* If multicast route do not exist use		   default one, but do not gateway in this case.		   Yes, it is hack.		 */		if (res->fi && res->prefixlen < 4) {			fib_info_put(res->fi);			res->fi = NULL;		}	}	rth = dst_alloc(&ipv4_dst_ops);	if (!rth) {		err = -ENOBUFS;		goto cleanup;	}	atomic_set(&rth->u.dst.__refcnt, 1);	rth->u.dst.flags= DST_HOST;	if (IN_DEV_CONF_GET(in_dev, NOXFRM))		rth->u.dst.flags |= DST_NOXFRM;	if (IN_DEV_CONF_GET(in_dev, NOPOLICY))		rth->u.dst.flags |= DST_NOPOLICY;	rth->fl.fl4_dst	= oldflp->fl4_dst;	rth->fl.fl4_tos	= tos;	rth->fl.fl4_src	= oldflp->fl4_src;	rth->fl.oif	= oldflp->oif;	rth->fl.mark    = oldflp->mark;	rth->rt_dst	= fl->fl4_dst;	rth->rt_src	= fl->fl4_src;	rth->rt_iif	= oldflp->oif ? : dev_out->ifindex;	/* get references to the devices that are to be hold by the routing	   cache entry */	rth->u.dst.dev	= dev_out;	dev_hold(dev_out);	rth->idev	= in_dev_get(dev_out);	rth->rt_gateway = fl->fl4_dst;	rth->rt_spec_dst= fl->fl4_src;	rth->u.dst.output=ip_output;	RT_CACHE_STAT_INC(out_slow_tot);	if (flags & RTCF_LOCAL) {		rth->u.dst.input = ip_local_deliver;		rth->rt_spec_dst = fl->fl4_dst;	}	if (flags & (RTCF_BROADCAST | RTCF_MULTICAST)) {		rth->rt_spec_dst = fl->fl4_src;		if (flags & RTCF_LOCAL &&		    !(dev_out->flags & IFF_LOOPBACK)) {			rth->u.dst.output = ip_mc_output;			RT_CACHE_STAT_INC(out_slow_mc);		}

⌨️ 快捷键说明

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