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_ipv4/ip_tables.h>
16 #include "../include/linux/netfilter_ipv4/ipt_policy.h"
19 * HACK: global pointer to current matchinfo for making
20 * final checks and adjustments in final_check.
22 static struct ipt_policy_info *policy_info;
24 static void policy_help(void)
27 "policy match options:\n"
28 " --dir in|out match policy applied during decapsulation/\n"
29 " policy to be applied during encapsulation\n"
30 " --pol none|ipsec match policy\n"
31 " --strict match entire policy instead of single element\n"
33 "[!] --reqid reqid match reqid\n"
34 "[!] --spi spi match SPI\n"
35 "[!] --proto proto match protocol (ah/esp/ipcomp)\n"
36 "[!] --mode mode match mode (transport/tunnel)\n"
37 "[!] --tunnel-src addr/mask match tunnel source\n"
38 "[!] --tunnel-dst addr/mask match tunnel destination\n"
39 " --next begin next element in policy\n");
42 static const struct option policy_opts[] =
95 static int parse_direction(char *s)
97 if (strcmp(s, "in") == 0)
98 return IPT_POLICY_MATCH_IN;
99 if (strcmp(s, "out") == 0)
100 return IPT_POLICY_MATCH_OUT;
101 exit_error(PARAMETER_PROBLEM, "policy_match: invalid dir `%s'", s);
104 static int parse_policy(char *s)
106 if (strcmp(s, "none") == 0)
107 return IPT_POLICY_MATCH_NONE;
108 if (strcmp(s, "ipsec") == 0)
110 exit_error(PARAMETER_PROBLEM, "policy match: invalid policy `%s'", s);
113 static int parse_mode(char *s)
115 if (strcmp(s, "transport") == 0)
116 return IPT_POLICY_MODE_TRANSPORT;
117 if (strcmp(s, "tunnel") == 0)
118 return IPT_POLICY_MODE_TUNNEL;
119 exit_error(PARAMETER_PROBLEM, "policy match: invalid mode `%s'", s);
122 static int policy_parse(int c, char **argv, int invert, unsigned int *flags,
123 const void *entry, struct xt_entry_match **match)
125 struct ipt_policy_info *info = (void *)(*match)->data;
126 struct ipt_policy_elem *e = &info->pol[info->len];
127 struct in_addr *addr = NULL, mask;
128 unsigned int naddr = 0;
131 check_inverse(optarg, &invert, &optind, 0);
135 if (info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT))
136 exit_error(PARAMETER_PROBLEM,
137 "policy match: double --dir option");
139 exit_error(PARAMETER_PROBLEM,
140 "policy match: can't invert --dir option");
142 info->flags |= parse_direction(argv[optind-1]);
146 exit_error(PARAMETER_PROBLEM,
147 "policy match: can't invert --policy option");
149 info->flags |= parse_policy(argv[optind-1]);
152 if (info->flags & IPT_POLICY_MATCH_STRICT)
153 exit_error(PARAMETER_PROBLEM,
154 "policy match: double --strict option");
157 exit_error(PARAMETER_PROBLEM,
158 "policy match: can't invert --strict option");
160 info->flags |= IPT_POLICY_MATCH_STRICT;
164 exit_error(PARAMETER_PROBLEM,
165 "policy match: double --reqid option");
168 e->invert.reqid = invert;
169 e->reqid = strtol(argv[optind-1], NULL, 10);
173 exit_error(PARAMETER_PROBLEM,
174 "policy match: double --spi option");
177 e->invert.spi = invert;
178 e->spi = strtol(argv[optind-1], NULL, 0x10);
182 exit_error(PARAMETER_PROBLEM,
183 "policy match: double --tunnel-src option");
185 ipparse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr);
187 exit_error(PARAMETER_PROBLEM,
188 "policy match: name resolves to multiple IPs");
191 e->invert.saddr = invert;
192 e->saddr.a4 = addr[0];
197 exit_error(PARAMETER_PROBLEM,
198 "policy match: double --tunnel-dst option");
200 ipparse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr);
202 exit_error(PARAMETER_PROBLEM,
203 "policy match: name resolves to multiple IPs");
206 e->invert.daddr = invert;
207 e->daddr.a4 = addr[0];
212 exit_error(PARAMETER_PROBLEM,
213 "policy match: double --proto option");
215 e->proto = parse_protocol(argv[optind-1]);
216 if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP &&
217 e->proto != IPPROTO_COMP)
218 exit_error(PARAMETER_PROBLEM,
219 "policy match: protocol must ah/esp/ipcomp");
221 e->invert.proto = invert;
225 exit_error(PARAMETER_PROBLEM,
226 "policy match: double --mode option");
228 mode = parse_mode(argv[optind-1]);
230 e->invert.mode = invert;
235 exit_error(PARAMETER_PROBLEM,
236 "policy match: can't invert --next option");
238 if (++info->len == IPT_POLICY_MAX_ELEM)
239 exit_error(PARAMETER_PROBLEM,
240 "policy match: maximum policy depth reached");
250 static void policy_check(unsigned int flags)
252 struct ipt_policy_info *info = policy_info;
253 struct ipt_policy_elem *e;
257 exit_error(PARAMETER_PROBLEM,
258 "policy match: no parameters given");
260 if (!(info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT)))
261 exit_error(PARAMETER_PROBLEM,
262 "policy match: neither --in nor --out specified");
264 if (info->flags & IPT_POLICY_MATCH_NONE) {
265 if (info->flags & IPT_POLICY_MATCH_STRICT)
266 exit_error(PARAMETER_PROBLEM,
267 "policy match: policy none but --strict given");
270 exit_error(PARAMETER_PROBLEM,
271 "policy match: policy none but policy given");
273 info->len++; /* increase len by 1, no --next after last element */
275 if (!(info->flags & IPT_POLICY_MATCH_STRICT) && info->len > 1)
276 exit_error(PARAMETER_PROBLEM,
277 "policy match: multiple elements but no --strict");
279 for (i = 0; i < info->len; i++) {
282 if (info->flags & IPT_POLICY_MATCH_STRICT &&
283 !(e->match.reqid || e->match.spi || e->match.saddr ||
284 e->match.daddr || e->match.proto || e->match.mode))
285 exit_error(PARAMETER_PROBLEM,
286 "policy match: empty policy element");
288 if ((e->match.saddr || e->match.daddr)
289 && ((e->mode == IPT_POLICY_MODE_TUNNEL && e->invert.mode) ||
290 (e->mode == IPT_POLICY_MODE_TRANSPORT && !e->invert.mode)))
291 exit_error(PARAMETER_PROBLEM,
292 "policy match: --tunnel-src/--tunnel-dst "
293 "is only valid in tunnel mode");
297 static void print_mode(char *prefix, u_int8_t mode, int numeric)
299 printf("%smode ", prefix);
302 case IPT_POLICY_MODE_TRANSPORT:
303 printf("transport ");
305 case IPT_POLICY_MODE_TUNNEL:
314 static void print_proto(char *prefix, u_int8_t proto, int numeric)
316 struct protoent *p = NULL;
318 printf("%sproto ", prefix);
320 p = getprotobynumber(proto);
322 printf("%s ", p->p_name);
324 printf("%u ", proto);
327 #define PRINT_INVERT(x) \
333 static void print_entry(char *prefix, const struct ipt_policy_elem *e,
336 if (e->match.reqid) {
337 PRINT_INVERT(e->invert.reqid);
338 printf("%sreqid %u ", prefix, e->reqid);
341 PRINT_INVERT(e->invert.spi);
342 printf("%sspi 0x%x ", prefix, e->spi);
344 if (e->match.proto) {
345 PRINT_INVERT(e->invert.proto);
346 print_proto(prefix, e->proto, numeric);
349 PRINT_INVERT(e->invert.mode);
350 print_mode(prefix, e->mode, numeric);
352 if (e->match.daddr) {
353 PRINT_INVERT(e->invert.daddr);
354 printf("%stunnel-dst %s%s ", prefix,
355 ipaddr_to_numeric((const void *)&e->daddr),
356 ipmask_to_numeric((const void *)&e->dmask));
358 if (e->match.saddr) {
359 PRINT_INVERT(e->invert.saddr);
360 printf("%stunnel-src %s%s ", prefix,
361 ipaddr_to_numeric((const void *)&e->saddr),
362 ipmask_to_numeric((const void *)&e->smask));
366 static void print_flags(char *prefix, const struct ipt_policy_info *info)
368 if (info->flags & IPT_POLICY_MATCH_IN)
369 printf("%sdir in ", prefix);
371 printf("%sdir out ", prefix);
373 if (info->flags & IPT_POLICY_MATCH_NONE)
374 printf("%spol none ", prefix);
376 printf("%spol ipsec ", prefix);
378 if (info->flags & IPT_POLICY_MATCH_STRICT)
379 printf("%sstrict ", prefix);
382 static void policy_print(const void *ip, const struct xt_entry_match *match,
385 const struct ipt_policy_info *info = (void *)match->data;
388 printf("policy match ");
389 print_flags("", info);
390 for (i = 0; i < info->len; i++) {
393 print_entry("", &info->pol[i], numeric);
397 static void policy_save(const void *ip, const struct xt_entry_match *match)
399 const struct ipt_policy_info *info = (void *)match->data;
402 print_flags("--", info);
403 for (i = 0; i < info->len; i++) {
404 print_entry("--", &info->pol[i], 0);
405 if (i + 1 < info->len)
410 static struct xtables_match policy_mt_reg = {
412 .version = XTABLES_VERSION,
414 .size = XT_ALIGN(sizeof(struct ipt_policy_info)),
415 .userspacesize = XT_ALIGN(sizeof(struct ipt_policy_info)),
417 .parse = policy_parse,
418 .final_check = policy_check,
419 .print = policy_print,
421 .extra_opts = policy_opts,
426 xtables_register_match(&policy_mt_reg);