diff options
author | Patrick McHardy <kaber@trash.net> | 2006-01-05 15:21:16 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-01-05 15:21:16 -0500 |
commit | b777e0ce7437a0e788e2aeb42aca9af2cce1f2e1 (patch) | |
tree | cecbfdf5b78b909b80f3f04cbfdac7599f5a3352 | |
parent | 1bd9bef6f9fe06dd0c628ac877c85b6b36aca062 (diff) |
[NETFILTER]: make ipv6_find_hdr() find transport protocol header
The original ipv6_find_hdr() finds the specified header in IPv6 packets.
This makes it possible to get transport header so that we can kill similar
loop in ip6_match_packet().
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/netfilter_ipv6/ip6_tables.h | 2 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 106 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_ah.c | 2 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_dst.c | 4 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_esp.c | 2 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_frag.c | 2 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_hbh.c | 4 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_rt.c | 2 |
8 files changed, 49 insertions, 75 deletions
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 2efc046d9e94..a291cb76ef18 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h | |||
@@ -474,7 +474,7 @@ extern unsigned int ip6t_do_table(struct sk_buff **pskb, | |||
474 | extern int ip6t_ext_hdr(u8 nexthdr); | 474 | extern int ip6t_ext_hdr(u8 nexthdr); |
475 | /* find specified header and get offset to it */ | 475 | /* find specified header and get offset to it */ |
476 | extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, | 476 | extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, |
477 | u8 target); | 477 | int target, unsigned short *fragoff); |
478 | 478 | ||
479 | #define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1)) | 479 | #define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1)) |
480 | 480 | ||
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index ea43ef1d94a7..13b1a525b92c 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -205,69 +205,21 @@ ip6_packet_match(const struct sk_buff *skb, | |||
205 | 205 | ||
206 | /* look for the desired protocol header */ | 206 | /* look for the desired protocol header */ |
207 | if((ip6info->flags & IP6T_F_PROTO)) { | 207 | if((ip6info->flags & IP6T_F_PROTO)) { |
208 | u_int8_t currenthdr = ipv6->nexthdr; | 208 | int protohdr; |
209 | struct ipv6_opt_hdr _hdr, *hp; | 209 | unsigned short _frag_off; |
210 | u_int16_t ptr; /* Header offset in skb */ | ||
211 | u_int16_t hdrlen; /* Header */ | ||
212 | u_int16_t _fragoff = 0, *fp = NULL; | ||
213 | |||
214 | ptr = IPV6_HDR_LEN; | ||
215 | |||
216 | while (ip6t_ext_hdr(currenthdr)) { | ||
217 | /* Is there enough space for the next ext header? */ | ||
218 | if (skb->len - ptr < IPV6_OPTHDR_LEN) | ||
219 | return 0; | ||
220 | |||
221 | /* NONE or ESP: there isn't protocol part */ | ||
222 | /* If we want to count these packets in '-p all', | ||
223 | * we will change the return 0 to 1*/ | ||
224 | if ((currenthdr == IPPROTO_NONE) || | ||
225 | (currenthdr == IPPROTO_ESP)) | ||
226 | break; | ||
227 | 210 | ||
228 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | 211 | protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off); |
229 | BUG_ON(hp == NULL); | 212 | if (protohdr < 0) |
230 | 213 | return 0; | |
231 | /* Size calculation */ | ||
232 | if (currenthdr == IPPROTO_FRAGMENT) { | ||
233 | fp = skb_header_pointer(skb, | ||
234 | ptr+offsetof(struct frag_hdr, | ||
235 | frag_off), | ||
236 | sizeof(_fragoff), | ||
237 | &_fragoff); | ||
238 | if (fp == NULL) | ||
239 | return 0; | ||
240 | |||
241 | _fragoff = ntohs(*fp) & ~0x7; | ||
242 | hdrlen = 8; | ||
243 | } else if (currenthdr == IPPROTO_AH) | ||
244 | hdrlen = (hp->hdrlen+2)<<2; | ||
245 | else | ||
246 | hdrlen = ipv6_optlen(hp); | ||
247 | |||
248 | currenthdr = hp->nexthdr; | ||
249 | ptr += hdrlen; | ||
250 | /* ptr is too large */ | ||
251 | if ( ptr > skb->len ) | ||
252 | return 0; | ||
253 | if (_fragoff) { | ||
254 | if (ip6t_ext_hdr(currenthdr)) | ||
255 | return 0; | ||
256 | break; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | *protoff = ptr; | ||
261 | *fragoff = _fragoff; | ||
262 | 214 | ||
263 | /* currenthdr contains the protocol header */ | 215 | *fragoff = _frag_off; |
264 | 216 | ||
265 | dprintf("Packet protocol %hi ?= %s%hi.\n", | 217 | dprintf("Packet protocol %hi ?= %s%hi.\n", |
266 | currenthdr, | 218 | protohdr, |
267 | ip6info->invflags & IP6T_INV_PROTO ? "!":"", | 219 | ip6info->invflags & IP6T_INV_PROTO ? "!":"", |
268 | ip6info->proto); | 220 | ip6info->proto); |
269 | 221 | ||
270 | if (ip6info->proto == currenthdr) { | 222 | if (ip6info->proto == protohdr) { |
271 | if(ip6info->invflags & IP6T_INV_PROTO) { | 223 | if(ip6info->invflags & IP6T_INV_PROTO) { |
272 | return 0; | 224 | return 0; |
273 | } | 225 | } |
@@ -2098,26 +2050,39 @@ static void __exit fini(void) | |||
2098 | } | 2050 | } |
2099 | 2051 | ||
2100 | /* | 2052 | /* |
2101 | * find specified header up to transport protocol header. | 2053 | * find the offset to specified header or the protocol number of last header |
2102 | * If found target header, the offset to the header is set to *offset | 2054 | * if target < 0. "last header" is transport protocol header, ESP, or |
2103 | * and return 0. otherwise, return -1. | 2055 | * "No next header". |
2056 | * | ||
2057 | * If target header is found, its offset is set in *offset and return protocol | ||
2058 | * number. Otherwise, return -1. | ||
2059 | * | ||
2060 | * Note that non-1st fragment is special case that "the protocol number | ||
2061 | * of last header" is "next header" field in Fragment header. In this case, | ||
2062 | * *offset is meaningless and fragment offset is stored in *fragoff if fragoff | ||
2063 | * isn't NULL. | ||
2104 | * | 2064 | * |
2105 | * Notes: - non-1st Fragment Header isn't skipped. | ||
2106 | * - ESP header isn't skipped. | ||
2107 | * - The target header may be trancated. | ||
2108 | */ | 2065 | */ |
2109 | int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target) | 2066 | int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, |
2067 | int target, unsigned short *fragoff) | ||
2110 | { | 2068 | { |
2111 | unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data; | 2069 | unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data; |
2112 | u8 nexthdr = skb->nh.ipv6h->nexthdr; | 2070 | u8 nexthdr = skb->nh.ipv6h->nexthdr; |
2113 | unsigned int len = skb->len - start; | 2071 | unsigned int len = skb->len - start; |
2114 | 2072 | ||
2073 | if (fragoff) | ||
2074 | *fragoff = 0; | ||
2075 | |||
2115 | while (nexthdr != target) { | 2076 | while (nexthdr != target) { |
2116 | struct ipv6_opt_hdr _hdr, *hp; | 2077 | struct ipv6_opt_hdr _hdr, *hp; |
2117 | unsigned int hdrlen; | 2078 | unsigned int hdrlen; |
2118 | 2079 | ||
2119 | if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) | 2080 | if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) { |
2081 | if (target < 0) | ||
2082 | break; | ||
2120 | return -1; | 2083 | return -1; |
2084 | } | ||
2085 | |||
2121 | hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); | 2086 | hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); |
2122 | if (hp == NULL) | 2087 | if (hp == NULL) |
2123 | return -1; | 2088 | return -1; |
@@ -2131,8 +2096,17 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target) | |||
2131 | if (fp == NULL) | 2096 | if (fp == NULL) |
2132 | return -1; | 2097 | return -1; |
2133 | 2098 | ||
2134 | if (ntohs(*fp) & ~0x7) | 2099 | _frag_off = ntohs(*fp) & ~0x7; |
2100 | if (_frag_off) { | ||
2101 | if (target < 0 && | ||
2102 | ((!ipv6_ext_hdr(hp->nexthdr)) || | ||
2103 | nexthdr == NEXTHDR_NONE)) { | ||
2104 | if (fragoff) | ||
2105 | *fragoff = _frag_off; | ||
2106 | return hp->nexthdr; | ||
2107 | } | ||
2135 | return -1; | 2108 | return -1; |
2109 | } | ||
2136 | hdrlen = 8; | 2110 | hdrlen = 8; |
2137 | } else if (nexthdr == NEXTHDR_AUTH) | 2111 | } else if (nexthdr == NEXTHDR_AUTH) |
2138 | hdrlen = (hp->hdrlen + 2) << 2; | 2112 | hdrlen = (hp->hdrlen + 2) << 2; |
@@ -2145,7 +2119,7 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target) | |||
2145 | } | 2119 | } |
2146 | 2120 | ||
2147 | *offset = start; | 2121 | *offset = start; |
2148 | return 0; | 2122 | return nexthdr; |
2149 | } | 2123 | } |
2150 | 2124 | ||
2151 | EXPORT_SYMBOL(ip6t_register_table); | 2125 | EXPORT_SYMBOL(ip6t_register_table); |
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index 268918d5deea..f5c1a7ff4a1f 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c | |||
@@ -54,7 +54,7 @@ match(const struct sk_buff *skb, | |||
54 | unsigned int ptr; | 54 | unsigned int ptr; |
55 | unsigned int hdrlen = 0; | 55 | unsigned int hdrlen = 0; |
56 | 56 | ||
57 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH) < 0) | 57 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL) < 0) |
58 | return 0; | 58 | return 0; |
59 | 59 | ||
60 | ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); | 60 | ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); |
diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c index c450a635e54b..48cf5f9efc95 100644 --- a/net/ipv6/netfilter/ip6t_dst.c +++ b/net/ipv6/netfilter/ip6t_dst.c | |||
@@ -71,9 +71,9 @@ match(const struct sk_buff *skb, | |||
71 | unsigned int optlen; | 71 | unsigned int optlen; |
72 | 72 | ||
73 | #if HOPBYHOP | 73 | #if HOPBYHOP |
74 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) | 74 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0) |
75 | #else | 75 | #else |
76 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) | 76 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0) |
77 | #endif | 77 | #endif |
78 | return 0; | 78 | return 0; |
79 | 79 | ||
diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c index 65937de1b58c..e1828f6d0a40 100644 --- a/net/ipv6/netfilter/ip6t_esp.c +++ b/net/ipv6/netfilter/ip6t_esp.c | |||
@@ -56,7 +56,7 @@ match(const struct sk_buff *skb, | |||
56 | /* Make sure this isn't an evil packet */ | 56 | /* Make sure this isn't an evil packet */ |
57 | /*DEBUGP("ipv6_esp entered \n");*/ | 57 | /*DEBUGP("ipv6_esp entered \n");*/ |
58 | 58 | ||
59 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP) < 0) | 59 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP, NULL) < 0) |
60 | return 0; | 60 | return 0; |
61 | 61 | ||
62 | eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp); | 62 | eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp); |
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index 085d5f8eea29..d1549b268669 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c | |||
@@ -52,7 +52,7 @@ match(const struct sk_buff *skb, | |||
52 | const struct ip6t_frag *fraginfo = matchinfo; | 52 | const struct ip6t_frag *fraginfo = matchinfo; |
53 | unsigned int ptr; | 53 | unsigned int ptr; |
54 | 54 | ||
55 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT) < 0) | 55 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL) < 0) |
56 | return 0; | 56 | return 0; |
57 | 57 | ||
58 | fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); | 58 | fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); |
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c index 1d09485111d0..e3bc8e2700e7 100644 --- a/net/ipv6/netfilter/ip6t_hbh.c +++ b/net/ipv6/netfilter/ip6t_hbh.c | |||
@@ -71,9 +71,9 @@ match(const struct sk_buff *skb, | |||
71 | unsigned int optlen; | 71 | unsigned int optlen; |
72 | 72 | ||
73 | #if HOPBYHOP | 73 | #if HOPBYHOP |
74 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) | 74 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0) |
75 | #else | 75 | #else |
76 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) | 76 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0) |
77 | #endif | 77 | #endif |
78 | return 0; | 78 | return 0; |
79 | 79 | ||
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index beb2fd5cebbb..c1e770e45543 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c | |||
@@ -58,7 +58,7 @@ match(const struct sk_buff *skb, | |||
58 | unsigned int ret = 0; | 58 | unsigned int ret = 0; |
59 | struct in6_addr *ap, _addr; | 59 | struct in6_addr *ap, _addr; |
60 | 60 | ||
61 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING) < 0) | 61 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL) < 0) |
62 | return 0; | 62 | return 0; |
63 | 63 | ||
64 | rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); | 64 | rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); |