aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2006-01-05 15:21:16 -0500
committerDavid S. Miller <davem@davemloft.net>2006-01-05 15:21:16 -0500
commitb777e0ce7437a0e788e2aeb42aca9af2cce1f2e1 (patch)
treececbfdf5b78b909b80f3f04cbfdac7599f5a3352
parent1bd9bef6f9fe06dd0c628ac877c85b6b36aca062 (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.h2
-rw-r--r--net/ipv6/netfilter/ip6_tables.c106
-rw-r--r--net/ipv6/netfilter/ip6t_ah.c2
-rw-r--r--net/ipv6/netfilter/ip6t_dst.c4
-rw-r--r--net/ipv6/netfilter/ip6t_esp.c2
-rw-r--r--net/ipv6/netfilter/ip6t_frag.c2
-rw-r--r--net/ipv6/netfilter/ip6t_hbh.c4
-rw-r--r--net/ipv6/netfilter/ip6t_rt.c2
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,
474extern int ip6t_ext_hdr(u8 nexthdr); 474extern int ip6t_ext_hdr(u8 nexthdr);
475/* find specified header and get offset to it */ 475/* find specified header and get offset to it */
476extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, 476extern 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 */
2109int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target) 2066int 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
2151EXPORT_SYMBOL(ip6t_register_table); 2125EXPORT_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);