From 902e92ceedba96d3241fa8ff701c061cd53a197d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 9 Oct 2014 20:11:16 +0200 Subject: ebtables-compat: use ebtables_command_state in bootstrap code And introduce fake ebt_entry. This gets the code in sync in other existing compat tools. This will likely allow to consolidate common infrastructure. This code is still quite experimental. Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter_bridge/ebtables.h | 276 ------------------------------ iptables/nft-bridge.c | 177 ++++++++++--------- iptables/nft-bridge.h | 98 +++++++++++ iptables/nft-shared.c | 4 +- iptables/nft-shared.h | 3 +- iptables/nft.h | 9 - iptables/xtables-eb-standalone.c | 3 + iptables/xtables-eb.c | 100 +++++------ iptables/xtables-ebtables.h | 49 ------ 9 files changed, 252 insertions(+), 467 deletions(-) delete mode 100644 include/linux/netfilter_bridge/ebtables.h create mode 100644 iptables/nft-bridge.h delete mode 100644 iptables/xtables-ebtables.h diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h deleted file mode 100644 index f7ed1dcf..00000000 --- a/include/linux/netfilter_bridge/ebtables.h +++ /dev/null @@ -1,276 +0,0 @@ -/* - * ebtables - * - * Authors: - * Bart De Schuymer - * - * ebtables.c,v 2.0, April, 2002 - * - * This code is stongly inspired on the iptables code which is - * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling - */ - -/* Local copy of the kernel file, needed for Sparc64 support */ -#ifndef __LINUX_BRIDGE_EFF_H -#define __LINUX_BRIDGE_EFF_H -#include -#include -#include - -#define EBT_TABLE_MAXNAMELEN 32 -#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN -#define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN - -/* verdicts >0 are "branches" */ -#define EBT_ACCEPT -1 -#define EBT_DROP -2 -#define EBT_CONTINUE -3 -#define EBT_RETURN -4 -#define NUM_STANDARD_TARGETS 4 -/* ebtables target modules store the verdict inside an int. We can - * reclaim a part of this int for backwards compatible extensions. - * The 4 lsb are more than enough to store the verdict. */ -#define EBT_VERDICT_BITS 0x0000000F - -struct ebt_counter -{ - uint64_t pcnt; - uint64_t bcnt; -}; - -struct ebt_replace -{ - char name[EBT_TABLE_MAXNAMELEN]; - unsigned int valid_hooks; - /* nr of rules in the table */ - unsigned int nentries; - /* total size of the entries */ - unsigned int entries_size; - /* start of the chains */ -#ifdef KERNEL_64_USERSPACE_32 - uint64_t hook_entry[NF_BR_NUMHOOKS]; -#else - struct ebt_entries *hook_entry[NF_BR_NUMHOOKS]; -#endif - /* nr of counters userspace expects back */ - unsigned int num_counters; - /* where the kernel will put the old counters */ -#ifdef KERNEL_64_USERSPACE_32 - uint64_t counters; - uint64_t entries; -#else - struct ebt_counter *counters; - char *entries; -#endif -}; - -struct ebt_entries { - /* this field is always set to zero - * See EBT_ENTRY_OR_ENTRIES. - * Must be same size as ebt_entry.bitmask */ - unsigned int distinguisher; - /* the chain name */ - char name[EBT_CHAIN_MAXNAMELEN]; - /* counter offset for this chain */ - unsigned int counter_offset; - /* one standard (accept, drop, return) per hook */ - int policy; - /* nr. of entries */ - unsigned int nentries; - /* entry list */ - char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); -}; - -/* used for the bitmask of struct ebt_entry */ - -/* This is a hack to make a difference between an ebt_entry struct and an - * ebt_entries struct when traversing the entries from start to end. - * Using this simplifies the code alot, while still being able to use - * ebt_entries. - * Contrary, iptables doesn't use something like ebt_entries and therefore uses - * different techniques for naming the policy and such. So, iptables doesn't - * need a hack like this. - */ -#define EBT_ENTRY_OR_ENTRIES 0x01 -/* these are the normal masks */ -#define EBT_NOPROTO 0x02 -#define EBT_802_3 0x04 -#define EBT_SOURCEMAC 0x08 -#define EBT_DESTMAC 0x10 -#define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \ - | EBT_ENTRY_OR_ENTRIES) - -#define EBT_IPROTO 0x01 -#define EBT_IIN 0x02 -#define EBT_IOUT 0x04 -#define EBT_ISOURCE 0x8 -#define EBT_IDEST 0x10 -#define EBT_ILOGICALIN 0x20 -#define EBT_ILOGICALOUT 0x40 -#define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \ - | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST) - -struct ebt_entry_match -{ - union { - char name[EBT_FUNCTION_MAXNAMELEN]; - struct ebt_match *match; - } u; - /* size of data */ - unsigned int match_size; -#ifdef KERNEL_64_USERSPACE_32 - unsigned int pad; -#endif - unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); -}; - -struct ebt_entry_watcher -{ - union { - char name[EBT_FUNCTION_MAXNAMELEN]; - struct ebt_watcher *watcher; - } u; - /* size of data */ - unsigned int watcher_size; -#ifdef KERNEL_64_USERSPACE_32 - unsigned int pad; -#endif - unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); -}; - -struct ebt_entry_target -{ - union { - char name[EBT_FUNCTION_MAXNAMELEN]; - struct ebt_target *target; - } u; - /* size of data */ - unsigned int target_size; -#ifdef KERNEL_64_USERSPACE_32 - unsigned int pad; -#endif - unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); -}; - -#define EBT_STANDARD_TARGET "standard" -struct ebt_standard_target -{ - struct ebt_entry_target target; - int verdict; -#ifdef KERNEL_64_USERSPACE_32 - unsigned int pad; -#endif -}; - -/* one entry */ -struct ebt_entry { - /* this needs to be the first field */ - unsigned int bitmask; - unsigned int invflags; - uint16_t ethproto; - /* the physical in-dev */ - char in[IFNAMSIZ]; - /* the logical in-dev */ - char logical_in[IFNAMSIZ]; - /* the physical out-dev */ - char out[IFNAMSIZ]; - /* the logical out-dev */ - char logical_out[IFNAMSIZ]; - unsigned char sourcemac[ETH_ALEN]; - unsigned char sourcemsk[ETH_ALEN]; - unsigned char destmac[ETH_ALEN]; - unsigned char destmsk[ETH_ALEN]; - /* sizeof ebt_entry + matches */ - unsigned int watchers_offset; - /* sizeof ebt_entry + matches + watchers */ - unsigned int target_offset; - /* sizeof ebt_entry + matches + watchers + target */ - unsigned int next_offset; - unsigned char elems[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); -}; - -/* {g,s}etsockopt numbers */ -#define EBT_BASE_CTL 128 - -#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL) -#define EBT_SO_SET_COUNTERS (EBT_SO_SET_ENTRIES+1) -#define EBT_SO_SET_MAX (EBT_SO_SET_COUNTERS+1) - -#define EBT_SO_GET_INFO (EBT_BASE_CTL) -#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO+1) -#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES+1) -#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO+1) -#define EBT_SO_GET_MAX (EBT_SO_GET_INIT_ENTRIES+1) - -/* blatently stolen from ip_tables.h - * fn returns 0 to continue iteration */ -#define EBT_MATCH_ITERATE(e, fn, args...) \ -({ \ - unsigned int __i; \ - int __ret = 0; \ - struct ebt_entry_match *__match; \ - \ - for (__i = sizeof(struct ebt_entry); \ - __i < (e)->watchers_offset; \ - __i += __match->match_size + \ - sizeof(struct ebt_entry_match)) { \ - __match = (void *)(e) + __i; \ - \ - __ret = fn(__match , ## args); \ - if (__ret != 0) \ - break; \ - } \ - if (__ret == 0) { \ - if (__i != (e)->watchers_offset) \ - __ret = -EINVAL; \ - } \ - __ret; \ -}) - -#define EBT_WATCHER_ITERATE(e, fn, args...) \ -({ \ - unsigned int __i; \ - int __ret = 0; \ - struct ebt_entry_watcher *__watcher; \ - \ - for (__i = e->watchers_offset; \ - __i < (e)->target_offset; \ - __i += __watcher->watcher_size + \ - sizeof(struct ebt_entry_watcher)) { \ - __watcher = (void *)(e) + __i; \ - \ - __ret = fn(__watcher , ## args); \ - if (__ret != 0) \ - break; \ - } \ - if (__ret == 0) { \ - if (__i != (e)->target_offset) \ - __ret = -EINVAL; \ - } \ - __ret; \ -}) - -#define EBT_ENTRY_ITERATE(entries, size, fn, args...) \ -({ \ - unsigned int __i; \ - int __ret = 0; \ - struct ebt_entry *__entry; \ - \ - for (__i = 0; __i < (size);) { \ - __entry = (void *)(entries) + __i; \ - __ret = fn(__entry , ## args); \ - if (__ret != 0) \ - break; \ - if (__entry->bitmask != 0) \ - __i += __entry->next_offset; \ - else \ - __i += sizeof(struct ebt_entries); \ - } \ - if (__ret == 0) { \ - if (__i != (size)) \ - __ret = -EINVAL; \ - } \ - __ret; \ -}) - -#endif diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 66361ee9..ab97881d 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -18,11 +18,13 @@ #include #include "nft-shared.h" +#include "nft-bridge.h" #include "nft.h" /* 0: default, print only 2 digits if necessary * 2: always print 2 digits, a printed mac address - * then always has the same length */ + * then always has the same length + */ int ebt_printstyle_mac; static void ebt_print_mac(const unsigned char *mac) @@ -132,31 +134,36 @@ static void add_logical_outiface(struct nft_rule *r, char *iface, int invflags) add_cmp_ptr(r, op, iface, iface_len + 1); } -static int _add_action(struct nft_rule *r, struct xtables_ebt_entry *fw) +/* TODO: Use generic add_action() once we convert this to use + * iptables_command_state. + */ +static int _add_action(struct nft_rule *r, struct ebtables_command_state *cs) { int ret = 0; - /* If no target at all, add nothing (default to continue) */ - if (fw->target != NULL) { - /* Standard target? */ - if (strcmp(fw->jumpto, XTC_LABEL_ACCEPT) == 0) - ret = add_verdict(r, NF_ACCEPT); - else if (strcmp(fw->jumpto, XTC_LABEL_DROP) == 0) - ret = add_verdict(r, NF_DROP); - else if (strcmp(fw->jumpto, XTC_LABEL_RETURN) == 0) - ret = add_verdict(r, NFT_RETURN); - else - ret = add_target(r, fw->target->t); - } else if (strlen(fw->jumpto) > 0) + /* If no target at all, add nothing (default to continue) */ + if (cs->target != NULL) { + /* Standard target? */ + if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0) + ret = add_verdict(r, NF_ACCEPT); + else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0) + ret = add_verdict(r, NF_DROP); + else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) + ret = add_verdict(r, NFT_RETURN); + else + ret = add_target(r, cs->target->t); + } else if (strlen(cs->jumpto) > 0) { /* Not standard, then it's a jump to chain */ - ret = add_jumpto(r, fw->jumpto, NFT_JUMP); + ret = add_jumpto(r, cs->jumpto, NFT_JUMP); + } - return ret; + return ret; } static int nft_bridge_add(struct nft_rule *r, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; + struct ebt_entry *fw = &cs->fw; uint8_t flags = ebt_to_ipt_flags(fw->invflags); char *addr; @@ -189,13 +196,14 @@ static int nft_bridge_add(struct nft_rule *r, void *data) add_cmp_u16(r, fw->ethproto, NFT_CMP_EQ); } - return _add_action(r, fw); + return _add_action(r, cs); } static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; + struct ebt_entry *fw = &cs->fw; uint8_t flags = 0; int iface = 0; const void *ifname; @@ -214,7 +222,7 @@ static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, memcpy(fw->logical_in, ifname, len); - if (fw->logical_in[len] == '\0') + if (fw->logical_in[len] == '\0') memset(fw->in_mask, 0xff, len); else { fw->logical_in[len] = '+'; @@ -248,7 +256,8 @@ out: static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; + struct ebt_entry *fw = &cs->fw; unsigned char addr[ETH_ALEN]; unsigned short int ethproto; bool inv; @@ -271,28 +280,30 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, break; } } + static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; - fw->jumpto = jumpto; + cs->jumpto = jumpto; } static void nft_bridge_parse_target(struct xtables_target *t, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; - fw->target = t; + cs->target = t; } -void nft_rule_to_xtables_ebt_entry(struct nft_rule *r, struct xtables_ebt_entry *fw) +void nft_rule_to_ebtables_command_state(struct nft_rule *r, + struct ebtables_command_state *cs) { struct nft_rule_expr_iter *iter; struct nft_rule_expr *expr; int family = nft_rule_attr_get_u32(r, NFT_RULE_ATTR_FAMILY); struct nft_xt_ctx ctx = { - .state.ebfw = fw, + .state.cs_eb = cs, .family = family, }; @@ -306,15 +317,19 @@ void nft_rule_to_xtables_ebt_entry(struct nft_rule *r, struct xtables_ebt_entry nft_rule_expr_get_str(expr, NFT_RULE_EXPR_ATTR_NAME); if (strcmp(name, "counter") == 0) - nft_parse_counter(expr, &fw->counters); + nft_parse_counter(expr, &cs->counters); else if (strcmp(name, "payload") == 0) nft_parse_payload(&ctx, expr); else if (strcmp(name, "meta") == 0) nft_parse_meta(&ctx, expr); + else if (strcmp(name, "bitwise") == 0) + nft_parse_bitwise(&ctx, expr); else if (strcmp(name, "cmp") == 0) nft_parse_cmp(&ctx, expr); else if (strcmp(name, "immediate") == 0) nft_parse_immediate(&ctx, expr); + else if (strcmp(name, "match") == 0) + nft_parse_match(&ctx, expr); else if (strcmp(name, "target") == 0) nft_parse_target(&ctx, expr); @@ -323,12 +338,12 @@ void nft_rule_to_xtables_ebt_entry(struct nft_rule *r, struct xtables_ebt_entry nft_rule_expr_iter_destroy(iter); - if (fw->target != NULL) - fw->jumpto = fw->target->name; - else if (fw->jumpto != NULL) - fw->target = xtables_find_target(fw->jumpto, XTF_TRY_LOAD); + if (cs->target != NULL) + cs->jumpto = cs->target->name; + else if (cs->jumpto != NULL) + cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); else - fw->jumpto = ""; + cs->jumpto = ""; } static void print_iface(const char *iface) @@ -351,81 +366,80 @@ static void nft_bridge_print_header(unsigned int format, const char *chain, print_header(format, chain, pol, counters, basechain, refs); } -static void -nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, - unsigned int format) +static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, + unsigned int format) { - struct xtables_ebt_entry fw = {}; + struct ebtables_command_state cs = {}; char *addr; - nft_rule_to_xtables_ebt_entry(r, &fw); + nft_rule_to_ebtables_command_state(r, &cs); if (format & FMT_LINENUMBERS) printf("%d ", num); /* Dont print anything about the protocol if no protocol was * specified, obviously this means any protocol will do. */ - if (fw.ethproto != 0) { + if (cs.fw.ethproto != 0) { printf("-p "); - if (fw.invflags & EBT_IPROTO) + if (cs.fw.invflags & EBT_IPROTO) printf("! "); - if (fw.bitmask & EBT_802_3) + if (cs.fw.bitmask & EBT_802_3) printf("Length "); else { struct ethertypeent *ent; - ent = getethertypebynumber(ntohs(fw.ethproto)); + ent = getethertypebynumber(ntohs(cs.fw.ethproto)); if (!ent) - printf("0x%x ", ntohs(fw.ethproto)); + printf("0x%x ", ntohs(cs.fw.ethproto)); else printf("%s ", ent->e_name); } } - addr = ether_ntoa((struct ether_addr *) fw.sourcemac); + addr = ether_ntoa((struct ether_addr *) cs.fw.sourcemac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { printf("-s "); - if (fw.invflags & EBT_ISOURCE) + if (cs.fw.invflags & EBT_ISOURCE) printf("! "); - ebt_print_mac_and_mask(fw.sourcemac, fw.sourcemsk); + ebt_print_mac_and_mask(cs.fw.sourcemac, cs.fw.sourcemsk); printf(" "); } - addr = ether_ntoa((struct ether_addr *) fw.destmac); + addr = ether_ntoa((struct ether_addr *) cs.fw.destmac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { printf("-d "); - if (fw.invflags & EBT_IDEST) + if (cs.fw.invflags & EBT_IDEST) printf("! "); - ebt_print_mac_and_mask(fw.destmac, fw.destmsk); + ebt_print_mac_and_mask(cs.fw.destmac, cs.fw.destmsk); printf(" "); } - if (fw.in[0] != '\0') { + if (cs.fw.in[0] != '\0') { printf("-i "); - if (fw.invflags & EBT_IIN) + if (cs.fw.invflags & EBT_IIN) printf("! "); - print_iface(fw.in); + print_iface(cs.fw.in); } - if (fw.logical_in[0] != '\0') { + if (cs.fw.logical_in[0] != '\0') { printf("--logical-in "); - if (fw.invflags & EBT_ILOGICALIN) + if (cs.fw.invflags & EBT_ILOGICALIN) printf("! "); - print_iface(fw.logical_in); + print_iface(cs.fw.logical_in); } - if (fw.logical_out[0] != '\0') { + if (cs.fw.logical_out[0] != '\0') { printf("--logical-out "); - if (fw.invflags & EBT_ILOGICALOUT) + if (cs.fw.invflags & EBT_ILOGICALOUT) printf("! "); - print_iface(fw.logical_out); + print_iface(cs.fw.logical_out); } - if (fw.out[0] != '\0') { + if (cs.fw.out[0] != '\0') { printf("-o "); - if (fw.invflags & EBT_IOUT) + if (cs.fw.invflags & EBT_IOUT) printf("! "); - print_iface(fw.out); + print_iface(cs.fw.out); } /* old code to adapt @@ -447,12 +461,12 @@ nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, }*/ printf("-j "); if (!(format & FMT_NOTARGET)) - printf("%s", fw.jumpto); + printf("%s", cs.jumpto); - if (fw.target != NULL) { - if (fw.target->print != NULL) { - fw.target->print(&fw, fw.target->t, - format & FMT_NUMERIC); + if (cs.target != NULL) { + if (cs.target->print != NULL) { + cs.target->print(&cs.fw, cs.target->t, + format & FMT_NUMERIC); } } @@ -460,16 +474,15 @@ nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, fputc('\n', stdout); } -static bool nft_bridge_is_same(const void *data_a, - const void *data_b) +static bool nft_bridge_is_same(const void *data_a, const void *data_b) { - const struct xtables_ebt_entry *a = data_a; - const struct xtables_ebt_entry *b = data_b; + const struct ebt_entry *a = data_a; + const struct ebt_entry *b = data_b; int i; - if (a->ethproto != b->ethproto - /*|| a->flags != b->flags*/ - || a->invflags != b->invflags) { + if (a->ethproto != b->ethproto || + /* FIXME: a->flags != b->flags || */ + a->invflags != b->invflags) { DEBUGP("different proto/flags/invflags\n"); return false; } @@ -515,27 +528,27 @@ static bool nft_bridge_is_same(const void *data_a, static bool nft_bridge_rule_find(struct nft_family_ops *ops, struct nft_rule *r, void *data) { - struct xtables_ebt_entry *fw = data; - struct xtables_ebt_entry this = {}; + struct ebtables_command_state *cs = data; + struct ebtables_command_state this = {}; - nft_rule_to_xtables_ebt_entry(r, &this); + nft_rule_to_ebtables_command_state(r, &this); DEBUGP("comparing with... "); - if (!ops->is_same(fw, &this)) + if (!nft_bridge_is_same(cs, &this)) return false; - if (!compare_matches(fw->matches, this.matches)) { + if (!compare_matches(cs->matches, this.matches)) { DEBUGP("Different matches\n"); return false; } - if (!compare_targets(fw->target, this.target)) { + if (!compare_targets(cs->target, this.target)) { DEBUGP("Different target\n"); return false; } - if (strcmp(fw->jumpto, this.jumpto) != 0) { + if (strcmp(cs->jumpto, this.jumpto) != 0) { DEBUGP("Different verdict\n"); return false; } @@ -550,9 +563,11 @@ struct nft_family_ops nft_family_ops_bridge = { .parse_meta = nft_bridge_parse_meta, .parse_payload = nft_bridge_parse_payload, .parse_immediate = nft_bridge_parse_immediate, + .parse_target = nft_bridge_parse_target, .print_header = nft_bridge_print_header, .print_firewall = nft_bridge_print_firewall, + .save_firewall = NULL, + .save_counters = NULL, .post_parse = NULL, .rule_find = nft_bridge_rule_find, - .parse_target = nft_bridge_parse_target, }; diff --git a/iptables/nft-bridge.h b/iptables/nft-bridge.h new file mode 100644 index 00000000..1e3f0a16 --- /dev/null +++ b/iptables/nft-bridge.h @@ -0,0 +1,98 @@ +#ifndef _NFT_BRIDGE_H_ +#define _NFT_BRIDGE_H_ + +#include +//#include +#include + +/* We use replace->flags, so we can't use the following values: + * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO */ +#define LIST_N 0x04 +#define LIST_C 0x08 +#define LIST_X 0x10 +#define LIST_MAC2 0x20 + +/* Be backwards compatible, so don't use '+' in kernel */ +#define IF_WILDCARD 1 + +extern unsigned char eb_mac_type_unicast[ETH_ALEN]; +extern unsigned char eb_msk_type_unicast[ETH_ALEN]; +extern unsigned char eb_mac_type_multicast[ETH_ALEN]; +extern unsigned char eb_msk_type_multicast[ETH_ALEN]; +extern unsigned char eb_mac_type_broadcast[ETH_ALEN]; +extern unsigned char eb_msk_type_broadcast[ETH_ALEN]; +extern unsigned char eb_mac_type_bridge_group[ETH_ALEN]; +extern unsigned char eb_msk_type_bridge_group[ETH_ALEN]; + +int ebt_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask); + +/* From: include/linux/netfilter_bridge/ebtables.h + * + * Adapted for the need of the ebtables-compat. + */ + +#define EBT_TABLE_MAXNAMELEN 32 +#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN +#define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN + +/* verdicts >0 are "branches" */ +#define EBT_ACCEPT -1 +#define EBT_DROP -2 +#define EBT_CONTINUE -3 +#define EBT_RETURN -4 +#define NUM_STANDARD_TARGETS 4 + +#define EBT_ENTRY_OR_ENTRIES 0x01 +/* these are the normal masks */ +#define EBT_NOPROTO 0x02 +#define EBT_802_3 0x04 +#define EBT_SOURCEMAC 0x08 +#define EBT_DESTMAC 0x10 +#define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \ + | EBT_ENTRY_OR_ENTRIES) + +#define EBT_IPROTO 0x01 +#define EBT_IIN 0x02 +#define EBT_IOUT 0x04 +#define EBT_ISOURCE 0x8 +#define EBT_IDEST 0x10 +#define EBT_ILOGICALIN 0x20 +#define EBT_ILOGICALOUT 0x40 +#define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \ + | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST) + +/* Fake ebt_entry */ +struct ebt_entry { + /* this needs to be the first field */ + unsigned int bitmask; + unsigned int invflags; + uint16_t ethproto; + /* the physical in-dev */ + char in[IFNAMSIZ]; + /* the logical in-dev */ + char logical_in[IFNAMSIZ]; + /* the physical out-dev */ + char out[IFNAMSIZ]; + /* the logical out-dev */ + char logical_out[IFNAMSIZ]; + unsigned char sourcemac[ETH_ALEN]; + unsigned char sourcemsk[ETH_ALEN]; + unsigned char destmac[ETH_ALEN]; + unsigned char destmsk[ETH_ALEN]; + + unsigned char in_mask[IFNAMSIZ]; + unsigned char out_mask[IFNAMSIZ]; +}; + +struct ebtables_command_state { + struct ebt_entry fw; + struct xtables_target *target; + struct xtables_rule_match *matches; + const char *jumpto; + struct xt_counters counters; +}; + +void nft_rule_to_ebtables_command_state(struct nft_rule *r, + struct ebtables_command_state *cs); + +#endif diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 9ca2e35c..71c44763 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -280,7 +280,7 @@ static void *nft_get_data(struct nft_xt_ctx *ctx) case NFPROTO_ARP: return ctx->state.cs_arp; case NFPROTO_BRIDGE: - return ctx->state.ebfw; + return ctx->state.cs_eb; default: /* Should not happen */ return NULL; @@ -320,7 +320,7 @@ void nft_parse_target(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) ops->parse_target(target, data); } -static void nft_parse_match(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) +void nft_parse_match(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) { uint32_t mt_len; const char *mt_name = nft_rule_expr_get_str(e, NFT_EXPR_MT_NAME); diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 97d41df8..361e9566 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -48,7 +48,7 @@ struct nft_xt_ctx { union { struct iptables_command_state *cs; struct arptables_command_state *cs_arp; - struct xtables_ebt_entry *ebfw; + struct ebtables_command_state *cs_eb; } state; struct nft_rule_expr_iter *iter; int family; @@ -130,6 +130,7 @@ void print_proto(uint16_t proto, int invert); void get_cmp_data(struct nft_rule_expr *e, void *data, size_t dlen, bool *inv); void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); +void nft_parse_match(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); void nft_parse_target(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); void nft_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); void nft_parse_payload(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); diff --git a/iptables/nft.h b/iptables/nft.h index 4f0b733c..ab3d64ac 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -170,13 +170,4 @@ int nft_arp_rule_insert(struct nft_handle *h, const char *chain, void nft_rule_to_arpt_entry(struct nft_rule *r, struct arpt_entry *fw); -/* - * BRIDGE - */ - -#include "xtables-ebtables.h" - -struct xtables_ebt_entry; - -void nft_rule_to_xtables_ebt_entry(struct nft_rule *r, struct xtables_ebt_entry *fw); #endif diff --git a/iptables/xtables-eb-standalone.c b/iptables/xtables-eb-standalone.c index 6ec418cb..1c3cbf07 100644 --- a/iptables/xtables-eb-standalone.c +++ b/iptables/xtables-eb-standalone.c @@ -83,5 +83,8 @@ int xtables_eb_main(int argc, char *argv[]) if (ret) ret = nft_commit(&h); + if (!ret) + fprintf(stderr, "%s\n", nft_strerror(errno)); + exit(!ret); } diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 73a38db9..99d930e5 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -31,9 +31,11 @@ #include #include +#include #include #include "xshared.h" #include "nft.h" +#include "nft-bridge.h" extern struct xtables_globals xtables_globals; #define prog_name xtables_globals.program_name @@ -213,16 +215,16 @@ static int append_entry(struct nft_handle *h, const char *chain, const char *table, - struct xtables_ebt_entry *fw, + struct ebtables_command_state *cs, int rule_nr, bool verbose, bool append) { int ret = 1; if (append) - ret = nft_rule_append(h, chain, table, fw, 0, verbose); + ret = nft_rule_append(h, chain, table, cs, 0, verbose); else - ret = nft_rule_insert(h, chain, table, fw, rule_nr, verbose); + ret = nft_rule_insert(h, chain, table, cs, rule_nr, verbose); return ret; } @@ -231,7 +233,7 @@ static int delete_entry(struct nft_handle *h, const char *chain, const char *table, - struct xtables_ebt_entry *fw, + struct ebtables_command_state *cs, int rule_nr, int rule_nr_end, bool verbose) @@ -239,7 +241,7 @@ delete_entry(struct nft_handle *h, int ret = 1; if (rule_nr == -1) - ret = nft_rule_delete(h, chain, table, fw, verbose); + ret = nft_rule_delete(h, chain, table, cs, verbose); else { do { ret = nft_rule_delete_num(h, chain, table, @@ -342,7 +344,7 @@ static struct option *ebt_options = ebt_original_options; /* * More glue code. */ -static struct xtables_target *command_jump(struct xtables_ebt_entry *fw, +static struct xtables_target *command_jump(struct ebtables_command_state *cs, const char *jumpto) { struct xtables_target *target; @@ -490,7 +492,7 @@ static int parse_rule_range(const char *argv, int *rule_nr, int *rule_nr_end) /* Incrementing or decrementing rules in daemon mode is not supported as the * involved code overload is not worth it (too annoying to take the increased * counters in the kernel into account). */ -static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int *rule_nr_end, int exec_style, struct xtables_ebt_entry *fw) +static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int *rule_nr_end, int exec_style, struct ebtables_command_state *cs) { char *buffer; int ret = 0; @@ -515,16 +517,16 @@ daemon_incr: xtables_error(PARAMETER_PROBLEM, "Incrementing rule counters (%s) not allowed in daemon mode", argv[optind]); ret += 1; - fw->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10); + cs->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10); } else if (argv[optind][0] == '-') { if (exec_style == EXEC_STYLE_DAEMON) daemon_decr: xtables_error(PARAMETER_PROBLEM, "Decrementing rule counters (%s) not allowed in daemon mode", argv[optind]); ret += 2; - fw->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10); + cs->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10); } else - fw->counters.pcnt = strtoull(argv[optind], &buffer, 10); + cs->counters.pcnt = strtoull(argv[optind], &buffer, 10); if (*buffer != '\0') goto invalid; @@ -533,14 +535,14 @@ daemon_decr: if (exec_style == EXEC_STYLE_DAEMON) goto daemon_incr; ret += 3; - fw->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10); + cs->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10); } else if (argv[optind][0] == '-') { if (exec_style == EXEC_STYLE_DAEMON) goto daemon_decr; ret += 6; - fw->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10); + cs->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10); } else - fw->counters.bcnt = strtoull(argv[optind], &buffer, 10); + cs->counters.bcnt = strtoull(argv[optind], &buffer, 10); if (*buffer != '\0') goto invalid; @@ -577,7 +579,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) int ret = 0; unsigned int flags = 0; struct xtables_target *t; - struct xtables_ebt_entry fw; + struct ebtables_command_state cs; char command = 'h'; const char *chain = NULL; const char *newname = NULL; @@ -585,7 +587,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) int exec_style = EXEC_STYLE_PRG; int selected_chain = -1; - memset(&fw, 0, sizeof(fw)); + memset(&cs, 0, sizeof(cs)); if (nft_init(h, xtables_bridge) < 0) xtables_error(OTHER_PROBLEM, @@ -651,7 +653,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) "Problem with the specified rule number(s) '%s'", argv[optind]); optind++; } else if (c == 'C') { - if ((chcounter = parse_change_counters_rule(argc, argv, &rule_nr, &rule_nr_end, exec_style, &fw)) == -1) + if ((chcounter = parse_change_counters_rule(argc, argv, &rule_nr, &rule_nr_end, exec_style, &cs)) == -1) return -1; } else if (c == 'I') { if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9'))) @@ -748,7 +750,7 @@ print_zero: struct ebt_u_watcher *w;*/ if (!strcasecmp("list_extensions", argv[optind])) { - ebt_list_extensions(xtables_targets, fw.matches); + ebt_list_extensions(xtables_targets, cs.matches); exit(0); } /*if ((m = ebt_find_match(argv[optind]))) @@ -761,7 +763,7 @@ print_zero: if (flags & OPT_JUMP) xtables_error(PARAMETER_PROBLEM,"Sorry, you can only see help for one target extension at a time"); flags |= OPT_JUMP; - fw.target = t; + cs.target = t; //} optind++; } @@ -798,14 +800,14 @@ print_zero: xtables_error(PARAMETER_PROBLEM, "Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains"); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_IIN; + cs.fw.invflags |= EBT_IIN; if (strlen(optarg) >= IFNAMSIZ) big_iface_length: xtables_error(PARAMETER_PROBLEM, "Interface name length cannot exceed %d characters", IFNAMSIZ - 1); - xtables_parse_interface(optarg, fw.in, fw.in_mask); + xtables_parse_interface(optarg, cs.fw.in, cs.fw.in_mask); break; } else if (c == 2) { ebt_check_option2(&flags, OPT_LOGICALIN); @@ -813,12 +815,12 @@ big_iface_length: xtables_error(PARAMETER_PROBLEM, "Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains"); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_ILOGICALIN; + cs.fw.invflags |= EBT_ILOGICALIN; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; - strcpy(fw.logical_in, optarg); - if (parse_iface(fw.logical_in, "--logical-in")) + strcpy(cs.fw.logical_in, optarg); + if (parse_iface(cs.fw.logical_in, "--logical-in")) return -1; break; } else if (c == 'o') { @@ -827,12 +829,12 @@ big_iface_length: xtables_error(PARAMETER_PROBLEM, "Use -o only in OUTPUT, FORWARD and POSTROUTING chains"); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_IOUT; + cs.fw.invflags |= EBT_IOUT; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; - xtables_parse_interface(optarg, fw.out, fw.out_mask); + xtables_parse_interface(optarg, cs.fw.out, cs.fw.out_mask); break; } else if (c == 3) { ebt_check_option2(&flags, OPT_LOGICALOUT); @@ -840,36 +842,36 @@ big_iface_length: xtables_error(PARAMETER_PROBLEM, "Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains"); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_ILOGICALOUT; + cs.fw.invflags |= EBT_ILOGICALOUT; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; - strcpy(fw.logical_out, optarg); - if (parse_iface(fw.logical_out, "--logical-out")) + strcpy(cs.fw.logical_out, optarg); + if (parse_iface(cs.fw.logical_out, "--logical-out")) return -1; break; } else if (c == 'j') { ebt_check_option2(&flags, OPT_JUMP); - fw.jumpto = parse_target(optarg); - fw.target = command_jump(&fw, fw.jumpto); + cs.jumpto = parse_target(optarg); + cs.target = command_jump(&cs, cs.jumpto); break; } else if (c == 's') { ebt_check_option2(&flags, OPT_SOURCE); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_ISOURCE; + cs.fw.invflags |= EBT_ISOURCE; - if (ebt_get_mac_and_mask(optarg, fw.sourcemac, fw.sourcemsk)) + if (ebt_get_mac_and_mask(optarg, cs.fw.sourcemac, cs.fw.sourcemsk)) xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg); - fw.bitmask |= EBT_SOURCEMAC; + cs.fw.bitmask |= EBT_SOURCEMAC; break; } else if (c == 'd') { ebt_check_option2(&flags, OPT_DEST); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_IDEST; + cs.fw.invflags |= EBT_IDEST; - if (ebt_get_mac_and_mask(optarg, fw.destmac, fw.destmsk)) + if (ebt_get_mac_and_mask(optarg, cs.fw.destmac, cs.fw.destmsk)) xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg); - fw.bitmask |= EBT_DESTMAC; + cs.fw.bitmask |= EBT_DESTMAC; break; } else if (c == 'c') { ebt_check_option2(&flags, OPT_COUNT); @@ -880,12 +882,12 @@ big_iface_length: xtables_error(PARAMETER_PROBLEM, "Option -c needs 2 arguments"); - fw.counters.pcnt = strtoull(optarg, &buffer, 10); + cs.counters.pcnt = strtoull(optarg, &buffer, 10); if (*buffer != '\0') xtables_error(PARAMETER_PROBLEM, "Packet counter '%s' invalid", optarg); - fw.counters.bcnt = strtoull(argv[optind], &buffer, 10); + cs.counters.bcnt = strtoull(argv[optind], &buffer, 10); if (*buffer != '\0') xtables_error(PARAMETER_PROBLEM, "Packet counter '%s' invalid", @@ -895,9 +897,9 @@ big_iface_length: } ebt_check_option2(&flags, OPT_PROTOCOL); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_IPROTO; + cs.fw.invflags |= EBT_IPROTO; - fw.bitmask &= ~((unsigned int)EBT_NOPROTO); + cs.fw.bitmask &= ~((unsigned int)EBT_NOPROTO); i = strtol(optarg, &buffer, 16); if (*buffer == '\0' && (i < 0 || i > 0xFFFF)) xtables_error(PARAMETER_PROBLEM, @@ -906,18 +908,18 @@ big_iface_length: struct ethertypeent *ent; if (!strcasecmp(optarg, "LENGTH")) { - fw.bitmask |= EBT_802_3; + cs.fw.bitmask |= EBT_802_3; break; } ent = getethertypebyname(optarg); if (!ent) xtables_error(PARAMETER_PROBLEM, "Problem with the specified Ethernet protocol '%s', perhaps "_PATH_ETHERTYPES " is missing", optarg); - fw.ethproto = ent->e_ethertype; + cs.fw.ethproto = ent->e_ethertype; } else - fw.ethproto = i; + cs.fw.ethproto = i; - if (fw.ethproto < 0x0600) + if (cs.fw.ethproto < 0x0600) xtables_error(PARAMETER_PROBLEM, "Sorry, protocols have values above or equal to 0x0600"); break; @@ -1103,7 +1105,7 @@ check_extension: */ ebt_print_error2("Bad table name");*/ if (command == 'h' && !(flags & OPT_ZERO)) { - print_help(fw.target, fw.matches, *table); + print_help(cs.target, cs.matches, *table); if (exec_style == EXEC_STYLE_PRG) exit(0); } @@ -1142,7 +1144,7 @@ check_extension: */ }*/ /* So, the extensions can work with the host endian. * The kernel does not have to do this of course */ - fw.ethproto = htons(fw.ethproto); + cs.fw.ethproto = htons(cs.fw.ethproto); if (command == 'P') { if (selected_chain < NF_BR_NUMHOOKS && strcmp(policy, "RETURN")==0) @@ -1166,13 +1168,13 @@ check_extension: */ } else if (command == 'F') { ret = nft_rule_flush(h, chain, *table); } else if (command == 'A') { - ret = append_entry(h, chain, *table, &fw, 0, + ret = append_entry(h, chain, *table, &cs, 0, flags&OPT_VERBOSE, true); } else if (command == 'I') { - ret = append_entry(h, chain, *table, &fw, rule_nr - 1, + ret = append_entry(h, chain, *table, &cs, rule_nr - 1, flags&OPT_VERBOSE, false); } else if (command == 'D') { - ret = delete_entry(h, chain, *table, &fw, rule_nr - 1, + ret = delete_entry(h, chain, *table, &cs, rule_nr - 1, rule_nr_end, flags&OPT_VERBOSE); } /*else if (replace->command == 'C') { ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus), chcounter); diff --git a/iptables/xtables-ebtables.h b/iptables/xtables-ebtables.h deleted file mode 100644 index 1e479b1b..00000000 --- a/iptables/xtables-ebtables.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef _XTABLES_EBTABLES_H_ -#define _XTABLES_EBTABLES_H_ - -#include -#include -#include - -/* We use replace->flags, so we can't use the following values: - * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO */ -#define LIST_N 0x04 -#define LIST_C 0x08 -#define LIST_X 0x10 -#define LIST_MAC2 0x20 - -/* Be backwards compatible, so don't use '+' in kernel */ -#define IF_WILDCARD 1 - -extern unsigned char eb_mac_type_unicast[ETH_ALEN]; -extern unsigned char eb_msk_type_unicast[ETH_ALEN]; -extern unsigned char eb_mac_type_multicast[ETH_ALEN]; -extern unsigned char eb_msk_type_multicast[ETH_ALEN]; -extern unsigned char eb_mac_type_broadcast[ETH_ALEN]; -extern unsigned char eb_msk_type_broadcast[ETH_ALEN]; -extern unsigned char eb_mac_type_bridge_group[ETH_ALEN]; -extern unsigned char eb_msk_type_bridge_group[ETH_ALEN]; - -int ebt_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask); - -struct xtables_ebt_entry { - unsigned int bitmask; - unsigned int invflags; - unsigned int flags; - uint16_t ethproto; - char in[IFNAMSIZ]; - char logical_in[IFNAMSIZ]; - unsigned char in_mask[IFNAMSIZ]; - char out[IFNAMSIZ]; - char logical_out[IFNAMSIZ]; - unsigned char out_mask[IFNAMSIZ]; - unsigned char sourcemac[ETH_ALEN]; - unsigned char sourcemsk[ETH_ALEN]; - unsigned char destmac[ETH_ALEN]; - unsigned char destmsk[ETH_ALEN]; - struct xtables_rule_match *matches; - struct xtables_target *target; - struct xt_counters counters; - const char *jumpto; -}; -#endif -- cgit v1.2.3