• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 2014 by Giuseppe Longo <giuseppelng@gmail.com>
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 by
6  * 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 <string.h>
13 #include <netinet/ether.h>
14 #include <inttypes.h>
15 
16 #include <xtables.h>
17 #include <libiptc/libxtc.h>
18 #include <linux/netfilter/nf_tables.h>
19 
20 #include <libnftnl/set.h>
21 
22 #include "nft-shared.h"
23 #include "nft-bridge.h"
24 #include "nft-cache.h"
25 #include "nft.h"
26 
ebt_cs_clean(struct iptables_command_state * cs)27 void ebt_cs_clean(struct iptables_command_state *cs)
28 {
29 	struct ebt_match *m, *nm;
30 
31 	xtables_rule_matches_free(&cs->matches);
32 
33 	for (m = cs->match_list; m;) {
34 		if (!m->ismatch) {
35 			struct xtables_target *target = m->u.watcher;
36 
37 			if (target->t) {
38 				free(target->t);
39 				target->t = NULL;
40 			}
41 			if (target == target->next)
42 				free(target);
43 		}
44 
45 		nm = m->next;
46 		free(m);
47 		m = nm;
48 	}
49 	cs->match_list = NULL;
50 
51 	if (cs->target) {
52 		free(cs->target->t);
53 		cs->target->t = NULL;
54 
55 		if (cs->target == cs->target->next) {
56 			free(cs->target);
57 			cs->target = NULL;
58 		}
59 	}
60 }
61 
62 /* Put the mac address into 6 (ETH_ALEN) bytes returns 0 on success. */
ebt_print_mac_and_mask(const unsigned char * mac,const unsigned char * mask)63 static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
64 {
65 	if (xtables_print_well_known_mac_and_mask(mac, mask))
66 		xtables_print_mac_and_mask(mac, mask);
67 }
68 
add_meta_broute(struct nftnl_rule * r)69 static int add_meta_broute(struct nftnl_rule *r)
70 {
71 	struct nftnl_expr *expr;
72 
73 	expr = nftnl_expr_alloc("immediate");
74 	if (expr == NULL)
75 		return -1;
76 
77 	nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG32_01);
78 	nftnl_expr_set_u8(expr, NFTNL_EXPR_IMM_DATA, 1);
79 	nftnl_rule_add_expr(r, expr);
80 
81 	expr = nftnl_expr_alloc("meta");
82 	if (expr == NULL)
83 		return -1;
84 	nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_BRI_BROUTE);
85 	nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG32_01);
86 
87 	nftnl_rule_add_expr(r, expr);
88 	return 0;
89 }
90 
_add_action(struct nftnl_rule * r,struct iptables_command_state * cs)91 static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs)
92 {
93 	const char *table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
94 
95 	if (cs->target &&
96 	    table && strcmp(table, "broute") == 0) {
97 		if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0) {
98 			int ret = add_meta_broute(r);
99 
100 			if (ret)
101 				return ret;
102 
103 			cs->jumpto = "ACCEPT";
104 		}
105 	}
106 
107 	return add_action(r, cs, false);
108 }
109 
110 static int
nft_bridge_add_match(struct nft_handle * h,const struct ebt_entry * fw,struct nft_rule_ctx * ctx,struct nftnl_rule * r,struct xt_entry_match * m)111 nft_bridge_add_match(struct nft_handle *h, const struct ebt_entry *fw,
112 		     struct nft_rule_ctx *ctx, struct nftnl_rule *r,
113 		     struct xt_entry_match *m)
114 {
115 	if (!strcmp(m->u.user.name, "802_3") && !(fw->bitmask & EBT_802_3))
116 		xtables_error(PARAMETER_PROBLEM,
117 			      "For 802.3 DSAP/SSAP filtering the protocol must be LENGTH");
118 
119 	if (!strcmp(m->u.user.name, "ip") && fw->ethproto != htons(ETH_P_IP))
120 		xtables_error(PARAMETER_PROBLEM,
121 			      "For IP filtering the protocol must be specified as IPv4.");
122 
123 	if (!strcmp(m->u.user.name, "ip6") && fw->ethproto != htons(ETH_P_IPV6))
124 		xtables_error(PARAMETER_PROBLEM,
125 			      "For IPv6 filtering the protocol must be specified as IPv6.");
126 
127 	return add_match(h, ctx, r, m);
128 }
129 
nft_bridge_add(struct nft_handle * h,struct nft_rule_ctx * ctx,struct nftnl_rule * r,struct iptables_command_state * cs)130 static int nft_bridge_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
131 			  struct nftnl_rule *r,
132 			  struct iptables_command_state *cs)
133 {
134 	struct ebt_match *iter;
135 	struct ebt_entry *fw = &cs->eb;
136 	uint32_t op;
137 
138 	if (fw->bitmask & EBT_SOURCEMAC) {
139 		op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE);
140 		add_addr(h, r, NFT_PAYLOAD_LL_HEADER,
141 			 offsetof(struct ethhdr, h_source),
142 			 fw->sourcemac, fw->sourcemsk, ETH_ALEN, op);
143 	}
144 
145 	if (fw->bitmask & EBT_DESTMAC) {
146 		op = nft_invflags2cmp(fw->invflags, EBT_IDEST);
147 		add_addr(h, r, NFT_PAYLOAD_LL_HEADER,
148 			 offsetof(struct ethhdr, h_dest),
149 			 fw->destmac, fw->destmsk, ETH_ALEN, op);
150 	}
151 
152 	if (fw->in[0] != '\0') {
153 		op = nft_invflags2cmp(fw->invflags, EBT_IIN);
154 		add_iface(h, r, fw->in, NFT_META_IIFNAME, op);
155 	}
156 
157 	if (fw->out[0] != '\0') {
158 		op = nft_invflags2cmp(fw->invflags, EBT_IOUT);
159 		add_iface(h, r, fw->out, NFT_META_OIFNAME, op);
160 	}
161 
162 	if (fw->logical_in[0] != '\0') {
163 		op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALIN);
164 		add_iface(h, r, fw->logical_in, NFT_META_BRI_IIFNAME, op);
165 	}
166 
167 	if (fw->logical_out[0] != '\0') {
168 		op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALOUT);
169 		add_iface(h, r, fw->logical_out, NFT_META_BRI_OIFNAME, op);
170 	}
171 
172 	if ((fw->bitmask & EBT_NOPROTO) == 0) {
173 		uint16_t ethproto = fw->ethproto;
174 		uint8_t reg;
175 
176 		op = nft_invflags2cmp(fw->invflags, EBT_IPROTO);
177 		add_payload(h, r, offsetof(struct ethhdr, h_proto), 2,
178 			    NFT_PAYLOAD_LL_HEADER, &reg);
179 
180 		if (fw->bitmask & EBT_802_3) {
181 			op = (op == NFT_CMP_EQ ? NFT_CMP_LT : NFT_CMP_GTE);
182 			ethproto = htons(0x0600);
183 		}
184 
185 		add_cmp_u16(r, ethproto, op, reg);
186 	}
187 
188 	add_compat(r, fw->ethproto, fw->invflags & EBT_IPROTO);
189 
190 	for (iter = cs->match_list; iter; iter = iter->next) {
191 		if (iter->ismatch) {
192 			if (nft_bridge_add_match(h, fw, ctx, r, iter->u.match->m))
193 				break;
194 		} else {
195 			if (add_target(r, iter->u.watcher->t))
196 				break;
197 		}
198 	}
199 
200 	if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0)
201 		return -1;
202 
203 	return _add_action(r, cs);
204 }
205 
nft_bridge_init_cs(struct iptables_command_state * cs)206 static void nft_bridge_init_cs(struct iptables_command_state *cs)
207 {
208 	cs->eb.bitmask = EBT_NOPROTO;
209 }
210 
print_iface(const char * option,const char * name,bool invert)211 static void print_iface(const char *option, const char *name, bool invert)
212 {
213 	if (*name && (strcmp(name, "+") || invert))
214 		printf("%s%s %s ", invert ? "! " : "", option, name);
215 }
216 
nft_bridge_print_table_header(const char * tablename)217 static void nft_bridge_print_table_header(const char *tablename)
218 {
219 	printf("Bridge table: %s\n\n", tablename);
220 }
221 
nft_bridge_print_header(unsigned int format,const char * chain,const char * pol,const struct xt_counters * counters,int refs,uint32_t entries)222 static void nft_bridge_print_header(unsigned int format, const char *chain,
223 				    const char *pol,
224 				    const struct xt_counters *counters,
225 				    int refs, uint32_t entries)
226 {
227 	printf("Bridge chain: %s, entries: %u, policy: %s\n",
228 	       chain, entries, pol ?: "RETURN");
229 }
230 
print_matches_and_watchers(const struct iptables_command_state * cs,unsigned int format)231 static void print_matches_and_watchers(const struct iptables_command_state *cs,
232 				       unsigned int format)
233 {
234 	struct xtables_target *watcherp;
235 	struct xtables_match *matchp;
236 	struct ebt_match *m;
237 
238 	for (m = cs->match_list; m; m = m->next) {
239 		if (m->ismatch) {
240 			matchp = m->u.match;
241 			if (matchp->print != NULL) {
242 				matchp->print(&cs->eb, matchp->m,
243 					      format & FMT_NUMERIC);
244 			}
245 		} else {
246 			watcherp = m->u.watcher;
247 			if (watcherp->print != NULL) {
248 				watcherp->print(&cs->eb, watcherp->t,
249 						format & FMT_NUMERIC);
250 			}
251 		}
252 	}
253 }
254 
print_mac(char option,const unsigned char * mac,const unsigned char * mask,bool invert)255 static void print_mac(char option, const unsigned char *mac,
256 		      const unsigned char *mask,
257 		      bool invert)
258 {
259 	printf("%s-%c ", invert ? "! " : "", option);
260 	ebt_print_mac_and_mask(mac, mask);
261 	printf(" ");
262 }
263 
264 
print_protocol(uint16_t ethproto,bool invert,unsigned int bitmask)265 static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask)
266 {
267 	struct xt_ethertypeent *ent;
268 
269 	/* Dont print anything about the protocol if no protocol was
270 	 * specified, obviously this means any protocol will do. */
271 	if (bitmask & EBT_NOPROTO)
272 		return;
273 
274 	printf("%s-p ", invert ? "! " : "");
275 
276 	if (bitmask & EBT_802_3) {
277 		printf("Length ");
278 		return;
279 	}
280 
281 	ent = xtables_getethertypebynumber(ntohs(ethproto));
282 	if (!ent)
283 		printf("0x%x ", ntohs(ethproto));
284 	else
285 		printf("%s ", ent->e_name);
286 }
287 
__nft_bridge_save_rule(const struct iptables_command_state * cs,unsigned int format)288 static void __nft_bridge_save_rule(const struct iptables_command_state *cs,
289 				   unsigned int format)
290 {
291 	if (!(cs->eb.bitmask & EBT_NOPROTO))
292 		print_protocol(cs->eb.ethproto, cs->eb.invflags & EBT_IPROTO,
293 			       cs->eb.bitmask);
294 	if (cs->eb.bitmask & EBT_ISOURCE)
295 		print_mac('s', cs->eb.sourcemac, cs->eb.sourcemsk,
296 		          cs->eb.invflags & EBT_ISOURCE);
297 	if (cs->eb.bitmask & EBT_IDEST)
298 		print_mac('d', cs->eb.destmac, cs->eb.destmsk,
299 		          cs->eb.invflags & EBT_IDEST);
300 
301 	print_iface("-i", cs->eb.in, cs->eb.invflags & EBT_IIN);
302 	print_iface("--logical-in", cs->eb.logical_in,
303 		    cs->eb.invflags & EBT_ILOGICALIN);
304 	print_iface("-o", cs->eb.out, cs->eb.invflags & EBT_IOUT);
305 	print_iface("--logical-out", cs->eb.logical_out,
306 		    cs->eb.invflags & EBT_ILOGICALOUT);
307 
308 	print_matches_and_watchers(cs, format);
309 
310 	printf("-j ");
311 
312 	if (cs->jumpto != NULL) {
313 		if (strcmp(cs->jumpto, "") != 0)
314 			printf("%s", cs->jumpto);
315 		else
316 			printf("CONTINUE");
317 	}
318 	if (cs->target != NULL && cs->target->print != NULL) {
319 		printf(" ");
320 		cs->target->print(&cs->fw, cs->target->t, format & FMT_NUMERIC);
321 	}
322 
323 	if ((format & (FMT_NOCOUNTS | FMT_C_COUNTS)) == FMT_C_COUNTS) {
324 		if (format & FMT_EBT_SAVE)
325 			printf(" -c %"PRIu64" %"PRIu64"",
326 			       (uint64_t)cs->counters.pcnt,
327 			       (uint64_t)cs->counters.bcnt);
328 		else
329 			printf(" , pcnt = %"PRIu64" -- bcnt = %"PRIu64"",
330 			       (uint64_t)cs->counters.pcnt,
331 			       (uint64_t)cs->counters.bcnt);
332 	}
333 
334 	if (!(format & FMT_NONEWLINE))
335 		fputc('\n', stdout);
336 }
337 
nft_bridge_save_rule(const struct iptables_command_state * cs,unsigned int format)338 static void nft_bridge_save_rule(const struct iptables_command_state *cs,
339 				 unsigned int format)
340 {
341 	printf(" ");
342 	__nft_bridge_save_rule(cs, format);
343 }
344 
nft_bridge_print_rule(struct nft_handle * h,struct nftnl_rule * r,unsigned int num,unsigned int format)345 static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r,
346 				  unsigned int num, unsigned int format)
347 {
348 	struct iptables_command_state cs = {};
349 
350 	if (format & FMT_LINENUMBERS)
351 		printf("%d. ", num);
352 
353 	nft_bridge_init_cs(&cs);
354 	nft_rule_to_iptables_command_state(h, r, &cs);
355 	__nft_bridge_save_rule(&cs, format);
356 	ebt_cs_clean(&cs);
357 }
358 
nft_bridge_save_chain(const struct nftnl_chain * c,const char * policy)359 static void nft_bridge_save_chain(const struct nftnl_chain *c,
360 				  const char *policy)
361 {
362 	const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
363 
364 	printf(":%s %s\n", chain, policy ?: "ACCEPT");
365 }
366 
nft_bridge_is_same(const struct iptables_command_state * cs_a,const struct iptables_command_state * cs_b)367 static bool nft_bridge_is_same(const struct iptables_command_state *cs_a,
368 			       const struct iptables_command_state *cs_b)
369 {
370 	const struct ebt_entry *a = &cs_a->eb;
371 	const struct ebt_entry *b = &cs_b->eb;
372 	int i;
373 
374 	if (a->ethproto != b->ethproto ||
375 	    a->bitmask != b->bitmask ||
376 	    a->invflags != b->invflags) {
377 		DEBUGP("different proto/bitmask/invflags\n");
378 		return false;
379 	}
380 
381 	for (i = 0; i < ETH_ALEN; i++) {
382 		if (a->sourcemac[i] != b->sourcemac[i]) {
383 			DEBUGP("different source mac %x, %x (%d)\n",
384 			a->sourcemac[i] & 0xff, b->sourcemac[i] & 0xff, i);
385 			return false;
386 		}
387 
388 		if (a->destmac[i] != b->destmac[i]) {
389 			DEBUGP("different destination mac %x, %x (%d)\n",
390 			a->destmac[i] & 0xff, b->destmac[i] & 0xff, i);
391 			return false;
392 		}
393 	}
394 
395 	for (i = 0; i < IFNAMSIZ; i++) {
396 		if (a->logical_in[i] != b->logical_in[i]) {
397 			DEBUGP("different logical iniface %x, %x (%d)\n",
398 			a->logical_in[i] & 0xff, b->logical_in[i] & 0xff, i);
399 			return false;
400 		}
401 
402 		if (a->logical_out[i] != b->logical_out[i]) {
403 			DEBUGP("different logical outiface %x, %x (%d)\n",
404 			a->logical_out[i] & 0xff, b->logical_out[i] & 0xff, i);
405 			return false;
406 		}
407 	}
408 
409 	return strcmp(a->in, b->in) == 0 && strcmp(a->out, b->out) == 0;
410 }
411 
xlate_ebmatches(const struct iptables_command_state * cs,struct xt_xlate * xl)412 static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xlate *xl)
413 {
414 	int ret = 1, numeric = cs->options & OPT_NUMERIC;
415 	struct ebt_match *m;
416 
417 	for (m = cs->match_list; m; m = m->next) {
418 		if (m->ismatch) {
419 			struct xtables_match *matchp = m->u.match;
420 			struct xt_xlate_mt_params mt_params = {
421 				.ip		= (const void *)&cs->eb,
422 				.numeric	= numeric,
423 				.match		= matchp->m,
424 			};
425 
426 			if (!matchp->xlate)
427 				return 0;
428 
429 			ret = matchp->xlate(xl, &mt_params);
430 		} else {
431 			struct xtables_target *watcherp = m->u.watcher;
432 			struct xt_xlate_tg_params wt_params = {
433 				.ip		= (const void *)&cs->eb,
434 				.numeric	= numeric,
435 				.target		= watcherp->t,
436 			};
437 
438 			if (!watcherp->xlate)
439 				return 0;
440 
441 			ret = watcherp->xlate(xl, &wt_params);
442 		}
443 
444 		if (!ret)
445 			break;
446 	}
447 
448 	return ret;
449 }
450 
xlate_ebaction(const struct iptables_command_state * cs,struct xt_xlate * xl)451 static int xlate_ebaction(const struct iptables_command_state *cs, struct xt_xlate *xl)
452 {
453 	int ret = 1, numeric = cs->options & OPT_NUMERIC;
454 
455 	/* If no target at all, add nothing (default to continue) */
456 	if (cs->target != NULL) {
457 		/* Standard target? */
458 		if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
459 			xt_xlate_add(xl, " accept");
460 		else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
461 			xt_xlate_add(xl, " drop");
462 		else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
463 			xt_xlate_add(xl, " return");
464 		else if (cs->target->xlate) {
465 			struct xt_xlate_tg_params params = {
466 				.ip		= (const void *)&cs->eb,
467 				.target		= cs->target->t,
468 				.numeric	= numeric,
469 			};
470 			ret = cs->target->xlate(xl, &params);
471 		}
472 		else
473 			return 0;
474 	} else if (cs->jumpto == NULL) {
475 	} else if (strlen(cs->jumpto) > 0)
476 		xt_xlate_add(xl, " jump %s", cs->jumpto);
477 
478 	return ret;
479 }
480 
xlate_mac(struct xt_xlate * xl,const unsigned char * mac)481 static void xlate_mac(struct xt_xlate *xl, const unsigned char *mac)
482 {
483 	int i;
484 
485 	xt_xlate_add(xl, "%02x", mac[0]);
486 
487 	for (i=1; i < ETH_ALEN; i++)
488 		xt_xlate_add(xl, ":%02x", mac[i]);
489 }
490 
nft_bridge_xlate_mac(struct xt_xlate * xl,const char * type,bool invert,const unsigned char * mac,const unsigned char * mask)491 static void nft_bridge_xlate_mac(struct xt_xlate *xl, const char *type, bool invert,
492 				 const unsigned char *mac, const unsigned char *mask)
493 {
494 	char one_msk[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
495 
496 	xt_xlate_add(xl, "ether %s %s", type, invert ? "!= " : "");
497 
498 	if (memcmp(mask, one_msk, ETH_ALEN)) {
499 		int i;
500 		xt_xlate_add(xl, "and");
501 
502 		xlate_mac(xl, mask);
503 
504 		xt_xlate_add(xl, " == %02x", mac[0] & mask[0]);
505 		for (i=1; i < ETH_ALEN; i++)
506 			xt_xlate_add(xl, ":%02x", mac[i] & mask[i]);
507 	} else {
508 		xlate_mac(xl, mac);
509 	}
510 }
511 
nft_bridge_xlate(const struct iptables_command_state * cs,struct xt_xlate * xl)512 static int nft_bridge_xlate(const struct iptables_command_state *cs,
513 			    struct xt_xlate *xl)
514 {
515 	int ret;
516 
517 	xlate_ifname(xl, "iifname", cs->eb.in,
518 		     cs->eb.invflags & EBT_IIN);
519 	xlate_ifname(xl, "meta ibrname", cs->eb.logical_in,
520 		     cs->eb.invflags & EBT_ILOGICALIN);
521 	xlate_ifname(xl, "oifname", cs->eb.out,
522 		     cs->eb.invflags & EBT_IOUT);
523 	xlate_ifname(xl, "meta obrname", cs->eb.logical_out,
524 		     cs->eb.invflags & EBT_ILOGICALOUT);
525 
526 	if (cs->eb.bitmask & EBT_802_3) {
527 		xt_xlate_add(xl, "ether type %s 0x0600 ",
528 			     cs->eb.invflags & EBT_IPROTO ? ">=" : "<");
529 	} else if ((cs->eb.bitmask & EBT_NOPROTO) == 0) {
530 		const char *implicit = NULL;
531 
532 		switch (ntohs(cs->eb.ethproto)) {
533 		case ETH_P_IP:
534 			implicit = "ip";
535 			break;
536 		case ETH_P_IPV6:
537 			implicit = "ip6";
538 			break;
539 		case ETH_P_8021Q:
540 			implicit = "vlan";
541 			break;
542 		default:
543 			break;
544 		}
545 
546 		if (!implicit || !xlate_find_match(cs, implicit))
547 			xt_xlate_add(xl, "ether type %s0x%x ",
548 				     cs->eb.invflags & EBT_IPROTO ? "!= " : "",
549 				     ntohs(cs->eb.ethproto));
550 	}
551 
552 	if (cs->eb.bitmask & EBT_ISOURCE)
553 		nft_bridge_xlate_mac(xl, "saddr", cs->eb.invflags & EBT_ISOURCE,
554 				     cs->eb.sourcemac, cs->eb.sourcemsk);
555 	if (cs->eb.bitmask & EBT_IDEST)
556 		nft_bridge_xlate_mac(xl, "daddr", cs->eb.invflags & EBT_IDEST,
557 				     cs->eb.destmac, cs->eb.destmsk);
558 	ret = xlate_ebmatches(cs, xl);
559 	if (ret == 0)
560 		return ret;
561 
562 	/* Always add counters per rule, as in ebtables */
563 	xt_xlate_add(xl, "counter");
564 	ret = xlate_ebaction(cs, xl);
565 
566 	return ret;
567 }
568 
nft_bridge_option_name(int option)569 static const char *nft_bridge_option_name(int option)
570 {
571 	switch (option) {
572 	/* ebtables specific ones */
573 	case OPT_LOGICALIN:	return "--logical-in";
574 	case OPT_LOGICALOUT:	return "--logical-out";
575 	case OPT_LINENUMBERS:	return "--Ln";
576 	case OPT_LIST_C:	return "--Lc";
577 	case OPT_LIST_X:	return "--Lx";
578 	case OPT_LIST_MAC2:	return "--Lmac2";
579 	default:		return ip46t_option_name(option);
580 	}
581 }
582 
nft_bridge_option_invert(int option)583 static int nft_bridge_option_invert(int option)
584 {
585 	switch (option) {
586 	case OPT_SOURCE:	return EBT_ISOURCE;
587 	case OPT_DESTINATION:	return EBT_IDEST;
588 	case OPT_PROTOCOL:	return EBT_IPROTO;
589 	case OPT_VIANAMEIN:	return EBT_IIN;
590 	case OPT_VIANAMEOUT:	return EBT_IOUT;
591 	case OPT_LOGICALIN:	return EBT_ILOGICALIN;
592 	case OPT_LOGICALOUT:	return EBT_ILOGICALOUT;
593 	default:		return -1;
594 	}
595 }
596 
nft_bridge_proto_parse(struct iptables_command_state * cs,struct xtables_args * args)597 static void nft_bridge_proto_parse(struct iptables_command_state *cs,
598 				   struct xtables_args *args)
599 {
600 	char *buffer;
601 	int i;
602 
603 	cs->eb.bitmask &= ~((unsigned int)EBT_NOPROTO);
604 
605 	i = strtol(cs->protocol, &buffer, 16);
606 	if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
607 		xtables_error(PARAMETER_PROBLEM,
608 			      "Problem with the specified protocol");
609 	if (*buffer != '\0') {
610 		struct xt_ethertypeent *ent;
611 
612 		if (!strcmp(cs->protocol, "length")) {
613 			cs->eb.bitmask |= EBT_802_3;
614 			return;
615 		}
616 		ent = xtables_getethertypebyname(cs->protocol);
617 		if (!ent)
618 			xtables_error(PARAMETER_PROBLEM,
619 				      "Problem with the specified Ethernet protocol '%s', perhaps "XT_PATH_ETHERTYPES " is missing",
620 				      cs->protocol);
621 		cs->eb.ethproto = ent->e_ethertype;
622 	} else
623 		cs->eb.ethproto = i;
624 
625 	if (cs->eb.ethproto < 0x0600)
626 		xtables_error(PARAMETER_PROBLEM,
627 			      "Sorry, protocols have values above or equal to 0x0600");
628 }
629 
nft_bridge_post_parse(int command,struct iptables_command_state * cs,struct xtables_args * args)630 static void nft_bridge_post_parse(int command,
631 				  struct iptables_command_state *cs,
632 				  struct xtables_args *args)
633 {
634 	struct ebt_match *match;
635 
636 	cs->eb.invflags = args->invflags;
637 
638 	memcpy(cs->eb.in, args->iniface, IFNAMSIZ);
639 	memcpy(cs->eb.out, args->outiface, IFNAMSIZ);
640 	memcpy(cs->eb.logical_in, args->bri_iniface, IFNAMSIZ);
641 	memcpy(cs->eb.logical_out, args->bri_outiface, IFNAMSIZ);
642 
643 	cs->counters.pcnt = args->pcnt_cnt;
644 	cs->counters.bcnt = args->bcnt_cnt;
645 
646 	if (args->shostnetworkmask) {
647 		if (xtables_parse_mac_and_mask(args->shostnetworkmask,
648 					       cs->eb.sourcemac,
649 					       cs->eb.sourcemsk))
650 			xtables_error(PARAMETER_PROBLEM,
651 				      "Problem with specified source mac '%s'",
652 				      args->shostnetworkmask);
653 		cs->eb.bitmask |= EBT_SOURCEMAC;
654 	}
655 	if (args->dhostnetworkmask) {
656 		if (xtables_parse_mac_and_mask(args->dhostnetworkmask,
657 					       cs->eb.destmac,
658 					       cs->eb.destmsk))
659 			xtables_error(PARAMETER_PROBLEM,
660 				      "Problem with specified destination mac '%s'",
661 				      args->dhostnetworkmask);
662 		cs->eb.bitmask |= EBT_DESTMAC;
663 	}
664 
665 	if ((cs->options & (OPT_LIST_X | OPT_LINENUMBERS)) ==
666 			(OPT_LIST_X | OPT_LINENUMBERS))
667 		xtables_error(PARAMETER_PROBLEM,
668 			      "--Lx is not compatible with --Ln");
669 
670 	/* So, the extensions can work with the host endian.
671 	 * The kernel does not have to do this of course */
672 	cs->eb.ethproto = htons(cs->eb.ethproto);
673 
674 	for (match = cs->match_list; match; match = match->next) {
675 		if (match->ismatch)
676 			continue;
677 
678 		xtables_option_tfcall(match->u.watcher);
679 	}
680 }
681 
682 struct nft_family_ops nft_family_ops_bridge = {
683 	.add			= nft_bridge_add,
684 	.is_same		= nft_bridge_is_same,
685 	.print_payload		= NULL,
686 	.rule_parse		= &nft_ruleparse_ops_bridge,
687 	.cmd_parse		= {
688 		.proto_parse	= nft_bridge_proto_parse,
689 		.post_parse	= nft_bridge_post_parse,
690 		.option_name	= nft_bridge_option_name,
691 		.option_invert	= nft_bridge_option_invert,
692 		.command_default = ebt_command_default,
693 		.print_help	= nft_bridge_print_help,
694 	},
695 	.print_table_header	= nft_bridge_print_table_header,
696 	.print_header		= nft_bridge_print_header,
697 	.print_rule		= nft_bridge_print_rule,
698 	.save_rule		= nft_bridge_save_rule,
699 	.save_chain		= nft_bridge_save_chain,
700 	.rule_to_cs		= nft_rule_to_iptables_command_state,
701 	.init_cs		= nft_bridge_init_cs,
702 	.clear_cs		= ebt_cs_clean,
703 	.xlate			= nft_bridge_xlate,
704 };
705