1 /* Shared library add-on to iptables to add policy support. */
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
15 #include <linux/netfilter/xt_policy.h>
18 * HACK: global pointer to current matchinfo for making
19 * final checks and adjustments in final_check.
21 static struct xt_policy_info *policy_info;
23 static void policy_help(void)
26 "policy match options:\n"
27 " --dir in|out match policy applied during decapsulation/\n"
28 " policy to be applied during encapsulation\n"
29 " --pol none|ipsec match policy\n"
30 " --strict match entire policy instead of single element\n"
32 "[!] --reqid reqid match reqid\n"
33 "[!] --spi spi match SPI\n"
34 "[!] --proto proto match protocol (ah/esp/ipcomp)\n"
35 "[!] --mode mode match mode (transport/tunnel)\n"
36 "[!] --tunnel-src addr/mask match tunnel source\n"
37 "[!] --tunnel-dst addr/mask match tunnel destination\n"
38 " --next begin next element in policy\n");
41 static const struct option policy_opts[] =
94 static int parse_direction(char *s)
96 if (strcmp(s, "in") == 0)
97 return XT_POLICY_MATCH_IN;
98 if (strcmp(s, "out") == 0)
99 return XT_POLICY_MATCH_OUT;
100 xtables_error(PARAMETER_PROBLEM, "policy_match: invalid dir \"%s\"", s);
103 static int parse_policy(char *s)
105 if (strcmp(s, "none") == 0)
106 return XT_POLICY_MATCH_NONE;
107 if (strcmp(s, "ipsec") == 0)
109 xtables_error(PARAMETER_PROBLEM, "policy match: invalid policy \"%s\"", s);
112 static int parse_mode(char *s)
114 if (strcmp(s, "transport") == 0)
115 return XT_POLICY_MODE_TRANSPORT;
116 if (strcmp(s, "tunnel") == 0)
117 return XT_POLICY_MODE_TUNNEL;
118 xtables_error(PARAMETER_PROBLEM, "policy match: invalid mode \"%s\"", s);
121 static int policy_parse(int c, char **argv, int invert, unsigned int *flags,
122 struct xt_policy_info *info, uint8_t family)
124 struct xt_policy_elem *e = &info->pol[info->len];
125 struct in_addr *addr = NULL, mask;
126 struct in6_addr *addr6 = NULL, mask6;
127 unsigned int naddr = 0, num;
130 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
134 if (info->flags & (XT_POLICY_MATCH_IN | XT_POLICY_MATCH_OUT))
135 xtables_error(PARAMETER_PROBLEM,
136 "policy match: double --dir option");
138 xtables_error(PARAMETER_PROBLEM,
139 "policy match: can't invert --dir option");
141 info->flags |= parse_direction(optarg);
145 xtables_error(PARAMETER_PROBLEM,
146 "policy match: can't invert --policy option");
148 info->flags |= parse_policy(optarg);
151 if (info->flags & XT_POLICY_MATCH_STRICT)
152 xtables_error(PARAMETER_PROBLEM,
153 "policy match: double --strict option");
156 xtables_error(PARAMETER_PROBLEM,
157 "policy match: can't invert --strict option");
159 info->flags |= XT_POLICY_MATCH_STRICT;
163 xtables_error(PARAMETER_PROBLEM,
164 "policy match: double --reqid option");
167 e->invert.reqid = invert;
168 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
169 xtables_param_act(XTF_BAD_VALUE, "policy", "--spi", optarg);
174 xtables_error(PARAMETER_PROBLEM,
175 "policy match: double --spi option");
178 e->invert.spi = invert;
179 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
180 xtables_param_act(XTF_BAD_VALUE, "policy", "--spi", optarg);
185 xtables_error(PARAMETER_PROBLEM,
186 "policy match: double --tunnel-src option");
188 if (family == NFPROTO_IPV6)
189 xtables_ip6parse_any(optarg, &addr6, &mask6, &naddr);
191 xtables_ipparse_any(optarg, &addr, &mask, &naddr);
193 xtables_error(PARAMETER_PROBLEM,
194 "policy match: name resolves to multiple IPs");
197 e->invert.saddr = invert;
198 if (family == NFPROTO_IPV6) {
199 memcpy(&e->saddr.a6, addr6, sizeof(*addr6));
200 memcpy(&e->smask.a6, &mask6, sizeof(mask6));
202 e->saddr.a4 = addr[0];
208 xtables_error(PARAMETER_PROBLEM,
209 "policy match: double --tunnel-dst option");
211 if (family == NFPROTO_IPV6)
212 xtables_ip6parse_any(optarg, &addr6, &mask6, &naddr);
214 xtables_ipparse_any(optarg, &addr, &mask, &naddr);
216 xtables_error(PARAMETER_PROBLEM,
217 "policy match: name resolves to multiple IPs");
220 e->invert.daddr = invert;
221 if (family == NFPROTO_IPV6) {
222 memcpy(&e->daddr.a6, addr6, sizeof(*addr6));
223 memcpy(&e->dmask.a6, &mask6, sizeof(mask6));
225 e->daddr.a4 = addr[0];
231 xtables_error(PARAMETER_PROBLEM,
232 "policy match: double --proto option");
234 e->proto = xtables_parse_protocol(optarg);
235 if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP &&
236 e->proto != IPPROTO_COMP)
237 xtables_error(PARAMETER_PROBLEM,
238 "policy match: protocol must ah/esp/ipcomp");
240 e->invert.proto = invert;
244 xtables_error(PARAMETER_PROBLEM,
245 "policy match: double --mode option");
247 mode = parse_mode(optarg);
249 e->invert.mode = invert;
254 xtables_error(PARAMETER_PROBLEM,
255 "policy match: can't invert --next option");
257 if (++info->len == XT_POLICY_MAX_ELEM)
258 xtables_error(PARAMETER_PROBLEM,
259 "policy match: maximum policy depth reached");
269 static int policy4_parse(int c, char **argv, int invert, unsigned int *flags,
270 const void *entry, struct xt_entry_match **match)
272 return policy_parse(c, argv, invert, flags, (void *)(*match)->data,
276 static int policy6_parse(int c, char **argv, int invert, unsigned int *flags,
277 const void *entry, struct xt_entry_match **match)
279 return policy_parse(c, argv, invert, flags, (void *)(*match)->data,
283 static void policy_check(unsigned int flags)
285 struct xt_policy_info *info = policy_info;
286 struct xt_policy_elem *e;
290 xtables_error(PARAMETER_PROBLEM,
291 "policy match: no parameters given");
293 if (!(info->flags & (XT_POLICY_MATCH_IN | XT_POLICY_MATCH_OUT)))
294 xtables_error(PARAMETER_PROBLEM,
295 "policy match: neither --dir in nor --dir out specified");
297 if (info->flags & XT_POLICY_MATCH_NONE) {
298 if (info->flags & XT_POLICY_MATCH_STRICT)
299 xtables_error(PARAMETER_PROBLEM,
300 "policy match: policy none but --strict given");
303 xtables_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 & XT_POLICY_MATCH_STRICT) && info->len > 1)
309 xtables_error(PARAMETER_PROBLEM,
310 "policy match: multiple elements but no --strict");
312 for (i = 0; i < info->len; i++) {
315 if (info->flags & XT_POLICY_MATCH_STRICT &&
316 !(e->match.reqid || e->match.spi || e->match.saddr ||
317 e->match.daddr || e->match.proto || e->match.mode))
318 xtables_error(PARAMETER_PROBLEM,
319 "policy match: empty policy element");
321 if ((e->match.saddr || e->match.daddr)
322 && ((e->mode == XT_POLICY_MODE_TUNNEL && e->invert.mode) ||
323 (e->mode == XT_POLICY_MODE_TRANSPORT && !e->invert.mode)))
324 xtables_error(PARAMETER_PROBLEM,
325 "policy match: --tunnel-src/--tunnel-dst "
326 "is only valid in tunnel mode");
330 static void print_mode(const char *prefix, u_int8_t mode, int numeric)
332 printf("%smode ", prefix);
335 case XT_POLICY_MODE_TRANSPORT:
336 printf("transport ");
338 case XT_POLICY_MODE_TUNNEL:
347 static void print_proto(const 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(const char *prefix, const struct xt_policy_elem *e,
367 bool numeric, uint8_t family)
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 if (family == NFPROTO_IPV6)
388 printf("%stunnel-dst %s%s ", prefix,
389 xtables_ip6addr_to_numeric(&e->daddr.a6),
390 xtables_ip6mask_to_numeric(&e->dmask.a6));
392 printf("%stunnel-dst %s%s ", prefix,
393 xtables_ipaddr_to_numeric(&e->daddr.a4),
394 xtables_ipmask_to_numeric(&e->dmask.a4));
396 if (e->match.saddr) {
397 PRINT_INVERT(e->invert.saddr);
398 if (family == NFPROTO_IPV6)
399 printf("%stunnel-src %s%s ", prefix,
400 xtables_ip6addr_to_numeric(&e->saddr.a6),
401 xtables_ip6mask_to_numeric(&e->smask.a6));
403 printf("%stunnel-src %s%s ", prefix,
404 xtables_ipaddr_to_numeric(&e->saddr.a4),
405 xtables_ipmask_to_numeric(&e->smask.a4));
409 static void print_flags(char *prefix, const struct xt_policy_info *info)
411 if (info->flags & XT_POLICY_MATCH_IN)
412 printf("%sdir in ", prefix);
414 printf("%sdir out ", prefix);
416 if (info->flags & XT_POLICY_MATCH_NONE)
417 printf("%spol none ", prefix);
419 printf("%spol ipsec ", prefix);
421 if (info->flags & XT_POLICY_MATCH_STRICT)
422 printf("%sstrict ", prefix);
425 static void policy4_print(const void *ip, const struct xt_entry_match *match,
428 const struct xt_policy_info *info = (void *)match->data;
431 printf("policy match ");
432 print_flags("", info);
433 for (i = 0; i < info->len; i++) {
436 print_entry("", &info->pol[i], numeric, NFPROTO_IPV4);
440 static void policy6_print(const void *ip, const struct xt_entry_match *match,
443 const struct xt_policy_info *info = (void *)match->data;
446 printf("policy match ");
447 print_flags("", info);
448 for (i = 0; i < info->len; i++) {
451 print_entry("", &info->pol[i], numeric, NFPROTO_IPV6);
455 static void policy4_save(const void *ip, const struct xt_entry_match *match)
457 const struct xt_policy_info *info = (void *)match->data;
460 print_flags("--", info);
461 for (i = 0; i < info->len; i++) {
462 print_entry("--", &info->pol[i], false, NFPROTO_IPV4);
463 if (i + 1 < info->len)
468 static void policy6_save(const void *ip, const struct xt_entry_match *match)
470 const struct xt_policy_info *info = (void *)match->data;
473 print_flags("--", info);
474 for (i = 0; i < info->len; i++) {
475 print_entry("--", &info->pol[i], false, NFPROTO_IPV6);
476 if (i + 1 < info->len)
481 static struct xtables_match policy_mt_reg[] = {
484 .version = XTABLES_VERSION,
485 .family = NFPROTO_IPV4,
486 .size = XT_ALIGN(sizeof(struct xt_policy_info)),
487 .userspacesize = XT_ALIGN(sizeof(struct xt_policy_info)),
489 .parse = policy4_parse,
490 .final_check = policy_check,
491 .print = policy4_print,
492 .save = policy4_save,
493 .extra_opts = policy_opts,
497 .version = XTABLES_VERSION,
498 .family = NFPROTO_IPV6,
499 .size = XT_ALIGN(sizeof(struct xt_policy_info)),
500 .userspacesize = XT_ALIGN(sizeof(struct xt_policy_info)),
502 .parse = policy6_parse,
503 .final_check = policy_check,
504 .print = policy6_print,
505 .save = policy6_save,
506 .extra_opts = policy_opts,
512 xtables_register_matches(policy_mt_reg, ARRAY_SIZE(policy_mt_reg));