• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <ctype.h>
2 #include <errno.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <stdbool.h>
6 #include <stdarg.h>
7 #include <string.h>
8 #include <fcntl.h>
9 #include <getopt.h>
10 #include <iptables.h>
11 #include <xtables.h>
12 
13 #include <netinet/ether.h>
14 
15 #include <linux/netfilter_bridge.h>
16 #include <linux/netfilter/nf_tables.h>
17 #include <libiptc/libxtc.h>
18 
19 #include "xshared.h"
20 #include "xtables-multi.h"
21 #include "nft-bridge.h"
22 #include "nft.h"
23 #include "nft-shared.h"
24 /*
25  * From include/ebtables_u.h
26  */
27 #define EXEC_STYLE_PRG    0
28 #define EXEC_STYLE_DAEMON 1
29 
30 #define ebt_check_option2(flags, mask) EBT_CHECK_OPTION(flags, mask)
31 
32 extern int ebt_invert;
33 
ebt_check_inverse2(const char option[],int argc,char ** argv)34 static int ebt_check_inverse2(const char option[], int argc, char **argv)
35 {
36 	if (!option)
37 		return ebt_invert;
38 	if (strcmp(option, "!") == 0) {
39 		if (ebt_invert == 1)
40 			xtables_error(PARAMETER_PROBLEM,
41 				      "Double use of '!' not allowed");
42 		if (optind >= argc)
43 			optarg = NULL;
44 		else
45 			optarg = argv[optind];
46 		optind++;
47 		ebt_invert = 1;
48 		return 1;
49 	}
50 	return ebt_invert;
51 }
52 
53 /*
54  * Glue code to use libxtables
55  */
parse_rule_number(const char * rule)56 static int parse_rule_number(const char *rule)
57 {
58 	unsigned int rule_nr;
59 
60 	if (!xtables_strtoui(rule, NULL, &rule_nr, 1, INT_MAX))
61 		xtables_error(PARAMETER_PROBLEM,
62 			      "Invalid rule number `%s'", rule);
63 
64 	return rule_nr;
65 }
66 
get_current_chain(const char * chain)67 static int get_current_chain(const char *chain)
68 {
69 	if (strcmp(chain, "PREROUTING") == 0)
70 		return NF_BR_PRE_ROUTING;
71 	else if (strcmp(chain, "INPUT") == 0)
72 		return NF_BR_LOCAL_IN;
73 	else if (strcmp(chain, "FORWARD") == 0)
74 		return NF_BR_FORWARD;
75 	else if (strcmp(chain, "OUTPUT") == 0)
76 		return NF_BR_LOCAL_OUT;
77 	else if (strcmp(chain, "POSTROUTING") == 0)
78 		return NF_BR_POST_ROUTING;
79 
80 	return -1;
81 }
82 
83 /*
84  * The original ebtables parser
85  */
86 
87 /* Checks whether a command has already been specified */
88 #define OPT_COMMANDS (flags & OPT_COMMAND || flags & OPT_ZERO)
89 
90 #define OPT_COMMAND	0x01
91 #define OPT_TABLE	0x02
92 #define OPT_IN		0x04
93 #define OPT_OUT		0x08
94 #define OPT_JUMP	0x10
95 #define OPT_PROTOCOL	0x20
96 #define OPT_SOURCE	0x40
97 #define OPT_DEST	0x80
98 #define OPT_ZERO	0x100
99 #define OPT_LOGICALIN	0x200
100 #define OPT_LOGICALOUT	0x400
101 #define OPT_COUNT	0x1000 /* This value is also defined in libebtc.c */
102 
103 /* Default command line options. Do not mess around with the already
104  * assigned numbers unless you know what you are doing */
105 extern struct option ebt_original_options[];
106 extern struct xtables_globals ebtables_globals;
107 #define opts ebtables_globals.opts
108 #define prog_name ebtables_globals.program_name
109 #define prog_vers ebtables_globals.program_version
110 
print_help(void)111 static void print_help(void)
112 {
113 	fprintf(stderr, "%s: Translate ebtables command to nft syntax\n"
114 			"no side effects occur, the translated command is written "
115 			"to standard output.\n"
116 			"A '#' followed by input means no translation "
117 			"is available.\n", prog_name);
118 	exit(0);
119 }
120 
parse_rule_range(const char * argv,int * rule_nr,int * rule_nr_end)121 static int parse_rule_range(const char *argv, int *rule_nr, int *rule_nr_end)
122 {
123 	char *colon = strchr(argv, ':'), *buffer;
124 
125 	if (colon) {
126 		*colon = '\0';
127 		if (*(colon + 1) == '\0')
128 			*rule_nr_end = -1; /* Until the last rule */
129 		else {
130 			*rule_nr_end = strtol(colon + 1, &buffer, 10);
131 			if (*buffer != '\0' || *rule_nr_end == 0)
132 				return -1;
133 		}
134 	}
135 	if (colon == argv)
136 		*rule_nr = 1; /* Beginning with the first rule */
137 	else {
138 		*rule_nr = strtol(argv, &buffer, 10);
139 		if (*buffer != '\0' || *rule_nr == 0)
140 			return -1;
141 	}
142 	if (!colon)
143 		*rule_nr_end = *rule_nr;
144 	return 0;
145 }
146 
ebtables_parse_interface(const char * arg,char * vianame)147 static void ebtables_parse_interface(const char *arg, char *vianame)
148 {
149 	unsigned char mask[IFNAMSIZ];
150 	char *c;
151 
152 	xtables_parse_interface(arg, vianame, mask);
153 
154 	if ((c = strchr(vianame, '+'))) {
155 		if (*(c + 1) != '\0')
156 			xtables_error(PARAMETER_PROBLEM,
157 				      "Spurious characters after '+' wildcard");
158 	}
159 }
160 
print_ebt_cmd(int argc,char * argv[])161 static void print_ebt_cmd(int argc, char *argv[])
162 {
163 	int i;
164 
165 	printf("# ");
166 	for (i = 1; i < argc; i++)
167 		printf("%s ", argv[i]);
168 
169 	printf("\n");
170 }
171 
nft_rule_eb_xlate_add(struct nft_handle * h,const struct nft_xt_cmd_parse * p,const struct iptables_command_state * cs,bool append)172 static int nft_rule_eb_xlate_add(struct nft_handle *h, const struct nft_xt_cmd_parse *p,
173 				 const struct iptables_command_state *cs, bool append)
174 {
175 	struct xt_xlate *xl = xt_xlate_alloc(10240);
176 	int ret;
177 
178 	if (append) {
179 		xt_xlate_add(xl, "add rule bridge %s %s ", p->table, p->chain);
180 	} else {
181 		xt_xlate_add(xl, "insert rule bridge %s %s ", p->table, p->chain);
182 	}
183 
184 	ret = h->ops->xlate(cs, xl);
185 	if (ret)
186 		printf("%s\n", xt_xlate_get(xl));
187 
188 	xt_xlate_free(xl);
189 	return ret;
190 }
191 
192 /* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */
do_commandeb_xlate(struct nft_handle * h,int argc,char * argv[],char ** table)193 static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char **table)
194 {
195 	char *buffer;
196 	int c, i;
197 	int rule_nr = 0;
198 	int rule_nr_end = 0;
199 	int ret = 0;
200 	unsigned int flags = 0;
201 	struct iptables_command_state cs = {
202 		.argv		= argv,
203 		.eb.bitmask	= EBT_NOPROTO,
204 	};
205 	char command = 'h';
206 	const char *chain = NULL;
207 	int exec_style = EXEC_STYLE_PRG;
208 	int selected_chain = -1;
209 	struct xtables_rule_match *xtrm_i;
210 	struct ebt_match *match;
211 	struct nft_xt_cmd_parse p = {
212 		.table          = *table,
213         };
214 
215 	/* prevent getopt to spoil our error reporting */
216 	opterr = false;
217 
218 	printf("nft ");
219 	/* Getopt saves the day */
220 	while ((c = getopt_long(argc, argv,
221 	   "-A:D:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) {
222 		cs.c = c;
223 		cs.invert = ebt_invert;
224 		switch (c) {
225 		case 'A': /* Add a rule */
226 		case 'D': /* Delete a rule */
227 		case 'P': /* Define policy */
228 		case 'I': /* Insert a rule */
229 		case 'N': /* Make a user defined chain */
230 		case 'E': /* Rename chain */
231 		case 'X': /* Delete chain */
232 			/* We allow -N chainname -P policy */
233 			/* XXX: Not in ebtables-compat */
234 			if (command == 'N' && c == 'P') {
235 				command = c;
236 				optind--; /* No table specified */
237 				break;
238 			}
239 			if (OPT_COMMANDS)
240 				xtables_error(PARAMETER_PROBLEM,
241 					      "Multiple commands are not allowed");
242 			command = c;
243 			chain = optarg;
244 			selected_chain = get_current_chain(chain);
245 			p.chain = chain;
246 			flags |= OPT_COMMAND;
247 
248 			if (c == 'N') {
249 				printf("add chain bridge %s %s\n", p.table, p.chain);
250 				ret = 1;
251 				break;
252 			} else if (c == 'X') {
253 				printf("delete chain bridge %s %s\n", p.table, p.chain);
254 				ret = 1;
255 				break;
256 			}
257 
258 			if (c == 'E') {
259 				break;
260 			} else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
261 				if (optind != argc - 1)
262 					xtables_error(PARAMETER_PROBLEM,
263 							 "No extra options allowed with -D start_nr[:end_nr]");
264 				if (parse_rule_range(argv[optind], &rule_nr, &rule_nr_end))
265 					xtables_error(PARAMETER_PROBLEM,
266 							 "Problem with the specified rule number(s) '%s'", argv[optind]);
267 				optind++;
268 			} else if (c == 'I') {
269 				if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')))
270 					rule_nr = 1;
271 				else {
272 					rule_nr = parse_rule_number(argv[optind]);
273 					optind++;
274 				}
275 				p.rulenum = rule_nr;
276 			} else if (c == 'P') {
277 				break;
278 			}
279 			break;
280 		case 'L': /* List */
281 			printf("list table bridge %s\n", p.table);
282 			ret = 1;
283 			break;
284 		case 'F': /* Flush */
285 			if (p.chain) {
286 				printf("flush chain bridge %s %s\n", p.table, p.chain);
287 			} else {
288 				printf("flush table bridge %s\n", p.table);
289 			}
290 			ret = 1;
291 			break;
292 		case 'Z': /* Zero counters */
293 			if (c == 'Z') {
294 				if ((flags & OPT_ZERO) || (flags & OPT_COMMAND && command != 'L'))
295 print_zero:
296 					xtables_error(PARAMETER_PROBLEM,
297 						      "Command -Z only allowed together with command -L");
298 				flags |= OPT_ZERO;
299 			} else {
300 				if (flags & OPT_COMMAND)
301 					xtables_error(PARAMETER_PROBLEM,
302 						      "Multiple commands are not allowed");
303 				command = c;
304 				flags |= OPT_COMMAND;
305 				if (flags & OPT_ZERO && c != 'L')
306 					goto print_zero;
307 			}
308 			break;
309 		case 'V': /* Version */
310 			if (OPT_COMMANDS)
311 				xtables_error(PARAMETER_PROBLEM,
312 					      "Multiple commands are not allowed");
313 			if (exec_style == EXEC_STYLE_DAEMON)
314 				xtables_error(PARAMETER_PROBLEM,
315 					      "%s %s\n", prog_name, prog_vers);
316 			printf("%s %s\n", prog_name, prog_vers);
317 			exit(0);
318 		case 'h':
319 			if (OPT_COMMANDS)
320 				xtables_error(PARAMETER_PROBLEM,
321 					      "Multiple commands are not allowed");
322 			print_help();
323 			break;
324 		case 't': /* Table */
325 			if (OPT_COMMANDS)
326 				xtables_error(PARAMETER_PROBLEM,
327 					      "Please put the -t option first");
328 			ebt_check_option2(&flags, OPT_TABLE);
329 			if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
330 				xtables_error(PARAMETER_PROBLEM,
331 					      "Table name length cannot exceed %d characters",
332 					      EBT_TABLE_MAXNAMELEN - 1);
333 			*table = optarg;
334 			p.table = optarg;
335 			break;
336 		case 'i': /* Input interface */
337 		case 2  : /* Logical input interface */
338 		case 'o': /* Output interface */
339 		case 3  : /* Logical output interface */
340 		case 'j': /* Target */
341 		case 'p': /* Net family protocol */
342 		case 's': /* Source mac */
343 		case 'd': /* Destination mac */
344 		case 'c': /* Set counters */
345 			if (!OPT_COMMANDS)
346 				xtables_error(PARAMETER_PROBLEM,
347 					      "No command specified");
348 			if (command != 'A' && command != 'D' && command != 'I')
349 				xtables_error(PARAMETER_PROBLEM,
350 					      "Command and option do not match");
351 			if (c == 'i') {
352 				ebt_check_option2(&flags, OPT_IN);
353 				if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
354 					xtables_error(PARAMETER_PROBLEM,
355 						      "Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains");
356 				if (ebt_check_inverse2(optarg, argc, argv))
357 					cs.eb.invflags |= EBT_IIN;
358 
359 				ebtables_parse_interface(optarg, cs.eb.in);
360 				break;
361 			} else if (c == 2) {
362 				ebt_check_option2(&flags, OPT_LOGICALIN);
363 				if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
364 					xtables_error(PARAMETER_PROBLEM,
365 						      "Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains");
366 				if (ebt_check_inverse2(optarg, argc, argv))
367 					cs.eb.invflags |= EBT_ILOGICALIN;
368 
369 				ebtables_parse_interface(optarg, cs.eb.logical_in);
370 				break;
371 			} else if (c == 'o') {
372 				ebt_check_option2(&flags, OPT_OUT);
373 				if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
374 					xtables_error(PARAMETER_PROBLEM,
375 						      "Use -o only in OUTPUT, FORWARD and POSTROUTING chains");
376 				if (ebt_check_inverse2(optarg, argc, argv))
377 					cs.eb.invflags |= EBT_IOUT;
378 
379 				ebtables_parse_interface(optarg, cs.eb.out);
380 				break;
381 			} else if (c == 3) {
382 				ebt_check_option2(&flags, OPT_LOGICALOUT);
383 				if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
384 					xtables_error(PARAMETER_PROBLEM,
385 						      "Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains");
386 				if (ebt_check_inverse2(optarg, argc, argv))
387 					cs.eb.invflags |= EBT_ILOGICALOUT;
388 
389 				ebtables_parse_interface(optarg, cs.eb.logical_out);
390 				break;
391 			} else if (c == 'j') {
392 				ebt_check_option2(&flags, OPT_JUMP);
393 				command_jump(&cs, optarg);
394 				break;
395 			} else if (c == 's') {
396 				ebt_check_option2(&flags, OPT_SOURCE);
397 				if (ebt_check_inverse2(optarg, argc, argv))
398 					cs.eb.invflags |= EBT_ISOURCE;
399 
400 				if (xtables_parse_mac_and_mask(optarg,
401 							       cs.eb.sourcemac,
402 							       cs.eb.sourcemsk))
403 					xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg);
404 				cs.eb.bitmask |= EBT_SOURCEMAC;
405 				break;
406 			} else if (c == 'd') {
407 				ebt_check_option2(&flags, OPT_DEST);
408 				if (ebt_check_inverse2(optarg, argc, argv))
409 					cs.eb.invflags |= EBT_IDEST;
410 
411 				if (xtables_parse_mac_and_mask(optarg,
412 							       cs.eb.destmac,
413 							       cs.eb.destmsk))
414 					xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg);
415 				cs.eb.bitmask |= EBT_DESTMAC;
416 				break;
417 			} else if (c == 'c') {
418 				ebt_check_option2(&flags, OPT_COUNT);
419 				if (ebt_check_inverse2(optarg, argc, argv))
420 					xtables_error(PARAMETER_PROBLEM,
421 						      "Unexpected '!' after -c");
422 				if (optind >= argc || optarg[0] == '-' || argv[optind][0] == '-')
423 					xtables_error(PARAMETER_PROBLEM,
424 						      "Option -c needs 2 arguments");
425 
426 				cs.counters.pcnt = strtoull(optarg, &buffer, 10);
427 				if (*buffer != '\0')
428 					xtables_error(PARAMETER_PROBLEM,
429 						      "Packet counter '%s' invalid",
430 						      optarg);
431 				cs.counters.bcnt = strtoull(argv[optind], &buffer, 10);
432 				if (*buffer != '\0')
433 					xtables_error(PARAMETER_PROBLEM,
434 						      "Packet counter '%s' invalid",
435 						      argv[optind]);
436 				optind++;
437 				break;
438 			}
439 			ebt_check_option2(&flags, OPT_PROTOCOL);
440 			if (ebt_check_inverse2(optarg, argc, argv))
441 				cs.eb.invflags |= EBT_IPROTO;
442 
443 			cs.eb.bitmask &= ~((unsigned int)EBT_NOPROTO);
444 			i = strtol(optarg, &buffer, 16);
445 			if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
446 				xtables_error(PARAMETER_PROBLEM,
447 					      "Problem with the specified protocol");
448 			if (*buffer != '\0') {
449 				struct xt_ethertypeent *ent;
450 
451 				if (!strcasecmp(optarg, "LENGTH")) {
452 					cs.eb.bitmask |= EBT_802_3;
453 					break;
454 				}
455 				ent = xtables_getethertypebyname(optarg);
456 				if (!ent)
457 					xtables_error(PARAMETER_PROBLEM,
458 						      "Problem with the specified Ethernet protocol '%s', perhaps "XT_PATH_ETHERTYPES " is missing", optarg);
459 				cs.eb.ethproto = ent->e_ethertype;
460 			} else
461 				cs.eb.ethproto = i;
462 
463 			if (cs.eb.ethproto < 0x0600)
464 				xtables_error(PARAMETER_PROBLEM,
465 					      "Sorry, protocols have values above or equal to 0x0600");
466 			break;
467 		case 4  : /* Lc */
468 			ebt_check_option2(&flags, LIST_C);
469 			if (command != 'L')
470 				xtables_error(PARAMETER_PROBLEM,
471 					      "Use --Lc with -L");
472 			flags |= LIST_C;
473 			break;
474 		case 5  : /* Ln */
475 			ebt_check_option2(&flags, LIST_N);
476 			if (command != 'L')
477 				xtables_error(PARAMETER_PROBLEM,
478 					      "Use --Ln with -L");
479 			if (flags & LIST_X)
480 				xtables_error(PARAMETER_PROBLEM,
481 					      "--Lx is not compatible with --Ln");
482 			flags |= LIST_N;
483 			break;
484 		case 6  : /* Lx */
485 			ebt_check_option2(&flags, LIST_X);
486 			if (command != 'L')
487 				xtables_error(PARAMETER_PROBLEM,
488 					      "Use --Lx with -L");
489 			if (flags & LIST_N)
490 				xtables_error(PARAMETER_PROBLEM,
491 					      "--Lx is not compatible with --Ln");
492 			flags |= LIST_X;
493 			break;
494 		case 12 : /* Lmac2 */
495 			ebt_check_option2(&flags, LIST_MAC2);
496 			if (command != 'L')
497 				xtables_error(PARAMETER_PROBLEM,
498 					       "Use --Lmac2 with -L");
499 			flags |= LIST_MAC2;
500 			break;
501 		case 1 :
502 			if (!strcmp(optarg, "!"))
503 				ebt_check_inverse2(optarg, argc, argv);
504 			else
505 				xtables_error(PARAMETER_PROBLEM,
506 					      "Bad argument : '%s'", optarg);
507 			/* ebt_ebt_check_inverse2() did optind++ */
508 			optind--;
509 			continue;
510 		default:
511 			ebt_check_inverse2(optarg, argc, argv);
512 
513 			if (ebt_command_default(&cs))
514 				xtables_error(PARAMETER_PROBLEM,
515 					      "Unknown argument: '%s'",
516 					      argv[optind - 1]);
517 
518 			if (command != 'A' && command != 'I' &&
519 			    command != 'D')
520 				xtables_error(PARAMETER_PROBLEM,
521 					      "Extensions only for -A, -I, -D");
522 		}
523 		ebt_invert = 0;
524 	}
525 
526 	/* Do the final checks */
527 	if (command == 'A' || command == 'I' || command == 'D') {
528 		for (xtrm_i = cs.matches; xtrm_i; xtrm_i = xtrm_i->next)
529 			xtables_option_mfcall(xtrm_i->match);
530 
531 		for (match = cs.match_list; match; match = match->next) {
532 			if (match->ismatch)
533 				continue;
534 
535 			xtables_option_tfcall(match->u.watcher);
536 		}
537 
538 		if (cs.target != NULL)
539 			xtables_option_tfcall(cs.target);
540 	}
541 
542 	cs.eb.ethproto = htons(cs.eb.ethproto);
543 
544 	if (command == 'P') {
545 		return 0;
546 	} else if (command == 'A') {
547 		ret = nft_rule_eb_xlate_add(h, &p, &cs, true);
548 		if (!ret)
549 			print_ebt_cmd(argc, argv);
550 	} else if (command == 'I') {
551 		ret = nft_rule_eb_xlate_add(h, &p, &cs, false);
552 		if (!ret)
553 			print_ebt_cmd(argc, argv);
554 	}
555 
556 	ebt_cs_clean(&cs);
557 	return ret;
558 }
559 
dummy_compat_rev(const char * name,uint8_t rev,int opt)560 static int dummy_compat_rev(const char *name, uint8_t rev, int opt)
561 {
562 	return 1;
563 }
564 
xtables_eb_xlate_main(int argc,char * argv[])565 int xtables_eb_xlate_main(int argc, char *argv[])
566 {
567 	int ret;
568 	char *table = "filter";
569 	struct nft_handle h;
570 
571 	nft_init_eb(&h, argv[0]);
572 	ebtables_globals.compat_rev = dummy_compat_rev;
573 
574 	ret = do_commandeb_xlate(&h, argc, argv, &table);
575 	if (!ret)
576 		fprintf(stderr, "Translation not implemented\n");
577 
578 	exit(!ret);
579 }
580 
581