aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/netfilter/ip6_tables.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/netfilter/ip6_tables.c')
-rw-r--r--net/ipv6/netfilter/ip6_tables.c116
1 files changed, 106 insertions, 10 deletions
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 125a90d6a79..14cb310064f 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -78,6 +78,19 @@ EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table);
78 78
79 Hence the start of any table is given by get_table() below. */ 79 Hence the start of any table is given by get_table() below. */
80 80
81/* Check for an extension */
82int
83ip6t_ext_hdr(u8 nexthdr)
84{
85 return (nexthdr == IPPROTO_HOPOPTS) ||
86 (nexthdr == IPPROTO_ROUTING) ||
87 (nexthdr == IPPROTO_FRAGMENT) ||
88 (nexthdr == IPPROTO_ESP) ||
89 (nexthdr == IPPROTO_AH) ||
90 (nexthdr == IPPROTO_NONE) ||
91 (nexthdr == IPPROTO_DSTOPTS);
92}
93
81/* Returns whether matches rule or not. */ 94/* Returns whether matches rule or not. */
82/* Performance critical - called for every packet */ 95/* Performance critical - called for every packet */
83static inline bool 96static inline bool
@@ -133,7 +146,7 @@ ip6_packet_match(const struct sk_buff *skb,
133 int protohdr; 146 int protohdr;
134 unsigned short _frag_off; 147 unsigned short _frag_off;
135 148
136 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off, NULL); 149 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
137 if (protohdr < 0) { 150 if (protohdr < 0) {
138 if (_frag_off == 0) 151 if (_frag_off == 0)
139 *hotdrop = true; 152 *hotdrop = true;
@@ -181,7 +194,8 @@ ip6_checkentry(const struct ip6t_ip6 *ipv6)
181static unsigned int 194static unsigned int
182ip6t_error(struct sk_buff *skb, const struct xt_action_param *par) 195ip6t_error(struct sk_buff *skb, const struct xt_action_param *par)
183{ 196{
184 net_info_ratelimited("error: `%s'\n", (const char *)par->targinfo); 197 if (net_ratelimit())
198 pr_info("error: `%s'\n", (const char *)par->targinfo);
185 199
186 return NF_DROP; 200 return NF_DROP;
187} 201}
@@ -207,7 +221,8 @@ ip6t_get_target_c(const struct ip6t_entry *e)
207 return ip6t_get_target((struct ip6t_entry *)e); 221 return ip6t_get_target((struct ip6t_entry *)e);
208} 222}
209 223
210#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) 224#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
225 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
211/* This cries for unification! */ 226/* This cries for unification! */
212static const char *const hooknames[] = { 227static const char *const hooknames[] = {
213 [NF_INET_PRE_ROUTING] = "PREROUTING", 228 [NF_INET_PRE_ROUTING] = "PREROUTING",
@@ -360,7 +375,6 @@ ip6t_do_table(struct sk_buff *skb,
360 const struct xt_entry_match *ematch; 375 const struct xt_entry_match *ematch;
361 376
362 IP_NF_ASSERT(e); 377 IP_NF_ASSERT(e);
363 acpar.thoff = 0;
364 if (!ip6_packet_match(skb, indev, outdev, &e->ipv6, 378 if (!ip6_packet_match(skb, indev, outdev, &e->ipv6,
365 &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) { 379 &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) {
366 no_match: 380 no_match:
@@ -380,7 +394,8 @@ ip6t_do_table(struct sk_buff *skb,
380 t = ip6t_get_target_c(e); 394 t = ip6t_get_target_c(e);
381 IP_NF_ASSERT(t->u.kernel.target); 395 IP_NF_ASSERT(t->u.kernel.target);
382 396
383#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) 397#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
398 defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
384 /* The packet is traced: log it */ 399 /* The packet is traced: log it */
385 if (unlikely(skb->nf_trace)) 400 if (unlikely(skb->nf_trace))
386 trace_packet(skb, hook, in, out, 401 trace_packet(skb, hook, in, out,
@@ -394,7 +409,7 @@ ip6t_do_table(struct sk_buff *skb,
394 if (v < 0) { 409 if (v < 0) {
395 /* Pop from stack? */ 410 /* Pop from stack? */
396 if (v != XT_RETURN) { 411 if (v != XT_RETURN) {
397 verdict = (unsigned int)(-v) - 1; 412 verdict = (unsigned)(-v) - 1;
398 break; 413 break;
399 } 414 }
400 if (*stackptr <= origptr) 415 if (*stackptr <= origptr)
@@ -1854,7 +1869,7 @@ compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
1854{ 1869{
1855 int ret; 1870 int ret;
1856 1871
1857 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 1872 if (!capable(CAP_NET_ADMIN))
1858 return -EPERM; 1873 return -EPERM;
1859 1874
1860 switch (cmd) { 1875 switch (cmd) {
@@ -1969,7 +1984,7 @@ compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1969{ 1984{
1970 int ret; 1985 int ret;
1971 1986
1972 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 1987 if (!capable(CAP_NET_ADMIN))
1973 return -EPERM; 1988 return -EPERM;
1974 1989
1975 switch (cmd) { 1990 switch (cmd) {
@@ -1991,7 +2006,7 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1991{ 2006{
1992 int ret; 2007 int ret;
1993 2008
1994 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 2009 if (!capable(CAP_NET_ADMIN))
1995 return -EPERM; 2010 return -EPERM;
1996 2011
1997 switch (cmd) { 2012 switch (cmd) {
@@ -2016,7 +2031,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2016{ 2031{
2017 int ret; 2032 int ret;
2018 2033
2019 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 2034 if (!capable(CAP_NET_ADMIN))
2020 return -EPERM; 2035 return -EPERM;
2021 2036
2022 switch (cmd) { 2037 switch (cmd) {
@@ -2271,9 +2286,90 @@ static void __exit ip6_tables_fini(void)
2271 unregister_pernet_subsys(&ip6_tables_net_ops); 2286 unregister_pernet_subsys(&ip6_tables_net_ops);
2272} 2287}
2273 2288
2289/*
2290 * find the offset to specified header or the protocol number of last header
2291 * if target < 0. "last header" is transport protocol header, ESP, or
2292 * "No next header".
2293 *
2294 * If target header is found, its offset is set in *offset and return protocol
2295 * number. Otherwise, return -ENOENT or -EBADMSG.
2296 *
2297 * If the first fragment doesn't contain the final protocol header or
2298 * NEXTHDR_NONE it is considered invalid.
2299 *
2300 * Note that non-1st fragment is special case that "the protocol number
2301 * of last header" is "next header" field in Fragment header. In this case,
2302 * *offset is meaningless. If fragoff is not NULL, the fragment offset is
2303 * stored in *fragoff; if it is NULL, return -EINVAL.
2304 */
2305int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
2306 int target, unsigned short *fragoff)
2307{
2308 unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
2309 u8 nexthdr = ipv6_hdr(skb)->nexthdr;
2310 unsigned int len = skb->len - start;
2311
2312 if (fragoff)
2313 *fragoff = 0;
2314
2315 while (nexthdr != target) {
2316 struct ipv6_opt_hdr _hdr, *hp;
2317 unsigned int hdrlen;
2318
2319 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
2320 if (target < 0)
2321 break;
2322 return -ENOENT;
2323 }
2324
2325 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2326 if (hp == NULL)
2327 return -EBADMSG;
2328 if (nexthdr == NEXTHDR_FRAGMENT) {
2329 unsigned short _frag_off;
2330 __be16 *fp;
2331 fp = skb_header_pointer(skb,
2332 start+offsetof(struct frag_hdr,
2333 frag_off),
2334 sizeof(_frag_off),
2335 &_frag_off);
2336 if (fp == NULL)
2337 return -EBADMSG;
2338
2339 _frag_off = ntohs(*fp) & ~0x7;
2340 if (_frag_off) {
2341 if (target < 0 &&
2342 ((!ipv6_ext_hdr(hp->nexthdr)) ||
2343 hp->nexthdr == NEXTHDR_NONE)) {
2344 if (fragoff) {
2345 *fragoff = _frag_off;
2346 return hp->nexthdr;
2347 } else {
2348 return -EINVAL;
2349 }
2350 }
2351 return -ENOENT;
2352 }
2353 hdrlen = 8;
2354 } else if (nexthdr == NEXTHDR_AUTH)
2355 hdrlen = (hp->hdrlen + 2) << 2;
2356 else
2357 hdrlen = ipv6_optlen(hp);
2358
2359 nexthdr = hp->nexthdr;
2360 len -= hdrlen;
2361 start += hdrlen;
2362 }
2363
2364 *offset = start;
2365 return nexthdr;
2366}
2367
2274EXPORT_SYMBOL(ip6t_register_table); 2368EXPORT_SYMBOL(ip6t_register_table);
2275EXPORT_SYMBOL(ip6t_unregister_table); 2369EXPORT_SYMBOL(ip6t_unregister_table);
2276EXPORT_SYMBOL(ip6t_do_table); 2370EXPORT_SYMBOL(ip6t_do_table);
2371EXPORT_SYMBOL(ip6t_ext_hdr);
2372EXPORT_SYMBOL(ipv6_find_hdr);
2277 2373
2278module_init(ip6_tables_init); 2374module_init(ip6_tables_init);
2279module_exit(ip6_tables_fini); 2375module_exit(ip6_tables_fini);