aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnsis Atteka <aatteka@nicira.com>2013-09-18 18:29:53 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-13 19:08:30 -0400
commit68a9e707892caf0fda14656963fd99c6a1c10e46 (patch)
treeef96c22ea4cfc833ecdb25a234231f5d085d8d94
parentcd176b578d356844f68176a1e0b6346c1cc9e33d (diff)
ip: generate unique IP identificator if local fragmentation is allowed
[ Upstream commit 703133de331a7a7df47f31fb9de51dc6f68a9de8 ] If local fragmentation is allowed, then ip_select_ident() and ip_select_ident_more() need to generate unique IDs to ensure correct defragmentation on the peer. For example, if IPsec (tunnel mode) has to encrypt large skbs that have local_df bit set, then all IP fragments that belonged to different ESP datagrams would have used the same identificator. If one of these IP fragments would get lost or reordered, then peer could possibly stitch together wrong IP fragments that did not belong to the same datagram. This would lead to a packet loss or data corruption. Signed-off-by: Ansis Atteka <aatteka@nicira.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/net/ppp/pptp.c2
-rw-r--r--include/net/ip.h12
-rw-r--r--net/ipv4/igmp.c4
-rw-r--r--net/ipv4/inetpeer.c4
-rw-r--r--net/ipv4/ip_output.c6
-rw-r--r--net/ipv4/ipmr.c2
-rw-r--r--net/ipv4/raw.c2
-rw-r--r--net/ipv4/xfrm4_mode_tunnel.c2
-rw-r--r--net/ipv6/sit.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c2
10 files changed, 21 insertions, 17 deletions
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 162464fe86bf..7f10588fe668 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -281,7 +281,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
281 nf_reset(skb); 281 nf_reset(skb);
282 282
283 skb->ip_summed = CHECKSUM_NONE; 283 skb->ip_summed = CHECKSUM_NONE;
284 ip_select_ident(iph, &rt->dst, NULL); 284 ip_select_ident(skb, &rt->dst, NULL);
285 ip_send_check(iph); 285 ip_send_check(iph);
286 286
287 ip_local_out(skb); 287 ip_local_out(skb);
diff --git a/include/net/ip.h b/include/net/ip.h
index a68f838a132c..edfa59174d9a 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -254,9 +254,11 @@ int ip_dont_fragment(struct sock *sk, struct dst_entry *dst)
254 254
255extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more); 255extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more);
256 256
257static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, struct sock *sk) 257static inline void ip_select_ident(struct sk_buff *skb, struct dst_entry *dst, struct sock *sk)
258{ 258{
259 if (iph->frag_off & htons(IP_DF)) { 259 struct iphdr *iph = ip_hdr(skb);
260
261 if ((iph->frag_off & htons(IP_DF)) && !skb->local_df) {
260 /* This is only to work around buggy Windows95/2000 262 /* This is only to work around buggy Windows95/2000
261 * VJ compression implementations. If the ID field 263 * VJ compression implementations. If the ID field
262 * does not change, they drop every other packet in 264 * does not change, they drop every other packet in
@@ -268,9 +270,11 @@ static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, str
268 __ip_select_ident(iph, dst, 0); 270 __ip_select_ident(iph, dst, 0);
269} 271}
270 272
271static inline void ip_select_ident_more(struct iphdr *iph, struct dst_entry *dst, struct sock *sk, int more) 273static inline void ip_select_ident_more(struct sk_buff *skb, struct dst_entry *dst, struct sock *sk, int more)
272{ 274{
273 if (iph->frag_off & htons(IP_DF)) { 275 struct iphdr *iph = ip_hdr(skb);
276
277 if ((iph->frag_off & htons(IP_DF)) && !skb->local_df) {
274 if (sk && inet_sk(sk)->inet_daddr) { 278 if (sk && inet_sk(sk)->inet_daddr) {
275 iph->id = htons(inet_sk(sk)->inet_id); 279 iph->id = htons(inet_sk(sk)->inet_id);
276 inet_sk(sk)->inet_id += 1 + more; 280 inet_sk(sk)->inet_id += 1 + more;
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index d8c232794bcb..516ade1d9839 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -343,7 +343,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
343 pip->saddr = fl4.saddr; 343 pip->saddr = fl4.saddr;
344 pip->protocol = IPPROTO_IGMP; 344 pip->protocol = IPPROTO_IGMP;
345 pip->tot_len = 0; /* filled in later */ 345 pip->tot_len = 0; /* filled in later */
346 ip_select_ident(pip, &rt->dst, NULL); 346 ip_select_ident(skb, &rt->dst, NULL);
347 ((u8 *)&pip[1])[0] = IPOPT_RA; 347 ((u8 *)&pip[1])[0] = IPOPT_RA;
348 ((u8 *)&pip[1])[1] = 4; 348 ((u8 *)&pip[1])[1] = 4;
349 ((u8 *)&pip[1])[2] = 0; 349 ((u8 *)&pip[1])[2] = 0;
@@ -687,7 +687,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
687 iph->daddr = dst; 687 iph->daddr = dst;
688 iph->saddr = fl4.saddr; 688 iph->saddr = fl4.saddr;
689 iph->protocol = IPPROTO_IGMP; 689 iph->protocol = IPPROTO_IGMP;
690 ip_select_ident(iph, &rt->dst, NULL); 690 ip_select_ident(skb, &rt->dst, NULL);
691 ((u8 *)&iph[1])[0] = IPOPT_RA; 691 ((u8 *)&iph[1])[0] = IPOPT_RA;
692 ((u8 *)&iph[1])[1] = 4; 692 ((u8 *)&iph[1])[1] = 4;
693 ((u8 *)&iph[1])[2] = 0; 693 ((u8 *)&iph[1])[2] = 0;
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index 000e3d239d64..33d5537881ed 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -32,8 +32,8 @@
32 * At the moment of writing this notes identifier of IP packets is generated 32 * At the moment of writing this notes identifier of IP packets is generated
33 * to be unpredictable using this code only for packets subjected 33 * to be unpredictable using this code only for packets subjected
34 * (actually or potentially) to defragmentation. I.e. DF packets less than 34 * (actually or potentially) to defragmentation. I.e. DF packets less than
35 * PMTU in size uses a constant ID and do not use this code (see 35 * PMTU in size when local fragmentation is disabled use a constant ID and do
36 * ip_select_ident() in include/net/ip.h). 36 * not use this code (see ip_select_ident() in include/net/ip.h).
37 * 37 *
38 * Route cache entries hold references to our nodes. 38 * Route cache entries hold references to our nodes.
39 * New cache entries get references via lookup by destination IP address in 39 * New cache entries get references via lookup by destination IP address in
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index b663b7bda131..ec2d430a6a55 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -148,7 +148,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
148 iph->daddr = (opt && opt->opt.srr ? opt->opt.faddr : daddr); 148 iph->daddr = (opt && opt->opt.srr ? opt->opt.faddr : daddr);
149 iph->saddr = saddr; 149 iph->saddr = saddr;
150 iph->protocol = sk->sk_protocol; 150 iph->protocol = sk->sk_protocol;
151 ip_select_ident(iph, &rt->dst, sk); 151 ip_select_ident(skb, &rt->dst, sk);
152 152
153 if (opt && opt->opt.optlen) { 153 if (opt && opt->opt.optlen) {
154 iph->ihl += opt->opt.optlen>>2; 154 iph->ihl += opt->opt.optlen>>2;
@@ -394,7 +394,7 @@ packet_routed:
394 ip_options_build(skb, &inet_opt->opt, inet->inet_daddr, rt, 0); 394 ip_options_build(skb, &inet_opt->opt, inet->inet_daddr, rt, 0);
395 } 395 }
396 396
397 ip_select_ident_more(iph, &rt->dst, sk, 397 ip_select_ident_more(skb, &rt->dst, sk,
398 (skb_shinfo(skb)->gso_segs ?: 1) - 1); 398 (skb_shinfo(skb)->gso_segs ?: 1) - 1);
399 399
400 skb->priority = sk->sk_priority; 400 skb->priority = sk->sk_priority;
@@ -1332,7 +1332,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
1332 iph->ttl = ttl; 1332 iph->ttl = ttl;
1333 iph->protocol = sk->sk_protocol; 1333 iph->protocol = sk->sk_protocol;
1334 ip_copy_addrs(iph, fl4); 1334 ip_copy_addrs(iph, fl4);
1335 ip_select_ident(iph, &rt->dst, sk); 1335 ip_select_ident(skb, &rt->dst, sk);
1336 1336
1337 if (opt) { 1337 if (opt) {
1338 iph->ihl += opt->optlen>>2; 1338 iph->ihl += opt->optlen>>2;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 9d9610ae7855..2c581da1fcab 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1658,7 +1658,7 @@ static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
1658 iph->protocol = IPPROTO_IPIP; 1658 iph->protocol = IPPROTO_IPIP;
1659 iph->ihl = 5; 1659 iph->ihl = 5;
1660 iph->tot_len = htons(skb->len); 1660 iph->tot_len = htons(skb->len);
1661 ip_select_ident(iph, skb_dst(skb), NULL); 1661 ip_select_ident(skb, skb_dst(skb), NULL);
1662 ip_send_check(iph); 1662 ip_send_check(iph);
1663 1663
1664 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); 1664 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 61e60d67adca..6fb233772f79 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -387,7 +387,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
387 iph->check = 0; 387 iph->check = 0;
388 iph->tot_len = htons(length); 388 iph->tot_len = htons(length);
389 if (!iph->id) 389 if (!iph->id)
390 ip_select_ident(iph, &rt->dst, NULL); 390 ip_select_ident(skb, &rt->dst, NULL);
391 391
392 iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); 392 iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
393 } 393 }
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index eb1dd4d643f2..b5663c37f089 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -117,7 +117,7 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
117 117
118 top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? 118 top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
119 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF)); 119 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF));
120 ip_select_ident(top_iph, dst->child, NULL); 120 ip_select_ident(skb, dst->child, NULL);
121 121
122 top_iph->ttl = ip4_dst_hoplimit(dst->child); 122 top_iph->ttl = ip4_dst_hoplimit(dst->child);
123 123
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 60df36d15390..bacc415287f6 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -865,7 +865,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
865 iph->ttl = iph6->hop_limit; 865 iph->ttl = iph6->hop_limit;
866 866
867 skb->ip_summed = CHECKSUM_NONE; 867 skb->ip_summed = CHECKSUM_NONE;
868 ip_select_ident(iph, skb_dst(skb), NULL); 868 ip_select_ident(skb, skb_dst(skb), NULL);
869 iptunnel_xmit(skb, dev); 869 iptunnel_xmit(skb, dev);
870 return NETDEV_TX_OK; 870 return NETDEV_TX_OK;
871 871
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index b75ff6429a04..c47444e4cf8c 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -883,7 +883,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
883 iph->daddr = cp->daddr.ip; 883 iph->daddr = cp->daddr.ip;
884 iph->saddr = saddr; 884 iph->saddr = saddr;
885 iph->ttl = old_iph->ttl; 885 iph->ttl = old_iph->ttl;
886 ip_select_ident(iph, &rt->dst, NULL); 886 ip_select_ident(skb, &rt->dst, NULL);
887 887
888 /* Another hack: avoid icmp_send in ip_fragment */ 888 /* Another hack: avoid icmp_send in ip_fragment */
889 skb->local_df = 1; 889 skb->local_df = 1;