Commit b777e0ce7437a0e788e2aeb42aca9af2cce1f2e1
Committed by
David S. Miller
1 parent
1bd9bef6f9
Exists in
master
and in
7 other branches
[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>
Showing 8 changed files with 49 additions and 75 deletions Side-by-side Diff
include/linux/netfilter_ipv6/ip6_tables.h
... | ... | @@ -474,7 +474,7 @@ |
474 | 474 | extern int ip6t_ext_hdr(u8 nexthdr); |
475 | 475 | /* find specified header and get offset to it */ |
476 | 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 | 479 | #define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1)) |
480 | 480 |
net/ipv6/netfilter/ip6_tables.c
... | ... | @@ -205,69 +205,21 @@ |
205 | 205 | |
206 | 206 | /* look for the desired protocol header */ |
207 | 207 | if((ip6info->flags & IP6T_F_PROTO)) { |
208 | - u_int8_t currenthdr = ipv6->nexthdr; | |
209 | - struct ipv6_opt_hdr _hdr, *hp; | |
210 | - u_int16_t ptr; /* Header offset in skb */ | |
211 | - u_int16_t hdrlen; /* Header */ | |
212 | - u_int16_t _fragoff = 0, *fp = NULL; | |
208 | + int protohdr; | |
209 | + unsigned short _frag_off; | |
213 | 210 | |
214 | - ptr = IPV6_HDR_LEN; | |
211 | + protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off); | |
212 | + if (protohdr < 0) | |
213 | + return 0; | |
215 | 214 | |
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; | |
215 | + *fragoff = _frag_off; | |
220 | 216 | |
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 | - | |
228 | - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | |
229 | - BUG_ON(hp == NULL); | |
230 | - | |
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 | - | |
263 | - /* currenthdr contains the protocol header */ | |
264 | - | |
265 | 217 | dprintf("Packet protocol %hi ?= %s%hi.\n", |
266 | - currenthdr, | |
218 | + protohdr, | |
267 | 219 | ip6info->invflags & IP6T_INV_PROTO ? "!":"", |
268 | 220 | ip6info->proto); |
269 | 221 | |
270 | - if (ip6info->proto == currenthdr) { | |
222 | + if (ip6info->proto == protohdr) { | |
271 | 223 | if(ip6info->invflags & IP6T_INV_PROTO) { |
272 | 224 | return 0; |
273 | 225 | } |
274 | 226 | |
275 | 227 | |
276 | 228 | |
277 | 229 | |
278 | 230 | |
... | ... | @@ -2098,26 +2050,39 @@ |
2098 | 2050 | } |
2099 | 2051 | |
2100 | 2052 | /* |
2101 | - * find specified header up to transport protocol header. | |
2102 | - * If found target header, the offset to the header is set to *offset | |
2103 | - * and return 0. otherwise, return -1. | |
2053 | + * find the offset to specified header or the protocol number of last header | |
2054 | + * if target < 0. "last header" is transport protocol header, ESP, or | |
2055 | + * "No next header". | |
2104 | 2056 | * |
2105 | - * Notes: - non-1st Fragment Header isn't skipped. | |
2106 | - * - ESP header isn't skipped. | |
2107 | - * - The target header may be trancated. | |
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. | |
2064 | + * | |
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 | 2069 | unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data; |
2112 | 2070 | u8 nexthdr = skb->nh.ipv6h->nexthdr; |
2113 | 2071 | unsigned int len = skb->len - start; |
2114 | 2072 | |
2073 | + if (fragoff) | |
2074 | + *fragoff = 0; | |
2075 | + | |
2115 | 2076 | while (nexthdr != target) { |
2116 | 2077 | struct ipv6_opt_hdr _hdr, *hp; |
2117 | 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 | 2083 | return -1; |
2084 | + } | |
2085 | + | |
2121 | 2086 | hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); |
2122 | 2087 | if (hp == NULL) |
2123 | 2088 | return -1; |
2124 | 2089 | |
... | ... | @@ -2131,8 +2096,17 @@ |
2131 | 2096 | if (fp == NULL) |
2132 | 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 | 2108 | return -1; |
2109 | + } | |
2136 | 2110 | hdrlen = 8; |
2137 | 2111 | } else if (nexthdr == NEXTHDR_AUTH) |
2138 | 2112 | hdrlen = (hp->hdrlen + 2) << 2; |
... | ... | @@ -2145,7 +2119,7 @@ |
2145 | 2119 | } |
2146 | 2120 | |
2147 | 2121 | *offset = start; |
2148 | - return 0; | |
2122 | + return nexthdr; | |
2149 | 2123 | } |
2150 | 2124 | |
2151 | 2125 | EXPORT_SYMBOL(ip6t_register_table); |
net/ipv6/netfilter/ip6t_ah.c
net/ipv6/netfilter/ip6t_dst.c
... | ... | @@ -71,9 +71,9 @@ |
71 | 71 | unsigned int optlen; |
72 | 72 | |
73 | 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 | 75 | #else |
76 | - if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) | |
76 | + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0) | |
77 | 77 | #endif |
78 | 78 | return 0; |
79 | 79 |
net/ipv6/netfilter/ip6t_esp.c
... | ... | @@ -56,7 +56,7 @@ |
56 | 56 | /* Make sure this isn't an evil packet */ |
57 | 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 | 60 | return 0; |
61 | 61 | |
62 | 62 | eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp); |
net/ipv6/netfilter/ip6t_frag.c
... | ... | @@ -52,7 +52,7 @@ |
52 | 52 | const struct ip6t_frag *fraginfo = matchinfo; |
53 | 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 | 56 | return 0; |
57 | 57 | |
58 | 58 | fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); |
net/ipv6/netfilter/ip6t_hbh.c
... | ... | @@ -71,9 +71,9 @@ |
71 | 71 | unsigned int optlen; |
72 | 72 | |
73 | 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 | 75 | #else |
76 | - if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) | |
76 | + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0) | |
77 | 77 | #endif |
78 | 78 | return 0; |
79 | 79 |
net/ipv6/netfilter/ip6t_rt.c