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 help(void)
28 "policy v%s 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",
44 static struct option opts
[] =
97 /* FIXME - Duplicated code from ip6tables.c */
98 /* Duplicated to stop too many changes in other files .... */
100 in6addrcpy(struct in6_addr
*dst
, struct in6_addr
*src
)
102 memcpy(dst
, src
, sizeof(struct in6_addr
));
103 /* dst->s6_addr = src->s6_addr; */
107 addr_to_numeric(const struct in6_addr
*addrp
)
109 /* 0000:0000:0000:0000:0000:000.000.000.000
110 * 0000:0000:0000:0000:0000:0000:0000:0000 */
111 static char buf
[50+1];
112 return (char *)inet_ntop(AF_INET6
, addrp
, buf
, sizeof(buf
));
116 mask_to_numeric(const struct in6_addr
*addrp
)
118 static char buf
[50+2];
119 int l
= ipv6_prefix_length(addrp
);
122 strcat(buf
, addr_to_numeric(addrp
));
125 sprintf(buf
, "/%d", l
);
129 /* These should be in include/ip6tables.h... */
130 extern u_int16_t
parse_protocol(const char *s
);
131 extern void parse_hostnetworkmask(const char *name
, struct in6_addr
**addrpp
,
132 struct in6_addr
*maskp
, unsigned int *naddrs
);
134 /* End duplicated code from ip6tables.c */
136 static void init(struct ip6t_entry_match
*m
, unsigned int *nfcache
)
138 *nfcache
|= NFC_UNKNOWN
;
141 static int parse_direction(char *s
)
143 if (strcmp(s
, "in") == 0)
144 return IP6T_POLICY_MATCH_IN
;
145 if (strcmp(s
, "out") == 0)
146 return IP6T_POLICY_MATCH_OUT
;
147 exit_error(PARAMETER_PROBLEM
, "policy_match: invalid dir `%s'", s
);
150 static int parse_policy(char *s
)
152 if (strcmp(s
, "none") == 0)
153 return IP6T_POLICY_MATCH_NONE
;
154 if (strcmp(s
, "ipsec") == 0)
156 exit_error(PARAMETER_PROBLEM
, "policy match: invalid policy `%s'", s
);
159 static int parse_mode(char *s
)
161 if (strcmp(s
, "transport") == 0)
162 return IP6T_POLICY_MODE_TRANSPORT
;
163 if (strcmp(s
, "tunnel") == 0)
164 return IP6T_POLICY_MODE_TUNNEL
;
165 exit_error(PARAMETER_PROBLEM
, "policy match: invalid mode `%s'", s
);
168 static int parse(int c
, char **argv
, int invert
, unsigned int *flags
,
169 const struct ip6t_entry
*entry
,
170 unsigned int *nfcache
,
171 struct ip6t_entry_match
**match
)
173 struct ip6t_policy_info
*info
= (void *)(*match
)->data
;
174 struct ip6t_policy_elem
*e
= &info
->pol
[info
->len
];
175 struct in6_addr
*addr
= NULL
, mask
;
176 unsigned int naddr
= 0;
179 check_inverse(optarg
, &invert
, &optind
, 0);
183 if (info
->flags
& (IP6T_POLICY_MATCH_IN
|IP6T_POLICY_MATCH_OUT
))
184 exit_error(PARAMETER_PROBLEM
,
185 "policy match: double --dir option");
187 exit_error(PARAMETER_PROBLEM
,
188 "policy match: can't invert --dir option");
190 info
->flags
|= parse_direction(argv
[optind
-1]);
194 exit_error(PARAMETER_PROBLEM
,
195 "policy match: can't invert --policy option");
197 info
->flags
|= parse_policy(argv
[optind
-1]);
200 if (info
->flags
& IP6T_POLICY_MATCH_STRICT
)
201 exit_error(PARAMETER_PROBLEM
,
202 "policy match: double --strict option");
205 exit_error(PARAMETER_PROBLEM
,
206 "policy match: can't invert --strict option");
208 info
->flags
|= IP6T_POLICY_MATCH_STRICT
;
212 exit_error(PARAMETER_PROBLEM
,
213 "policy match: double --reqid option");
216 e
->invert
.reqid
= invert
;
217 e
->reqid
= strtol(argv
[optind
-1], NULL
, 10);
221 exit_error(PARAMETER_PROBLEM
,
222 "policy match: double --spi option");
225 e
->invert
.spi
= invert
;
226 e
->spi
= strtol(argv
[optind
-1], NULL
, 0x10);
230 exit_error(PARAMETER_PROBLEM
,
231 "policy match: double --tunnel-src option");
233 parse_hostnetworkmask(argv
[optind
-1], &addr
, &mask
, &naddr
);
235 exit_error(PARAMETER_PROBLEM
,
236 "policy match: name resolves to multiple IPs");
239 e
->invert
.saddr
= invert
;
240 in6addrcpy(&e
->saddr
.a6
, addr
);
241 in6addrcpy(&e
->smask
.a6
, &mask
);
245 exit_error(PARAMETER_PROBLEM
,
246 "policy match: double --tunnel-dst option");
248 parse_hostnetworkmask(argv
[optind
-1], &addr
, &mask
, &naddr
);
250 exit_error(PARAMETER_PROBLEM
,
251 "policy match: name resolves to multiple IPs");
254 e
->invert
.daddr
= invert
;
255 in6addrcpy(&e
->daddr
.a6
, addr
);
256 in6addrcpy(&e
->dmask
.a6
, &mask
);
260 exit_error(PARAMETER_PROBLEM
,
261 "policy match: double --proto option");
263 e
->proto
= parse_protocol(argv
[optind
-1]);
264 if (e
->proto
!= IPPROTO_AH
&& e
->proto
!= IPPROTO_ESP
&&
265 e
->proto
!= IPPROTO_COMP
)
266 exit_error(PARAMETER_PROBLEM
,
267 "policy match: protocol must ah/esp/ipcomp");
269 e
->invert
.proto
= invert
;
273 exit_error(PARAMETER_PROBLEM
,
274 "policy match: double --mode option");
276 mode
= parse_mode(argv
[optind
-1]);
278 e
->invert
.mode
= invert
;
283 exit_error(PARAMETER_PROBLEM
,
284 "policy match: can't invert --next option");
286 if (++info
->len
== IP6T_POLICY_MAX_ELEM
)
287 exit_error(PARAMETER_PROBLEM
,
288 "policy match: maximum policy depth reached");
298 static void final_check(unsigned int flags
)
300 struct ip6t_policy_info
*info
= policy_info
;
301 struct ip6t_policy_elem
*e
;
305 exit_error(PARAMETER_PROBLEM
,
306 "policy match: no parameters given");
308 if (!(info
->flags
& (IP6T_POLICY_MATCH_IN
|IP6T_POLICY_MATCH_OUT
)))
309 exit_error(PARAMETER_PROBLEM
,
310 "policy match: neither --in nor --out specified");
312 if (info
->flags
& IP6T_POLICY_MATCH_NONE
) {
313 if (info
->flags
& IP6T_POLICY_MATCH_STRICT
)
314 exit_error(PARAMETER_PROBLEM
,
315 "policy match: policy none but --strict given");
318 exit_error(PARAMETER_PROBLEM
,
319 "policy match: policy none but policy given");
321 info
->len
++; /* increase len by 1, no --next after last element */
323 if (!(info
->flags
& IP6T_POLICY_MATCH_STRICT
) && info
->len
> 1)
324 exit_error(PARAMETER_PROBLEM
,
325 "policy match: multiple elements but no --strict");
327 for (i
= 0; i
< info
->len
; i
++) {
330 if (info
->flags
& IP6T_POLICY_MATCH_STRICT
&&
331 !(e
->match
.reqid
|| e
->match
.spi
|| e
->match
.saddr
||
332 e
->match
.daddr
|| e
->match
.proto
|| e
->match
.mode
))
333 exit_error(PARAMETER_PROBLEM
,
334 "policy match: empty policy element");
336 if ((e
->match
.saddr
|| e
->match
.daddr
)
337 && ((e
->mode
== IP6T_POLICY_MODE_TUNNEL
&& e
->invert
.mode
) ||
338 (e
->mode
== IP6T_POLICY_MODE_TRANSPORT
&& !e
->invert
.mode
)))
339 exit_error(PARAMETER_PROBLEM
,
340 "policy match: --tunnel-src/--tunnel-dst "
341 "is only valid in tunnel mode");
345 static void print_mode(char *prefix
, u_int8_t mode
, int numeric
)
347 printf("%smode ", prefix
);
350 case IP6T_POLICY_MODE_TRANSPORT
:
351 printf("transport ");
353 case IP6T_POLICY_MODE_TUNNEL
:
362 static void print_proto(char *prefix
, u_int8_t proto
, int numeric
)
364 struct protoent
*p
= NULL
;
366 printf("%sproto ", prefix
);
368 p
= getprotobynumber(proto
);
370 printf("%s ", p
->p_name
);
372 printf("%u ", proto
);
375 #define PRINT_INVERT(x) \
381 static void print_entry(char *prefix
, const struct ip6t_policy_elem
*e
,
384 if (e
->match
.reqid
) {
385 PRINT_INVERT(e
->invert
.reqid
);
386 printf("%sreqid %u ", prefix
, e
->reqid
);
389 PRINT_INVERT(e
->invert
.spi
);
390 printf("%sspi 0x%x ", prefix
, e
->spi
);
392 if (e
->match
.proto
) {
393 PRINT_INVERT(e
->invert
.proto
);
394 print_proto(prefix
, e
->proto
, numeric
);
397 PRINT_INVERT(e
->invert
.mode
);
398 print_mode(prefix
, e
->mode
, numeric
);
400 if (e
->match
.daddr
) {
401 PRINT_INVERT(e
->invert
.daddr
);
402 printf("%stunnel-dst %s%s ", prefix
,
403 addr_to_numeric((struct in6_addr
*)&e
->daddr
),
404 mask_to_numeric((struct in6_addr
*)&e
->dmask
));
406 if (e
->match
.saddr
) {
407 PRINT_INVERT(e
->invert
.saddr
);
408 printf("%stunnel-src %s%s ", prefix
,
409 addr_to_numeric((struct in6_addr
*)&e
->saddr
),
410 mask_to_numeric((struct in6_addr
*)&e
->smask
));
414 static void print_flags(char *prefix
, const struct ip6t_policy_info
*info
)
416 if (info
->flags
& IP6T_POLICY_MATCH_IN
)
417 printf("%sdir in ", prefix
);
419 printf("%sdir out ", prefix
);
421 if (info
->flags
& IP6T_POLICY_MATCH_NONE
)
422 printf("%spol none ", prefix
);
424 printf("%spol ipsec ", prefix
);
426 if (info
->flags
& IP6T_POLICY_MATCH_STRICT
)
427 printf("%sstrict ", prefix
);
430 static void print(const struct ip6t_ip6
*ip
,
431 const struct ip6t_entry_match
*match
,
434 const struct ip6t_policy_info
*info
= (void *)match
->data
;
437 printf("policy match ");
438 print_flags("", info
);
439 for (i
= 0; i
< info
->len
; i
++) {
442 print_entry("", &info
->pol
[i
], numeric
);
448 static void save(const struct ip6t_ip6
*ip
, const struct ip6t_entry_match
*match
)
450 const struct ip6t_policy_info
*info
= (void *)match
->data
;
453 print_flags("--", info
);
454 for (i
= 0; i
< info
->len
; i
++) {
455 print_entry("--", &info
->pol
[i
], 0);
456 if (i
+ 1 < info
->len
)
461 struct ip6tables_match policy
= {
463 .version
= IPTABLES_VERSION
,
464 .size
= IP6T_ALIGN(sizeof(struct ip6t_policy_info
)),
465 .userspacesize
= IP6T_ALIGN(sizeof(struct ip6t_policy_info
)),
469 .final_check
= final_check
,
477 register_match6(&policy
);