blob: 00d5d5b46b37f9a020c14a4262892cd79147bc45 [file] [log] [blame]
Harald Welte46281d42001-12-18 07:55:41 +00001/* ipv6header match - matches IPv6 packets based
2on whether they contain certain headers */
3
4/* Original idea: Brad Chapman
5 * Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */
Jan Engelhardtb26d08b2011-03-01 19:51:16 +01006#include <stdint.h>
Harald Welte46281d42001-12-18 07:55:41 +00007#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <netdb.h>
Jan Engelhardtb26d08b2011-03-01 19:51:16 +010011#include <xtables.h>
Harald Welte46281d42001-12-18 07:55:41 +000012#include <linux/netfilter_ipv6/ip6t_ipv6header.h>
13
Jan Engelhardtb26d08b2011-03-01 19:51:16 +010014enum {
15 O_HEADER = 0,
16 O_SOFT,
17};
Harald Welte46281d42001-12-18 07:55:41 +000018
19/* A few hardcoded protocols for 'all' and in case the user has no
20 * /etc/protocols */
21struct pprot {
22 char *name;
Jan Engelhardt7ac40522011-01-07 12:34:04 +010023 uint8_t num;
Harald Welte46281d42001-12-18 07:55:41 +000024};
25
26struct numflag {
Jan Engelhardt7ac40522011-01-07 12:34:04 +010027 uint8_t proto;
28 uint8_t flag;
Harald Welte46281d42001-12-18 07:55:41 +000029};
30
31static const struct pprot chain_protos[] = {
32 { "hop-by-hop", IPPROTO_HOPOPTS },
33 { "protocol", IPPROTO_RAW },
34 { "hop", IPPROTO_HOPOPTS },
35 { "dst", IPPROTO_DSTOPTS },
36 { "route", IPPROTO_ROUTING },
37 { "frag", IPPROTO_FRAGMENT },
38 { "auth", IPPROTO_AH },
39 { "esp", IPPROTO_ESP },
40 { "none", IPPROTO_NONE },
41 { "prot", IPPROTO_RAW },
42 { "0", IPPROTO_HOPOPTS },
43 { "60", IPPROTO_DSTOPTS },
44 { "43", IPPROTO_ROUTING },
45 { "44", IPPROTO_FRAGMENT },
46 { "51", IPPROTO_AH },
47 { "50", IPPROTO_ESP },
48 { "59", IPPROTO_NONE },
49 { "255", IPPROTO_RAW },
50 /* { "all", 0 }, */
51};
52
53static const struct numflag chain_flags[] = {
54 { IPPROTO_HOPOPTS, MASK_HOPOPTS },
55 { IPPROTO_DSTOPTS, MASK_DSTOPTS },
56 { IPPROTO_ROUTING, MASK_ROUTING },
57 { IPPROTO_FRAGMENT, MASK_FRAGMENT },
58 { IPPROTO_AH, MASK_AH },
59 { IPPROTO_ESP, MASK_ESP },
60 { IPPROTO_NONE, MASK_NONE },
61 { IPPROTO_RAW, MASK_PROTO },
62};
63
Jan Engelhardtdd6e4b92011-05-07 00:05:24 +020064static const char *
Jan Engelhardt7ac40522011-01-07 12:34:04 +010065proto_to_name(uint8_t proto, int nolookup)
Harald Welte46281d42001-12-18 07:55:41 +000066{
67 unsigned int i;
68
69 if (proto && !nolookup) {
Jan Engelhardtdd6e4b92011-05-07 00:05:24 +020070 const struct protoent *pent = getprotobynumber(proto);
Harald Welte46281d42001-12-18 07:55:41 +000071 if (pent)
72 return pent->p_name;
73 }
74
Jan Engelhardt2c69b552009-04-30 19:32:02 +020075 for (i = 0; i < ARRAY_SIZE(chain_protos); ++i)
Harald Welte46281d42001-12-18 07:55:41 +000076 if (chain_protos[i].num == proto)
77 return chain_protos[i].name;
78
79 return NULL;
80}
81
Jan Engelhardt7ac40522011-01-07 12:34:04 +010082static uint16_t
Harald Welte46281d42001-12-18 07:55:41 +000083name_to_proto(const char *s)
84{
85 unsigned int proto=0;
Jan Engelhardtdd6e4b92011-05-07 00:05:24 +020086 const struct protoent *pent;
Harald Welte46281d42001-12-18 07:55:41 +000087
88 if ((pent = getprotobyname(s)))
89 proto = pent->p_proto;
90 else {
91 unsigned int i;
Jan Engelhardt2c69b552009-04-30 19:32:02 +020092 for (i = 0; i < ARRAY_SIZE(chain_protos); ++i)
Harald Welte46281d42001-12-18 07:55:41 +000093 if (strcmp(s, chain_protos[i].name) == 0) {
94 proto = chain_protos[i].num;
95 break;
96 }
Harald Welte46281d42001-12-18 07:55:41 +000097
Jan Engelhardt2c69b552009-04-30 19:32:02 +020098 if (i == ARRAY_SIZE(chain_protos))
Jan Engelhardt1829ed42009-02-21 03:29:44 +010099 xtables_error(PARAMETER_PROBLEM,
Harald Welte46281d42001-12-18 07:55:41 +0000100 "unknown header `%s' specified",
101 s);
102 }
103
Jan Engelhardt213e1852009-01-27 17:24:34 +0100104 return proto;
Harald Welte46281d42001-12-18 07:55:41 +0000105}
106
107static unsigned int
108add_proto_to_mask(int proto){
109 unsigned int i=0, flag=0;
110
Jan Engelhardt2c69b552009-04-30 19:32:02 +0200111 for (i = 0; i < ARRAY_SIZE(chain_flags); ++i)
Harald Welte46281d42001-12-18 07:55:41 +0000112 if (proto == chain_flags[i].proto){
113 flag = chain_flags[i].flag;
114 break;
115 }
Harald Welte46281d42001-12-18 07:55:41 +0000116
Jan Engelhardt2c69b552009-04-30 19:32:02 +0200117 if (i == ARRAY_SIZE(chain_flags))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100118 xtables_error(PARAMETER_PROBLEM,
Harald Welte46281d42001-12-18 07:55:41 +0000119 "unknown header `%d' specified",
120 proto);
121
122 return flag;
123}
124
Jan Engelhardt997045f2007-10-04 16:29:21 +0000125static void ipv6header_help(void)
Harald Welte46281d42001-12-18 07:55:41 +0000126{
127 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200128"ipv6header match options:\n"
Jan Engelhardt96727922008-08-13 14:42:41 +0200129"[!] --header headers Type of header to match, by name\n"
Harald Welte46281d42001-12-18 07:55:41 +0000130" names: hop,dst,route,frag,auth,esp,none,proto\n"
131" long names: hop-by-hop,ipv6-opts,ipv6-route,\n"
132" ipv6-frag,ah,esp,ipv6-nonxt,protocol\n"
Harald Welte426d9012001-12-25 09:27:03 +0000133" numbers: 0,60,43,44,51,50,59\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200134"--soft The header CONTAINS the specified extensions\n");
Harald Welte46281d42001-12-18 07:55:41 +0000135}
136
Jan Engelhardtb26d08b2011-03-01 19:51:16 +0100137static const struct xt_option_entry ipv6header_opts[] = {
138 {.name = "header", .id = O_HEADER, .type = XTTYPE_STRING,
139 .flags = XTOPT_MAND | XTOPT_INVERT},
140 {.name = "soft", .id = O_SOFT, .type = XTTYPE_NONE},
141 XTOPT_TABLEEND,
Harald Welte46281d42001-12-18 07:55:41 +0000142};
143
Harald Welte46281d42001-12-18 07:55:41 +0000144static unsigned int
145parse_header(const char *flags) {
146 unsigned int ret = 0;
147 char *ptr;
148 char *buffer;
149
150 buffer = strdup(flags);
151
152 for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ","))
153 ret |= add_proto_to_mask(name_to_proto(ptr));
154
155 free(buffer);
156 return ret;
157}
158
Jan Engelhardtb26d08b2011-03-01 19:51:16 +0100159static void ipv6header_parse(struct xt_option_call *cb)
Harald Welte46281d42001-12-18 07:55:41 +0000160{
Jan Engelhardtb26d08b2011-03-01 19:51:16 +0100161 struct ip6t_ipv6header_info *info = cb->data;
Harald Welte46281d42001-12-18 07:55:41 +0000162
Jan Engelhardtb26d08b2011-03-01 19:51:16 +0100163 xtables_option_parse(cb);
164 switch (cb->entry->id) {
165 case O_HEADER:
166 if (!(info->matchflags = parse_header(cb->arg)))
167 xtables_error(PARAMETER_PROBLEM, "ip6t_ipv6header: cannot parse header names");
168 if (cb->invert)
169 info->invflags |= 0xFF;
170 break;
171 case O_SOFT:
172 info->modeflag |= 0xFF;
173 break;
Harald Welte46281d42001-12-18 07:55:41 +0000174 }
Harald Welte46281d42001-12-18 07:55:41 +0000175}
176
177static void
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100178print_header(uint8_t flags){
Harald Welte46281d42001-12-18 07:55:41 +0000179 int have_flag = 0;
180
181 while (flags) {
182 unsigned int i;
183
184 for (i = 0; (flags & chain_flags[i].flag) == 0; i++);
185
186 if (have_flag)
187 printf(",");
188
189 printf("%s", proto_to_name(chain_flags[i].proto,0));
190 have_flag = 1;
191
192 flags &= ~chain_flags[i].flag;
193 }
194
195 if (!have_flag)
196 printf("NONE");
197}
198
Jan Engelhardt997045f2007-10-04 16:29:21 +0000199static void ipv6header_print(const void *ip,
200 const struct xt_entry_match *match, int numeric)
Harald Welte46281d42001-12-18 07:55:41 +0000201{
202 const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
Jan Engelhardt73866352010-12-18 02:04:59 +0100203 printf(" ipv6header");
Harald Welte46281d42001-12-18 07:55:41 +0000204
205 if (info->matchflags || info->invflags) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100206 printf(" flags:%s", info->invflags ? "!" : "");
Harald Welte46281d42001-12-18 07:55:41 +0000207 if (numeric)
Jan Engelhardt73866352010-12-18 02:04:59 +0100208 printf("0x%02X", info->matchflags);
Harald Welte46281d42001-12-18 07:55:41 +0000209 else {
210 print_header(info->matchflags);
Harald Welte46281d42001-12-18 07:55:41 +0000211 }
212 }
213
Harald Welte426d9012001-12-25 09:27:03 +0000214 if (info->modeflag)
Jan Engelhardt73866352010-12-18 02:04:59 +0100215 printf(" soft");
Harald Welte46281d42001-12-18 07:55:41 +0000216}
217
Jan Engelhardt997045f2007-10-04 16:29:21 +0000218static void ipv6header_save(const void *ip, const struct xt_entry_match *match)
Harald Welte46281d42001-12-18 07:55:41 +0000219{
220
221 const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
222
Jan Engelhardt73866352010-12-18 02:04:59 +0100223 printf("%s --header ", info->invflags ? " !" : "");
Harald Welte46281d42001-12-18 07:55:41 +0000224 print_header(info->matchflags);
Harald Welte426d9012001-12-25 09:27:03 +0000225 if (info->modeflag)
Jan Engelhardt73866352010-12-18 02:04:59 +0100226 printf(" --soft");
Harald Welte46281d42001-12-18 07:55:41 +0000227}
228
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200229static struct xtables_match ipv6header_mt6_reg = {
Harald Welte02aa7332005-02-01 15:38:20 +0000230 .name = "ipv6header",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200231 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100232 .family = NFPROTO_IPV6,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200233 .size = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
234 .userspacesize = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
Jan Engelhardt997045f2007-10-04 16:29:21 +0000235 .help = ipv6header_help,
Jan Engelhardt997045f2007-10-04 16:29:21 +0000236 .print = ipv6header_print,
237 .save = ipv6header_save,
Jan Engelhardtb26d08b2011-03-01 19:51:16 +0100238 .x6_parse = ipv6header_parse,
239 .x6_options = ipv6header_opts,
Harald Welte46281d42001-12-18 07:55:41 +0000240};
241
242void _init(void)
243{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200244 xtables_register_match(&ipv6header_mt6_reg);
Harald Welte46281d42001-12-18 07:55:41 +0000245}