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

📄 icmp.c

📁 ipv6地址转换器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Internet Control Message Protocol (ICMPv6) *	Linux INET6 implementation * *	Authors: *	Pedro Roque		<roque@di.fc.ul.pt> * *	$Id: icmp.c,v 1.21.2.1 1999/05/19 22:07:36 davem Exp $ * *	Based on net/ipv4/icmp.c * *	RFC 1885 * *	This program is free software; you can redistribute it and/or *      modify it under the terms of the GNU General Public License *      as published by the Free Software Foundation; either version *      2 of the License, or (at your option) any later version. *//* *	Changes: * *	Andi Kleen		:	exception handling *	Andi Kleen			add rate limits. never reply to a icmp. *					add more length checks and other fixes. */#define __NO_VERSION__#include <linux/module.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/in.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/sockios.h>#include <linux/net.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/icmpv6.h>#include <net/ip.h>#include <net/sock.h>#include <net/ipv6.h>#include <net/checksum.h>#include <net/protocol.h>#include <net/raw.h>#include <net/rawv6.h>#include <net/transp_v6.h>#include <net/ip6_route.h>#include <net/addrconf.h>#include <net/icmp.h>#include <asm/uaccess.h>#include <asm/system.h>struct icmpv6_mib icmpv6_statistics;/* *	ICMP socket for flow control. */struct socket *icmpv6_socket;int icmpv6_rcv(struct sk_buff *skb, unsigned long len);static struct inet6_protocol icmpv6_protocol = {	icmpv6_rcv,		/* handler		*/	NULL,			/* error control	*/	NULL,			/* next			*/	IPPROTO_ICMPV6,		/* protocol ID		*/	0,			/* copy			*/	NULL,			/* data			*/	"ICMPv6"	       	/* name			*/};struct icmpv6_msg {	struct icmp6hdr		icmph;	__u8 			*data;	struct in6_addr		*daddr;	int			len;	__u32			csum;};/* *	getfrag callback */static int icmpv6_getfrag(const void *data, struct in6_addr *saddr, 			   char *buff, unsigned int offset, unsigned int len){	struct icmpv6_msg *msg = (struct icmpv6_msg *) data;	struct icmp6hdr *icmph;	__u32 csum;	/* 	 *	in theory offset must be 0 since we never send more 	 *	than IPV6_MIN_MTU bytes on an error or more than the path mtu	 *	on an echo reply. (those are the rules on RFC 1883)	 *	 * 	Luckily, this statement is obsolete after	 *	draft-ietf-ipngwg-icmp-v2-00           --ANK (980730)	 */	if (offset) {		csum = csum_partial_copy((void *) msg->data +					 offset - sizeof(struct icmp6hdr), 					 buff, len, msg->csum);		msg->csum = csum;		return 0;	}	csum = csum_partial_copy((void *) &msg->icmph, buff,				 sizeof(struct icmp6hdr), msg->csum);	csum = csum_partial_copy((void *) msg->data, 				 buff + sizeof(struct icmp6hdr),				 len - sizeof(struct icmp6hdr), csum);	icmph = (struct icmp6hdr *) buff;	icmph->icmp6_cksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,					     IPPROTO_ICMPV6, csum);	return 0; }/*  * Slightly more convenient version of icmpv6_send. */void icmpv6_param_prob(struct sk_buff *skb, int code, void *pos){	int offset = (u8*)pos - (u8*)skb->nh.ipv6h; 		icmpv6_send(skb, ICMPV6_PARAMPROB, code, offset, skb->dev);	kfree_skb(skb);}/* * Figure out, may we reply to this packet with icmp error. * * We do not reply, if: *	- it was icmp error message. *	- it is truncated, so that it is known, that protocol is ICMPV6 *	  (i.e. in the middle of some exthdr) *	- it is not the first fragment. BTW IPv6 specs say nothing about *	  this case, but it is clear, that our reply would be useless *	  for sender. * *	--ANK (980726) */static int is_ineligible(struct ipv6hdr *hdr, int len){	u8 *ptr;	__u8 nexthdr = hdr->nexthdr;	if (len < (int)sizeof(*hdr))		return 1;	ptr = ipv6_skip_exthdr((struct ipv6_opt_hdr *)(hdr+1), &nexthdr, len - sizeof(*hdr));	if (!ptr)		return 0;	if (nexthdr == IPPROTO_ICMPV6) {		struct icmp6hdr *ihdr =	(struct icmp6hdr *)ptr;		return (ptr - (u8*)hdr) > len || !(ihdr->icmp6_type & 0x80); 	}	return nexthdr == NEXTHDR_FRAGMENT;}int sysctl_icmpv6_time = 1*HZ; /*  * Check the ICMP output rate limit  */static inline int icmpv6_xrlim_allow(struct sock *sk, int type,				     struct flowi *fl){	struct dst_entry *dst;	int res = 0;	/* Informational messages are not limited. */	if (type & 0x80)		return 1;	/* Do not limit pmtu discovery, it would break it. */	if (type == ICMPV6_PKT_TOOBIG)		return 1;	/* 	 * Look up the output route.	 * XXX: perhaps the expire for routing entries cloned by	 * this lookup should be more aggressive (not longer than timeout).	 */	dst = ip6_route_output(sk, fl);	if (dst->error) {		ipv6_statistics.Ip6OutNoRoutes++;	} else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {		res = 1;	} else {		struct rt6_info *rt = (struct rt6_info *)dst;		int tmo = sysctl_icmpv6_time;		/* Give more bandwidth to wider prefixes. */		if (rt->rt6i_dst.plen < 128)			tmo >>= ((128 - rt->rt6i_dst.plen)>>5);		res = xrlim_allow(dst, tmo);	}	dst_release(dst);	return res;}/* *	an inline helper for the "simple" if statement below *	checks if parameter problem report is caused by an *	unrecognized IPv6 option that has the Option Type  *	highest-order two bits set to 10 */static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset){	u8 *buff = skb->nh.raw;	return ( ( *(buff + offset) & 0xC0 ) == 0x80 );}/* *	Send an ICMP message in response to a packet in error */void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, 		 struct device *dev){	struct ipv6hdr *hdr = skb->nh.ipv6h;	struct sock *sk = icmpv6_socket->sk;	struct in6_addr *saddr = NULL;	int iif = 0;	struct icmpv6_msg msg;	struct flowi fl;	int addr_type = 0;	int len;	/*	 *	sanity check pointer in case of parameter problem	 */	if (type == ICMPV6_PARAMPROB && 	    (info > (skb->tail - ((unsigned char *) hdr)))) {		printk(KERN_DEBUG "icmpv6_send: bug! pointer > skb\n");		return;	}	/*	 *	Make sure we respect the rules 	 *	i.e. RFC 1885 2.4(e)	 *	Rule (e.1) is enforced by not using icmpv6_send	 *	in any code that processes icmp errors.	 */		addr_type = ipv6_addr_type(&hdr->daddr);	if (ipv6_chk_addr(&hdr->daddr, skb->dev, 0))		saddr = &hdr->daddr;	/*	 *	Dest addr check	 */	if ((addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST)) {		if (type != ICMPV6_PKT_TOOBIG &&		    !(type == ICMPV6_PARAMPROB && 		      code == ICMPV6_UNK_OPTION && 		      (opt_unrec(skb, info))))			return;		saddr = NULL;	}	addr_type = ipv6_addr_type(&hdr->saddr);	/*	 *	Source addr check	 */	if (addr_type & IPV6_ADDR_LINKLOCAL)		iif = skb->dev->ifindex;	/*	 *	Must not send if we know that source is Anycast also.	 *	for now we don't know that.	 */	if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {		printk(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n");		return;	}	/* 	 *	Never answer to a ICMP packet.	 */	if (is_ineligible(hdr, (u8*)skb->tail - (u8*)hdr)) {		if (net_ratelimit())			printk(KERN_DEBUG "icmpv6_send: no reply to icmp error/fragment\n"); 		return;	}	fl.proto = IPPROTO_ICMPV6;	fl.nl_u.ip6_u.daddr = &hdr->saddr;	fl.nl_u.ip6_u.saddr = saddr;	fl.oif = iif;	fl.fl6_flowlabel = 0;	fl.uli_u.icmpt.type = type;	fl.uli_u.icmpt.code = code;	if (!icmpv6_xrlim_allow(sk, type, &fl)) 		return; 	/*	 *	ok. kick it. checksum will be provided by the 	 *	getfrag_t callback.	 */	msg.icmph.icmp6_type = type;	msg.icmph.icmp6_code = code;	msg.icmph.icmp6_cksum = 0;	msg.icmph.icmp6_pointer = htonl(info);	msg.data = skb->nh.raw;	msg.csum = 0;	msg.daddr = &hdr->saddr;

⌨️ 快捷键说明

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