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 help(void)
27 "policy v%s 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",
43 static struct option opts
[] =
96 static void init(struct ipt_entry_match
*m
, unsigned int *nfcache
)
98 *nfcache
|= NFC_UNKNOWN
;
101 static int parse_direction(char *s
)
103 if (strcmp(s
, "in") == 0)
104 return IPT_POLICY_MATCH_IN
;
105 if (strcmp(s
, "out") == 0)
106 return IPT_POLICY_MATCH_OUT
;
107 exit_error(PARAMETER_PROBLEM
, "policy_match: invalid dir `%s'", s
);
110 static int parse_policy(char *s
)
112 if (strcmp(s
, "none") == 0)
113 return IPT_POLICY_MATCH_NONE
;
114 if (strcmp(s
, "ipsec") == 0)
116 exit_error(PARAMETER_PROBLEM
, "policy match: invalid policy `%s'", s
);
119 static int parse_mode(char *s
)
121 if (strcmp(s
, "transport") == 0)
122 return IPT_POLICY_MODE_TRANSPORT
;
123 if (strcmp(s
, "tunnel") == 0)
124 return IPT_POLICY_MODE_TUNNEL
;
125 exit_error(PARAMETER_PROBLEM
, "policy match: invalid mode `%s'", s
);
128 static int parse(int c
, char **argv
, int invert
, unsigned int *flags
,
129 const struct ipt_entry
*entry
,
130 unsigned int *nfcache
,
131 struct ipt_entry_match
**match
)
133 struct ipt_policy_info
*info
= (void *)(*match
)->data
;
134 struct ipt_policy_elem
*e
= &info
->pol
[info
->len
];
135 struct in_addr
*addr
= NULL
, mask
;
136 unsigned int naddr
= 0;
139 check_inverse(optarg
, &invert
, &optind
, 0);
143 if (info
->flags
& (IPT_POLICY_MATCH_IN
|IPT_POLICY_MATCH_OUT
))
144 exit_error(PARAMETER_PROBLEM
,
145 "policy match: double --dir option");
147 exit_error(PARAMETER_PROBLEM
,
148 "policy match: can't invert --dir option");
150 info
->flags
|= parse_direction(argv
[optind
-1]);
154 exit_error(PARAMETER_PROBLEM
,
155 "policy match: can't invert --policy option");
157 info
->flags
|= parse_policy(argv
[optind
-1]);
160 if (info
->flags
& IPT_POLICY_MATCH_STRICT
)
161 exit_error(PARAMETER_PROBLEM
,
162 "policy match: double --strict option");
165 exit_error(PARAMETER_PROBLEM
,
166 "policy match: can't invert --strict option");
168 info
->flags
|= IPT_POLICY_MATCH_STRICT
;
172 exit_error(PARAMETER_PROBLEM
,
173 "policy match: double --reqid option");
176 e
->invert
.reqid
= invert
;
177 e
->reqid
= strtol(argv
[optind
-1], NULL
, 10);
181 exit_error(PARAMETER_PROBLEM
,
182 "policy match: double --spi option");
185 e
->invert
.spi
= invert
;
186 e
->spi
= strtol(argv
[optind
-1], NULL
, 0x10);
190 exit_error(PARAMETER_PROBLEM
,
191 "policy match: double --tunnel-src option");
193 parse_hostnetworkmask(argv
[optind
-1], &addr
, &mask
, &naddr
);
195 exit_error(PARAMETER_PROBLEM
,
196 "policy match: name resolves to multiple IPs");
199 e
->invert
.saddr
= invert
;
200 e
->saddr
.a4
= addr
[0];
205 exit_error(PARAMETER_PROBLEM
,
206 "policy match: double --tunnel-dst option");
208 parse_hostnetworkmask(argv
[optind
-1], &addr
, &mask
, &naddr
);
210 exit_error(PARAMETER_PROBLEM
,
211 "policy match: name resolves to multiple IPs");
214 e
->invert
.daddr
= invert
;
215 e
->daddr
.a4
= addr
[0];
220 exit_error(PARAMETER_PROBLEM
,
221 "policy match: double --proto option");
223 e
->proto
= parse_protocol(argv
[optind
-1]);
224 if (e
->proto
!= IPPROTO_AH
&& e
->proto
!= IPPROTO_ESP
&&
225 e
->proto
!= IPPROTO_COMP
)
226 exit_error(PARAMETER_PROBLEM
,
227 "policy match: protocol must ah/esp/ipcomp");
229 e
->invert
.proto
= invert
;
233 exit_error(PARAMETER_PROBLEM
,
234 "policy match: double --mode option");
236 mode
= parse_mode(argv
[optind
-1]);
238 e
->invert
.mode
= invert
;
243 exit_error(PARAMETER_PROBLEM
,
244 "policy match: can't invert --next option");
246 if (++info
->len
== IPT_POLICY_MAX_ELEM
)
247 exit_error(PARAMETER_PROBLEM
,
248 "policy match: maximum policy depth reached");
258 static void final_check(unsigned int flags
)
260 struct ipt_policy_info
*info
= policy_info
;
261 struct ipt_policy_elem
*e
;
265 exit_error(PARAMETER_PROBLEM
,
266 "policy match: no parameters given");
268 if (!(info
->flags
& (IPT_POLICY_MATCH_IN
|IPT_POLICY_MATCH_OUT
)))
269 exit_error(PARAMETER_PROBLEM
,
270 "policy match: neither --in nor --out specified");
272 if (info
->flags
& IPT_POLICY_MATCH_NONE
) {
273 if (info
->flags
& IPT_POLICY_MATCH_STRICT
)
274 exit_error(PARAMETER_PROBLEM
,
275 "policy match: policy none but --strict given");
278 exit_error(PARAMETER_PROBLEM
,
279 "policy match: policy none but policy given");
281 info
->len
++; /* increase len by 1, no --next after last element */
283 if (!(info
->flags
& IPT_POLICY_MATCH_STRICT
) && info
->len
> 1)
284 exit_error(PARAMETER_PROBLEM
,
285 "policy match: multiple elements but no --strict");
287 for (i
= 0; i
< info
->len
; i
++) {
290 if (info
->flags
& IPT_POLICY_MATCH_STRICT
&&
291 !(e
->match
.reqid
|| e
->match
.spi
|| e
->match
.saddr
||
292 e
->match
.daddr
|| e
->match
.proto
|| e
->match
.mode
))
293 exit_error(PARAMETER_PROBLEM
,
294 "policy match: empty policy element");
296 if ((e
->match
.saddr
|| e
->match
.daddr
)
297 && ((e
->mode
== IPT_POLICY_MODE_TUNNEL
&& e
->invert
.mode
) ||
298 (e
->mode
== IPT_POLICY_MODE_TRANSPORT
&& !e
->invert
.mode
)))
299 exit_error(PARAMETER_PROBLEM
,
300 "policy match: --tunnel-src/--tunnel-dst "
301 "is only valid in tunnel mode");
305 static void print_mode(char *prefix
, u_int8_t mode
, int numeric
)
307 printf("%smode ", prefix
);
310 case IPT_POLICY_MODE_TRANSPORT
:
311 printf("transport ");
313 case IPT_POLICY_MODE_TUNNEL
:
322 static void print_proto(char *prefix
, u_int8_t proto
, int numeric
)
324 struct protoent
*p
= NULL
;
326 printf("%sproto ", prefix
);
328 p
= getprotobynumber(proto
);
330 printf("%s ", p
->p_name
);
332 printf("%u ", proto
);
335 #define PRINT_INVERT(x) \
341 static void print_entry(char *prefix
, const struct ipt_policy_elem
*e
,
344 if (e
->match
.reqid
) {
345 PRINT_INVERT(e
->invert
.reqid
);
346 printf("%sreqid %u ", prefix
, e
->reqid
);
349 PRINT_INVERT(e
->invert
.spi
);
350 printf("%sspi 0x%x ", prefix
, e
->spi
);
352 if (e
->match
.proto
) {
353 PRINT_INVERT(e
->invert
.proto
);
354 print_proto(prefix
, e
->proto
, numeric
);
357 PRINT_INVERT(e
->invert
.mode
);
358 print_mode(prefix
, e
->mode
, numeric
);
360 if (e
->match
.daddr
) {
361 PRINT_INVERT(e
->invert
.daddr
);
362 printf("%stunnel-dst %s%s ", prefix
,
363 addr_to_dotted((struct in_addr
*)&e
->daddr
),
364 mask_to_dotted((struct in_addr
*)&e
->dmask
));
366 if (e
->match
.saddr
) {
367 PRINT_INVERT(e
->invert
.saddr
);
368 printf("%stunnel-src %s%s ", prefix
,
369 addr_to_dotted((struct in_addr
*)&e
->saddr
),
370 mask_to_dotted((struct in_addr
*)&e
->smask
));
374 static void print_flags(char *prefix
, const struct ipt_policy_info
*info
)
376 if (info
->flags
& IPT_POLICY_MATCH_IN
)
377 printf("%sdir in ", prefix
);
379 printf("%sdir out ", prefix
);
381 if (info
->flags
& IPT_POLICY_MATCH_NONE
)
382 printf("%spol none ", prefix
);
384 printf("%spol ipsec ", prefix
);
386 if (info
->flags
& IPT_POLICY_MATCH_STRICT
)
387 printf("%sstrict ", prefix
);
390 static void print(const struct ipt_ip
*ip
,
391 const struct ipt_entry_match
*match
,
394 const struct ipt_policy_info
*info
= (void *)match
->data
;
397 printf("policy match ");
398 print_flags("", info
);
399 for (i
= 0; i
< info
->len
; i
++) {
402 print_entry("", &info
->pol
[i
], numeric
);
406 static void save(const struct ipt_ip
*ip
, const struct ipt_entry_match
*match
)
408 const struct ipt_policy_info
*info
= (void *)match
->data
;
411 print_flags("--", info
);
412 for (i
= 0; i
< info
->len
; i
++) {
413 print_entry("--", &info
->pol
[i
], 0);
414 if (i
+ 1 < info
->len
)
419 struct iptables_match policy
= {
421 .version
= IPTABLES_VERSION
,
422 .size
= IPT_ALIGN(sizeof(struct ipt_policy_info
)),
423 .userspacesize
= IPT_ALIGN(sizeof(struct ipt_policy_info
)),
427 .final_check
= final_check
,
435 register_match(&policy
);