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

📄 icmp.c

📁 GNU Hurd 源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 * 	Shared between ICMPv4 and ICMPv6. */#define XRLIM_BURST_FACTOR 6int xrlim_allow(struct dst_entry *dst, int timeout){	unsigned long now;	now = jiffies;	dst->rate_tokens += now - dst->rate_last;	dst->rate_last = now;	if (dst->rate_tokens > XRLIM_BURST_FACTOR*timeout)		dst->rate_tokens = XRLIM_BURST_FACTOR*timeout;	if (dst->rate_tokens >= timeout) {		dst->rate_tokens -= timeout;		return 1;	}	return 0; }static inline int icmpv4_xrlim_allow(struct rtable *rt, int type, int code){	struct dst_entry *dst = &rt->u.dst; 	if (type > NR_ICMP_TYPES || !icmp_pointers[type].timeout)		return 1;	/* Don't limit PMTU discovery. */	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)		return 1;	/* Redirect has its own rate limit mechanism */	if (type == ICMP_REDIRECT)		return 1;	/* No rate limit on loopback */	if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) 		return 1;	return xrlim_allow(dst, *(icmp_pointers[type].timeout));}/* *	Maintain the counters used in the SNMP statistics for outgoing ICMP */ static void icmp_out_count(int type){	if (type>NR_ICMP_TYPES)		return;	(*icmp_pointers[type].output)++;	icmp_statistics.IcmpOutMsgs++;} /* *	Checksum each fragment, and on the first include the headers and final checksum. */ static int icmp_glue_bits(const void *p, char *to, unsigned int offset, unsigned int fraglen){	struct icmp_bxm *icmp_param = (struct icmp_bxm *)p;	struct icmphdr *icmph;	unsigned long csum;	if (offset) {		icmp_param->csum=csum_partial_copy(icmp_param->data_ptr+offset-sizeof(struct icmphdr), 				to, fraglen,icmp_param->csum);		return 0;	}	/*	 *	First fragment includes header. Note that we've done	 *	the other fragments first, so that we get the checksum	 *	for the whole packet here.	 */	csum = csum_partial_copy((void *)&icmp_param->icmph,		to, sizeof(struct icmphdr), 		icmp_param->csum);	csum = csum_partial_copy(icmp_param->data_ptr,		to+sizeof(struct icmphdr),		fraglen-sizeof(struct icmphdr), csum);	icmph=(struct icmphdr *)to;	icmph->checksum = csum_fold(csum);	return 0;} /* *	Driving logic for building and sending ICMP messages. */static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb){	struct sock *sk=icmp_socket->sk;	struct ipcm_cookie ipc;	struct rtable *rt = (struct rtable*)skb->dst;	u32 daddr;	if (ip_options_echo(&icmp_param->replyopts, skb))		return;	icmp_param->icmph.checksum=0;	icmp_param->csum=0;	icmp_out_count(icmp_param->icmph.type);	sk->ip_tos = skb->nh.iph->tos;	daddr = ipc.addr = rt->rt_src;	ipc.opt = &icmp_param->replyopts;	if (ipc.opt->srr)		daddr = icmp_param->replyopts.faddr;	if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0))		return;	ip_build_xmit(sk, icmp_glue_bits, icmp_param, 		icmp_param->data_len+sizeof(struct icmphdr),		&ipc, rt, MSG_DONTWAIT);	ip_rt_put(rt);}/* *	Send an ICMP message in response to a situation * *	RFC 1122: 3.2.2	MUST send at least the IP header and 8 bytes of header. MAY send more (we do). *			MUST NOT change this header information. *			MUST NOT reply to a multicast/broadcast IP address. *			MUST NOT reply to a multicast/broadcast MAC address. *			MUST reply to only the first fragment. */void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info){	struct iphdr *iph;	struct icmphdr *icmph;	int room;	struct icmp_bxm icmp_param;	struct rtable *rt = (struct rtable*)skb_in->dst;	struct ipcm_cookie ipc;	u32 saddr;	u8  tos;		/*	 *	Find the original header	 */	 	iph = skb_in->nh.iph;		/*	 *	No replies to physical multicast/broadcast	 */	 	if (skb_in->pkt_type!=PACKET_HOST)		return;			/*	 *	Now check at the protocol level	 */	if (!rt) {                if (sysctl_ip_always_defrag == 0 &&                    net_ratelimit())			printk(KERN_DEBUG "icmp_send: destinationless packet\n");		return;	}	if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))		return;	 			/*	 *	Only reply to fragment 0. We byte re-order the constant	 *	mask for efficiency.	 */	 	if (iph->frag_off&htons(IP_OFFSET))		return;			/* 	 *	If we send an ICMP error to an ICMP error a mess would result..	 */	 	if (icmp_pointers[type].error) {		/*		 *	We are an error, check if we are replying to an ICMP error		 */		 		if (iph->protocol==IPPROTO_ICMP) {			icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));			/*			 *	Assume any unknown ICMP type is an error. This isn't			 *	specified by the RFC, but think about it..			 */			if (icmph->type>NR_ICMP_TYPES || icmp_pointers[icmph->type].error)				return;		}	}	/*	 *	Construct source address and options.	 */#ifdef CONFIG_IP_ROUTE_NAT		/*	 *	Restore original addresses if packet has been translated.	 */	if (rt->rt_flags&RTCF_NAT && IPCB(skb_in)->flags&IPSKB_TRANSLATED) {		iph->daddr = rt->key.dst;		iph->saddr = rt->key.src;	}#endif#ifdef CONFIG_IP_MASQUERADE	if (type==ICMP_DEST_UNREACH && IPCB(skb_in)->flags&IPSKB_MASQUERADED) {			ip_fw_unmasq_icmp(skb_in);	}#endif	saddr = iph->daddr;	if (!(rt->rt_flags & RTCF_LOCAL))		saddr = 0;	tos = icmp_pointers[type].error ?		((iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL) :			iph->tos;	/* XXX: use a more aggressive expire for routes created by 	 * this call (not longer than the rate limit timeout). 	 * It could be also worthwhile to not put them into ipv4	 * fast routing cache at first. Otherwise an attacker can	 * grow the routing table.	 */	if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))		return;		if (ip_options_echo(&icmp_param.replyopts, skb_in)) 		goto ende;	/*	 *	Prepare data for ICMP header.	 */	icmp_param.icmph.type=type;	icmp_param.icmph.code=code;	icmp_param.icmph.un.gateway = info;	icmp_param.icmph.checksum=0;	icmp_param.csum=0;	icmp_param.data_ptr=iph;	icmp_out_count(icmp_param.icmph.type);	icmp_socket->sk->ip_tos = tos;	ipc.addr = iph->saddr;	ipc.opt = &icmp_param.replyopts;	if (icmp_param.replyopts.srr) {		ip_rt_put(rt);		if (ip_route_output(&rt, icmp_param.replyopts.faddr, saddr, RT_TOS(tos), 0))			return;	}	if (!icmpv4_xrlim_allow(rt, type, code))		goto ende;	/* RFC says return as much as we can without exceeding 576 bytes. */	room = rt->u.dst.pmtu;	if (room > 576)		room = 576;	room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;	room -= sizeof(struct icmphdr);	icmp_param.data_len=(iph->ihl<<2)+skb_in->len;	if (icmp_param.data_len > room)		icmp_param.data_len = room;		ip_build_xmit(icmp_socket->sk, icmp_glue_bits, &icmp_param, 		icmp_param.data_len+sizeof(struct icmphdr),		&ipc, rt, MSG_DONTWAIT);ende:	ip_rt_put(rt);}/*  *	Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH.  */static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len){	struct iphdr *iph;	int hash;	struct inet_protocol *ipprot;	unsigned char *dp;	struct sock *raw_sk;		/*	 *	Incomplete header ?	 * 	Only checks for the IP header, there should be an	 *	additional check for longer headers in upper levels.	 */	if(len<sizeof(struct iphdr)) {		icmp_statistics.IcmpInErrors++;		return;	}			iph = (struct iphdr *) (icmph + 1);	dp = (unsigned char*)iph;		if(icmph->type==ICMP_DEST_UNREACH) {		switch(icmph->code & 15) {			case ICMP_NET_UNREACH:				break;			case ICMP_HOST_UNREACH:				break;			case ICMP_PROT_UNREACH:				break;			case ICMP_PORT_UNREACH:				break;			case ICMP_FRAG_NEEDED:				if (ipv4_config.no_pmtu_disc) {					if (sysctl_ip_always_defrag == 0 && net_ratelimit())						printk(KERN_INFO "ICMP: %d.%d.%d.%d: fragmentation needed and DF set.\n",					       NIPQUAD(iph->daddr));				} else {					unsigned short new_mtu;					new_mtu = ip_rt_frag_needed(iph, ntohs(icmph->un.frag.mtu));					if (!new_mtu) 						return;					icmph->un.frag.mtu = htons(new_mtu);				}				break;			case ICMP_SR_FAILED:				if (sysctl_ip_always_defrag == 0 && net_ratelimit())					printk(KERN_INFO "ICMP: %d.%d.%d.%d: Source Route Failed.\n", NIPQUAD(iph->daddr));				break;			default:				break;		}		if (icmph->code>NR_ICMP_UNREACH) 			return;	}		/*	 *	Throw it at our lower layers	 *	 *	RFC 1122: 3.2.2 MUST extract the protocol ID from the passed header.	 *	RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the transport layer.	 *	RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to transport layer.	 */	 	/*	 *	Check the other end isnt violating RFC 1122. Some routers send	 *	bogus responses to broadcast frames. If you see this message	 *	first check your netmask matches at both ends, if it does then	 *	get the other vendor to fix their kit.	 */	if (!sysctl_icmp_ignore_bogus_error_responses)	{			if (inet_addr_type(iph->daddr) == RTN_BROADCAST)		{			if (net_ratelimit())				printk(KERN_WARNING "%d.%d.%d.%d sent an invalid ICMP error to a broadcast.\n",			       	NIPQUAD(skb->nh.iph->saddr));			return; 		}	}	/*	 *	Deliver ICMP message to raw sockets. Pretty useless feature?	 */	/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */	hash = iph->protocol & (MAX_INET_PROTOS - 1);	if ((raw_sk = raw_v4_htable[hash]) != NULL) 	{		while ((raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr,					       iph->daddr, skb->dev->ifindex)) != NULL) {			raw_err(raw_sk, skb);			raw_sk = raw_sk->next;		}	}	/*	 *	This can't change while we are doing it. 	 */	ipprot = (struct inet_protocol *) inet_protos[hash];	while(ipprot != NULL) {		struct inet_protocol *nextip;

⌨️ 快捷键说明

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