• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 2014 by Pablo Neira Ayuso <pablo@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 
xlate_ifname(struct xt_xlate * xl,const char * nftmeta,const char * ifname,bool invert)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 
xlate_action(const struct iptables_command_state * cs,bool goto_set,struct xt_xlate * xl)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 
xlate_matches(const struct iptables_command_state * cs,struct xt_xlate * xl)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 
xlate_find_match(const struct iptables_command_state * cs,const char * p_name)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 
nft_rule_xlate_add(struct nft_handle * h,const struct nft_xt_cmd_parse * p,const struct iptables_command_state * cs,bool append)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 
xlate(struct nft_handle * h,struct nft_xt_cmd_parse * p,struct iptables_command_state * cs,struct xtables_args * args,bool append,int (* cb)(struct nft_handle * h,const struct nft_xt_cmd_parse * p,const struct iptables_command_state * cs,bool append))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 
print_ipt_cmd(int argc,char * argv[])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 
do_command_xlate(struct nft_handle * h,int argc,char * argv[],char ** table,bool restore)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 
print_usage(const char * name,const char * version)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@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 
xlate_chain_user_add(struct nft_handle * h,const char * chain,const char * table)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 
commit(struct nft_handle * h)341 static int commit(struct nft_handle *h)
342 {
343 	return 1;
344 }
345 
xlate_table_new(struct nft_handle * h,const char * table)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 
xlate_chain_set(struct nft_handle * h,const char * table,const char * chain,const char * policy,const struct xt_counters * counters)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 
xtables_xlate_main(int family,const char * progname,int argc,char * argv[])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 
xtables_restore_xlate_main(int family,const char * progname,int argc,char * argv[])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 
xtables_ip4_xlate_main(int argc,char * argv[])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 
xtables_ip6_xlate_main(int argc,char * argv[])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 
xtables_ip4_xlate_restore_main(int argc,char * argv[])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 
xtables_ip6_xlate_restore_main(int argc,char * argv[])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