aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter_ipv6/ip6_tables.h7
-rw-r--r--net/ipv6/netfilter/ip6_tables.c36
-rw-r--r--net/ipv6/netfilter/ip6t_ah.c4
-rw-r--r--net/ipv6/netfilter/ip6t_frag.c4
-rw-r--r--net/ipv6/netfilter/ip6t_hbh.c4
-rw-r--r--net/ipv6/netfilter/ip6t_rt.c4
-rw-r--r--net/netfilter/xt_TPROXY.c4
-rw-r--r--net/netfilter/xt_socket.c4
8 files changed, 49 insertions, 18 deletions
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index 1bc898b14a80..08c2cbbaa32b 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -298,9 +298,14 @@ ip6t_ext_hdr(u8 nexthdr)
298 (nexthdr == IPPROTO_DSTOPTS); 298 (nexthdr == IPPROTO_DSTOPTS);
299} 299}
300 300
301enum {
302 IP6T_FH_F_FRAG = (1 << 0),
303 IP6T_FH_F_AUTH = (1 << 1),
304};
305
301/* find specified header and get offset to it */ 306/* find specified header and get offset to it */
302extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, 307extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
303 int target, unsigned short *fragoff); 308 int target, unsigned short *fragoff, int *fragflg);
304 309
305#ifdef CONFIG_COMPAT 310#ifdef CONFIG_COMPAT
306#include <net/compat.h> 311#include <net/compat.h>
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index d4e350f72bbb..308bdd651230 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -133,7 +133,7 @@ ip6_packet_match(const struct sk_buff *skb,
133 int protohdr; 133 int protohdr;
134 unsigned short _frag_off; 134 unsigned short _frag_off;
135 135
136 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off); 136 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off, NULL);
137 if (protohdr < 0) { 137 if (protohdr < 0) {
138 if (_frag_off == 0) 138 if (_frag_off == 0)
139 *hotdrop = true; 139 *hotdrop = true;
@@ -362,6 +362,7 @@ ip6t_do_table(struct sk_buff *skb,
362 const struct xt_entry_match *ematch; 362 const struct xt_entry_match *ematch;
363 363
364 IP_NF_ASSERT(e); 364 IP_NF_ASSERT(e);
365 acpar.thoff = 0;
365 if (!ip6_packet_match(skb, indev, outdev, &e->ipv6, 366 if (!ip6_packet_match(skb, indev, outdev, &e->ipv6,
366 &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) { 367 &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) {
367 no_match: 368 no_match:
@@ -2278,6 +2279,10 @@ static void __exit ip6_tables_fini(void)
2278 * if target < 0. "last header" is transport protocol header, ESP, or 2279 * if target < 0. "last header" is transport protocol header, ESP, or
2279 * "No next header". 2280 * "No next header".
2280 * 2281 *
2282 * Note that *offset is used as input/output parameter. an if it is not zero,
2283 * then it must be a valid offset to an inner IPv6 header. This can be used
2284 * to explore inner IPv6 header, eg. ICMPv6 error messages.
2285 *
2281 * If target header is found, its offset is set in *offset and return protocol 2286 * If target header is found, its offset is set in *offset and return protocol
2282 * number. Otherwise, return -1. 2287 * number. Otherwise, return -1.
2283 * 2288 *
@@ -2289,17 +2294,33 @@ static void __exit ip6_tables_fini(void)
2289 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff 2294 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
2290 * isn't NULL. 2295 * isn't NULL.
2291 * 2296 *
2297 * if flags is not NULL and it's a fragment, then the frag flag IP6T_FH_F_FRAG
2298 * will be set. If it's an AH header, the IP6T_FH_F_AUTH flag is set and
2299 * target < 0, then this function will stop at the AH header.
2292 */ 2300 */
2293int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, 2301int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
2294 int target, unsigned short *fragoff) 2302 int target, unsigned short *fragoff, int *flags)
2295{ 2303{
2296 unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr); 2304 unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
2297 u8 nexthdr = ipv6_hdr(skb)->nexthdr; 2305 u8 nexthdr = ipv6_hdr(skb)->nexthdr;
2298 unsigned int len = skb->len - start; 2306 unsigned int len;
2299 2307
2300 if (fragoff) 2308 if (fragoff)
2301 *fragoff = 0; 2309 *fragoff = 0;
2302 2310
2311 if (*offset) {
2312 struct ipv6hdr _ip6, *ip6;
2313
2314 ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6);
2315 if (!ip6 || (ip6->version != 6)) {
2316 printk(KERN_ERR "IPv6 header not found\n");
2317 return -EBADMSG;
2318 }
2319 start = *offset + sizeof(struct ipv6hdr);
2320 nexthdr = ip6->nexthdr;
2321 }
2322 len = skb->len - start;
2323
2303 while (nexthdr != target) { 2324 while (nexthdr != target) {
2304 struct ipv6_opt_hdr _hdr, *hp; 2325 struct ipv6_opt_hdr _hdr, *hp;
2305 unsigned int hdrlen; 2326 unsigned int hdrlen;
@@ -2316,6 +2337,9 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
2316 if (nexthdr == NEXTHDR_FRAGMENT) { 2337 if (nexthdr == NEXTHDR_FRAGMENT) {
2317 unsigned short _frag_off; 2338 unsigned short _frag_off;
2318 __be16 *fp; 2339 __be16 *fp;
2340
2341 if (flags) /* Indicate that this is a fragment */
2342 *flags |= IP6T_FH_F_FRAG;
2319 fp = skb_header_pointer(skb, 2343 fp = skb_header_pointer(skb,
2320 start+offsetof(struct frag_hdr, 2344 start+offsetof(struct frag_hdr,
2321 frag_off), 2345 frag_off),
@@ -2336,9 +2360,11 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
2336 return -ENOENT; 2360 return -ENOENT;
2337 } 2361 }
2338 hdrlen = 8; 2362 hdrlen = 8;
2339 } else if (nexthdr == NEXTHDR_AUTH) 2363 } else if (nexthdr == NEXTHDR_AUTH) {
2364 if (flags && (*flags & IP6T_FH_F_AUTH) && (target < 0))
2365 break;
2340 hdrlen = (hp->hdrlen + 2) << 2; 2366 hdrlen = (hp->hdrlen + 2) << 2;
2341 else 2367 } else
2342 hdrlen = ipv6_optlen(hp); 2368 hdrlen = ipv6_optlen(hp);
2343 2369
2344 nexthdr = hp->nexthdr; 2370 nexthdr = hp->nexthdr;
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c
index 89cccc5a9c92..04099ab7d2e3 100644
--- a/net/ipv6/netfilter/ip6t_ah.c
+++ b/net/ipv6/netfilter/ip6t_ah.c
@@ -41,11 +41,11 @@ static bool ah_mt6(const struct sk_buff *skb, struct xt_action_param *par)
41 struct ip_auth_hdr _ah; 41 struct ip_auth_hdr _ah;
42 const struct ip_auth_hdr *ah; 42 const struct ip_auth_hdr *ah;
43 const struct ip6t_ah *ahinfo = par->matchinfo; 43 const struct ip6t_ah *ahinfo = par->matchinfo;
44 unsigned int ptr; 44 unsigned int ptr = 0;
45 unsigned int hdrlen = 0; 45 unsigned int hdrlen = 0;
46 int err; 46 int err;
47 47
48 err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL); 48 err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL, NULL);
49 if (err < 0) { 49 if (err < 0) {
50 if (err != -ENOENT) 50 if (err != -ENOENT)
51 par->hotdrop = true; 51 par->hotdrop = true;
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c
index eda898fda6ca..3b5735e56bfe 100644
--- a/net/ipv6/netfilter/ip6t_frag.c
+++ b/net/ipv6/netfilter/ip6t_frag.c
@@ -40,10 +40,10 @@ frag_mt6(const struct sk_buff *skb, struct xt_action_param *par)
40 struct frag_hdr _frag; 40 struct frag_hdr _frag;
41 const struct frag_hdr *fh; 41 const struct frag_hdr *fh;
42 const struct ip6t_frag *fraginfo = par->matchinfo; 42 const struct ip6t_frag *fraginfo = par->matchinfo;
43 unsigned int ptr; 43 unsigned int ptr = 0;
44 int err; 44 int err;
45 45
46 err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL); 46 err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL, NULL);
47 if (err < 0) { 47 if (err < 0) {
48 if (err != -ENOENT) 48 if (err != -ENOENT)
49 par->hotdrop = true; 49 par->hotdrop = true;
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c
index 59df051eaef6..01df142bb027 100644
--- a/net/ipv6/netfilter/ip6t_hbh.c
+++ b/net/ipv6/netfilter/ip6t_hbh.c
@@ -50,7 +50,7 @@ hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
50 const struct ipv6_opt_hdr *oh; 50 const struct ipv6_opt_hdr *oh;
51 const struct ip6t_opts *optinfo = par->matchinfo; 51 const struct ip6t_opts *optinfo = par->matchinfo;
52 unsigned int temp; 52 unsigned int temp;
53 unsigned int ptr; 53 unsigned int ptr = 0;
54 unsigned int hdrlen = 0; 54 unsigned int hdrlen = 0;
55 bool ret = false; 55 bool ret = false;
56 u8 _opttype; 56 u8 _opttype;
@@ -62,7 +62,7 @@ hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
62 62
63 err = ipv6_find_hdr(skb, &ptr, 63 err = ipv6_find_hdr(skb, &ptr,
64 (par->match == &hbh_mt6_reg[0]) ? 64 (par->match == &hbh_mt6_reg[0]) ?
65 NEXTHDR_HOP : NEXTHDR_DEST, NULL); 65 NEXTHDR_HOP : NEXTHDR_DEST, NULL, NULL);
66 if (err < 0) { 66 if (err < 0) {
67 if (err != -ENOENT) 67 if (err != -ENOENT)
68 par->hotdrop = true; 68 par->hotdrop = true;
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
index d8488c50a8e0..2c99b94eeca3 100644
--- a/net/ipv6/netfilter/ip6t_rt.c
+++ b/net/ipv6/netfilter/ip6t_rt.c
@@ -42,14 +42,14 @@ static bool rt_mt6(const struct sk_buff *skb, struct xt_action_param *par)
42 const struct ipv6_rt_hdr *rh; 42 const struct ipv6_rt_hdr *rh;
43 const struct ip6t_rt *rtinfo = par->matchinfo; 43 const struct ip6t_rt *rtinfo = par->matchinfo;
44 unsigned int temp; 44 unsigned int temp;
45 unsigned int ptr; 45 unsigned int ptr = 0;
46 unsigned int hdrlen = 0; 46 unsigned int hdrlen = 0;
47 bool ret = false; 47 bool ret = false;
48 struct in6_addr _addr; 48 struct in6_addr _addr;
49 const struct in6_addr *ap; 49 const struct in6_addr *ap;
50 int err; 50 int err;
51 51
52 err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL); 52 err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL, NULL);
53 if (err < 0) { 53 if (err < 0) {
54 if (err != -ENOENT) 54 if (err != -ENOENT)
55 par->hotdrop = true; 55 par->hotdrop = true;
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index 35a959a096e0..146033a86de8 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -282,10 +282,10 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
282 struct sock *sk; 282 struct sock *sk;
283 const struct in6_addr *laddr; 283 const struct in6_addr *laddr;
284 __be16 lport; 284 __be16 lport;
285 int thoff; 285 int thoff = 0;
286 int tproto; 286 int tproto;
287 287
288 tproto = ipv6_find_hdr(skb, &thoff, -1, NULL); 288 tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
289 if (tproto < 0) { 289 if (tproto < 0) {
290 pr_debug("unable to find transport header in IPv6 packet, dropping\n"); 290 pr_debug("unable to find transport header in IPv6 packet, dropping\n");
291 return NF_DROP; 291 return NF_DROP;
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index 72bb07f57f97..9ea482d08cf7 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -263,10 +263,10 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par)
263 struct sock *sk; 263 struct sock *sk;
264 struct in6_addr *daddr, *saddr; 264 struct in6_addr *daddr, *saddr;
265 __be16 dport, sport; 265 __be16 dport, sport;
266 int thoff, tproto; 266 int thoff = 0, tproto;
267 const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; 267 const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
268 268
269 tproto = ipv6_find_hdr(skb, &thoff, -1, NULL); 269 tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
270 if (tproto < 0) { 270 if (tproto < 0) {
271 pr_debug("unable to find transport header in IPv6 packet, dropping\n"); 271 pr_debug("unable to find transport header in IPv6 packet, dropping\n");
272 return NF_DROP; 272 return NF_DROP;