Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* ipv6header match - matches IPv6 packets based |
| 2 | on whether they contain certain headers */ |
| 3 | |
YOSHIFUJI Hideaki | 1ab1457 | 2007-02-09 23:24:49 +0900 | [diff] [blame] | 4 | /* Original idea: Brad Chapman |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 5 | * Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */ |
| 6 | |
| 7 | /* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu> |
| 8 | * |
| 9 | * This program is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU General Public License version 2 as |
| 11 | * published by the Free Software Foundation. |
| 12 | */ |
| 13 | |
| 14 | #include <linux/module.h> |
| 15 | #include <linux/skbuff.h> |
| 16 | #include <linux/ipv6.h> |
| 17 | #include <linux/types.h> |
| 18 | #include <net/checksum.h> |
| 19 | #include <net/ipv6.h> |
| 20 | |
Jan Engelhardt | 6709dbb | 2007-02-07 15:11:19 -0800 | [diff] [blame] | 21 | #include <linux/netfilter/x_tables.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 22 | #include <linux/netfilter_ipv6/ip6_tables.h> |
| 23 | #include <linux/netfilter_ipv6/ip6t_ipv6header.h> |
| 24 | |
| 25 | MODULE_LICENSE("GPL"); |
Jan Engelhardt | 2ae15b6 | 2008-01-14 23:42:28 -0800 | [diff] [blame] | 26 | MODULE_DESCRIPTION("Xtables: IPv6 header types match"); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 27 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); |
| 28 | |
Jan Engelhardt | 1d93a9c | 2007-07-07 22:15:35 -0700 | [diff] [blame] | 29 | static bool |
Jan Engelhardt | 62fc805 | 2009-07-07 20:42:08 +0200 | [diff] [blame] | 30 | ipv6header_mt6(const struct sk_buff *skb, struct xt_action_param *par) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 | { |
Jan Engelhardt | f7108a2 | 2008-10-08 11:35:18 +0200 | [diff] [blame] | 32 | const struct ip6t_ipv6header_info *info = par->matchinfo; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 33 | unsigned int temp; |
| 34 | int len; |
| 35 | u8 nexthdr; |
| 36 | unsigned int ptr; |
| 37 | |
| 38 | /* Make sure this isn't an evil packet */ |
| 39 | |
| 40 | /* type of the 1st exthdr */ |
Arnaldo Carvalho de Melo | 0660e03 | 2007-04-25 17:54:47 -0700 | [diff] [blame] | 41 | nexthdr = ipv6_hdr(skb)->nexthdr; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 42 | /* pointer to the 1st exthdr */ |
| 43 | ptr = sizeof(struct ipv6hdr); |
| 44 | /* available length */ |
| 45 | len = skb->len - ptr; |
| 46 | temp = 0; |
| 47 | |
Yasuyuki Kozakai | f0daaa6 | 2006-01-17 02:39:39 -0800 | [diff] [blame] | 48 | while (ip6t_ext_hdr(nexthdr)) { |
Jan Engelhardt | 3cf93c9 | 2008-04-14 09:56:05 +0200 | [diff] [blame] | 49 | const struct ipv6_opt_hdr *hp; |
| 50 | struct ipv6_opt_hdr _hdr; |
Yasuyuki Kozakai | f0daaa6 | 2006-01-17 02:39:39 -0800 | [diff] [blame] | 51 | int hdrlen; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 53 | /* No more exthdr -> evaluate */ |
Yasuyuki Kozakai | f0daaa6 | 2006-01-17 02:39:39 -0800 | [diff] [blame] | 54 | if (nexthdr == NEXTHDR_NONE) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 55 | temp |= MASK_NONE; |
| 56 | break; |
| 57 | } |
Christoph Paasch | b98b494 | 2009-05-05 15:32:16 +0200 | [diff] [blame] | 58 | /* Is there enough space for the next ext header? */ |
| 59 | if (len < (int)sizeof(struct ipv6_opt_hdr)) |
| 60 | return false; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 61 | /* ESP -> evaluate */ |
Yasuyuki Kozakai | f0daaa6 | 2006-01-17 02:39:39 -0800 | [diff] [blame] | 62 | if (nexthdr == NEXTHDR_ESP) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 63 | temp |= MASK_ESP; |
| 64 | break; |
| 65 | } |
| 66 | |
| 67 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); |
| 68 | BUG_ON(hp == NULL); |
| 69 | |
| 70 | /* Calculate the header length */ |
Jan Engelhardt | 7c4e36b | 2007-07-07 22:19:08 -0700 | [diff] [blame] | 71 | if (nexthdr == NEXTHDR_FRAGMENT) |
Yasuyuki Kozakai | f0daaa6 | 2006-01-17 02:39:39 -0800 | [diff] [blame] | 72 | hdrlen = 8; |
Jan Engelhardt | 7c4e36b | 2007-07-07 22:19:08 -0700 | [diff] [blame] | 73 | else if (nexthdr == NEXTHDR_AUTH) |
Yasuyuki Kozakai | f0daaa6 | 2006-01-17 02:39:39 -0800 | [diff] [blame] | 74 | hdrlen = (hp->hdrlen + 2) << 2; |
| 75 | else |
| 76 | hdrlen = ipv6_optlen(hp); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 77 | |
| 78 | /* set the flag */ |
Yasuyuki Kozakai | f0daaa6 | 2006-01-17 02:39:39 -0800 | [diff] [blame] | 79 | switch (nexthdr) { |
| 80 | case NEXTHDR_HOP: |
| 81 | temp |= MASK_HOPOPTS; |
| 82 | break; |
| 83 | case NEXTHDR_ROUTING: |
| 84 | temp |= MASK_ROUTING; |
| 85 | break; |
| 86 | case NEXTHDR_FRAGMENT: |
| 87 | temp |= MASK_FRAGMENT; |
| 88 | break; |
| 89 | case NEXTHDR_AUTH: |
| 90 | temp |= MASK_AH; |
| 91 | break; |
| 92 | case NEXTHDR_DEST: |
| 93 | temp |= MASK_DSTOPTS; |
| 94 | break; |
| 95 | default: |
Jan Engelhardt | 1d93a9c | 2007-07-07 22:15:35 -0700 | [diff] [blame] | 96 | return false; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 97 | } |
| 98 | |
Yasuyuki Kozakai | f0daaa6 | 2006-01-17 02:39:39 -0800 | [diff] [blame] | 99 | nexthdr = hp->nexthdr; |
| 100 | len -= hdrlen; |
| 101 | ptr += hdrlen; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 102 | if (ptr > skb->len) |
| 103 | break; |
Yasuyuki Kozakai | f0daaa6 | 2006-01-17 02:39:39 -0800 | [diff] [blame] | 104 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 105 | |
Jan Engelhardt | 7c4e36b | 2007-07-07 22:19:08 -0700 | [diff] [blame] | 106 | if (nexthdr != NEXTHDR_NONE && nexthdr != NEXTHDR_ESP) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 107 | temp |= MASK_PROTO; |
| 108 | |
| 109 | if (info->modeflag) |
| 110 | return !((temp ^ info->matchflags ^ info->invflags) |
| 111 | & info->matchflags); |
| 112 | else { |
| 113 | if (info->invflags) |
| 114 | return temp != info->matchflags; |
| 115 | else |
| 116 | return temp == info->matchflags; |
| 117 | } |
| 118 | } |
| 119 | |
Jan Engelhardt | b0f3845 | 2010-03-19 17:16:42 +0100 | [diff] [blame] | 120 | static int ipv6header_mt6_check(const struct xt_mtchk_param *par) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 121 | { |
Jan Engelhardt | 9b4fce7 | 2008-10-08 11:35:18 +0200 | [diff] [blame] | 122 | const struct ip6t_ipv6header_info *info = par->matchinfo; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 123 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 124 | /* invflags is 0 or 0xff in hard mode */ |
Yasuyuki Kozakai | f0daaa6 | 2006-01-17 02:39:39 -0800 | [diff] [blame] | 125 | if ((!info->modeflag) && info->invflags != 0x00 && |
| 126 | info->invflags != 0xFF) |
Jan Engelhardt | bd414ee | 2010-03-23 16:35:56 +0100 | [diff] [blame] | 127 | return -EINVAL; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 128 | |
Jan Engelhardt | bd414ee | 2010-03-23 16:35:56 +0100 | [diff] [blame] | 129 | return 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 130 | } |
| 131 | |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 132 | static struct xt_match ipv6header_mt6_reg __read_mostly = { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 133 | .name = "ipv6header", |
Jan Engelhardt | ee999d8 | 2008-10-08 11:35:01 +0200 | [diff] [blame] | 134 | .family = NFPROTO_IPV6, |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 135 | .match = ipv6header_mt6, |
Patrick McHardy | 7f93971 | 2006-03-20 18:01:43 -0800 | [diff] [blame] | 136 | .matchsize = sizeof(struct ip6t_ipv6header_info), |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 137 | .checkentry = ipv6header_mt6_check, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 138 | .destroy = NULL, |
| 139 | .me = THIS_MODULE, |
| 140 | }; |
| 141 | |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 142 | static int __init ipv6header_mt6_init(void) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 143 | { |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 144 | return xt_register_match(&ipv6header_mt6_reg); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 145 | } |
| 146 | |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 147 | static void __exit ipv6header_mt6_exit(void) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 148 | { |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 149 | xt_unregister_match(&ipv6header_mt6_reg); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 150 | } |
| 151 | |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 152 | module_init(ipv6header_mt6_init); |
| 153 | module_exit(ipv6header_mt6_exit); |