diff options
Diffstat (limited to 'net/ipv4/icmp.c')
| -rw-r--r-- | net/ipv4/icmp.c | 56 | 
1 files changed, 40 insertions, 16 deletions
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 5f7d11a4587..42b7bcf8045 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -337,6 +337,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)  	struct sock *sk;  	struct inet_sock *inet;  	__be32 daddr, saddr; +	u32 mark = IP4_REPLY_MARK(net, skb->mark);  	if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb))  		return; @@ -349,10 +350,14 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)  	icmp_param->data.icmph.checksum = 0;  	inet->tos = ip_hdr(skb)->tos; +	sk->sk_mark = mark;  	daddr = ipc.addr = ip_hdr(skb)->saddr;  	saddr = fib_compute_spec_dst(skb);  	ipc.opt = NULL;  	ipc.tx_flags = 0; +	ipc.ttl = 0; +	ipc.tos = -1; +  	if (icmp_param->replyopts.opt.opt.optlen) {  		ipc.opt = &icmp_param->replyopts.opt;  		if (ipc.opt->opt.srr) @@ -361,6 +366,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)  	memset(&fl4, 0, sizeof(fl4));  	fl4.daddr = daddr;  	fl4.saddr = saddr; +	fl4.flowi4_mark = mark;  	fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);  	fl4.flowi4_proto = IPPROTO_ICMP;  	security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); @@ -379,7 +385,7 @@ static struct rtable *icmp_route_lookup(struct net *net,  					struct flowi4 *fl4,  					struct sk_buff *skb_in,  					const struct iphdr *iph, -					__be32 saddr, u8 tos, +					__be32 saddr, u8 tos, u32 mark,  					int type, int code,  					struct icmp_bxm *param)  { @@ -391,6 +397,7 @@ static struct rtable *icmp_route_lookup(struct net *net,  	fl4->daddr = (param->replyopts.opt.opt.srr ?  		      param->replyopts.opt.opt.faddr : iph->saddr);  	fl4->saddr = saddr; +	fl4->flowi4_mark = mark;  	fl4->flowi4_tos = RT_TOS(tos);  	fl4->flowi4_proto = IPPROTO_ICMP;  	fl4->fl4_icmp_type = type; @@ -488,6 +495,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)  	struct flowi4 fl4;  	__be32 saddr;  	u8  tos; +	u32 mark;  	struct net *net;  	struct sock *sk; @@ -589,6 +597,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)  	tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) |  					   IPTOS_PREC_INTERNETCONTROL) :  					  iph->tos; +	mark = IP4_REPLY_MARK(net, skb_in->mark);  	if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb_in))  		goto out_unlock; @@ -605,11 +614,14 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)  	icmp_param->skb	  = skb_in;  	icmp_param->offset = skb_network_offset(skb_in);  	inet_sk(sk)->tos = tos; +	sk->sk_mark = mark;  	ipc.addr = iph->saddr;  	ipc.opt = &icmp_param->replyopts.opt;  	ipc.tx_flags = 0; +	ipc.ttl = 0; +	ipc.tos = -1; -	rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, +	rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, mark,  			       type, code, icmp_param);  	if (IS_ERR(rt))  		goto out_unlock; @@ -663,6 +675,16 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info)  	rcu_read_unlock();  } +static bool icmp_tag_validation(int proto) +{ +	bool ok; + +	rcu_read_lock(); +	ok = rcu_dereference(inet_protos[proto])->icmp_strict_tag_validation; +	rcu_read_unlock(); +	return ok; +} +  /*   *	Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, ICMP_QUENCH, and   *	ICMP_PARAMETERPROB. @@ -700,13 +722,23 @@ static void icmp_unreach(struct sk_buff *skb)  		case ICMP_PORT_UNREACH:  			break;  		case ICMP_FRAG_NEEDED: -			if (ipv4_config.no_pmtu_disc) { +			/* for documentation of the ip_no_pmtu_disc +			 * values please see +			 * Documentation/networking/ip-sysctl.txt +			 */ +			switch (net->ipv4.sysctl_ip_no_pmtu_disc) { +			default:  				LIMIT_NETDEBUG(KERN_INFO pr_fmt("%pI4: fragmentation needed and DF set\n"),  					       &iph->daddr); -			} else { -				info = ntohs(icmph->un.frag.mtu); -				if (!info) +				break; +			case 2: +				goto out; +			case 3: +				if (!icmp_tag_validation(iph->protocol))  					goto out; +				/* fall through */ +			case 0: +				info = ntohs(icmph->un.frag.mtu);  			}  			break;  		case ICMP_SR_FAILED: @@ -881,16 +913,8 @@ int icmp_rcv(struct sk_buff *skb)  	ICMP_INC_STATS_BH(net, ICMP_MIB_INMSGS); -	switch (skb->ip_summed) { -	case CHECKSUM_COMPLETE: -		if (!csum_fold(skb->csum)) -			break; -		/* fall through */ -	case CHECKSUM_NONE: -		skb->csum = 0; -		if (__skb_checksum_complete(skb)) -			goto csum_error; -	} +	if (skb_checksum_simple_validate(skb)) +		goto csum_error;  	if (!pskb_pull(skb, sizeof(*icmph)))  		goto error;  | 
