2 * (C) 2014 by Pablo Neira Ayuso <pablo@netfilter.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
11 #include "xtables-multi.h"
26 #include <libiptc/libxtc.h>
30 #include "nft-shared.h"
32 void xlate_ifname(struct xt_xlate
*xl
, const char *nftmeta
, const char *ifname
,
35 int ifaclen
= strlen(ifname
), i
, j
;
36 char iface
[IFNAMSIZ
* 2];
38 if (ifaclen
< 1 || ifaclen
>= IFNAMSIZ
)
41 for (i
= 0, j
= 0; i
< ifaclen
+ 1; i
++, j
++) {
44 /* asterisk is non-special mid-string */
54 if (ifaclen
== 1 && ifname
[0] == '+') {
55 /* Nftables does not support wildcard only string. Workaround
56 * is easy, given that this will match always or never
57 * depending on 'invert' value. To match always, simply don't
58 * generate an expression. To match never, use an invalid
59 * interface name (kernel doesn't accept '/' in names) to match
63 strcpy(iface
, "INVAL/D");
67 if (iface
[j
- 2] == '+')
70 xt_xlate_add(xl
, "%s %s\"%s\" ", nftmeta
, invert
? "!= " : "", iface
);
73 int xlate_action(const struct iptables_command_state
*cs
, bool goto_set
,
76 int ret
= 1, numeric
= cs
->options
& OPT_NUMERIC
;
78 /* If no target at all, add nothing (default to continue) */
79 if (cs
->target
!= NULL
) {
80 /* Standard target? */
81 if (strcmp(cs
->jumpto
, XTC_LABEL_ACCEPT
) == 0)
82 xt_xlate_add(xl
, " accept");
83 else if (strcmp(cs
->jumpto
, XTC_LABEL_DROP
) == 0)
84 xt_xlate_add(xl
, " drop");
85 else if (strcmp(cs
->jumpto
, XTC_LABEL_RETURN
) == 0)
86 xt_xlate_add(xl
, " return");
87 else if (cs
->target
->xlate
) {
88 struct xt_xlate_tg_params params
= {
89 .ip
= (const void *)&cs
->fw
,
90 .target
= cs
->target
->t
,
93 ret
= cs
->target
->xlate(xl
, ¶ms
);
97 } else if (strlen(cs
->jumpto
) > 0) {
98 /* Not standard, then it's a go / jump to chain */
100 xt_xlate_add(xl
, " goto %s", cs
->jumpto
);
102 xt_xlate_add(xl
, " jump %s", cs
->jumpto
);
108 int xlate_matches(const struct iptables_command_state
*cs
, struct xt_xlate
*xl
)
110 struct xtables_rule_match
*matchp
;
111 int ret
= 1, numeric
= cs
->options
& OPT_NUMERIC
;
113 for (matchp
= cs
->matches
; matchp
; matchp
= matchp
->next
) {
114 struct xt_xlate_mt_params params
= {
115 .ip
= (const void *)&cs
->fw
,
116 .match
= matchp
->match
->m
,
120 if (!matchp
->match
->xlate
)
123 ret
= matchp
->match
->xlate(xl
, ¶ms
);
130 bool xlate_find_match(const struct iptables_command_state
*cs
, const char *p_name
)
132 struct xtables_rule_match
*matchp
;
134 for (matchp
= cs
->matches
; matchp
; matchp
= matchp
->next
) {
135 if (strcmp(matchp
->match
->name
, p_name
) == 0)
141 bool xlate_find_protomatch(const struct iptables_command_state
*cs
,
144 struct protoent
*pent
;
147 /* Skip redundant protocol, eg. ip protocol tcp tcp dport */
148 for (i
= 0; xtables_chain_protos
[i
].name
!= NULL
; i
++) {
149 if (xtables_chain_protos
[i
].num
== proto
&&
150 xlate_find_match(cs
, xtables_chain_protos
[i
].name
))
153 pent
= getprotobynumber(proto
);
154 return pent
&& xlate_find_match(cs
, pent
->p_name
);
157 const char *family2str
[] = {
158 [NFPROTO_ARP
] = "arp",
159 [NFPROTO_IPV4
] = "ip",
160 [NFPROTO_IPV6
] = "ip6",
163 static int nft_rule_xlate_add(struct nft_handle
*h
,
164 const struct xt_cmd_parse
*p
,
165 const struct iptables_command_state
*cs
,
168 struct xt_xlate
*xl
= xt_xlate_alloc(10240);
169 const char *tick
= cs
->restore
? "" : "'";
173 xl_xlate_set_family(xl
, h
->family
);
174 ret
= h
->ops
->xlate(cs
, xl
);
178 set
= xt_xlate_set_get(xl
);
180 printf("%sadd set %s %s %s%s\n",
181 tick
, family2str
[h
->family
], p
->table
,
182 xt_xlate_set_get(xl
), tick
);
184 if (!cs
->restore
&& p
->command
!= CMD_NONE
)
188 printf("%s%s rule %s %s %s ",
190 append
? "add" : "insert",
191 family2str
[h
->family
], p
->table
, p
->chain
);
192 if (!append
&& p
->rulenum
> 1)
193 printf("index %d ", p
->rulenum
);
195 printf("%s%s\n", xt_xlate_rule_get(xl
), tick
);
202 static int xlate(struct nft_handle
*h
, struct xt_cmd_parse
*p
,
203 struct iptables_command_state
*cs
,
204 struct xtables_args
*args
, bool append
,
205 int (*cb
)(struct nft_handle
*h
,
206 const struct xt_cmd_parse
*p
,
207 const struct iptables_command_state
*cs
,
213 for (i
= 0; i
< args
->s
.naddrs
; i
++) {
216 cs
->arp
.arp
.src
.s_addr
= args
->s
.addr
.v4
[i
].s_addr
;
217 cs
->arp
.arp
.smsk
.s_addr
= args
->s
.mask
.v4
[i
].s_addr
;
218 for (j
= 0; j
< args
->d
.naddrs
; j
++) {
219 cs
->arp
.arp
.tgt
.s_addr
= args
->d
.addr
.v4
[j
].s_addr
;
220 cs
->arp
.arp
.tmsk
.s_addr
= args
->d
.mask
.v4
[j
].s_addr
;
221 ret
= cb(h
, p
, cs
, append
);
225 cs
->fw
.ip
.src
.s_addr
= args
->s
.addr
.v4
[i
].s_addr
;
226 cs
->fw
.ip
.smsk
.s_addr
= args
->s
.mask
.v4
[i
].s_addr
;
227 for (j
= 0; j
< args
->d
.naddrs
; j
++) {
228 cs
->fw
.ip
.dst
.s_addr
=
229 args
->d
.addr
.v4
[j
].s_addr
;
230 cs
->fw
.ip
.dmsk
.s_addr
=
231 args
->d
.mask
.v4
[j
].s_addr
;
232 ret
= cb(h
, p
, cs
, append
);
236 memcpy(&cs
->fw6
.ipv6
.src
,
237 &args
->s
.addr
.v6
[i
], sizeof(struct in6_addr
));
238 memcpy(&cs
->fw6
.ipv6
.smsk
,
239 &args
->s
.mask
.v6
[i
], sizeof(struct in6_addr
));
240 for (j
= 0; j
< args
->d
.naddrs
; j
++) {
241 memcpy(&cs
->fw6
.ipv6
.dst
,
243 sizeof(struct in6_addr
));
244 memcpy(&cs
->fw6
.ipv6
.dmsk
,
246 sizeof(struct in6_addr
));
247 ret
= cb(h
, p
, cs
, append
);
251 if (!cs
->restore
&& i
< args
->s
.naddrs
- 1)
258 static void print_ipt_cmd(int argc
, char *argv
[])
263 for (i
= 1; i
< argc
; i
++)
264 printf("%s ", argv
[i
]);
269 static int do_command_xlate(struct nft_handle
*h
, int argc
, char *argv
[],
270 char **table
, bool restore
)
273 struct xt_cmd_parse p
= {
277 .ops
= &h
->ops
->cmd_parse
,
279 struct iptables_command_state cs
= {
284 struct xtables_args args
= {
289 h
->ops
->init_cs(&cs
);
291 do_parse(argc
, argv
, &p
, &cs
, &args
);
293 cs
.restore
= restore
;
295 if (!restore
&& p
.command
!= CMD_NONE
)
301 if (!xlate(h
, &p
, &cs
, &args
, true, nft_rule_xlate_add
))
302 print_ipt_cmd(argc
, argv
);
314 if (!xlate(h
, &p
, &cs
, &args
, false, nft_rule_xlate_add
))
315 print_ipt_cmd(argc
, argv
);
319 printf("flush chain %s %s %s\n",
320 family2str
[h
->family
], p
.table
, p
.chain
);
322 printf("flush table %s %s\n",
323 family2str
[h
->family
], p
.table
);
332 case CMD_LIST
|CMD_ZERO
:
333 case CMD_LIST
|CMD_ZERO_NUM
:
334 printf("list table %s %s\n",
335 family2str
[h
->family
], p
.table
);
339 case CMD_LIST_RULES
|CMD_ZERO
:
340 case CMD_LIST_RULES
|CMD_ZERO_NUM
:
343 printf("add chain %s %s %s\n",
344 family2str
[h
->family
], p
.table
, p
.chain
);
347 case CMD_DELETE_CHAIN
:
348 printf("delete chain %s %s %s\n",
349 family2str
[h
->family
], p
.table
, p
.chain
);
352 case CMD_RENAME_CHAIN
:
360 /* We should never reach this... */
361 printf("Unsupported command?\n");
365 h
->ops
->clear_cs(&cs
);
367 xtables_clear_args(&args
);
368 xtables_free_opts(1);
373 static void print_usage(const char *name
, const char *version
)
375 fprintf(stderr
, "%s %s "
376 "(c) 2014 by Pablo Neira Ayuso <pablo@netfilter.org>\n"
377 "Usage: %s [-h] [-f <FILE>] [-V]\n"
379 " [ --file=<FILE> ]\n"
380 " [ --version ]\n", name
, version
, name
);
384 static const struct option options
[] = {
385 { .name
= "help", .has_arg
= false, .val
= 'h' },
386 { .name
= "file", .has_arg
= true, .val
= 'f' },
387 { .name
= "version", .has_arg
= false, .val
= 'V' },
391 static int xlate_chain_user_restore(struct nft_handle
*h
, const char *chain
,
394 printf("add chain %s %s %s\n", family2str
[h
->family
], table
, chain
);
398 static int commit(struct nft_handle
*h
)
403 static void xlate_table_new(struct nft_handle
*h
, const char *table
)
405 printf("add table %s %s\n", family2str
[h
->family
], table
);
408 static int get_hook_prio(const char *table
, const char *chain
)
412 if (strcmp("nat", table
) == 0) {
413 if (strcmp(chain
, "PREROUTING") == 0)
414 prio
= NF_IP_PRI_NAT_DST
;
415 if (strcmp(chain
, "INPUT") == 0)
416 prio
= NF_IP_PRI_NAT_SRC
;
417 if (strcmp(chain
, "OUTPUT") == 0)
418 prio
= NF_IP_PRI_NAT_DST
;
419 if (strcmp(chain
, "POSTROUTING") == 0)
420 prio
= NF_IP_PRI_NAT_SRC
;
421 } else if (strcmp("mangle", table
) == 0) {
422 prio
= NF_IP_PRI_MANGLE
;
423 } else if (strcmp("raw", table
) == 0) {
424 prio
= NF_IP_PRI_RAW
;
425 } else if (strcmp(chain
, "security") == 0) {
426 prio
= NF_IP_PRI_SECURITY
;
432 static int xlate_chain_set(struct nft_handle
*h
, const char *table
,
433 const char *chain
, const char *policy
,
434 const struct xt_counters
*counters
)
436 const char *type
= "filter";
439 if (strcmp(table
, "nat") == 0)
441 else if (strcmp(table
, "mangle") == 0 && strcmp(chain
, "OUTPUT") == 0)
444 printf("add chain %s %s %s { type %s ",
445 family2str
[h
->family
], table
, chain
, type
);
446 prio
= get_hook_prio(table
, chain
);
447 if (strcmp(chain
, "PREROUTING") == 0)
448 printf("hook prerouting priority %d; ", prio
);
449 else if (strcmp(chain
, "INPUT") == 0)
450 printf("hook input priority %d; ", prio
);
451 else if (strcmp(chain
, "FORWARD") == 0)
452 printf("hook forward priority %d; ", prio
);
453 else if (strcmp(chain
, "OUTPUT") == 0)
454 printf("hook output priority %d; ", prio
);
455 else if (strcmp(chain
, "POSTROUTING") == 0)
456 printf("hook postrouting priority %d; ", prio
);
458 if (strcmp(policy
, "ACCEPT") == 0)
459 printf("policy accept; ");
460 else if (strcmp(policy
, "DROP") == 0)
461 printf("policy drop; ");
467 static int dummy_compat_rev(const char *name
, uint8_t rev
, int opt
)
469 /* Avoid querying the kernel - it's not needed when just translating
470 * rules and not even possible when running as unprivileged user.
475 static const struct nft_xt_restore_cb cb_xlate
= {
476 .table_new
= xlate_table_new
,
477 .chain_set
= xlate_chain_set
,
478 .chain_restore
= xlate_chain_user_restore
,
479 .do_command
= do_command_xlate
,
484 static int xtables_xlate_main_common(struct nft_handle
*h
,
486 const char *progname
)
490 xtables_globals
.program_name
= progname
;
491 xtables_globals
.compat_rev
= dummy_compat_rev
;
495 ret
= xtables_init_all(&xtables_globals
, family
);
498 ret
= xtables_init_all(&xtables_globals
, family
);
501 arptables_globals
.program_name
= progname
;
502 arptables_globals
.compat_rev
= dummy_compat_rev
;
503 ret
= xtables_init_all(&arptables_globals
, family
);
511 fprintf(stderr
, "%s/%s Failed to initialize xtables\n",
512 xtables_globals
.program_name
,
513 xtables_globals
.program_version
);
531 fprintf(stderr
, "Unknown family %d\n", family
);
535 if (nft_init(h
, family
) < 0) {
536 fprintf(stderr
, "%s/%s Failed to initialize nft: %s\n",
537 xtables_globals
.program_name
,
538 xtables_globals
.program_version
,
546 static int xtables_xlate_main(int family
, const char *progname
, int argc
,
550 char *table
= "filter";
551 struct nft_handle h
= {
555 ret
= xtables_xlate_main_common(&h
, family
, progname
);
559 ret
= do_command_xlate(&h
, argc
, argv
, &table
, false);
561 fprintf(stderr
, "Translation not implemented\n");
568 static int xtables_restore_xlate_main(int family
, const char *progname
,
569 int argc
, char *argv
[])
572 struct nft_handle h
= {
575 const char *file
= NULL
;
576 struct nft_xt_restore_parse p
= {
579 time_t now
= time(NULL
);
582 ret
= xtables_xlate_main_common(&h
, family
, progname
);
587 while ((c
= getopt_long(argc
, argv
, "hf:V", options
, NULL
)) != -1) {
590 print_usage(argv
[0], PACKAGE_VERSION
);
596 printf("%s v%s\n", argv
[0], PACKAGE_VERSION
);
602 fprintf(stderr
, "ERROR: missing file name\n");
603 print_usage(argv
[0], PACKAGE_VERSION
);
607 p
.in
= fopen(file
, "r");
609 fprintf(stderr
, "Cannot open file %s\n", file
);
613 printf("# Translated by %s v%s on %s",
614 argv
[0], PACKAGE_VERSION
, ctime(&now
));
615 xtables_restore_parse(&h
, &p
);
616 printf("# Completed on %s", ctime(&now
));
624 int xtables_arp_xlate_main(int argc
, char *argv
[])
626 return xtables_xlate_main(NFPROTO_ARP
, "arptables-translate",
630 int xtables_ip4_xlate_main(int argc
, char *argv
[])
632 return xtables_xlate_main(NFPROTO_IPV4
, "iptables-translate",
636 int xtables_ip6_xlate_main(int argc
, char *argv
[])
638 return xtables_xlate_main(NFPROTO_IPV6
, "ip6tables-translate",
642 int xtables_ip4_xlate_restore_main(int argc
, char *argv
[])
644 return xtables_restore_xlate_main(NFPROTO_IPV4
,
645 "iptables-translate-restore",
649 int xtables_ip6_xlate_restore_main(int argc
, char *argv
[])
651 return xtables_restore_xlate_main(NFPROTO_IPV6
,
652 "ip6tables-translate-restore",