Home | History | Annotate | Download | only in iptables
      1 /*
      2  * (C) 2014 by Pablo Neira Ayuso <pablo (at) netfilter.org>
      3  *
      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 
     10 #include <stdio.h>
     11 #include <stdlib.h>
     12 #include <errno.h>
     13 #include <string.h>
     14 #include <iptables.h>
     15 #include <time.h>
     16 #include "xtables-multi.h"
     17 #include "nft.h"
     18 
     19 #include <string.h>
     20 #include <netdb.h>
     21 #include <errno.h>
     22 #include <stdbool.h>
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <ctype.h>
     26 #include <stdarg.h>
     27 #include <limits.h>
     28 #include <unistd.h>
     29 #include <iptables.h>
     30 #include <xtables.h>
     31 #include <libiptc/libxtc.h>
     32 #include <fcntl.h>
     33 #include <getopt.h>
     34 #include "xshared.h"
     35 #include "nft-shared.h"
     36 
     37 void xlate_ifname(struct xt_xlate *xl, const char *nftmeta, const char *ifname,
     38 		  bool invert)
     39 {
     40 	char iface[IFNAMSIZ];
     41 	int ifaclen;
     42 
     43 	if (ifname[0] == '\0')
     44 		return;
     45 
     46 	strcpy(iface, ifname);
     47 	ifaclen = strlen(iface);
     48 	if (iface[ifaclen - 1] == '+')
     49 		iface[ifaclen - 1] = '*';
     50 
     51 	xt_xlate_add(xl, "%s %s%s ", nftmeta, invert ? "!= " : "", iface);
     52 }
     53 
     54 int xlate_action(const struct iptables_command_state *cs, bool goto_set,
     55 		 struct xt_xlate *xl)
     56 {
     57 	int ret = 1, numeric = cs->options & OPT_NUMERIC;
     58 
     59 	/* If no target at all, add nothing (default to continue) */
     60 	if (cs->target != NULL) {
     61 		/* Standard target? */
     62 		if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
     63 			xt_xlate_add(xl, "accept");
     64 		else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
     65 			xt_xlate_add(xl, "drop");
     66 		else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
     67 			xt_xlate_add(xl, "return");
     68 		else if (cs->target->xlate) {
     69 			struct xt_xlate_tg_params params = {
     70 				.ip		= (const void *)&cs->fw,
     71 				.target		= cs->target->t,
     72 				.numeric	= numeric,
     73 				.escape_quotes	= !cs->restore,
     74 			};
     75 			ret = cs->target->xlate(xl, &params);
     76 		}
     77 		else
     78 			return 0;
     79 	} else if (strlen(cs->jumpto) > 0) {
     80 		/* Not standard, then it's a go / jump to chain */
     81 		if (goto_set)
     82 			xt_xlate_add(xl, "goto %s", cs->jumpto);
     83 		else
     84 			xt_xlate_add(xl, "jump %s", cs->jumpto);
     85 	}
     86 
     87 	return ret;
     88 }
     89 
     90 int xlate_matches(const struct iptables_command_state *cs, struct xt_xlate *xl)
     91 {
     92 	struct xtables_rule_match *matchp;
     93 	int ret = 1, numeric = cs->options & OPT_NUMERIC;
     94 
     95 	for (matchp = cs->matches; matchp; matchp = matchp->next) {
     96 		struct xt_xlate_mt_params params = {
     97 			.ip		= (const void *)&cs->fw,
     98 			.match		= matchp->match->m,
     99 			.numeric	= numeric,
    100 			.escape_quotes	= !cs->restore,
    101 		};
    102 
    103 		if (!matchp->match->xlate)
    104 			return 0;
    105 
    106 		ret = matchp->match->xlate(xl, &params);
    107 
    108 		if (strcmp(matchp->match->name, "comment") != 0)
    109 			xt_xlate_add(xl, " ");
    110 
    111 		if (!ret)
    112 			break;
    113 	}
    114 	return ret;
    115 }
    116 
    117 bool xlate_find_match(const struct iptables_command_state *cs, const char *p_name)
    118 {
    119 	struct xtables_rule_match *matchp;
    120 
    121 	/* Skip redundant protocol, eg. ip protocol tcp tcp dport */
    122 	for (matchp = cs->matches; matchp; matchp = matchp->next) {
    123 		if (strcmp(matchp->match->name, p_name) == 0)
    124 			return true;
    125 	}
    126 	return false;
    127 }
    128 
    129 const char *family2str[] = {
    130 	[NFPROTO_IPV4]	= "ip",
    131 	[NFPROTO_IPV6]	= "ip6",
    132 };
    133 
    134 static int nft_rule_xlate_add(struct nft_handle *h,
    135 			      const struct nft_xt_cmd_parse *p,
    136 			      const struct iptables_command_state *cs,
    137 			      bool append)
    138 {
    139 	struct xt_xlate *xl = xt_xlate_alloc(10240);
    140 	int ret;
    141 
    142 	if (append) {
    143 		xt_xlate_add(xl, "add rule %s %s %s ",
    144 			   family2str[h->family], p->table, p->chain);
    145 	} else {
    146 		xt_xlate_add(xl, "insert rule %s %s %s ",
    147 			   family2str[h->family], p->table, p->chain);
    148 	}
    149 
    150 	ret = h->ops->xlate(cs, xl);
    151 	if (ret)
    152 		printf("%s\n", xt_xlate_get(xl));
    153 
    154 	xt_xlate_free(xl);
    155 	return ret;
    156 }
    157 
    158 static int xlate(struct nft_handle *h, struct nft_xt_cmd_parse *p,
    159 		 struct iptables_command_state *cs,
    160 		 struct xtables_args *args, bool append,
    161 		 int (*cb)(struct nft_handle *h,
    162 			   const struct nft_xt_cmd_parse *p,
    163 			   const struct iptables_command_state *cs,
    164 			   bool append))
    165 {
    166 	unsigned int i, j;
    167 	int ret = 1;
    168 
    169 	for (i = 0; i < args->s.naddrs; i++) {
    170 		switch (h->family) {
    171 		case AF_INET:
    172 			cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr;
    173 			cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr;
    174 			for (j = 0; j < args->d.naddrs; j++) {
    175 				cs->fw.ip.dst.s_addr =
    176 					args->d.addr.v4[j].s_addr;
    177 				cs->fw.ip.dmsk.s_addr =
    178 					args->d.mask.v4[j].s_addr;
    179 				ret = cb(h, p, cs, append);
    180 			}
    181 			break;
    182 		case AF_INET6:
    183 			memcpy(&cs->fw6.ipv6.src,
    184 			       &args->s.addr.v6[i], sizeof(struct in6_addr));
    185 			memcpy(&cs->fw6.ipv6.smsk,
    186 			       &args->s.mask.v6[i], sizeof(struct in6_addr));
    187 			for (j = 0; j < args->d.naddrs; j++) {
    188 				memcpy(&cs->fw6.ipv6.dst,
    189 				       &args->d.addr.v6[j],
    190 				       sizeof(struct in6_addr));
    191 				memcpy(&cs->fw6.ipv6.dmsk,
    192 				       &args->d.mask.v6[j],
    193 				       sizeof(struct in6_addr));
    194 				ret = cb(h, p, cs, append);
    195 			}
    196 			break;
    197 		}
    198 	}
    199 
    200 	return ret;
    201 }
    202 
    203 static void print_ipt_cmd(int argc, char *argv[])
    204 {
    205 	int i;
    206 
    207 	printf("# ");
    208 	for (i = 1; i < argc; i++)
    209 		printf("%s ", argv[i]);
    210 
    211 	printf("\n");
    212 }
    213 
    214 static int do_command_xlate(struct nft_handle *h, int argc, char *argv[],
    215 			    char **table, bool restore)
    216 {
    217 	int ret = 0;
    218 	struct nft_xt_cmd_parse p = {
    219 		.table		= *table,
    220 		.restore	= restore,
    221 	};
    222 	struct iptables_command_state cs;
    223 	struct xtables_args args = {
    224 		.family = h->family,
    225 	};
    226 
    227 	do_parse(h, argc, argv, &p, &cs, &args);
    228 
    229 	cs.restore = restore;
    230 
    231 	if (!restore)
    232 		printf("nft ");
    233 
    234 	switch (p.command) {
    235 	case CMD_APPEND:
    236 		ret = 1;
    237 		if (!xlate(h, &p, &cs, &args, true, nft_rule_xlate_add)) {
    238 			print_ipt_cmd(argc, argv);
    239 		}
    240 		break;
    241 	case CMD_DELETE:
    242 		break;
    243 	case CMD_DELETE_NUM:
    244 		break;
    245 	case CMD_CHECK:
    246 		break;
    247 	case CMD_REPLACE:
    248 		break;
    249 	case CMD_INSERT:
    250 		ret = 1;
    251 		if (!xlate(h, &p, &cs, &args, false, nft_rule_xlate_add)) {
    252 			print_ipt_cmd(argc, argv);
    253 		}
    254 		break;
    255 	case CMD_FLUSH:
    256 		if (p.chain) {
    257 			printf("flush chain %s %s %s\n",
    258 				family2str[h->family], p.table, p.chain);
    259 		} else {
    260 			printf("flush table %s %s\n",
    261 				family2str[h->family], p.table);
    262 		}
    263 		ret = 1;
    264 		break;
    265 	case CMD_ZERO:
    266 		break;
    267 	case CMD_ZERO_NUM:
    268 		break;
    269 	case CMD_LIST:
    270 	case CMD_LIST|CMD_ZERO:
    271 	case CMD_LIST|CMD_ZERO_NUM:
    272 		printf("list table %s %s\n",
    273 		       family2str[h->family], p.table);
    274 		ret = 1;
    275 		break;
    276 	case CMD_LIST_RULES:
    277 	case CMD_LIST_RULES|CMD_ZERO:
    278 	case CMD_LIST_RULES|CMD_ZERO_NUM:
    279 		break;
    280 	case CMD_NEW_CHAIN:
    281 		printf("add chain %s %s %s\n",
    282 		       family2str[h->family], p.table, p.chain);
    283 		ret = 1;
    284 		break;
    285 	case CMD_DELETE_CHAIN:
    286 		printf("delete chain %s %s %s\n",
    287 		       family2str[h->family], p.table, p.chain);
    288 		ret = 1;
    289 		break;
    290 	case CMD_RENAME_CHAIN:
    291 		break;
    292 	case CMD_SET_POLICY:
    293 		break;
    294 	default:
    295 		/* We should never reach this... */
    296 		printf("Unsupported command?\n");
    297 		exit(1);
    298 	}
    299 
    300 	xtables_rule_matches_free(&cs.matches);
    301 
    302 	if (h->family == AF_INET) {
    303 		free(args.s.addr.v4);
    304 		free(args.s.mask.v4);
    305 		free(args.d.addr.v4);
    306 		free(args.d.mask.v4);
    307 	} else if (h->family == AF_INET6) {
    308 		free(args.s.addr.v6);
    309 		free(args.s.mask.v6);
    310 		free(args.d.addr.v6);
    311 		free(args.d.mask.v6);
    312 	}
    313 	xtables_free_opts(1);
    314 
    315 	return ret;
    316 }
    317 
    318 static void print_usage(const char *name, const char *version)
    319 {
    320 	fprintf(stderr, "%s %s "
    321 			"(c) 2014 by Pablo Neira Ayuso <pablo (at) netfilter.org>\n"
    322 			"Usage: %s [-h] [-f]\n"
    323                         "	[ --help ]\n"
    324                         "	[ --file=<FILE> ]\n", name, version, name);
    325         exit(1);
    326 }
    327 
    328 static const struct option options[] = {
    329 	{ .name = "help",	.has_arg = false,	.val = 'h' },
    330 	{ .name = "file",	.has_arg = true,	.val = 'f' },
    331 	{ NULL },
    332 };
    333 
    334 static int xlate_chain_user_add(struct nft_handle *h, const char *chain,
    335 				const char *table)
    336 {
    337 	printf("add chain %s %s %s\n", family2str[h->family], table, chain);
    338 	return 0;
    339 }
    340 
    341 static int commit(struct nft_handle *h)
    342 {
    343 	return 1;
    344 }
    345 
    346 static void xlate_table_new(struct nft_handle *h, const char *table)
    347 {
    348 	printf("add table %s %s\n", family2str[h->family], table);
    349 }
    350 
    351 static int xlate_chain_set(struct nft_handle *h, const char *table,
    352 			   const char *chain, const char *policy,
    353 			   const struct xt_counters *counters)
    354 {
    355 	const char *type = "filter";
    356 
    357 	if (strcmp(table, "nat") == 0)
    358 		type = "nat";
    359 
    360 	printf("add chain %s %s %s { type %s ",
    361 	       family2str[h->family], table, chain, type);
    362 	if (strcmp(chain, "PREROUTING") == 0)
    363 		printf("hook prerouting priority 0; ");
    364 	else if (strcmp(chain, "INPUT") == 0)
    365 		printf("hook input priority 0; ");
    366 	else if (strcmp(chain, "FORWARD") == 0)
    367 		printf("hook forward priority 0; ");
    368 	else if (strcmp(chain, "OUTPUT") == 0)
    369 		printf("hook output priority 0; ");
    370 	else if (strcmp(chain, "POSTROUTING") == 0)
    371 		printf("hook postrouting priority 0; ");
    372 
    373 	if (strcmp(policy, "ACCEPT") == 0)
    374 		printf("policy accept; ");
    375 	else if (strcmp(policy, "DROP") == 0)
    376 		printf("policy drop; ");
    377 
    378 	printf("}\n");
    379 	return 1;
    380 }
    381 
    382 static struct nft_xt_restore_cb cb_xlate = {
    383 	.table_new	= xlate_table_new,
    384 	.chain_set	= xlate_chain_set,
    385 	.chain_user_add	= xlate_chain_user_add,
    386 	.do_command	= do_command_xlate,
    387 	.commit		= commit,
    388 	.abort		= commit,
    389 };
    390 
    391 static int xtables_xlate_main(int family, const char *progname, int argc,
    392 			      char *argv[])
    393 {
    394 	int ret;
    395 	char *table = "filter";
    396 	struct nft_handle h = {
    397 		.family = family,
    398 	};
    399 
    400 	xtables_globals.program_name = progname;
    401 	ret = xtables_init_all(&xtables_globals, family);
    402 	if (ret < 0) {
    403 		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
    404 				xtables_globals.program_name,
    405 				xtables_globals.program_version);
    406 				exit(1);
    407 	}
    408 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
    409 	init_extensions();
    410 	init_extensions4();
    411 #endif
    412 
    413 	if (nft_init(&h, xtables_ipv4) < 0) {
    414 		fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
    415 				xtables_globals.program_name,
    416 				xtables_globals.program_version,
    417 				strerror(errno));
    418 		nft_fini(&h);
    419 		exit(EXIT_FAILURE);
    420 	}
    421 
    422 	ret = do_command_xlate(&h, argc, argv, &table, false);
    423 	if (!ret)
    424 		fprintf(stderr, "Translation not implemented\n");
    425 
    426 	nft_fini(&h);
    427 	exit(!ret);
    428 }
    429 
    430 static int xtables_restore_xlate_main(int family, const char *progname,
    431 				      int argc, char *argv[])
    432 {
    433 	int ret;
    434 	struct nft_handle h = {
    435 		.family = family,
    436 	};
    437 	const char *file = NULL;
    438 	struct nft_xt_restore_parse p = {};
    439 	time_t now = time(NULL);
    440 	int c;
    441 
    442 	xtables_globals.program_name = progname;
    443 	ret = xtables_init_all(&xtables_globals, family);
    444 	if (ret < 0) {
    445 		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
    446 				xtables_globals.program_name,
    447 				xtables_globals.program_version);
    448 				exit(1);
    449 	}
    450 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
    451 	init_extensions();
    452 	init_extensions4();
    453 #endif
    454 
    455 	if (nft_init(&h, xtables_ipv4) < 0) {
    456 		fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
    457 				xtables_globals.program_name,
    458 				xtables_globals.program_version,
    459 				strerror(errno));
    460 		nft_fini(&h);
    461 		exit(EXIT_FAILURE);
    462 	}
    463 
    464 	opterr = 0;
    465 	while ((c = getopt_long(argc, argv, "hf:", options, NULL)) != -1) {
    466 		switch (c) {
    467 		case 'h':
    468 			print_usage(argv[0], IPTABLES_VERSION);
    469 			exit(0);
    470 		case 'f':
    471 			file = optarg;
    472 			break;
    473 		}
    474 	}
    475 
    476 	if (file == NULL) {
    477 		fprintf(stderr, "ERROR: missing file name\n");
    478 		print_usage(argv[0], IPTABLES_VERSION);
    479 		exit(0);
    480 	}
    481 
    482 	p.in = fopen(file, "r");
    483 	if (p.in == NULL) {
    484 		fprintf(stderr, "Cannot open file %s\n", file);
    485 		exit(1);
    486 	}
    487 
    488 	printf("# Translated by %s v%s on %s",
    489 	       argv[0], IPTABLES_VERSION, ctime(&now));
    490 	xtables_restore_parse(&h, &p, &cb_xlate, argc, argv);
    491 	printf("# Completed on %s", ctime(&now));
    492 
    493 	nft_fini(&h);
    494 	fclose(p.in);
    495 	exit(0);
    496 }
    497 
    498 int xtables_ip4_xlate_main(int argc, char *argv[])
    499 {
    500 	return xtables_xlate_main(NFPROTO_IPV4, "iptables-translate",
    501 				  argc, argv);
    502 }
    503 
    504 int xtables_ip6_xlate_main(int argc, char *argv[])
    505 {
    506 	return xtables_xlate_main(NFPROTO_IPV6, "ip6tables-translate",
    507 				  argc, argv);
    508 }
    509 
    510 int xtables_ip4_xlate_restore_main(int argc, char *argv[])
    511 {
    512 	return xtables_restore_xlate_main(NFPROTO_IPV4,
    513 					  "iptables-translate-restore",
    514 					  argc, argv);
    515 }
    516 
    517 int xtables_ip6_xlate_restore_main(int argc, char *argv[])
    518 {
    519 	return xtables_restore_xlate_main(NFPROTO_IPV6,
    520 					  "ip6tables-translate-restore",
    521 					  argc, argv);
    522 }
    523