configure: Avoid addition assignment operators
[iptables-mirror.git] / iptables / xtables-translate.c
blob3d8617f05b120fa56291f060415f62e3a4c0e54a
1 /*
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.
8 */
9 #include "config.h"
10 #include <time.h>
11 #include "xtables-multi.h"
12 #include "nft.h"
14 #include <string.h>
15 #include <netdb.h>
16 #include <errno.h>
17 #include <stdbool.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <ctype.h>
21 #include <stdarg.h>
22 #include <limits.h>
23 #include <unistd.h>
24 #include <iptables.h>
25 #include <xtables.h>
26 #include <libiptc/libxtc.h>
27 #include <fcntl.h>
28 #include <getopt.h>
29 #include "xshared.h"
30 #include "nft-shared.h"
32 void xlate_ifname(struct xt_xlate *xl, const char *nftmeta, const char *ifname,
33 bool invert)
35 int ifaclen = strlen(ifname), i, j;
36 char iface[IFNAMSIZ * 2];
38 if (ifaclen < 1 || ifaclen >= IFNAMSIZ)
39 return;
41 for (i = 0, j = 0; i < ifaclen + 1; i++, j++) {
42 switch (ifname[i]) {
43 case '*':
44 /* asterisk is non-special mid-string */
45 if (i == ifaclen - 1)
46 iface[j++] = '\\';
47 /* fall through */
48 default:
49 iface[j] = ifname[i];
50 break;
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
60 * against. */
61 if (!invert)
62 return;
63 strcpy(iface, "INVAL/D");
64 invert = false;
67 if (iface[j - 2] == '+')
68 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,
74 struct xt_xlate *xl)
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,
91 .numeric = numeric,
93 ret = cs->target->xlate(xl, &params);
95 else
96 return 0;
97 } else if (strlen(cs->jumpto) > 0) {
98 /* Not standard, then it's a go / jump to chain */
99 if (goto_set)
100 xt_xlate_add(xl, " goto %s", cs->jumpto);
101 else
102 xt_xlate_add(xl, " jump %s", cs->jumpto);
105 return ret;
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,
117 .numeric = numeric,
120 if (!matchp->match->xlate)
121 return 0;
123 ret = matchp->match->xlate(xl, &params);
124 if (!ret)
125 break;
127 return ret;
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)
136 return true;
138 return false;
141 bool xlate_find_protomatch(const struct iptables_command_state *cs,
142 uint16_t proto)
144 struct protoent *pent;
145 int i;
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))
151 return true;
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,
166 bool append)
168 struct xt_xlate *xl = xt_xlate_alloc(10240);
169 const char *tick = cs->restore ? "" : "'";
170 const char *set;
171 int ret;
173 xl_xlate_set_family(xl, h->family);
174 ret = h->ops->xlate(cs, xl);
175 if (!ret)
176 goto err_out;
178 set = xt_xlate_set_get(xl);
179 if (set[0]) {
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)
185 printf("nft ");
188 printf("%s%s rule %s %s %s ",
189 tick,
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);
197 err_out:
198 xt_xlate_free(xl);
199 return ret;
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,
208 bool append))
210 unsigned int i, j;
211 int ret = 1;
213 for (i = 0; i < args->s.naddrs; i++) {
214 switch (h->family) {
215 case NFPROTO_ARP:
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);
223 break;
224 case AF_INET:
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);
234 break;
235 case AF_INET6:
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,
242 &args->d.addr.v6[j],
243 sizeof(struct in6_addr));
244 memcpy(&cs->fw6.ipv6.dmsk,
245 &args->d.mask.v6[j],
246 sizeof(struct in6_addr));
247 ret = cb(h, p, cs, append);
249 break;
251 if (!cs->restore && i < args->s.naddrs - 1)
252 printf("nft ");
255 return ret;
258 static void print_ipt_cmd(int argc, char *argv[])
260 int i;
262 printf("# ");
263 for (i = 1; i < argc; i++)
264 printf("%s ", argv[i]);
266 printf("\n");
269 static int do_command_xlate(struct nft_handle *h, int argc, char *argv[],
270 char **table, bool restore)
272 int ret = 0;
273 struct xt_cmd_parse p = {
274 .table = *table,
275 .restore = restore,
276 .line = line,
277 .ops = &h->ops->cmd_parse,
279 struct iptables_command_state cs = {
280 .jumpto = "",
281 .argv = argv,
284 struct xtables_args args = {
285 .family = h->family,
288 if (h->ops->init_cs)
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)
296 printf("nft ");
298 switch (p.command) {
299 case CMD_APPEND:
300 ret = 1;
301 if (!xlate(h, &p, &cs, &args, true, nft_rule_xlate_add))
302 print_ipt_cmd(argc, argv);
303 break;
304 case CMD_DELETE:
305 break;
306 case CMD_DELETE_NUM:
307 break;
308 case CMD_CHECK:
309 break;
310 case CMD_REPLACE:
311 break;
312 case CMD_INSERT:
313 ret = 1;
314 if (!xlate(h, &p, &cs, &args, false, nft_rule_xlate_add))
315 print_ipt_cmd(argc, argv);
316 break;
317 case CMD_FLUSH:
318 if (p.chain) {
319 printf("flush chain %s %s %s\n",
320 family2str[h->family], p.table, p.chain);
321 } else {
322 printf("flush table %s %s\n",
323 family2str[h->family], p.table);
325 ret = 1;
326 break;
327 case CMD_ZERO:
328 break;
329 case CMD_ZERO_NUM:
330 break;
331 case CMD_LIST:
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);
336 ret = 1;
337 break;
338 case CMD_LIST_RULES:
339 case CMD_LIST_RULES|CMD_ZERO:
340 case CMD_LIST_RULES|CMD_ZERO_NUM:
341 break;
342 case CMD_NEW_CHAIN:
343 printf("add chain %s %s %s\n",
344 family2str[h->family], p.table, p.chain);
345 ret = 1;
346 break;
347 case CMD_DELETE_CHAIN:
348 printf("delete chain %s %s %s\n",
349 family2str[h->family], p.table, p.chain);
350 ret = 1;
351 break;
352 case CMD_RENAME_CHAIN:
353 break;
354 case CMD_SET_POLICY:
355 break;
356 case CMD_NONE:
357 ret = 1;
358 break;
359 default:
360 /* We should never reach this... */
361 printf("Unsupported command?\n");
362 exit(1);
365 h->ops->clear_cs(&cs);
367 xtables_clear_args(&args);
368 xtables_free_opts(1);
370 return ret;
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"
378 " [ --help ]\n"
379 " [ --file=<FILE> ]\n"
380 " [ --version ]\n", name, version, name);
381 exit(1);
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' },
388 { NULL },
391 static int xlate_chain_user_restore(struct nft_handle *h, const char *chain,
392 const char *table)
394 printf("add chain %s %s %s\n", family2str[h->family], table, chain);
395 return 0;
398 static int commit(struct nft_handle *h)
400 return 1;
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)
410 int prio = 0;
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;
429 return prio;
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";
437 int prio;
439 if (strcmp(table, "nat") == 0)
440 type = "nat";
441 else if (strcmp(table, "mangle") == 0 && strcmp(chain, "OUTPUT") == 0)
442 type = "route";
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; ");
463 printf("}\n");
464 return 1;
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.
472 return 1;
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,
480 .commit = commit,
481 .abort = commit,
484 static int xtables_xlate_main_common(struct nft_handle *h,
485 int family,
486 const char *progname)
488 int ret;
490 xtables_globals.program_name = progname;
491 xtables_globals.compat_rev = dummy_compat_rev;
493 switch (family) {
494 case NFPROTO_IPV4:
495 ret = xtables_init_all(&xtables_globals, family);
496 break;
497 case NFPROTO_IPV6:
498 ret = xtables_init_all(&xtables_globals, family);
499 break;
500 case NFPROTO_ARP:
501 arptables_globals.program_name = progname;
502 arptables_globals.compat_rev = dummy_compat_rev;
503 ret = xtables_init_all(&arptables_globals, family);
504 break;
505 default:
506 ret = -1;
507 break;
510 if (ret < 0) {
511 fprintf(stderr, "%s/%s Failed to initialize xtables\n",
512 xtables_globals.program_name,
513 xtables_globals.program_version);
514 return 1;
516 init_extensions();
517 switch (family) {
518 case NFPROTO_IPV4:
519 init_extensions4();
520 break;
521 case NFPROTO_IPV6:
522 init_extensions6();
523 break;
524 case NFPROTO_ARP:
525 init_extensionsa();
526 break;
527 case NFPROTO_BRIDGE:
528 init_extensionsb();
529 break;
530 default:
531 fprintf(stderr, "Unknown family %d\n", family);
532 return 1;
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,
539 strerror(errno));
540 return 1;
543 return 0;
546 static int xtables_xlate_main(int family, const char *progname, int argc,
547 char *argv[])
549 int ret;
550 char *table = "filter";
551 struct nft_handle h = {
552 .family = family,
555 ret = xtables_xlate_main_common(&h, family, progname);
556 if (ret < 0)
557 exit(EXIT_FAILURE);
559 ret = do_command_xlate(&h, argc, argv, &table, false);
560 if (!ret)
561 fprintf(stderr, "Translation not implemented\n");
563 nft_fini(&h);
564 xtables_fini();
565 exit(!ret);
568 static int xtables_restore_xlate_main(int family, const char *progname,
569 int argc, char *argv[])
571 int ret;
572 struct nft_handle h = {
573 .family = family,
575 const char *file = NULL;
576 struct nft_xt_restore_parse p = {
577 .cb = &cb_xlate,
579 time_t now = time(NULL);
580 int c;
582 ret = xtables_xlate_main_common(&h, family, progname);
583 if (ret < 0)
584 exit(EXIT_FAILURE);
586 opterr = 0;
587 while ((c = getopt_long(argc, argv, "hf:V", options, NULL)) != -1) {
588 switch (c) {
589 case 'h':
590 print_usage(argv[0], PACKAGE_VERSION);
591 exit(0);
592 case 'f':
593 file = optarg;
594 break;
595 case 'V':
596 printf("%s v%s\n", argv[0], PACKAGE_VERSION);
597 exit(0);
601 if (file == NULL) {
602 fprintf(stderr, "ERROR: missing file name\n");
603 print_usage(argv[0], PACKAGE_VERSION);
604 exit(0);
607 p.in = fopen(file, "r");
608 if (p.in == NULL) {
609 fprintf(stderr, "Cannot open file %s\n", file);
610 exit(1);
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));
618 nft_fini(&h);
619 xtables_fini();
620 fclose(p.in);
621 exit(0);
624 int xtables_arp_xlate_main(int argc, char *argv[])
626 return xtables_xlate_main(NFPROTO_ARP, "arptables-translate",
627 argc, argv);
630 int xtables_ip4_xlate_main(int argc, char *argv[])
632 return xtables_xlate_main(NFPROTO_IPV4, "iptables-translate",
633 argc, argv);
636 int xtables_ip6_xlate_main(int argc, char *argv[])
638 return xtables_xlate_main(NFPROTO_IPV6, "ip6tables-translate",
639 argc, argv);
642 int xtables_ip4_xlate_restore_main(int argc, char *argv[])
644 return xtables_restore_xlate_main(NFPROTO_IPV4,
645 "iptables-translate-restore",
646 argc, argv);
649 int xtables_ip6_xlate_restore_main(int argc, char *argv[])
651 return xtables_restore_xlate_main(NFPROTO_IPV6,
652 "ip6tables-translate-restore",
653 argc, argv);