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/ipt_policy.h>
18
* HACK: global pointer to current matchinfo for making
19
* final checks and adjustments in final_check.
21
static struct ipt_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 IPT_POLICY_MATCH_IN;
98
if (strcmp(s, "out") == 0)
99
return IPT_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 IPT_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 IPT_POLICY_MODE_TRANSPORT;
116
if (strcmp(s, "tunnel") == 0)
117
return IPT_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
const void *entry, struct xt_entry_match **match)
124
struct ipt_policy_info *info = (void *)(*match)->data;
125
struct ipt_policy_elem *e = &info->pol[info->len];
126
struct in_addr *addr = NULL, mask;
127
unsigned int naddr = 0, num;
130
xtables_check_inverse(optarg, &invert, &optind, 0);
134
if (info->flags & (IPT_POLICY_MATCH_IN|IPT_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(argv[optind-1]);
145
xtables_error(PARAMETER_PROBLEM,
146
"policy match: can't invert --policy option");
148
info->flags |= parse_policy(argv[optind-1]);
151
if (info->flags & IPT_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 |= IPT_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
xtables_ipparse_any(argv[optind-1], &addr, &mask, &naddr);
190
xtables_error(PARAMETER_PROBLEM,
191
"policy match: name resolves to multiple IPs");
194
e->invert.saddr = invert;
195
e->saddr.a4 = addr[0];
200
xtables_error(PARAMETER_PROBLEM,
201
"policy match: double --tunnel-dst option");
203
xtables_ipparse_any(argv[optind-1], &addr, &mask, &naddr);
205
xtables_error(PARAMETER_PROBLEM,
206
"policy match: name resolves to multiple IPs");
209
e->invert.daddr = invert;
210
e->daddr.a4 = addr[0];
215
xtables_error(PARAMETER_PROBLEM,
216
"policy match: double --proto option");
218
e->proto = xtables_parse_protocol(argv[optind-1]);
219
if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP &&
220
e->proto != IPPROTO_COMP)
221
xtables_error(PARAMETER_PROBLEM,
222
"policy match: protocol must ah/esp/ipcomp");
224
e->invert.proto = invert;
228
xtables_error(PARAMETER_PROBLEM,
229
"policy match: double --mode option");
231
mode = parse_mode(argv[optind-1]);
233
e->invert.mode = invert;
238
xtables_error(PARAMETER_PROBLEM,
239
"policy match: can't invert --next option");
241
if (++info->len == IPT_POLICY_MAX_ELEM)
242
xtables_error(PARAMETER_PROBLEM,
243
"policy match: maximum policy depth reached");
253
static void policy_check(unsigned int flags)
255
struct ipt_policy_info *info = policy_info;
256
struct ipt_policy_elem *e;
260
xtables_error(PARAMETER_PROBLEM,
261
"policy match: no parameters given");
263
if (!(info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT)))
264
xtables_error(PARAMETER_PROBLEM,
265
"policy match: neither --in nor --out specified");
267
if (info->flags & IPT_POLICY_MATCH_NONE) {
268
if (info->flags & IPT_POLICY_MATCH_STRICT)
269
xtables_error(PARAMETER_PROBLEM,
270
"policy match: policy none but --strict given");
273
xtables_error(PARAMETER_PROBLEM,
274
"policy match: policy none but policy given");
276
info->len++; /* increase len by 1, no --next after last element */
278
if (!(info->flags & IPT_POLICY_MATCH_STRICT) && info->len > 1)
279
xtables_error(PARAMETER_PROBLEM,
280
"policy match: multiple elements but no --strict");
282
for (i = 0; i < info->len; i++) {
285
if (info->flags & IPT_POLICY_MATCH_STRICT &&
286
!(e->match.reqid || e->match.spi || e->match.saddr ||
287
e->match.daddr || e->match.proto || e->match.mode))
288
xtables_error(PARAMETER_PROBLEM,
289
"policy match: empty policy element");
291
if ((e->match.saddr || e->match.daddr)
292
&& ((e->mode == IPT_POLICY_MODE_TUNNEL && e->invert.mode) ||
293
(e->mode == IPT_POLICY_MODE_TRANSPORT && !e->invert.mode)))
294
xtables_error(PARAMETER_PROBLEM,
295
"policy match: --tunnel-src/--tunnel-dst "
296
"is only valid in tunnel mode");
300
static void print_mode(char *prefix, u_int8_t mode, int numeric)
302
printf("%smode ", prefix);
305
case IPT_POLICY_MODE_TRANSPORT:
306
printf("transport ");
308
case IPT_POLICY_MODE_TUNNEL:
317
static void print_proto(char *prefix, u_int8_t proto, int numeric)
319
struct protoent *p = NULL;
321
printf("%sproto ", prefix);
323
p = getprotobynumber(proto);
325
printf("%s ", p->p_name);
327
printf("%u ", proto);
330
#define PRINT_INVERT(x) \
336
static void print_entry(char *prefix, const struct ipt_policy_elem *e,
339
if (e->match.reqid) {
340
PRINT_INVERT(e->invert.reqid);
341
printf("%sreqid %u ", prefix, e->reqid);
344
PRINT_INVERT(e->invert.spi);
345
printf("%sspi 0x%x ", prefix, e->spi);
347
if (e->match.proto) {
348
PRINT_INVERT(e->invert.proto);
349
print_proto(prefix, e->proto, numeric);
352
PRINT_INVERT(e->invert.mode);
353
print_mode(prefix, e->mode, numeric);
355
if (e->match.daddr) {
356
PRINT_INVERT(e->invert.daddr);
357
printf("%stunnel-dst %s%s ", prefix,
358
xtables_ipaddr_to_numeric((const void *)&e->daddr),
359
xtables_ipmask_to_numeric((const void *)&e->dmask));
361
if (e->match.saddr) {
362
PRINT_INVERT(e->invert.saddr);
363
printf("%stunnel-src %s%s ", prefix,
364
xtables_ipaddr_to_numeric((const void *)&e->saddr),
365
xtables_ipmask_to_numeric((const void *)&e->smask));
369
static void print_flags(char *prefix, const struct ipt_policy_info *info)
371
if (info->flags & IPT_POLICY_MATCH_IN)
372
printf("%sdir in ", prefix);
374
printf("%sdir out ", prefix);
376
if (info->flags & IPT_POLICY_MATCH_NONE)
377
printf("%spol none ", prefix);
379
printf("%spol ipsec ", prefix);
381
if (info->flags & IPT_POLICY_MATCH_STRICT)
382
printf("%sstrict ", prefix);
385
static void policy_print(const void *ip, const struct xt_entry_match *match,
388
const struct ipt_policy_info *info = (void *)match->data;
391
printf("policy match ");
392
print_flags("", info);
393
for (i = 0; i < info->len; i++) {
396
print_entry("", &info->pol[i], numeric);
400
static void policy_save(const void *ip, const struct xt_entry_match *match)
402
const struct ipt_policy_info *info = (void *)match->data;
405
print_flags("--", info);
406
for (i = 0; i < info->len; i++) {
407
print_entry("--", &info->pol[i], 0);
408
if (i + 1 < info->len)
413
static struct xtables_match policy_mt_reg = {
415
.version = XTABLES_VERSION,
416
.family = NFPROTO_IPV4,
417
.size = XT_ALIGN(sizeof(struct ipt_policy_info)),
418
.userspacesize = XT_ALIGN(sizeof(struct ipt_policy_info)),
420
.parse = policy_parse,
421
.final_check = policy_check,
422
.print = policy_print,
424
.extra_opts = policy_opts,
429
xtables_register_match(&policy_mt_reg);