ipv6: fix the bug when propagating Redirect Message
Subsystems (3)
PATCH 1/1 ipv6: fix the bug when propagating Redirect Message
Before using icmpv6_notify() to propagate redirect, change skb->data to poing the IP packet that triggered the sending of the Redirect.
--- net/ipv6/ndisc.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 39 insertions(+), 0 deletions(-)
net/ipv6/ndisc.c +39 -0
@@ -1334,6 +1334,11 @@ out:static void ndisc_redirect_rcv (struct sk_buff *skb) { +int opt_len; +int opt_offset; +int ndisc_head_len; +struct nd_opt_hdr *nd_opt; +#ifdef CONFIG_IPV6_NDISC_NODETYPE switch (skb->ndisc_nodetype) {case NDISC_NODETYPE_HOST :
@@ -1350,6 +1355,40 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)return ; } + ndisc_head_len =sizeof (struct icmp6hdr ) +2 *sizeof (struct in6_addr ); +if (!pskb_may_pull (skb, ndisc_head_len)) { +return ; + } + + nd_opt = (struct nd_opt_hdr *)(skb->data + ndisc_head_len); + + opt_len = skb->tail - skb->transport_header - ndisc_head_len; +if (opt_len <0 ) { +return ; + } +while (opt_len) { +int l; + +if (opt_len <sizeof (struct nd_opt_hdr )) { +return ; + } + l = nd_opt->nd_opt_len <<3 ; +if (opt_len < l || l ==0 ) { +return ; + } +if (nd_opt->nd_opt_type ==ND_OPT_REDIRECT_HDR ) { +__skb_pull (skb, ndisc_head_len + opt_offset +8 ); +break ; + } + opt_len -= l; + nd_opt = ((void *)nd_opt) +1 ; + opt_offset +=1 ; + } + +if (opt_len ==0 ) { +return ; + } +icmpv6_notify (skb,NDISC_REDIRECT ,0 ,0 ); }
Signature · 1 line
1.7.4.4
Quoted 48 lines · Duan Jiong
Before using
icmpv6_notify()to propagate redirect, changeskb->datato poing the IP packet that triggered the sending of the Redirect.Signed-off-by Duan Jiong <[email protected]>--- net/ipv6/ndisc.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 39 insertions(+), 0 deletions(-)net/ipv6/ndisc.c +24
-0@@ -1334,6 +1334,11 @@ out:static void ndisc_redirect_rcv (struct sk_buff *skb) { +int opt_len; +int opt_offset; +int ndisc_head_len; +struct nd_opt_hdr *nd_opt; +#ifdef CONFIG_IPV6_NDISC_NODETYPE switch (skb->ndisc_nodetype) {case NDISC_NODETYPE_HOST :@@ -1350,6 +1355,40 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)return ; } + ndisc_head_len =sizeof (struct icmp6hdr ) +2 *sizeof (struct in6_addr ); +if (!pskb_may_pull (skb, ndisc_head_len)) { +return ; + } + + nd_opt = (struct nd_opt_hdr *)(skb->data + ndisc_head_len); + + opt_len = skb->tail - skb->transport_header - ndisc_head_len; +if (opt_len <0 ) { +return ; + } +while (opt_len) { +int l; + +if (opt_len <sizeof (struct nd_opt_hdr )) { +return ; + } + l = nd_opt->nd_opt_len <<3 ; +if (opt_len < l || l ==0 ) {
net/ipv6/ndisc.c static void ndisc_redirect_rcv(struct sk_buff *skb) · line 1386
Quoted 10 lines
net/ipv6/ndisc.c +10
-0+return ; + } +if (nd_opt->nd_opt_type ==ND_OPT_REDIRECT_HDR ) { +__skb_pull (skb, ndisc_head_len + opt_offset +8 ); +break ; + } + opt_len -= l; + nd_opt = ((void *)nd_opt) +1 ; + opt_offset +=1 ; + }
Instead of the above loop, you could use ndisc_parse_options(). This does the same what you are doing here and it would make it a bit clearer what's going on.
Quoted 15 lines · Steffen Klassert
Quoted 14 lines · Duan Jiong
net/ipv6/ndisc.c +14
-0+while (opt_len) { +int l; + +if (opt_len <sizeof (struct nd_opt_hdr )) { +return ; + } + l = nd_opt->nd_opt_len <<3 ; +if (opt_len < l || l ==0 ) { +return ; + } +if (nd_opt->nd_opt_type ==ND_OPT_REDIRECT_HDR ) { +__skb_pull (skb, ndisc_head_len + opt_offset +8 ); +break ; + }
Quoted 9 lines
net/ipv6/ndisc.c static void ndisc_redirect_rcv(struct sk_buff *skb) · line 1386
Quoted 4 lines
net/ipv6/ndisc.c +4
-0+ opt_len -= l; + nd_opt = ((void *)nd_opt) +1 ; + opt_offset +=1 ; + }Instead of the above loop, you could use
ndisc_parse_options(). This does the same what you are doing here and it would make it a bit clearer what's going on.
Duan, are you going to update your patches? We really need fixes for the problems you have discovered.
Thanks!
Quoted 55 lines · Steffen Klassert
Quoted 54 lines · Duan Jiong
Before using
icmpv6_notify()to propagate redirect, changeskb->datato poing the IP packet that triggered the sending of the Redirect.Signed-off-by Duan Jiong <[email protected]>--- net/ipv6/ndisc.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 39 insertions(+), 0 deletions(-)net/ipv6/ndisc.c +30
-0@@ -1334,6 +1334,11 @@ out:static void ndisc_redirect_rcv (struct sk_buff *skb) { +int opt_len; +int opt_offset; +int ndisc_head_len; +struct nd_opt_hdr *nd_opt; +#ifdef CONFIG_IPV6_NDISC_NODETYPE switch (skb->ndisc_nodetype) {case NDISC_NODETYPE_HOST :@@ -1350,6 +1355,40 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)return ; } + ndisc_head_len =sizeof (struct icmp6hdr ) +2 *sizeof (struct in6_addr ); +if (!pskb_may_pull (skb, ndisc_head_len)) { +return ; + } + + nd_opt = (struct nd_opt_hdr *)(skb->data + ndisc_head_len); + + opt_len = skb->tail - skb->transport_header - ndisc_head_len; +if (opt_len <0 ) { +return ; + } +while (opt_len) { +int l; + +if (opt_len <sizeof (struct nd_opt_hdr )) { +return ; + } + l = nd_opt->nd_opt_len <<3 ; +if (opt_len < l || l ==0 ) { +return ; + } +if (nd_opt->nd_opt_type ==ND_OPT_REDIRECT_HDR ) { +__skb_pull (skb, ndisc_head_len + opt_offset +8 ); +break ; + }
Quoted 9 lines
net/ipv6/ndisc.c static void ndisc_redirect_rcv(struct sk_buff *skb) · line 1386
Quoted 4 lines
net/ipv6/ndisc.c +4
-0+ opt_len -= l; + nd_opt = ((void *)nd_opt) +1 ; + opt_offset +=1 ; + }Instead of the above loop, you could use
ndisc_parse_options(). This does the same what you are doing here and it would make it a bit clearer what's going on.
I apologize for not replying to you earlier,and i will continue to update my patches.
Just like you said, i try to use ndisc_parse_options() to instead of the loop, but i find the skb->data can't be changed in function ndisc_parse_options() due to lack of arguments. So i think it is better to continue to use the loop. How do you think this?
Thanks!
Quoted 6 lines · Duan Jiong
Just like you said, i try to use
ndisc_parse_options()to instead of the loop, but i find theskb->datacan't be changed in functionndisc_parse_options()due to lack of arguments. So i think it is better to continue to use the loop. How do you think this?
You can change the data pointer after ndisc_parse_options(). Something like the (untested) patch below should do it.
include/net/ndisc.h | 7 +++++++ net/ipv6/ndisc.c | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+)
include/net/ndisc.h +7 -0
@@ -78,6 +78,13 @@ struct ra_msg {__be32 retrans_timer; }; +struct rd_msg { +struct icmp6hdr icmph; +struct in6_addr target; +struct in6_addr dest; +__u8 opt[0 ]; +}; +struct nd_opt_hdr {__u8 nd_opt_type;__u8 nd_opt_len;
net/ipv6/ndisc.c +20 -0
@@ -1333,6 +1333,12 @@ out:static void ndisc_redirect_rcv (struct sk_buff *skb) { +u8 *hdr; +struct ndisc_options ndopts; +struct rd_msg *msg = (struct rd_msg *)skb_transport_header (skb); +u32 ndoptlen = skb->tail - (skb->transport_header + + offsetof(struct rd_msg , opt)); +#ifdef CONFIG_IPV6_NDISC_NODETYPE switch (skb->ndisc_nodetype) {case NDISC_NODETYPE_HOST :
@@ -1349,6 +1355,20 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)return ; } +if (!ndisc_parse_options (msg->opt, ndoptlen, &ndopts)) { +ND_PRINTK (2 , warn,"Redirect: invalid ND options\n" ); +return ; + } + +if (!ndopts.nd_opts_rh) +return ; + + hdr = (u8 *) ndopts.nd_opts_rh; + hdr +=8 ; + +if (!pskb_pull (skb, hdr -skb_transport_header (skb))) +return ; +icmpv6_notify (skb,NDISC_REDIRECT ,0 ,0 ); }
Signature · 1 line
1.7.9.5
Quoted 62 lines · Steffen Klassert
Quoted 6 lines · Duan Jiong
Just like you said, i try to use
ndisc_parse_options()to instead of the loop, but i find theskb->datacan't be changed in functionndisc_parse_options()due to lack of arguments. So i think it is better to continue to use the loop. How do you think this?You can change the data pointer after
ndisc_parse_options(). Something like the (untested) patch below should do it.include/net/ndisc.h | 7 +++++++ net/ipv6/ndisc.c | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+)include/net/ndisc.h +7
-0@@ -78,6 +78,13 @@ struct ra_msg {__be32 retrans_timer; }; +struct rd_msg { +struct icmp6hdr icmph; +struct in6_addr target; +struct in6_addr dest; +__u8 opt[0 ]; +}; +struct nd_opt_hdr {__u8 nd_opt_type;__u8 nd_opt_len;net/ipv6/ndisc.c +13
-0@@ -1333,6 +1333,12 @@ out:static void ndisc_redirect_rcv (struct sk_buff *skb) { +u8 *hdr; +struct ndisc_options ndopts; +struct rd_msg *msg = (struct rd_msg *)skb_transport_header (skb); +u32 ndoptlen = skb->tail - (skb->transport_header + + offsetof(struct rd_msg , opt)); +#ifdef CONFIG_IPV6_NDISC_NODETYPE switch (skb->ndisc_nodetype) {case NDISC_NODETYPE_HOST :@@ -1349,6 +1355,20 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)return ; } +if (!ndisc_parse_options (msg->opt, ndoptlen, &ndopts)) { +ND_PRINTK (2 , warn,"Redirect: invalid ND options\n" ); +return ; + } + +if (!ndopts.nd_opts_rh) +return ;
net/ipv6/ndisc.c static void ndisc_redirect_rcv(struct sk_buff *skb) · line 1374
Quoted 10 lines
net/ipv6/ndisc.c +7
-0+ + hdr = (u8 *) ndopts.nd_opts_rh; + hdr +=8 ; + +if (!pskb_pull (skb, hdr -skb_transport_header (skb))) +return ; +icmpv6_notify (skb,NDISC_REDIRECT ,0 ,0 ); }
Thanks for you help. I will test it.