1*a71a9546SAutomerger Merge Worker /* ipv6header match - matches IPv6 packets based
2*a71a9546SAutomerger Merge Worker on whether they contain certain headers */
3*a71a9546SAutomerger Merge Worker
4*a71a9546SAutomerger Merge Worker /* Original idea: Brad Chapman
5*a71a9546SAutomerger Merge Worker * Rewritten by: Andras Kis-Szabo <[email protected]> */
6*a71a9546SAutomerger Merge Worker #include <stdint.h>
7*a71a9546SAutomerger Merge Worker #include <stdio.h>
8*a71a9546SAutomerger Merge Worker #include <stdlib.h>
9*a71a9546SAutomerger Merge Worker #include <string.h>
10*a71a9546SAutomerger Merge Worker #include <netdb.h>
11*a71a9546SAutomerger Merge Worker #include <xtables.h>
12*a71a9546SAutomerger Merge Worker #include <linux/netfilter_ipv6/ip6t_ipv6header.h>
13*a71a9546SAutomerger Merge Worker
14*a71a9546SAutomerger Merge Worker enum {
15*a71a9546SAutomerger Merge Worker O_HEADER = 0,
16*a71a9546SAutomerger Merge Worker O_SOFT,
17*a71a9546SAutomerger Merge Worker };
18*a71a9546SAutomerger Merge Worker
19*a71a9546SAutomerger Merge Worker /* A few hardcoded protocols for 'all' and in case the user has no
20*a71a9546SAutomerger Merge Worker * /etc/protocols */
21*a71a9546SAutomerger Merge Worker struct pprot {
22*a71a9546SAutomerger Merge Worker char *name;
23*a71a9546SAutomerger Merge Worker uint8_t num;
24*a71a9546SAutomerger Merge Worker };
25*a71a9546SAutomerger Merge Worker
26*a71a9546SAutomerger Merge Worker struct numflag {
27*a71a9546SAutomerger Merge Worker uint8_t proto;
28*a71a9546SAutomerger Merge Worker uint8_t flag;
29*a71a9546SAutomerger Merge Worker };
30*a71a9546SAutomerger Merge Worker
31*a71a9546SAutomerger Merge Worker static const struct pprot chain_protos[] = {
32*a71a9546SAutomerger Merge Worker { "hop-by-hop", IPPROTO_HOPOPTS },
33*a71a9546SAutomerger Merge Worker { "protocol", IPPROTO_RAW },
34*a71a9546SAutomerger Merge Worker { "hop", IPPROTO_HOPOPTS },
35*a71a9546SAutomerger Merge Worker { "dst", IPPROTO_DSTOPTS },
36*a71a9546SAutomerger Merge Worker { "route", IPPROTO_ROUTING },
37*a71a9546SAutomerger Merge Worker { "frag", IPPROTO_FRAGMENT },
38*a71a9546SAutomerger Merge Worker { "auth", IPPROTO_AH },
39*a71a9546SAutomerger Merge Worker { "esp", IPPROTO_ESP },
40*a71a9546SAutomerger Merge Worker { "none", IPPROTO_NONE },
41*a71a9546SAutomerger Merge Worker { "prot", IPPROTO_RAW },
42*a71a9546SAutomerger Merge Worker { "0", IPPROTO_HOPOPTS },
43*a71a9546SAutomerger Merge Worker { "60", IPPROTO_DSTOPTS },
44*a71a9546SAutomerger Merge Worker { "43", IPPROTO_ROUTING },
45*a71a9546SAutomerger Merge Worker { "44", IPPROTO_FRAGMENT },
46*a71a9546SAutomerger Merge Worker { "51", IPPROTO_AH },
47*a71a9546SAutomerger Merge Worker { "50", IPPROTO_ESP },
48*a71a9546SAutomerger Merge Worker { "59", IPPROTO_NONE },
49*a71a9546SAutomerger Merge Worker { "255", IPPROTO_RAW },
50*a71a9546SAutomerger Merge Worker /* { "all", 0 }, */
51*a71a9546SAutomerger Merge Worker };
52*a71a9546SAutomerger Merge Worker
53*a71a9546SAutomerger Merge Worker static const struct numflag chain_flags[] = {
54*a71a9546SAutomerger Merge Worker { IPPROTO_HOPOPTS, MASK_HOPOPTS },
55*a71a9546SAutomerger Merge Worker { IPPROTO_DSTOPTS, MASK_DSTOPTS },
56*a71a9546SAutomerger Merge Worker { IPPROTO_ROUTING, MASK_ROUTING },
57*a71a9546SAutomerger Merge Worker { IPPROTO_FRAGMENT, MASK_FRAGMENT },
58*a71a9546SAutomerger Merge Worker { IPPROTO_AH, MASK_AH },
59*a71a9546SAutomerger Merge Worker { IPPROTO_ESP, MASK_ESP },
60*a71a9546SAutomerger Merge Worker { IPPROTO_NONE, MASK_NONE },
61*a71a9546SAutomerger Merge Worker { IPPROTO_RAW, MASK_PROTO },
62*a71a9546SAutomerger Merge Worker };
63*a71a9546SAutomerger Merge Worker
64*a71a9546SAutomerger Merge Worker static const char *
proto_to_name(uint8_t proto,int nolookup)65*a71a9546SAutomerger Merge Worker proto_to_name(uint8_t proto, int nolookup)
66*a71a9546SAutomerger Merge Worker {
67*a71a9546SAutomerger Merge Worker unsigned int i;
68*a71a9546SAutomerger Merge Worker
69*a71a9546SAutomerger Merge Worker if (proto && !nolookup) {
70*a71a9546SAutomerger Merge Worker const struct protoent *pent = getprotobynumber(proto);
71*a71a9546SAutomerger Merge Worker if (pent)
72*a71a9546SAutomerger Merge Worker return pent->p_name;
73*a71a9546SAutomerger Merge Worker }
74*a71a9546SAutomerger Merge Worker
75*a71a9546SAutomerger Merge Worker for (i = 0; i < ARRAY_SIZE(chain_protos); ++i)
76*a71a9546SAutomerger Merge Worker if (chain_protos[i].num == proto)
77*a71a9546SAutomerger Merge Worker return chain_protos[i].name;
78*a71a9546SAutomerger Merge Worker
79*a71a9546SAutomerger Merge Worker return NULL;
80*a71a9546SAutomerger Merge Worker }
81*a71a9546SAutomerger Merge Worker
82*a71a9546SAutomerger Merge Worker static uint16_t
name_to_proto(const char * s)83*a71a9546SAutomerger Merge Worker name_to_proto(const char *s)
84*a71a9546SAutomerger Merge Worker {
85*a71a9546SAutomerger Merge Worker unsigned int proto=0;
86*a71a9546SAutomerger Merge Worker const struct protoent *pent;
87*a71a9546SAutomerger Merge Worker
88*a71a9546SAutomerger Merge Worker if ((pent = getprotobyname(s)))
89*a71a9546SAutomerger Merge Worker proto = pent->p_proto;
90*a71a9546SAutomerger Merge Worker else {
91*a71a9546SAutomerger Merge Worker unsigned int i;
92*a71a9546SAutomerger Merge Worker for (i = 0; i < ARRAY_SIZE(chain_protos); ++i)
93*a71a9546SAutomerger Merge Worker if (strcmp(s, chain_protos[i].name) == 0) {
94*a71a9546SAutomerger Merge Worker proto = chain_protos[i].num;
95*a71a9546SAutomerger Merge Worker break;
96*a71a9546SAutomerger Merge Worker }
97*a71a9546SAutomerger Merge Worker
98*a71a9546SAutomerger Merge Worker if (i == ARRAY_SIZE(chain_protos))
99*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
100*a71a9546SAutomerger Merge Worker "unknown header `%s' specified",
101*a71a9546SAutomerger Merge Worker s);
102*a71a9546SAutomerger Merge Worker }
103*a71a9546SAutomerger Merge Worker
104*a71a9546SAutomerger Merge Worker return proto;
105*a71a9546SAutomerger Merge Worker }
106*a71a9546SAutomerger Merge Worker
107*a71a9546SAutomerger Merge Worker static unsigned int
add_proto_to_mask(int proto)108*a71a9546SAutomerger Merge Worker add_proto_to_mask(int proto){
109*a71a9546SAutomerger Merge Worker unsigned int i=0, flag=0;
110*a71a9546SAutomerger Merge Worker
111*a71a9546SAutomerger Merge Worker for (i = 0; i < ARRAY_SIZE(chain_flags); ++i)
112*a71a9546SAutomerger Merge Worker if (proto == chain_flags[i].proto){
113*a71a9546SAutomerger Merge Worker flag = chain_flags[i].flag;
114*a71a9546SAutomerger Merge Worker break;
115*a71a9546SAutomerger Merge Worker }
116*a71a9546SAutomerger Merge Worker
117*a71a9546SAutomerger Merge Worker if (i == ARRAY_SIZE(chain_flags))
118*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
119*a71a9546SAutomerger Merge Worker "unknown header `%d' specified",
120*a71a9546SAutomerger Merge Worker proto);
121*a71a9546SAutomerger Merge Worker
122*a71a9546SAutomerger Merge Worker return flag;
123*a71a9546SAutomerger Merge Worker }
124*a71a9546SAutomerger Merge Worker
ipv6header_help(void)125*a71a9546SAutomerger Merge Worker static void ipv6header_help(void)
126*a71a9546SAutomerger Merge Worker {
127*a71a9546SAutomerger Merge Worker printf(
128*a71a9546SAutomerger Merge Worker "ipv6header match options:\n"
129*a71a9546SAutomerger Merge Worker "[!] --header headers Type of header to match, by name\n"
130*a71a9546SAutomerger Merge Worker " names: hop,dst,route,frag,auth,esp,none,prot\n"
131*a71a9546SAutomerger Merge Worker " long names: hop-by-hop,ipv6-opts,ipv6-route,\n"
132*a71a9546SAutomerger Merge Worker " ipv6-frag,ah,esp,ipv6-nonxt,protocol\n"
133*a71a9546SAutomerger Merge Worker " numbers: 0,60,43,44,51,50,59\n"
134*a71a9546SAutomerger Merge Worker "--soft The header CONTAINS the specified extensions\n");
135*a71a9546SAutomerger Merge Worker }
136*a71a9546SAutomerger Merge Worker
137*a71a9546SAutomerger Merge Worker static const struct xt_option_entry ipv6header_opts[] = {
138*a71a9546SAutomerger Merge Worker {.name = "header", .id = O_HEADER, .type = XTTYPE_STRING,
139*a71a9546SAutomerger Merge Worker .flags = XTOPT_MAND | XTOPT_INVERT},
140*a71a9546SAutomerger Merge Worker {.name = "soft", .id = O_SOFT, .type = XTTYPE_NONE},
141*a71a9546SAutomerger Merge Worker XTOPT_TABLEEND,
142*a71a9546SAutomerger Merge Worker };
143*a71a9546SAutomerger Merge Worker
144*a71a9546SAutomerger Merge Worker static unsigned int
parse_header(const char * flags)145*a71a9546SAutomerger Merge Worker parse_header(const char *flags) {
146*a71a9546SAutomerger Merge Worker unsigned int ret = 0;
147*a71a9546SAutomerger Merge Worker char *ptr;
148*a71a9546SAutomerger Merge Worker char *buffer;
149*a71a9546SAutomerger Merge Worker
150*a71a9546SAutomerger Merge Worker buffer = xtables_strdup(flags);
151*a71a9546SAutomerger Merge Worker
152*a71a9546SAutomerger Merge Worker for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ","))
153*a71a9546SAutomerger Merge Worker ret |= add_proto_to_mask(name_to_proto(ptr));
154*a71a9546SAutomerger Merge Worker
155*a71a9546SAutomerger Merge Worker free(buffer);
156*a71a9546SAutomerger Merge Worker return ret;
157*a71a9546SAutomerger Merge Worker }
158*a71a9546SAutomerger Merge Worker
ipv6header_parse(struct xt_option_call * cb)159*a71a9546SAutomerger Merge Worker static void ipv6header_parse(struct xt_option_call *cb)
160*a71a9546SAutomerger Merge Worker {
161*a71a9546SAutomerger Merge Worker struct ip6t_ipv6header_info *info = cb->data;
162*a71a9546SAutomerger Merge Worker
163*a71a9546SAutomerger Merge Worker xtables_option_parse(cb);
164*a71a9546SAutomerger Merge Worker switch (cb->entry->id) {
165*a71a9546SAutomerger Merge Worker case O_HEADER:
166*a71a9546SAutomerger Merge Worker if (!(info->matchflags = parse_header(cb->arg)))
167*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM, "ip6t_ipv6header: cannot parse header names");
168*a71a9546SAutomerger Merge Worker if (cb->invert)
169*a71a9546SAutomerger Merge Worker info->invflags |= 0xFF;
170*a71a9546SAutomerger Merge Worker break;
171*a71a9546SAutomerger Merge Worker case O_SOFT:
172*a71a9546SAutomerger Merge Worker info->modeflag |= 0xFF;
173*a71a9546SAutomerger Merge Worker break;
174*a71a9546SAutomerger Merge Worker }
175*a71a9546SAutomerger Merge Worker }
176*a71a9546SAutomerger Merge Worker
177*a71a9546SAutomerger Merge Worker static void
print_header(uint8_t flags)178*a71a9546SAutomerger Merge Worker print_header(uint8_t flags){
179*a71a9546SAutomerger Merge Worker int have_flag = 0;
180*a71a9546SAutomerger Merge Worker
181*a71a9546SAutomerger Merge Worker while (flags) {
182*a71a9546SAutomerger Merge Worker unsigned int i;
183*a71a9546SAutomerger Merge Worker
184*a71a9546SAutomerger Merge Worker for (i = 0; (flags & chain_flags[i].flag) == 0; i++);
185*a71a9546SAutomerger Merge Worker
186*a71a9546SAutomerger Merge Worker if (have_flag)
187*a71a9546SAutomerger Merge Worker printf(",");
188*a71a9546SAutomerger Merge Worker
189*a71a9546SAutomerger Merge Worker printf("%s", proto_to_name(chain_flags[i].proto,0));
190*a71a9546SAutomerger Merge Worker have_flag = 1;
191*a71a9546SAutomerger Merge Worker
192*a71a9546SAutomerger Merge Worker flags &= ~chain_flags[i].flag;
193*a71a9546SAutomerger Merge Worker }
194*a71a9546SAutomerger Merge Worker
195*a71a9546SAutomerger Merge Worker if (!have_flag)
196*a71a9546SAutomerger Merge Worker printf("NONE");
197*a71a9546SAutomerger Merge Worker }
198*a71a9546SAutomerger Merge Worker
ipv6header_print(const void * ip,const struct xt_entry_match * match,int numeric)199*a71a9546SAutomerger Merge Worker static void ipv6header_print(const void *ip,
200*a71a9546SAutomerger Merge Worker const struct xt_entry_match *match, int numeric)
201*a71a9546SAutomerger Merge Worker {
202*a71a9546SAutomerger Merge Worker const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
203*a71a9546SAutomerger Merge Worker printf(" ipv6header");
204*a71a9546SAutomerger Merge Worker
205*a71a9546SAutomerger Merge Worker if (info->matchflags || info->invflags) {
206*a71a9546SAutomerger Merge Worker printf(" flags:%s", info->invflags ? "!" : "");
207*a71a9546SAutomerger Merge Worker if (numeric)
208*a71a9546SAutomerger Merge Worker printf("0x%02X", info->matchflags);
209*a71a9546SAutomerger Merge Worker else {
210*a71a9546SAutomerger Merge Worker print_header(info->matchflags);
211*a71a9546SAutomerger Merge Worker }
212*a71a9546SAutomerger Merge Worker }
213*a71a9546SAutomerger Merge Worker
214*a71a9546SAutomerger Merge Worker if (info->modeflag)
215*a71a9546SAutomerger Merge Worker printf(" soft");
216*a71a9546SAutomerger Merge Worker }
217*a71a9546SAutomerger Merge Worker
ipv6header_save(const void * ip,const struct xt_entry_match * match)218*a71a9546SAutomerger Merge Worker static void ipv6header_save(const void *ip, const struct xt_entry_match *match)
219*a71a9546SAutomerger Merge Worker {
220*a71a9546SAutomerger Merge Worker
221*a71a9546SAutomerger Merge Worker const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
222*a71a9546SAutomerger Merge Worker
223*a71a9546SAutomerger Merge Worker printf("%s --header ", info->invflags ? " !" : "");
224*a71a9546SAutomerger Merge Worker print_header(info->matchflags);
225*a71a9546SAutomerger Merge Worker if (info->modeflag)
226*a71a9546SAutomerger Merge Worker printf(" --soft");
227*a71a9546SAutomerger Merge Worker }
228*a71a9546SAutomerger Merge Worker
229*a71a9546SAutomerger Merge Worker static struct xtables_match ipv6header_mt6_reg = {
230*a71a9546SAutomerger Merge Worker .name = "ipv6header",
231*a71a9546SAutomerger Merge Worker .version = XTABLES_VERSION,
232*a71a9546SAutomerger Merge Worker .family = NFPROTO_IPV6,
233*a71a9546SAutomerger Merge Worker .size = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
234*a71a9546SAutomerger Merge Worker .userspacesize = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
235*a71a9546SAutomerger Merge Worker .help = ipv6header_help,
236*a71a9546SAutomerger Merge Worker .print = ipv6header_print,
237*a71a9546SAutomerger Merge Worker .save = ipv6header_save,
238*a71a9546SAutomerger Merge Worker .x6_parse = ipv6header_parse,
239*a71a9546SAutomerger Merge Worker .x6_options = ipv6header_opts,
240*a71a9546SAutomerger Merge Worker };
241*a71a9546SAutomerger Merge Worker
_init(void)242*a71a9546SAutomerger Merge Worker void _init(void)
243*a71a9546SAutomerger Merge Worker {
244*a71a9546SAutomerger Merge Worker xtables_register_match(&ipv6header_mt6_reg);
245*a71a9546SAutomerger Merge Worker }
246