diff options
-rw-r--r-- | include/linux/netfilter_ipv6/ip6_tables.h | 7 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 36 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_ah.c | 4 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_frag.c | 4 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_hbh.c | 4 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_rt.c | 4 | ||||
-rw-r--r-- | net/netfilter/xt_TPROXY.c | 4 | ||||
-rw-r--r-- | net/netfilter/xt_socket.c | 4 |
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 | ||
301 | enum { | ||
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 */ |
302 | extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, | 307 | extern 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 | */ |
2293 | int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, | 2301 | int 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; |