aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorstephen hemminger <shemminger@vyatta.com>2012-09-24 14:12:23 -0400
committerDavid S. Miller <davem@davemloft.net>2012-09-27 18:12:37 -0400
commitd208328765a0ab425e36b5b828285f3337a85451 (patch)
tree80897cfb2f5537bdfbda57a736a91a04c85a1ceb /net/ipv4
parentaa99521eed6b77628f6f54ff6b2903f4130c0808 (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.c44
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 */
218static 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
219static struct ip_tunnel *ipgre_tunnel_lookup(struct net_device *dev, 232static 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);