1 /* Shared library add-on to iptables to add policy support. */
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <ip6tables.h>
16 #include <linux/netfilter_ipv6/ip6_tables.h>
17 #include "../include/linux/netfilter_ipv6/ip6t_policy.h"
20 * HACK: global pointer to current matchinfo for making
21 * final checks and adjustments in final_check.
23 static struct ip6t_policy_info *policy_info;
25 static void policy_help(void)
28 "policy match options:\n"
29 " --dir in|out match policy applied during decapsulation/\n"
30 " policy to be applied during encapsulation\n"
31 " --pol none|ipsec match policy\n"
32 " --strict match entire policy instead of single element\n"
34 "[!] --reqid reqid match reqid\n"
35 "[!] --spi spi match SPI\n"
36 "[!] --proto proto match protocol (ah/esp/ipcomp)\n"
37 "[!] --mode mode match mode (transport/tunnel)\n"
38 "[!] --tunnel-src addr/masklen match tunnel source\n"
39 "[!] --tunnel-dst addr/masklen match tunnel destination\n"
40 " --next begin next element in policy\n");
43 static const struct option policy_opts[] =
96 /* FIXME - Duplicated code from ip6tables.c */
97 /* Duplicated to stop too many changes in other files .... */
99 in6addrcpy(struct in6_addr *dst, struct in6_addr *src)
101 memcpy(dst, src, sizeof(struct in6_addr));
102 /* dst->s6_addr = src->s6_addr; */
106 addr_to_numeric(const struct in6_addr *addrp)
108 /* 0000:0000:0000:0000:0000:000.000.000.000
109 * 0000:0000:0000:0000:0000:0000:0000:0000 */
110 static char buf[50+1];
111 return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
115 mask_to_numeric(const struct in6_addr *addrp)
117 static char buf[50+2];
118 int l = ipv6_prefix_length(addrp);
121 strcat(buf, addr_to_numeric(addrp));
124 sprintf(buf, "/%d", l);
128 static int parse_direction(char *s)
130 if (strcmp(s, "in") == 0)
131 return IP6T_POLICY_MATCH_IN;
132 if (strcmp(s, "out") == 0)
133 return IP6T_POLICY_MATCH_OUT;
134 exit_error(PARAMETER_PROBLEM, "policy_match: invalid dir `%s'", s);
137 static int parse_policy(char *s)
139 if (strcmp(s, "none") == 0)
140 return IP6T_POLICY_MATCH_NONE;
141 if (strcmp(s, "ipsec") == 0)
143 exit_error(PARAMETER_PROBLEM, "policy match: invalid policy `%s'", s);
146 static int parse_mode(char *s)
148 if (strcmp(s, "transport") == 0)
149 return IP6T_POLICY_MODE_TRANSPORT;
150 if (strcmp(s, "tunnel") == 0)
151 return IP6T_POLICY_MODE_TUNNEL;
152 exit_error(PARAMETER_PROBLEM, "policy match: invalid mode `%s'", s);
155 static int policy_parse(int c, char **argv, int invert, unsigned int *flags,
156 const void *entry, struct xt_entry_match **match)
158 struct ip6t_policy_info *info = (void *)(*match)->data;
159 struct ip6t_policy_elem *e = &info->pol[info->len];
160 struct in6_addr *addr = NULL, mask;
161 unsigned int naddr = 0;
164 check_inverse(optarg, &invert, &optind, 0);
168 if (info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))
169 exit_error(PARAMETER_PROBLEM,
170 "policy match: double --dir option");
172 exit_error(PARAMETER_PROBLEM,
173 "policy match: can't invert --dir option");
175 info->flags |= parse_direction(argv[optind-1]);
179 exit_error(PARAMETER_PROBLEM,
180 "policy match: can't invert --policy option");
182 info->flags |= parse_policy(argv[optind-1]);
185 if (info->flags & IP6T_POLICY_MATCH_STRICT)
186 exit_error(PARAMETER_PROBLEM,
187 "policy match: double --strict option");
190 exit_error(PARAMETER_PROBLEM,
191 "policy match: can't invert --strict option");
193 info->flags |= IP6T_POLICY_MATCH_STRICT;
197 exit_error(PARAMETER_PROBLEM,
198 "policy match: double --reqid option");
201 e->invert.reqid = invert;
202 e->reqid = strtol(argv[optind-1], NULL, 10);
206 exit_error(PARAMETER_PROBLEM,
207 "policy match: double --spi option");
210 e->invert.spi = invert;
211 e->spi = strtol(argv[optind-1], NULL, 0x10);
215 exit_error(PARAMETER_PROBLEM,
216 "policy match: double --tunnel-src option");
218 ip6parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr);
220 exit_error(PARAMETER_PROBLEM,
221 "policy match: name resolves to multiple IPs");
224 e->invert.saddr = invert;
225 in6addrcpy(&e->saddr.a6, addr);
226 in6addrcpy(&e->smask.a6, &mask);
230 exit_error(PARAMETER_PROBLEM,
231 "policy match: double --tunnel-dst option");
233 ip6parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr);
235 exit_error(PARAMETER_PROBLEM,
236 "policy match: name resolves to multiple IPs");
239 e->invert.daddr = invert;
240 in6addrcpy(&e->daddr.a6, addr);
241 in6addrcpy(&e->dmask.a6, &mask);
245 exit_error(PARAMETER_PROBLEM,
246 "policy match: double --proto option");
248 e->proto = parse_protocol(argv[optind-1]);
249 if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP &&
250 e->proto != IPPROTO_COMP)
251 exit_error(PARAMETER_PROBLEM,
252 "policy match: protocol must ah/esp/ipcomp");
254 e->invert.proto = invert;
258 exit_error(PARAMETER_PROBLEM,
259 "policy match: double --mode option");
261 mode = parse_mode(argv[optind-1]);
263 e->invert.mode = invert;
268 exit_error(PARAMETER_PROBLEM,
269 "policy match: can't invert --next option");
271 if (++info->len == IP6T_POLICY_MAX_ELEM)
272 exit_error(PARAMETER_PROBLEM,
273 "policy match: maximum policy depth reached");
283 static void policy_check(unsigned int flags)
285 struct ip6t_policy_info *info = policy_info;
286 struct ip6t_policy_elem *e;
290 exit_error(PARAMETER_PROBLEM,
291 "policy match: no parameters given");
293 if (!(info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT)))
294 exit_error(PARAMETER_PROBLEM,
295 "policy match: neither --in nor --out specified");
297 if (info->flags & IP6T_POLICY_MATCH_NONE) {
298 if (info->flags & IP6T_POLICY_MATCH_STRICT)
299 exit_error(PARAMETER_PROBLEM,
300 "policy match: policy none but --strict given");
303 exit_error(PARAMETER_PROBLEM,
304 "policy match: policy none but policy given");
306 info->len++; /* increase len by 1, no --next after last element */
308 if (!(info->flags & IP6T_POLICY_MATCH_STRICT) && info->len > 1)
309 exit_error(PARAMETER_PROBLEM,
310 "policy match: multiple elements but no --strict");
312 for (i = 0; i < info->len; i++) {
315 if (info->flags & IP6T_POLICY_MATCH_STRICT &&
316 !(e->match.reqid || e->match.spi || e->match.saddr ||
317 e->match.daddr || e->match.proto || e->match.mode))
318 exit_error(PARAMETER_PROBLEM,
319 "policy match: empty policy element");
321 if ((e->match.saddr || e->match.daddr)
322 && ((e->mode == IP6T_POLICY_MODE_TUNNEL && e->invert.mode) ||
323 (e->mode == IP6T_POLICY_MODE_TRANSPORT && !e->invert.mode)))
324 exit_error(PARAMETER_PROBLEM,
325 "policy match: --tunnel-src/--tunnel-dst "
326 "is only valid in tunnel mode");
330 static void print_mode(char *prefix, u_int8_t mode, int numeric)
332 printf("%smode ", prefix);
335 case IP6T_POLICY_MODE_TRANSPORT:
336 printf("transport ");
338 case IP6T_POLICY_MODE_TUNNEL:
347 static void print_proto(char *prefix, u_int8_t proto, int numeric)
349 struct protoent *p = NULL;
351 printf("%sproto ", prefix);
353 p = getprotobynumber(proto);
355 printf("%s ", p->p_name);
357 printf("%u ", proto);
360 #define PRINT_INVERT(x) \
366 static void print_entry(char *prefix, const struct ip6t_policy_elem *e,
369 if (e->match.reqid) {
370 PRINT_INVERT(e->invert.reqid);
371 printf("%sreqid %u ", prefix, e->reqid);
374 PRINT_INVERT(e->invert.spi);
375 printf("%sspi 0x%x ", prefix, e->spi);
377 if (e->match.proto) {
378 PRINT_INVERT(e->invert.proto);
379 print_proto(prefix, e->proto, numeric);
382 PRINT_INVERT(e->invert.mode);
383 print_mode(prefix, e->mode, numeric);
385 if (e->match.daddr) {
386 PRINT_INVERT(e->invert.daddr);
387 printf("%stunnel-dst %s%s ", prefix,
388 addr_to_numeric((struct in6_addr *)&e->daddr),
389 mask_to_numeric((struct in6_addr *)&e->dmask));
391 if (e->match.saddr) {
392 PRINT_INVERT(e->invert.saddr);
393 printf("%stunnel-src %s%s ", prefix,
394 addr_to_numeric((struct in6_addr *)&e->saddr),
395 mask_to_numeric((struct in6_addr *)&e->smask));
399 static void print_flags(char *prefix, const struct ip6t_policy_info *info)
401 if (info->flags & IP6T_POLICY_MATCH_IN)
402 printf("%sdir in ", prefix);
404 printf("%sdir out ", prefix);
406 if (info->flags & IP6T_POLICY_MATCH_NONE)
407 printf("%spol none ", prefix);
409 printf("%spol ipsec ", prefix);
411 if (info->flags & IP6T_POLICY_MATCH_STRICT)
412 printf("%sstrict ", prefix);
415 static void policy_print(const void *ip, const struct xt_entry_match *match,
418 const struct ip6t_policy_info *info = (void *)match->data;
421 printf("policy match ");
422 print_flags("", info);
423 for (i = 0; i < info->len; i++) {
426 print_entry("", &info->pol[i], numeric);
432 static void policy_save(const void *ip, const struct xt_entry_match *match)
434 const struct ip6t_policy_info *info = (void *)match->data;
437 print_flags("--", info);
438 for (i = 0; i < info->len; i++) {
439 print_entry("--", &info->pol[i], 0);
440 if (i + 1 < info->len)
445 static struct xtables_match policy_mt6_reg = {
447 .version = XTABLES_VERSION,
449 .size = XT_ALIGN(sizeof(struct ip6t_policy_info)),
450 .userspacesize = XT_ALIGN(sizeof(struct ip6t_policy_info)),
452 .parse = policy_parse,
453 .final_check = policy_check,
454 .print = policy_print,
456 .extra_opts = policy_opts,
461 xtables_register_match(&policy_mt6_reg);