[IPV6] IP6TUNNEL: Enable to control the handled inner protocol.

ip6_tunnel before supporting IPv4/IPv6 tunnel allows only IPPROTO_IPV6
in configurations from userland. This allows userland to set IPPROTO_IPIP
and 0(wildcard). ip6_tunnel only handles allowed inner protocols.

Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Yasuyuki Kozakai 2006-11-30 14:43:28 +09:00 committed by David S. Miller
parent 3144581cb0
commit 502b093569
1 changed files with 26 additions and 11 deletions

View File

@ -384,7 +384,7 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
**/ **/
static int static int
ip6_tnl_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
int *type, int *code, int *msg, __be32 *info, int offset) int *type, int *code, int *msg, __be32 *info, int offset)
{ {
struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data; struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
@ -404,6 +404,9 @@ ip6_tnl_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if ((t = ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL) if ((t = ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL)
goto out; goto out;
if (t->parms.proto != ipproto && t->parms.proto != 0)
goto out;
err = 0; err = 0;
switch (*type) { switch (*type) {
@ -487,8 +490,8 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
struct flowi fl; struct flowi fl;
struct rtable *rt; struct rtable *rt;
err = ip6_tnl_err(skb, opt, &rel_type, &rel_code, &rel_msg, &rel_info, err = ip6_tnl_err(skb, IPPROTO_IPIP, opt, &rel_type, &rel_code,
offset); &rel_msg, &rel_info, offset);
if (err < 0) if (err < 0)
return err; return err;
@ -581,8 +584,8 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
__u32 rel_info = info; __u32 rel_info = info;
int err; int err;
err = ip6_tnl_err(skb, opt, &rel_type, &rel_code, &rel_msg, &rel_info, err = ip6_tnl_err(skb, IPPROTO_IPV6, opt, &rel_type, &rel_code,
offset); &rel_msg, &rel_info, offset);
if (err < 0) if (err < 0)
return err; return err;
@ -671,6 +674,7 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t)
**/ **/
static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
__u8 ipproto,
void (*dscp_ecn_decapsulate)(struct ip6_tnl *t, void (*dscp_ecn_decapsulate)(struct ip6_tnl *t,
struct ipv6hdr *ipv6h, struct ipv6hdr *ipv6h,
struct sk_buff *skb)) struct sk_buff *skb))
@ -683,6 +687,11 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
read_lock(&ip6_tnl_lock); read_lock(&ip6_tnl_lock);
if ((t = ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) { if ((t = ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
if (t->parms.proto != ipproto && t->parms.proto != 0) {
read_unlock(&ip6_tnl_lock);
goto discard;
}
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
read_unlock(&ip6_tnl_lock); read_unlock(&ip6_tnl_lock);
goto discard; goto discard;
@ -722,12 +731,14 @@ discard:
static int ip4ip6_rcv(struct sk_buff *skb) static int ip4ip6_rcv(struct sk_buff *skb)
{ {
return ip6_tnl_rcv(skb, ETH_P_IP, ip4ip6_dscp_ecn_decapsulate); return ip6_tnl_rcv(skb, ETH_P_IP, IPPROTO_IPIP,
ip4ip6_dscp_ecn_decapsulate);
} }
static int ip6ip6_rcv(struct sk_buff *skb) static int ip6ip6_rcv(struct sk_buff *skb)
{ {
return ip6_tnl_rcv(skb, ETH_P_IPV6, ip6ip6_dscp_ecn_decapsulate); return ip6_tnl_rcv(skb, ETH_P_IPV6, IPPROTO_IPV6,
ip6ip6_dscp_ecn_decapsulate);
} }
struct ipv6_tel_txoption { struct ipv6_tel_txoption {
@ -939,7 +950,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
__u32 mtu; __u32 mtu;
int err; int err;
if (!ip6_tnl_xmit_ctl(t)) if ((t->parms.proto != IPPROTO_IPIP && t->parms.proto != 0) ||
!ip6_tnl_xmit_ctl(t))
return -1; return -1;
if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
@ -978,7 +990,8 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
__u32 mtu; __u32 mtu;
int err; int err;
if (!ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h)) if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
!ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h))
return -1; return -1;
if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) { if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) {
@ -1140,6 +1153,7 @@ ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
t->parms.encap_limit = p->encap_limit; t->parms.encap_limit = p->encap_limit;
t->parms.flowinfo = p->flowinfo; t->parms.flowinfo = p->flowinfo;
t->parms.link = p->link; t->parms.link = p->link;
t->parms.proto = p->proto;
ip6_tnl_dst_reset(t); ip6_tnl_dst_reset(t);
ip6_tnl_link_config(t); ip6_tnl_link_config(t);
return 0; return 0;
@ -1205,7 +1219,8 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
break; break;
err = -EINVAL; err = -EINVAL;
if (p.proto != IPPROTO_IPV6) if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP &&
p.proto != 0)
break; break;
t = ip6_tnl_locate(&p, cmd == SIOCADDTUNNEL); t = ip6_tnl_locate(&p, cmd == SIOCADDTUNNEL);
if (dev != ip6_fb_tnl_dev && cmd == SIOCCHGTUNNEL) { if (dev != ip6_fb_tnl_dev && cmd == SIOCCHGTUNNEL) {
@ -1324,7 +1339,6 @@ static inline void
ip6_tnl_dev_init_gen(struct net_device *dev) ip6_tnl_dev_init_gen(struct net_device *dev)
{ {
struct ip6_tnl *t = netdev_priv(dev); struct ip6_tnl *t = netdev_priv(dev);
t->fl.proto = IPPROTO_IPV6;
t->dev = dev; t->dev = dev;
strcpy(t->parms.name, dev->name); strcpy(t->parms.name, dev->name);
} }
@ -1355,6 +1369,7 @@ ip6_fb_tnl_dev_init(struct net_device *dev)
{ {
struct ip6_tnl *t = netdev_priv(dev); struct ip6_tnl *t = netdev_priv(dev);
ip6_tnl_dev_init_gen(dev); ip6_tnl_dev_init_gen(dev);
t->parms.proto = IPPROTO_IPV6;
dev_hold(dev); dev_hold(dev);
tnls_wc[0] = t; tnls_wc[0] = t;
return 0; return 0;