diff options
author | stephen hemminger <shemminger@vyatta.com> | 2012-09-24 14:12:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-09-27 18:12:37 -0400 |
commit | d208328765a0ab425e36b5b828285f3337a85451 (patch) | |
tree | 80897cfb2f5537bdfbda57a736a91a04c85a1ceb /net/ipv4 | |
parent | aa99521eed6b77628f6f54ff6b2903f4130c0808 (diff) |
gre: fix handling of key 0
GRE driver incorrectly uses zero as a flag value. Zero is a perfectly
valid value for key, and the tunnel should match packets with no key only
with tunnels created without key, and vice versa.
This is a slightly visible change since previously it might be possible to
construct a working tunnel that sent key 0 and received only because
of the key wildcard of zero. I.e the sender sent key of zero, but tunnel
was defined without key.
Note: using gre key 0 requires iproute2 utilities v3.2 or later.
The original utility code was broken as well.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/ip_gre.c | 44 |
1 files changed, 34 insertions, 10 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index f233c1da207..0d4c3832d49 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -214,11 +214,25 @@ static struct rtnl_link_stats64 *ipgre_get_stats64(struct net_device *dev, | |||
214 | return tot; | 214 | return tot; |
215 | } | 215 | } |
216 | 216 | ||
217 | /* Does key in tunnel parameters match packet */ | ||
218 | static bool ipgre_key_match(const struct ip_tunnel_parm *p, | ||
219 | __u32 flags, __be32 key) | ||
220 | { | ||
221 | if (p->i_flags & GRE_KEY) { | ||
222 | if (flags & GRE_KEY) | ||
223 | return key == p->i_key; | ||
224 | else | ||
225 | return false; /* key expected, none present */ | ||
226 | } else | ||
227 | return !(flags & GRE_KEY); | ||
228 | } | ||
229 | |||
217 | /* Given src, dst and key, find appropriate for input tunnel. */ | 230 | /* Given src, dst and key, find appropriate for input tunnel. */ |
218 | 231 | ||
219 | static struct ip_tunnel *ipgre_tunnel_lookup(struct net_device *dev, | 232 | static struct ip_tunnel *ipgre_tunnel_lookup(struct net_device *dev, |
220 | __be32 remote, __be32 local, | 233 | __be32 remote, __be32 local, |
221 | __be32 key, __be16 gre_proto) | 234 | __u32 flags, __be32 key, |
235 | __be16 gre_proto) | ||
222 | { | 236 | { |
223 | struct net *net = dev_net(dev); | 237 | struct net *net = dev_net(dev); |
224 | int link = dev->ifindex; | 238 | int link = dev->ifindex; |
@@ -233,10 +247,12 @@ static struct ip_tunnel *ipgre_tunnel_lookup(struct net_device *dev, | |||
233 | for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) { | 247 | for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) { |
234 | if (local != t->parms.iph.saddr || | 248 | if (local != t->parms.iph.saddr || |
235 | remote != t->parms.iph.daddr || | 249 | remote != t->parms.iph.daddr || |
236 | key != t->parms.i_key || | ||
237 | !(t->dev->flags & IFF_UP)) | 250 | !(t->dev->flags & IFF_UP)) |
238 | continue; | 251 | continue; |
239 | 252 | ||
253 | if (!ipgre_key_match(&t->parms, flags, key)) | ||
254 | continue; | ||
255 | |||
240 | if (t->dev->type != ARPHRD_IPGRE && | 256 | if (t->dev->type != ARPHRD_IPGRE && |
241 | t->dev->type != dev_type) | 257 | t->dev->type != dev_type) |
242 | continue; | 258 | continue; |
@@ -257,10 +273,12 @@ static struct ip_tunnel *ipgre_tunnel_lookup(struct net_device *dev, | |||
257 | 273 | ||
258 | for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) { | 274 | for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) { |
259 | if (remote != t->parms.iph.daddr || | 275 | if (remote != t->parms.iph.daddr || |
260 | key != t->parms.i_key || | ||
261 | !(t->dev->flags & IFF_UP)) | 276 | !(t->dev->flags & IFF_UP)) |
262 | continue; | 277 | continue; |
263 | 278 | ||
279 | if (!ipgre_key_match(&t->parms, flags, key)) | ||
280 | continue; | ||
281 | |||
264 | if (t->dev->type != ARPHRD_IPGRE && | 282 | if (t->dev->type != ARPHRD_IPGRE && |
265 | t->dev->type != dev_type) | 283 | t->dev->type != dev_type) |
266 | continue; | 284 | continue; |
@@ -283,10 +301,12 @@ static struct ip_tunnel *ipgre_tunnel_lookup(struct net_device *dev, | |||
283 | if ((local != t->parms.iph.saddr && | 301 | if ((local != t->parms.iph.saddr && |
284 | (local != t->parms.iph.daddr || | 302 | (local != t->parms.iph.daddr || |
285 | !ipv4_is_multicast(local))) || | 303 | !ipv4_is_multicast(local))) || |
286 | key != t->parms.i_key || | ||
287 | !(t->dev->flags & IFF_UP)) | 304 | !(t->dev->flags & IFF_UP)) |
288 | continue; | 305 | continue; |
289 | 306 | ||
307 | if (!ipgre_key_match(&t->parms, flags, key)) | ||
308 | continue; | ||
309 | |||
290 | if (t->dev->type != ARPHRD_IPGRE && | 310 | if (t->dev->type != ARPHRD_IPGRE && |
291 | t->dev->type != dev_type) | 311 | t->dev->type != dev_type) |
292 | continue; | 312 | continue; |
@@ -489,6 +509,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info) | |||
489 | const int code = icmp_hdr(skb)->code; | 509 | const int code = icmp_hdr(skb)->code; |
490 | struct ip_tunnel *t; | 510 | struct ip_tunnel *t; |
491 | __be16 flags; | 511 | __be16 flags; |
512 | __be32 key = 0; | ||
492 | 513 | ||
493 | flags = p[0]; | 514 | flags = p[0]; |
494 | if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) { | 515 | if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) { |
@@ -505,6 +526,9 @@ static void ipgre_err(struct sk_buff *skb, u32 info) | |||
505 | if (skb_headlen(skb) < grehlen) | 526 | if (skb_headlen(skb) < grehlen) |
506 | return; | 527 | return; |
507 | 528 | ||
529 | if (flags & GRE_KEY) | ||
530 | key = *(((__be32 *)p) + (grehlen / 4) - 1); | ||
531 | |||
508 | switch (type) { | 532 | switch (type) { |
509 | default: | 533 | default: |
510 | case ICMP_PARAMETERPROB: | 534 | case ICMP_PARAMETERPROB: |
@@ -535,9 +559,8 @@ static void ipgre_err(struct sk_buff *skb, u32 info) | |||
535 | 559 | ||
536 | rcu_read_lock(); | 560 | rcu_read_lock(); |
537 | t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr, | 561 | t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr, |
538 | flags & GRE_KEY ? | 562 | flags, key, p[1]); |
539 | *(((__be32 *)p) + (grehlen / 4) - 1) : 0, | 563 | |
540 | p[1]); | ||
541 | if (t == NULL) | 564 | if (t == NULL) |
542 | goto out; | 565 | goto out; |
543 | 566 | ||
@@ -642,9 +665,10 @@ static int ipgre_rcv(struct sk_buff *skb) | |||
642 | gre_proto = *(__be16 *)(h + 2); | 665 | gre_proto = *(__be16 *)(h + 2); |
643 | 666 | ||
644 | rcu_read_lock(); | 667 | rcu_read_lock(); |
645 | if ((tunnel = ipgre_tunnel_lookup(skb->dev, | 668 | tunnel = ipgre_tunnel_lookup(skb->dev, |
646 | iph->saddr, iph->daddr, key, | 669 | iph->saddr, iph->daddr, flags, key, |
647 | gre_proto))) { | 670 | gre_proto); |
671 | if (tunnel) { | ||
648 | struct pcpu_tstats *tstats; | 672 | struct pcpu_tstats *tstats; |
649 | 673 | ||
650 | secpath_reset(skb); | 674 | secpath_reset(skb); |