From da871de2a6efb576b6378a66222c0871f4282e96 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 9 Oct 2014 15:02:02 +0200 Subject: nft: bootstrap ebtables-compat This patch bootstraps ebtables-compat, the ebtables compatibility software upon nf_tables. [ Original patches: http://patchwork.ozlabs.org/patch/395544/ http://patchwork.ozlabs.org/patch/395545/ http://patchwork.ozlabs.org/patch/395546/ I have also forward port them on top of the current git HEAD, otherwise compilation breaks. This bootstrap is experimental, this still needs more work. --Pablo ] Signed-off-by: Giuseppe Longo Signed-off-by: Pablo Neira Ayuso --- iptables/Makefile.am | 6 +- iptables/getethertype.c | 161 +++++ iptables/nft-bridge.c | 558 ++++++++++++++++++ iptables/nft-shared.c | 16 +- iptables/nft-shared.h | 4 +- iptables/nft.c | 53 +- iptables/nft.h | 12 + iptables/xtables-compat-multi.c | 1 + iptables/xtables-eb-standalone.c | 87 +++ iptables/xtables-eb.c | 1196 ++++++++++++++++++++++++++++++++++++++ iptables/xtables-ebtables.h | 49 ++ iptables/xtables-multi.c | 1 + iptables/xtables-multi.h | 1 + 13 files changed, 2136 insertions(+), 9 deletions(-) create mode 100644 iptables/getethertype.c create mode 100644 iptables/nft-bridge.c create mode 100644 iptables/xtables-eb-standalone.c create mode 100644 iptables/xtables-eb.c create mode 100644 iptables/xtables-ebtables.h (limited to 'iptables') diff --git a/iptables/Makefile.am b/iptables/Makefile.am index aaaade85..b3e417bf 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -39,7 +39,9 @@ xtables_compat_multi_SOURCES += xtables-save.c xtables-restore.c \ xtables-standalone.c xtables.c nft.c \ nft-shared.c nft-ipv4.c nft-ipv6.c nft-arp.c \ xtables-config.c xtables-events.c \ - xtables-arp-standalone.c xtables-arp.c + xtables-arp-standalone.c xtables-arp.c \ + getethertype.c nft-bridge.c \ + xtables-eb-standalone.c xtables-eb.c xtables_compat_multi_LDADD += ${libmnl_LIBS} ${libnftnl_LIBS} ../extensions/libext4.a ../extensions/libext6.a # yacc and lex generate dirty code xtables_compat_multi-xtables-config-parser.o xtables_compat_multi-xtables-config-syntax.o: AM_CFLAGS += -Wno-missing-prototypes -Wno-missing-declarations -Wno-implicit-function-declaration -Wno-nested-externs -Wno-undef -Wno-redundant-decls @@ -67,7 +69,7 @@ endif if ENABLE_NFTABLES x_sbin_links = iptables-compat iptables-compat-restore iptables-compat-save \ ip6tables-compat ip6tables-compat-restore ip6tables-compat-save \ - arptables-compat xtables-config xtables-events + arptables-compat ebtables-compat xtables-config xtables-events endif iptables-extensions.8: iptables-extensions.8.tmpl ../extensions/matches.man ../extensions/targets.man diff --git a/iptables/getethertype.c b/iptables/getethertype.c new file mode 100644 index 00000000..027ef4ad --- /dev/null +++ b/iptables/getethertype.c @@ -0,0 +1,161 @@ +/* +* getethertype.c +* +* This file was part of the NYS Library. +* +** The NYS Library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public License as +** published by the Free Software Foundation; either version 2 of the +** License, or (at your option) any later version. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/******************************************************************** +* Description: Ethertype name service switch and the ethertypes +* database access functions +* Author: Nick Fedchik +* Checker: Bart De Schuymer +* Origin: uClibc-0.9.16/libc/inet/getproto.c +* Created at: Mon Nov 11 12:20:11 EET 2002 +********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MAXALIASES 35 + +static FILE *etherf = NULL; +static char line[BUFSIZ + 1]; +static struct ethertypeent et_ent; +static char *ethertype_aliases[MAXALIASES]; +static int ethertype_stayopen; + +void setethertypeent(int f) +{ + if (etherf == NULL) + etherf = fopen(_PATH_ETHERTYPES, "r"); + else + rewind(etherf); + ethertype_stayopen |= f; +} + +void endethertypeent(void) +{ + if (etherf) { + fclose(etherf); + etherf = NULL; + } + ethertype_stayopen = 0; +} + +struct ethertypeent *getethertypeent(void) +{ + char *e; + char *endptr; + register char *cp, **q; + + if (etherf == NULL + && (etherf = fopen(_PATH_ETHERTYPES, "r")) == NULL) { + return (NULL); + } + +again: + if ((e = fgets(line, BUFSIZ, etherf)) == NULL) { + return (NULL); + } + if (*e == '#') + goto again; + cp = strpbrk(e, "#\n"); + if (cp == NULL) + goto again; + *cp = '\0'; + et_ent.e_name = e; + cp = strpbrk(e, " \t"); + if (cp == NULL) + goto again; + *cp++ = '\0'; + while (*cp == ' ' || *cp == '\t') + cp++; + e = strpbrk(cp, " \t"); + if (e != NULL) + *e++ = '\0'; +// Check point + et_ent.e_ethertype = strtol(cp, &endptr, 16); + if (*endptr != '\0' + || (et_ent.e_ethertype < ETH_ZLEN + || et_ent.e_ethertype > 0xFFFF)) + goto again; // Skip invalid etherproto type entry + q = et_ent.e_aliases = ethertype_aliases; + if (e != NULL) { + cp = e; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < ðertype_aliases[MAXALIASES - 1]) + *q++ = cp; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + } + *q = NULL; + return (&et_ent); +} + + +struct ethertypeent *getethertypebyname(const char *name) +{ + register struct ethertypeent *e; + register char **cp; + + setethertypeent(ethertype_stayopen); + while ((e = getethertypeent()) != NULL) { + if (strcasecmp(e->e_name, name) == 0) + break; + for (cp = e->e_aliases; *cp != 0; cp++) + if (strcasecmp(*cp, name) == 0) + goto found; + } +found: + if (!ethertype_stayopen) + endethertypeent(); + return (e); +} + +struct ethertypeent *getethertypebynumber(int type) +{ + register struct ethertypeent *e; + + setethertypeent(ethertype_stayopen); + while ((e = getethertypeent()) != NULL) + if (e->e_ethertype == type) + break; + if (!ethertype_stayopen) + endethertypeent(); + return (e); +} diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c new file mode 100644 index 00000000..66361ee9 --- /dev/null +++ b/iptables/nft-bridge.c @@ -0,0 +1,558 @@ +/* + * (C) 2014 by Giuseppe Longo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "nft-shared.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 */ +int ebt_printstyle_mac; + +static void ebt_print_mac(const unsigned char *mac) +{ + if (ebt_printstyle_mac == 2) { + int j; + for (j = 0; j < ETH_ALEN; j++) + printf("%02x%s", mac[j], + (j==ETH_ALEN-1) ? "" : ":"); + } else + printf("%s", ether_ntoa((struct ether_addr *) mac)); +} + +/* Put the mac address into 6 (ETH_ALEN) bytes returns 0 on success. */ +static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask) +{ + char hlpmsk[6] = {}; + + if (!memcmp(mac, eb_mac_type_unicast, 6) && + !memcmp(mask, eb_msk_type_unicast, 6)) + printf("Unicast"); + else if (!memcmp(mac, eb_mac_type_multicast, 6) && + !memcmp(mask, eb_msk_type_multicast, 6)) + printf("Multicast"); + else if (!memcmp(mac, eb_mac_type_broadcast, 6) && + !memcmp(mask, eb_msk_type_broadcast, 6)) + printf("Broadcast"); + else if (!memcmp(mac, eb_mac_type_bridge_group, 6) && + !memcmp(mask, eb_msk_type_bridge_group, 6)) + printf("BGA"); + else { + ebt_print_mac(mac); + if (memcmp(mask, hlpmsk, 6)) { + printf("/"); + ebt_print_mac(mask); + } + } +} + +static uint8_t ebt_to_ipt_flags(uint16_t invflags) +{ + uint8_t result = 0; + + if (invflags & EBT_IIN) + result |= IPT_INV_VIA_IN; + + if (invflags & EBT_IOUT) + result |= IPT_INV_VIA_OUT; + + if (invflags & EBT_IPROTO) + result |= IPT_INV_PROTO; + + return result; +} + +static uint16_t ipt_to_ebt_flags(uint8_t invflags) +{ + uint16_t result = 0; + + if (invflags & IPT_INV_VIA_IN) + result |= EBT_IIN; + + if (invflags & IPT_INV_VIA_OUT) + result |= EBT_IOUT; + + if (invflags & IPT_INV_PROTO) + result |= EBT_IPROTO; + + return result; +} + +static void add_logical_iniface(struct nft_rule *r, char *iface, int invflags) +{ + int iface_len; + uint32_t op; + + iface_len = strlen(iface); + + if (invflags & EBT_ILOGICALIN) + op = NFT_CMP_NEQ; + else + op = NFT_CMP_EQ; + + add_meta(r, NFT_META_BRI_IIFNAME); + if (iface[iface_len - 1] == '+') + add_cmp_ptr(r, op, iface, iface_len - 1); + else + add_cmp_ptr(r, op, iface, iface_len + 1); +} + +static void add_logical_outiface(struct nft_rule *r, char *iface, int invflags) +{ + int iface_len; + uint32_t op; + + iface_len = strlen(iface); + + if (invflags & EBT_ILOGICALOUT) + op = NFT_CMP_NEQ; + else + op = NFT_CMP_EQ; + + add_meta(r, NFT_META_BRI_OIFNAME); + if (iface[iface_len - 1] == '+') + add_cmp_ptr(r, op, iface, iface_len - 1); + else + add_cmp_ptr(r, op, iface, iface_len + 1); +} + +static int _add_action(struct nft_rule *r, struct xtables_ebt_entry *fw) +{ + 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) + /* Not standard, then it's a jump to chain */ + ret = add_jumpto(r, fw->jumpto, NFT_JUMP); + + return ret; +} + +static int nft_bridge_add(struct nft_rule *r, void *data) +{ + struct xtables_ebt_entry *fw = data; + uint8_t flags = ebt_to_ipt_flags(fw->invflags); + char *addr; + + if (fw->in[0] != '\0') + add_iniface(r, fw->in, flags); + + if (fw->out[0] != '\0') + add_outiface(r, fw->out, flags); + + if (fw->logical_in[0] != '\0') + add_logical_iniface(r, fw->logical_in, flags); + + if (fw->logical_out[0] != '\0') + add_logical_outiface(r, fw->logical_out, flags); + + addr = ether_ntoa((struct ether_addr *) fw->sourcemac); + if (strcmp(addr, "0:0:0:0:0:0") != 0) { + add_payload(r, offsetof(struct ethhdr, h_source), 6); + add_cmp_ptr(r, NFT_CMP_EQ, fw->sourcemac, 6); + } + + addr = ether_ntoa((struct ether_addr *) fw->destmac); + if (strcmp(addr, "0:0:0:0:0:0") != 0) { + add_payload(r, offsetof(struct ethhdr, h_dest), 6); + add_cmp_ptr(r, NFT_CMP_EQ, fw->destmac, 6); + } + + if (fw->ethproto != 0) { + add_payload(r, offsetof(struct ethhdr, h_proto), 2); + add_cmp_u16(r, fw->ethproto, NFT_CMP_EQ); + } + + return _add_action(r, fw); +} + +static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, + struct nft_rule_expr *e, void *data) +{ + struct xtables_ebt_entry *fw = data; + uint8_t flags = 0; + int iface = 0; + const void *ifname; + uint32_t len; + + iface = parse_meta(e, ctx->meta.key, fw->in, fw->in_mask, + fw->out, fw->out_mask, &flags); + if (!iface) + goto out; + + switch (ctx->meta.key) { + case NFT_META_BRI_IIFNAME: + ifname = nft_rule_expr_get(e, NFT_EXPR_CMP_DATA, &len); + if (nft_rule_expr_get_u32(e, NFT_EXPR_CMP_OP) == NFT_CMP_NEQ) + flags |= IPT_INV_VIA_IN; + + memcpy(fw->logical_in, ifname, len); + + if (fw->logical_in[len] == '\0') + memset(fw->in_mask, 0xff, len); + else { + fw->logical_in[len] = '+'; + fw->logical_in[len+1] = '\0'; + memset(fw->in_mask, 0xff, len + 1); + } + break; + case NFT_META_BRI_OIFNAME: + ifname = nft_rule_expr_get(e, NFT_EXPR_CMP_DATA, &len); + if (nft_rule_expr_get_u32(e, NFT_EXPR_CMP_OP) == NFT_CMP_NEQ) + flags |= IPT_INV_VIA_OUT; + + memcpy(fw->logical_out, ifname, len); + + if (fw->logical_out[len] == '\0') + memset(fw->out_mask, 0xff, len); + else { + fw->logical_out[len] = '+'; + fw->logical_out[len+1] = '\0'; + memset(fw->out_mask, 0xff, len + 1); + } + break; + default: + break; + } + +out: + fw->invflags |= ipt_to_ebt_flags(flags); +} + +static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, + struct nft_rule_expr *e, void *data) +{ + struct xtables_ebt_entry *fw = data; + unsigned char addr[ETH_ALEN]; + unsigned short int ethproto; + bool inv; + int i; + + switch (ctx->payload.offset) { + case offsetof(struct ethhdr, h_dest): + get_cmp_data(e, addr, sizeof(addr), &inv); + for (i = 0; i < ETH_ALEN; i++) + fw->destmac[i] = addr[i]; + break; + case offsetof(struct ethhdr, h_source): + get_cmp_data(e, addr, sizeof(addr), &inv); + for (i = 0; i < ETH_ALEN; i++) + fw->sourcemac[i] = addr[i]; + break; + case offsetof(struct ethhdr, h_proto): + get_cmp_data(e, ðproto, sizeof(ethproto), &inv); + fw->ethproto = ethproto; + break; + } +} +static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto, + void *data) +{ + struct xtables_ebt_entry *fw = data; + + fw->jumpto = jumpto; +} + +static void nft_bridge_parse_target(struct xtables_target *t, void *data) +{ + struct xtables_ebt_entry *fw = data; + + fw->target = t; +} + +void nft_rule_to_xtables_ebt_entry(struct nft_rule *r, struct xtables_ebt_entry *fw) +{ + 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, + .family = family, + }; + + iter = nft_rule_expr_iter_create(r); + if (iter == NULL) + return; + + expr = nft_rule_expr_iter_next(iter); + while (expr != NULL) { + const char *name = + nft_rule_expr_get_str(expr, NFT_RULE_EXPR_ATTR_NAME); + + if (strcmp(name, "counter") == 0) + nft_parse_counter(expr, &fw->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, "cmp") == 0) + nft_parse_cmp(&ctx, expr); + else if (strcmp(name, "immediate") == 0) + nft_parse_immediate(&ctx, expr); + else if (strcmp(name, "target") == 0) + nft_parse_target(&ctx, expr); + + expr = nft_rule_expr_iter_next(iter); + } + + 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); + else + fw->jumpto = ""; +} + +static void print_iface(const char *iface) +{ + char *c; + + if ((c = strchr(iface, IF_WILDCARD))) + *c = '+'; + printf("%s ", iface); + if (c) + *c = IF_WILDCARD; +} + +static void nft_bridge_print_header(unsigned int format, const char *chain, + const char *pol, + const struct xt_counters *counters, + bool basechain, uint32_t refs) +{ + /* FIXME: Giuseppe replace this with ebtables format */ + print_header(format, chain, pol, counters, basechain, refs); +} + +static void +nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, + unsigned int format) +{ + struct xtables_ebt_entry fw = {}; + char *addr; + + nft_rule_to_xtables_ebt_entry(r, &fw); + + 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) { + printf("-p "); + if (fw.invflags & EBT_IPROTO) + printf("! "); + if (fw.bitmask & EBT_802_3) + printf("Length "); + else { + struct ethertypeent *ent; + + ent = getethertypebynumber(ntohs(fw.ethproto)); + if (!ent) + printf("0x%x ", ntohs(fw.ethproto)); + else + printf("%s ", ent->e_name); + } + } + + addr = ether_ntoa((struct ether_addr *) fw.sourcemac); + if (strcmp(addr, "0:0:0:0:0:0") != 0) { + printf("-s "); + if (fw.invflags & EBT_ISOURCE) + printf("! "); + ebt_print_mac_and_mask(fw.sourcemac, fw.sourcemsk); + printf(" "); + } + + addr = ether_ntoa((struct ether_addr *) fw.destmac); + if (strcmp(addr, "0:0:0:0:0:0") != 0) { + printf("-d "); + if (fw.invflags & EBT_IDEST) + printf("! "); + ebt_print_mac_and_mask(fw.destmac, fw.destmsk); + printf(" "); + } + + if (fw.in[0] != '\0') { + printf("-i "); + if (fw.invflags & EBT_IIN) + printf("! "); + print_iface(fw.in); + } + + if (fw.logical_in[0] != '\0') { + printf("--logical-in "); + if (fw.invflags & EBT_ILOGICALIN) + printf("! "); + print_iface(fw.logical_in); + } + + if (fw.logical_out[0] != '\0') { + printf("--logical-out "); + if (fw.invflags & EBT_ILOGICALOUT) + printf("! "); + print_iface(fw.logical_out); + } + + if (fw.out[0] != '\0') { + printf("-o "); + if (fw.invflags & EBT_IOUT) + printf("! "); + print_iface(fw.out); + } + + /* old code to adapt + m_l = hlp->m_list; + while (m_l) { + m = ebt_find_match(m_l->m->u.name); + if (!m) + ebt_print_bug("Match not found"); + m->print(hlp, m_l->m); + m_l = m_l->next; + } + w_l = hlp->w_list; + while (w_l) { + w = ebt_find_watcher(w_l->w->u.name); + if (!w) + ebt_print_bug("Watcher not found"); + w->print(hlp, w_l->w); + w_l = w_l->next; + }*/ + printf("-j "); + if (!(format & FMT_NOTARGET)) + printf("%s", fw.jumpto); + + if (fw.target != NULL) { + if (fw.target->print != NULL) { + fw.target->print(&fw, fw.target->t, + format & FMT_NUMERIC); + } + } + + if (!(format & FMT_NONEWLINE)) + fputc('\n', stdout); +} + +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; + int i; + + if (a->ethproto != b->ethproto + /*|| a->flags != b->flags*/ + || a->invflags != b->invflags) { + DEBUGP("different proto/flags/invflags\n"); + return false; + } + + for (i = 0; i < ETH_ALEN; i++) { + if (a->sourcemac[i] != b->sourcemac[i]) { + DEBUGP("different source mac %x, %x (%d)\n", + a->sourcemac[i] & 0xff, b->sourcemac[i] & 0xff, i); + return false; + } + + if (a->destmac[i] != b->destmac[i]) { + DEBUGP("different destination mac %x, %x (%d)\n", + a->destmac[i] & 0xff, b->destmac[i] & 0xff, i); + return false; + } + } + + for (i = 0; i < IFNAMSIZ; i++) { + if (a->logical_in[i] != b->logical_in[i]) { + DEBUGP("different logical iniface %x, %x (%d)\n", + a->logical_in[i] & 0xff, b->logical_in[i] & 0xff, i); + return false; + } + + if (a->logical_out[i] != b->logical_out[i]) { + DEBUGP("different logical outiface %x, %x (%d)\n", + a->logical_out[i] & 0xff, b->logical_out[i] & 0xff, i); + return false; + } + } + + return is_same_interfaces((char *)a->in, + (char *)a->out, + a->in_mask, + a->out_mask, + (char *)b->in, + (char *)b->out, + b->in_mask, + b->out_mask); +} + +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 = {}; + + nft_rule_to_xtables_ebt_entry(r, &this); + + DEBUGP("comparing with... "); + + if (!ops->is_same(fw, &this)) + return false; + + if (!compare_matches(fw->matches, this.matches)) { + DEBUGP("Different matches\n"); + return false; + } + + if (!compare_targets(fw->target, this.target)) { + DEBUGP("Different target\n"); + return false; + } + + if (strcmp(fw->jumpto, this.jumpto) != 0) { + DEBUGP("Different verdict\n"); + return false; + } + + return true; +} + +struct nft_family_ops nft_family_ops_bridge = { + .add = nft_bridge_add, + .is_same = nft_bridge_is_same, + .print_payload = NULL, + .parse_meta = nft_bridge_parse_meta, + .parse_payload = nft_bridge_parse_payload, + .parse_immediate = nft_bridge_parse_immediate, + .print_header = nft_bridge_print_header, + .print_firewall = nft_bridge_print_firewall, + .post_parse = NULL, + .rule_find = nft_bridge_rule_find, + .parse_target = nft_bridge_parse_target, +}; diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index d4a54bee..9ca2e35c 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -32,6 +32,7 @@ extern struct nft_family_ops nft_family_ops_ipv4; extern struct nft_family_ops nft_family_ops_ipv6; extern struct nft_family_ops nft_family_ops_arp; +extern struct nft_family_ops nft_family_ops_bridge; void add_meta(struct nft_rule *r, uint32_t key) { @@ -206,7 +207,7 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface, return true; } -void parse_meta(struct nft_rule_expr *e, uint8_t key, char *iniface, +int parse_meta(struct nft_rule_expr *e, uint8_t key, char *iniface, unsigned char *iniface_mask, char *outiface, unsigned char *outiface_mask, uint8_t *invflags) { @@ -264,9 +265,10 @@ void parse_meta(struct nft_rule_expr *e, uint8_t key, char *iniface, } break; default: - DEBUGP("unknown meta key %d\n", key); - break; + return -1; } + + return 0; } static void *nft_get_data(struct nft_xt_ctx *ctx) @@ -277,6 +279,8 @@ static void *nft_get_data(struct nft_xt_ctx *ctx) return ctx->state.cs; case NFPROTO_ARP: return ctx->state.cs_arp; + case NFPROTO_BRIDGE: + return ctx->state.ebfw; default: /* Should not happen */ return NULL; @@ -734,6 +738,8 @@ struct nft_family_ops *nft_family_ops_lookup(int family) return &nft_family_ops_ipv6; case NFPROTO_ARP: return &nft_family_ops_arp; + case NFPROTO_BRIDGE: + return &nft_family_ops_bridge; default: break; } @@ -741,8 +747,8 @@ struct nft_family_ops *nft_family_ops_lookup(int family) return NULL; } -static bool -compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2) +bool compare_matches(struct xtables_rule_match *mt1, + struct xtables_rule_match *mt2) { struct xtables_rule_match *mp1; struct xtables_rule_match *mp2; diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 1b16d4e0..97d41df8 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -48,6 +48,7 @@ struct nft_xt_ctx { union { struct iptables_command_state *cs; struct arptables_command_state *cs_arp; + struct xtables_ebt_entry *ebfw; } state; struct nft_rule_expr_iter *iter; int family; @@ -122,7 +123,7 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface, unsigned const char *b_iniface_mask, unsigned const char *b_outiface_mask); -void parse_meta(struct nft_rule_expr *e, uint8_t key, char *iniface, +int parse_meta(struct nft_rule_expr *e, uint8_t key, char *iniface, unsigned char *iniface_mask, char *outiface, unsigned char *outiface_mask, uint8_t *invflags); void print_proto(uint16_t proto, int invert); @@ -165,6 +166,7 @@ struct nft_handle; bool nft_ipv46_rule_find(struct nft_family_ops *ops, struct nft_rule *r, struct iptables_command_state *cs); +bool compare_matches(struct xtables_rule_match *mt1, struct xtables_rule_match *mt2); bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2); struct addr_mask { diff --git a/iptables/nft.c b/iptables/nft.c index 568faa19..804ebe97 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -469,6 +469,57 @@ struct builtin_table xtables_arp[TABLES_MAX] = { }, }; +#include + +struct builtin_table xtables_bridge[TABLES_MAX] = { + [FILTER] = { + .name = "filter", + .chains = { + { + .name = "INPUT", + .type = "filter", + .prio = NF_BR_PRI_FILTER_BRIDGED, + .hook = NF_BR_LOCAL_IN, + }, + { + .name = "FORWARD", + .type = "filter", + .prio = NF_BR_PRI_FILTER_BRIDGED, + .hook = NF_BR_FORWARD, + }, + { + .name = "OUTPUT", + .type = "filter", + .prio = NF_BR_PRI_FILTER_BRIDGED, + .hook = NF_BR_LOCAL_OUT, + }, + }, + }, + [NAT] = { + .name = "nat", + .chains = { + { + .name = "PREROUTING", + .type = "filter", + .prio = NF_BR_PRI_NAT_DST_BRIDGED, + .hook = NF_BR_PRE_ROUTING, + }, + { + .name = "OUTPUT", + .type = "filter", + .prio = NF_BR_PRI_NAT_DST_OTHER, + .hook = NF_BR_LOCAL_OUT, + }, + { + .name = "POSTROUTING", + .type = "filter", + .prio = NF_BR_PRI_NAT_SRC, + .hook = NF_BR_POST_ROUTING, + }, + }, + }, +}; + int nft_table_add(struct nft_handle *h, struct nft_table *t, uint16_t flags) { char buf[MNL_SOCKET_BUFFER_SIZE]; @@ -587,7 +638,7 @@ nft_table_builtin_find(struct nft_handle *h, const char *table) for (i=0; itables[i].name == NULL) - break; + continue; if (strcmp(h->tables[i].name, table) != 0) continue; diff --git a/iptables/nft.h b/iptables/nft.h index 9f6561f5..4f0b733c 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -41,6 +41,7 @@ struct nft_handle { extern struct builtin_table xtables_ipv4[TABLES_MAX]; extern struct builtin_table xtables_arp[TABLES_MAX]; +extern struct builtin_table xtables_bridge[TABLES_MAX]; int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh, int (*cb)(const struct nlmsghdr *nlh, void *data), @@ -135,6 +136,8 @@ const char *nft_strerror(int err); int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, bool restore); /* For xtables-arptables.c */ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table); +/* For xtables-eb.c */ +int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table); /* * Parse config for tables and chain helper functions @@ -167,4 +170,13 @@ 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-compat-multi.c b/iptables/xtables-compat-multi.c index 47810524..ed8ad07f 100644 --- a/iptables/xtables-compat-multi.c +++ b/iptables/xtables-compat-multi.c @@ -28,6 +28,7 @@ static const struct subcommand multi_subcommands[] = { {"ip6tables-compat-restore", xtables_ip6_restore_main}, {"arptables", xtables_arp_main}, {"arptables-compat", xtables_arp_main}, + {"ebtables-compat", xtables_eb_main}, {"xtables-config", xtables_config_main}, {"xtables-events", xtables_events_main}, {NULL}, diff --git a/iptables/xtables-eb-standalone.c b/iptables/xtables-eb-standalone.c new file mode 100644 index 00000000..6ec418cb --- /dev/null +++ b/iptables/xtables-eb-standalone.c @@ -0,0 +1,87 @@ +/* + * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au + * + * Based on the ipchains code by Paul Russell and Michael Neuling + * + * (C) 2000-2002 by the netfilter coreteam : + * Paul 'Rusty' Russell + * Marc Boucher + * James Morris + * Harald Welte + * Jozsef Kadlecsik + * + * arptables -- IP firewall administration for kernels with + * firewall table (aimed for the 2.3 kernels) + * + * See the accompanying manual page arptables(8) for information + * about proper usage of this program. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include "nft.h" + +#include "xtables-multi.h" + +extern struct xtables_globals xtables_globals; +extern const char *program_version, *program_name; + +static const struct xtables_afinfo afinfo_bridge = { + .kmod = "eb_tables", + .proc_exists = "/proc/net/eb_tables_names", + .libprefix = "libeb_", + .family = NFPROTO_BRIDGE, + .ipproto = IPPROTO_IP, + .so_rev_match = -1, + .so_rev_target = -1, +}; + +int xtables_eb_main(int argc, char *argv[]) +{ + int ret; + char *table = "filter"; + struct nft_handle h = { + .family = NFPROTO_BRIDGE, + }; + + xtables_globals.program_name = "ebtables"; + /* This code below could be replaced by xtables_init_all, which + * doesn't support NFPROTO_BRIDGE yet. + */ + xtables_init(); + afinfo = &afinfo_bridge; + ret = xtables_set_params(&xtables_globals); + if (ret < 0) { + fprintf(stderr, "%s/%s Failed to initialize xtables\n", + xtables_globals.program_name, + xtables_globals.program_version); + exit(1); + } + +#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) + init_extensions(); +#endif + + ret = do_commandeb(&h, argc, argv, &table); + if (ret) + ret = nft_commit(&h); + + exit(!ret); +} diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c new file mode 100644 index 00000000..73a38db9 --- /dev/null +++ b/iptables/xtables-eb.c @@ -0,0 +1,1196 @@ +/* + * ebtables.c, v2.0 July 2002 + * + * Author: Bart De Schuymer + * + * This code was stongly inspired on the iptables code which is + * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "xshared.h" +#include "nft.h" + +extern struct xtables_globals xtables_globals; +#define prog_name xtables_globals.program_name +#define prog_vers xtables_globals.program_version + +/* + * From include/ebtables_u.h + */ +#define EXEC_STYLE_PRG 0 +#define EXEC_STYLE_DAEMON 1 + +/* + * From useful_functions.c + */ + +/* 0: default + * 1: the inverse '!' of the option has already been specified */ +int ebt_invert = 0; + +unsigned char eb_mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0}; +unsigned char eb_msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0}; +unsigned char eb_mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0}; +unsigned char eb_msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0}; +unsigned char eb_mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255}; +unsigned char eb_msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255}; +unsigned char eb_mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0}; +unsigned char eb_msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255}; + +int ebt_get_mac_and_mask(const char *from, unsigned char *to, + unsigned char *mask) +{ + char *p; + int i; + struct ether_addr *addr = NULL; + + if (strcasecmp(from, "Unicast") == 0) { + memcpy(to, eb_mac_type_unicast, ETH_ALEN); + memcpy(mask, eb_msk_type_unicast, ETH_ALEN); + return 0; + } + if (strcasecmp(from, "Multicast") == 0) { + memcpy(to, eb_mac_type_multicast, ETH_ALEN); + memcpy(mask, eb_msk_type_multicast, ETH_ALEN); + return 0; + } + if (strcasecmp(from, "Broadcast") == 0) { + memcpy(to, eb_mac_type_broadcast, ETH_ALEN); + memcpy(mask, eb_msk_type_broadcast, ETH_ALEN); + return 0; + } + if (strcasecmp(from, "BGA") == 0) { + memcpy(to, eb_mac_type_bridge_group, ETH_ALEN); + memcpy(mask, eb_msk_type_bridge_group, ETH_ALEN); + return 0; + } + if ( (p = strrchr(from, '/')) != NULL) { + *p = '\0'; + if (!(addr = ether_aton(p + 1))) + return -1; + memcpy(mask, addr, ETH_ALEN); + } else + memset(mask, 0xff, ETH_ALEN); + if (!(addr = ether_aton(from))) + return -1; + memcpy(to, addr, ETH_ALEN); + for (i = 0; i < ETH_ALEN; i++) + to[i] &= mask[i]; + return 0; +} + +/* This is a replacement for the ebt_check_option2() macro. + * + * Make sure the same option wasn't specified twice. This is used in the parse + * functions of the extensions and ebtables.c. + */ +static void ebt_check_option2(unsigned int *flags, unsigned int mask) +{ + if (*flags & mask) + xtables_error(PARAMETER_PROBLEM, + "Multiple use of same option not allowed"); + *flags |= mask; +} + +static int ebt_check_inverse2(const char option[], int argc, char **argv) +{ + if (!option) + return ebt_invert; + if (strcmp(option, "!") == 0) { + if (ebt_invert == 1) + xtables_error(PARAMETER_PROBLEM, + "Double use of '!' not allowed"); + if (optind >= argc) + optarg = NULL; + else + optarg = argv[optind]; + optind++; + ebt_invert = 1; + return 1; + } + return ebt_invert; +} + +/* + * From libebtc.c + */ + +/* The four target names, from libebtc.c */ +const char* ebt_standard_targets[NUM_STANDARD_TARGETS] = +{ + "ACCEPT", + "DROP", + "CONTINUE", + "RETURN", +}; + +/* Prints all registered extensions */ +static void ebt_list_extensions(const struct xtables_target *t, + const struct xtables_rule_match *m) +{ + printf("%s v%s\n", prog_name, prog_vers); + printf("Loaded userspace extensions:\n"); + /*printf("\nLoaded tables:\n"); + while (tbl) { + printf("%s\n", tbl->name); + tbl = tbl->next; + }*/ + printf("\nLoaded targets:\n"); + for (t = xtables_targets; t; t = t->next) { + printf("%s\n", t->name); + } + printf("\nLoaded matches:\n"); + for (; m != NULL; m = m->next) + printf("%s\n", m->match->name); + /*printf("\nLoaded watchers:\n"); + while (w) { + printf("%s\n", w->name); + w = w->next; + }*/ +} + +/* + * Glue code to use libxtables + */ +static int parse_rule_number(const char *rule) +{ + unsigned int rule_nr; + + if (!xtables_strtoui(rule, NULL, &rule_nr, 1, INT_MAX)) + xtables_error(PARAMETER_PROBLEM, + "Invalid rule number `%s'", rule); + + return rule_nr; +} + +static const char * +parse_target(const char *targetname) +{ + const char *ptr; + + if (strlen(targetname) < 1) + xtables_error(PARAMETER_PROBLEM, + "Invalid target name (too short)"); + + if (strlen(targetname)+1 > EBT_CHAIN_MAXNAMELEN) + xtables_error(PARAMETER_PROBLEM, + "Invalid target '%s' (%d chars max)", + targetname, EBT_CHAIN_MAXNAMELEN); + + for (ptr = targetname; *ptr; ptr++) + if (isspace(*ptr)) + xtables_error(PARAMETER_PROBLEM, + "Invalid target name `%s'", targetname); + return targetname; +} + +static int +append_entry(struct nft_handle *h, + const char *chain, + const char *table, + struct xtables_ebt_entry *fw, + int rule_nr, + bool verbose, bool append) +{ + int ret = 1; + + if (append) + ret = nft_rule_append(h, chain, table, fw, 0, verbose); + else + ret = nft_rule_insert(h, chain, table, fw, rule_nr, verbose); + + return ret; +} + +static int +delete_entry(struct nft_handle *h, + const char *chain, + const char *table, + struct xtables_ebt_entry *fw, + int rule_nr, + int rule_nr_end, + bool verbose) +{ + int ret = 1; + + if (rule_nr == -1) + ret = nft_rule_delete(h, chain, table, fw, verbose); + else { + do { + ret = nft_rule_delete_num(h, chain, table, + rule_nr, verbose); + rule_nr++; + } while (rule_nr < rule_nr_end); + } + + return ret; +} + +static int get_current_chain(const char *chain) +{ + if (strcmp(chain, "PREROUTING") == 0) + return NF_BR_PRE_ROUTING; + else if (strcmp(chain, "INPUT") == 0) + return NF_BR_LOCAL_IN; + else if (strcmp(chain, "FORWARD") == 0) + return NF_BR_FORWARD; + else if (strcmp(chain, "OUTPUT") == 0) + return NF_BR_LOCAL_OUT; + else if (strcmp(chain, "POSTROUTING") == 0) + return NF_BR_POST_ROUTING; + + return -1; +} + +/* + * The original ebtables parser + */ + +/* Checks whether a command has already been specified */ +#define OPT_COMMANDS (flags & OPT_COMMAND || flags & OPT_ZERO) + +#define OPT_COMMAND 0x01 +#define OPT_TABLE 0x02 +#define OPT_IN 0x04 +#define OPT_OUT 0x08 +#define OPT_JUMP 0x10 +#define OPT_PROTOCOL 0x20 +#define OPT_SOURCE 0x40 +#define OPT_DEST 0x80 +#define OPT_ZERO 0x100 +#define OPT_LOGICALIN 0x200 +#define OPT_LOGICALOUT 0x400 +#define OPT_KERNELDATA 0x800 /* This value is also defined in ebtablesd.c */ +#define OPT_COUNT 0x1000 /* This value is also defined in libebtc.c */ +#define OPT_CNT_INCR 0x2000 /* This value is also defined in libebtc.c */ +#define OPT_CNT_DECR 0x4000 /* This value is also defined in libebtc.c */ + +/* Default command line options. Do not mess around with the already + * assigned numbers unless you know what you are doing */ +static struct option ebt_original_options[] = +{ + { "append" , required_argument, 0, 'A' }, + { "insert" , required_argument, 0, 'I' }, + { "delete" , required_argument, 0, 'D' }, + { "list" , optional_argument, 0, 'L' }, + { "Lc" , no_argument , 0, 4 }, + { "Ln" , no_argument , 0, 5 }, + { "Lx" , no_argument , 0, 6 }, + { "Lmac2" , no_argument , 0, 12 }, + { "zero" , optional_argument, 0, 'Z' }, + { "flush" , optional_argument, 0, 'F' }, + { "policy" , required_argument, 0, 'P' }, + { "in-interface" , required_argument, 0, 'i' }, + { "in-if" , required_argument, 0, 'i' }, + { "logical-in" , required_argument, 0, 2 }, + { "logical-out" , required_argument, 0, 3 }, + { "out-interface" , required_argument, 0, 'o' }, + { "out-if" , required_argument, 0, 'o' }, + { "version" , no_argument , 0, 'V' }, + { "help" , no_argument , 0, 'h' }, + { "jump" , required_argument, 0, 'j' }, + { "set-counters" , required_argument, 0, 'c' }, + { "change-counters", required_argument, 0, 'C' }, + { "proto" , required_argument, 0, 'p' }, + { "protocol" , required_argument, 0, 'p' }, + { "db" , required_argument, 0, 'b' }, + { "source" , required_argument, 0, 's' }, + { "src" , required_argument, 0, 's' }, + { "destination" , required_argument, 0, 'd' }, + { "dst" , required_argument, 0, 'd' }, + { "table" , required_argument, 0, 't' }, + { "modprobe" , required_argument, 0, 'M' }, + { "new-chain" , required_argument, 0, 'N' }, + { "rename-chain" , required_argument, 0, 'E' }, + { "delete-chain" , optional_argument, 0, 'X' }, + { "atomic-init" , no_argument , 0, 7 }, + { "atomic-commit" , no_argument , 0, 8 }, + { "atomic-file" , required_argument, 0, 9 }, + { "atomic-save" , no_argument , 0, 10 }, + { "init-table" , no_argument , 0, 11 }, + { "concurrent" , no_argument , 0, 13 }, + { 0 } +}; + +static struct option *ebt_options = ebt_original_options; + +/* + * More glue code. + */ +static struct xtables_target *command_jump(struct xtables_ebt_entry *fw, + const char *jumpto) +{ + struct xtables_target *target; + size_t size; + + /* XTF_TRY_LOAD (may be chain name) */ + target = xtables_find_target(jumpto, XTF_TRY_LOAD); + + if (!target) + return NULL; + + size = XT_ALIGN(sizeof(struct xt_entry_target)) + + target->size; + + target->t = xtables_calloc(1, size); + target->t->u.target_size = size; + strncpy(target->t->u.user.name, jumpto, sizeof(target->t->u.user.name)); + target->t->u.user.name[sizeof(target->t->u.user.name)-1] = '\0'; + target->t->u.user.revision = target->revision; + + xs_init_target(target); + + if (target->x6_options != NULL) + ebt_options = xtables_options_xfrm(xtables_globals.orig_opts, + ebt_options, target->x6_options, + &target->option_offset); + else + ebt_options = xtables_merge_options(xtables_globals.orig_opts, + ebt_options, target->extra_opts, + &target->option_offset); + + return target; +} + +static void print_help(const struct xtables_target *t, + const struct xtables_rule_match *m, const char *table) +{ + printf("%s %s\n", prog_name, prog_vers); + printf( +"Usage:\n" +"ebtables -[ADI] chain rule-specification [options]\n" +"ebtables -P chain target\n" +"ebtables -[LFZ] [chain]\n" +"ebtables -[NX] [chain]\n" +"ebtables -E old-chain-name new-chain-name\n\n" +"Commands:\n" +"--append -A chain : append to chain\n" +"--delete -D chain : delete matching rule from chain\n" +"--delete -D chain rulenum : delete rule at position rulenum from chain\n" +"--change-counters -C chain\n" +" [rulenum] pcnt bcnt : change counters of existing rule\n" +"--insert -I chain rulenum : insert rule at position rulenum in chain\n" +"--list -L [chain] : list the rules in a chain or in all chains\n" +"--flush -F [chain] : delete all rules in chain or in all chains\n" +"--init-table : replace the kernel table with the initial table\n" +"--zero -Z [chain] : put counters on zero in chain or in all chains\n" +"--policy -P chain target : change policy on chain to target\n" +"--new-chain -N chain : create a user defined chain\n" +"--rename-chain -E old new : rename a chain\n" +"--delete-chain -X [chain] : delete a user defined chain\n" +"--atomic-commit : update the kernel w/t table contained in \n" +"--atomic-init : put the initial kernel table into \n" +"--atomic-save : put the current kernel table into \n" +"--atomic-file file : set to file\n\n" +"Options:\n" +"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n" +"--src -s [!] address[/mask]: source mac address\n" +"--dst -d [!] address[/mask]: destination mac address\n" +"--in-if -i [!] name[+] : network input interface name\n" +"--out-if -o [!] name[+] : network output interface name\n" +"--logical-in [!] name[+] : logical bridge input interface name\n" +"--logical-out [!] name[+] : logical bridge output interface name\n" +"--set-counters -c chain\n" +" pcnt bcnt : set the counters of the to be added rule\n" +"--modprobe -M program : try to insert modules using this program\n" +"--concurrent : use a file lock to support concurrent scripts\n" +"--version -V : print package version\n\n" +"Environment variable:\n" +/*ATOMIC_ENV_VARIABLE " : if set (see above) will equal its value"*/ +"\n\n"); + for (; m != NULL; m = m->next) { + printf("\n"); + m->match->help(); + } + if (t != NULL) { + printf("\n"); + t->help(); + } + +// if (table->help) +// table->help(ebt_hooknames); +} + +/* Execute command L */ +static int list_rules(struct nft_handle *h, const char *chain, const char *table, + int rule_nr, int verbose, int numeric, int expanded, + int linenumbers) +{ + unsigned int format; + + format = FMT_OPTIONS; + if (!verbose) + format |= FMT_NOCOUNTS; + else + format |= FMT_VIA; + + if (numeric) + format |= FMT_NUMERIC; + + if (!expanded) + format |= FMT_KILOMEGAGIGA; + + if (linenumbers) + format |= FMT_LINENUMBERS; + + return nft_rule_list(h, chain, table, rule_nr, format); +} + +static int parse_rule_range(const char *argv, int *rule_nr, int *rule_nr_end) +{ + char *colon = strchr(argv, ':'), *buffer; + + if (colon) { + *colon = '\0'; + if (*(colon + 1) == '\0') + *rule_nr_end = -1; /* Until the last rule */ + else { + *rule_nr_end = strtol(colon + 1, &buffer, 10); + if (*buffer != '\0' || *rule_nr_end == 0) + return -1; + } + } + if (colon == argv) + *rule_nr = 1; /* Beginning with the first rule */ + else { + *rule_nr = strtol(argv, &buffer, 10); + if (*buffer != '\0' || *rule_nr == 0) + return -1; + } + if (!colon) + *rule_nr_end = *rule_nr; + return 0; +} + +/* 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) +{ + char *buffer; + int ret = 0; + + if (optind + 1 >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')) || + (argv[optind + 1][0] == '-' && (argv[optind + 1][1] < '0' && argv[optind + 1][1] > '9'))) + xtables_error(PARAMETER_PROBLEM, + "The command -C needs at least 2 arguments"); + if (optind + 2 < argc && (argv[optind + 2][0] != '-' || (argv[optind + 2][1] >= '0' && argv[optind + 2][1] <= '9'))) { + if (optind + 3 != argc) + xtables_error(PARAMETER_PROBLEM, + "No extra options allowed with -C start_nr[:end_nr] pcnt bcnt"); + if (parse_rule_range(argv[optind], rule_nr, rule_nr_end)) + xtables_error(PARAMETER_PROBLEM, + "Something is wrong with the rule number specification '%s'", argv[optind]); + optind++; + } + + if (argv[optind][0] == '+') { + if (exec_style == EXEC_STYLE_DAEMON) +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); + } 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); + } else + fw->counters.pcnt = strtoull(argv[optind], &buffer, 10); + + if (*buffer != '\0') + goto invalid; + optind++; + if (argv[optind][0] == '+') { + if (exec_style == EXEC_STYLE_DAEMON) + goto daemon_incr; + ret += 3; + fw->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); + } else + fw->counters.bcnt = strtoull(argv[optind], &buffer, 10); + + if (*buffer != '\0') + goto invalid; + optind++; + return ret; +invalid: + xtables_error(PARAMETER_PROBLEM,"Packet counter '%s' invalid", argv[optind]); +} + +static int parse_iface(char *iface, char *option) +{ + char *c; + + if ((c = strchr(iface, '+'))) { + if (*(c + 1) != '\0') { + xtables_error(PARAMETER_PROBLEM, + "Spurious characters after '+' wildcard for '%s'", option); + return -1; + } else + *c = IF_WILDCARD; + } + return 0; +} + +/* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */ +int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) +{ + char *buffer; + int c, i; + int zerochain = -1; /* Needed for the -Z option (we can have -Z -L ) */ + int chcounter = 0; /* Needed for -C */ + int rule_nr = 0; + int rule_nr_end = 0; + int ret = 0; + unsigned int flags = 0; + struct xtables_target *t; + struct xtables_ebt_entry fw; + char command = 'h'; + const char *chain = NULL; + const char *newname = NULL; + const char *policy = NULL; + int exec_style = EXEC_STYLE_PRG; + int selected_chain = -1; + + memset(&fw, 0, sizeof(fw)); + + if (nft_init(h, xtables_bridge) < 0) + xtables_error(OTHER_PROBLEM, + "Could not initialize nftables layer."); + + h->ops = nft_family_ops_lookup(h->family); + if (h->ops == NULL) + xtables_error(PARAMETER_PROBLEM, "Unknown family"); + + for (t = xtables_targets; t; t = t->next) { + t->tflags = 0; + t->used = 0; + } + + /* Getopt saves the day */ + while ((c = getopt_long(argc, argv, + "-A:D:C:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", ebt_options, NULL)) != -1) { + switch (c) { + + case 'A': /* Add a rule */ + case 'D': /* Delete a rule */ + case 'C': /* Change counters */ + case 'P': /* Define policy */ + case 'I': /* Insert a rule */ + case 'N': /* Make a user defined chain */ + case 'E': /* Rename chain */ + case 'X': /* Delete chain */ + /* We allow -N chainname -P policy */ + if (command == 'N' && c == 'P') { + command = c; + optind--; /* No table specified */ + goto handle_P; + } + if (OPT_COMMANDS) + xtables_error(PARAMETER_PROBLEM, + "Multiple commands are not allowed"); + + command = c; + chain = optarg; + selected_chain = get_current_chain(chain); + flags |= OPT_COMMAND; + /*if (!(replace->flags & OPT_KERNELDATA)) + ebt_get_kernel_table(replace, 0);*/ + /*if (optarg && (optarg[0] == '-' || !strcmp(optarg, "!"))) + ebt_print_error2("No chain name specified");*/ + if (c == 'N') { + ret = nft_chain_user_add(h, chain, *table); + break; + } else if (c == 'X') { + ret = nft_chain_user_del(h, chain, *table); + break; + } + + if (c == 'E') { + ret = nft_chain_user_rename(h, chain, *table, newname); + break; + } else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) { + if (optind != argc - 1) + xtables_error(PARAMETER_PROBLEM, + "No extra options allowed with -D start_nr[:end_nr]"); + if (parse_rule_range(argv[optind], &rule_nr, &rule_nr_end)) + xtables_error(PARAMETER_PROBLEM, + "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) + return -1; + } else if (c == 'I') { + if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9'))) + rule_nr = 1; + else { + rule_nr = parse_rule_number(argv[optind]); + optind++; + } + } else if (c == 'P') { +handle_P: + if (optind >= argc) + xtables_error(PARAMETER_PROBLEM, + "No policy specified"); + for (i = 0; i < NUM_STANDARD_TARGETS; i++) + if (!strcmp(argv[optind], ebt_standard_targets[i])) { + policy = argv[optind]; + printf("policy: %s\n", policy); + if (-i-1 == EBT_CONTINUE) + xtables_error(PARAMETER_PROBLEM, + "Wrong policy '%s'", + argv[optind]); + break; + } + if (i == NUM_STANDARD_TARGETS) + xtables_error(PARAMETER_PROBLEM, + "Unknown policy '%s'", argv[optind]); + optind++; + } + break; + case 'L': /* List */ + case 'F': /* Flush */ + case 'Z': /* Zero counters */ + if (c == 'Z') { + if ((flags & OPT_ZERO) || (flags & OPT_COMMAND && command != 'L')) +print_zero: + xtables_error(PARAMETER_PROBLEM, + "Command -Z only allowed together with command -L"); + flags |= OPT_ZERO; + } else { + if (flags & OPT_COMMAND) + xtables_error(PARAMETER_PROBLEM, + "Multiple commands are not allowed"); + command = c; + flags |= OPT_COMMAND; + if (flags & OPT_ZERO && c != 'L') + goto print_zero; + } + +#ifdef SILENT_DAEMON + if (c== 'L' && exec_style == EXEC_STYLE_DAEMON) + xtables_error(PARAMETER_PROBLEM, + "-L not supported in daemon mode"); +#endif + + /*if (!(replace->flags & OPT_KERNELDATA)) + ebt_get_kernel_table(replace, 0); + i = -1; + if (optind < argc && argv[optind][0] != '-') { + if ((i = ebt_get_chainnr(replace, argv[optind])) == -1) + ebt_print_error2("Chain '%s' doesn't exist", argv[optind]); + optind++; + } + if (i != -1) { + if (c == 'Z') + zerochain = i; + else + replace->selected_chain = i; + }*/ + break; + case 'V': /* Version */ + if (OPT_COMMANDS) + xtables_error(PARAMETER_PROBLEM, + "Multiple commands are not allowed"); + command = 'V'; + if (exec_style == EXEC_STYLE_DAEMON) + xtables_error(PARAMETER_PROBLEM, + "%s %s\n", prog_name, prog_vers); + printf("%s %s\n", prog_name, prog_vers); + exit(0); + case 'h': /* Help */ +#ifdef SILENT_DAEMON + if (exec_style == EXEC_STYLE_DAEMON) + xtables_error(PARAMETER_PROBLEM, + "-h not supported in daemon mode"); +#endif + if (OPT_COMMANDS) + xtables_error(PARAMETER_PROBLEM, + "Multiple commands are not allowed"); + command = 'h'; + + /* All other arguments should be extension names */ + while (optind < argc) { + /*struct ebt_u_match *m; + struct ebt_u_watcher *w;*/ + + if (!strcasecmp("list_extensions", argv[optind])) { + ebt_list_extensions(xtables_targets, fw.matches); + exit(0); + } + /*if ((m = ebt_find_match(argv[optind]))) + ebt_add_match(new_entry, m); + else if ((w = ebt_find_watcher(argv[optind]))) + ebt_add_watcher(new_entry, w); + else {*/ + if (!(t = xtables_find_target(argv[optind], XTF_TRY_LOAD))) + xtables_error(PARAMETER_PROBLEM,"Extension '%s' not found", argv[optind]); + 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; + //} + optind++; + } + break; + case 't': /* Table */ + if (OPT_COMMANDS) + xtables_error(PARAMETER_PROBLEM, + "Please put the -t option first"); + ebt_check_option2(&flags, OPT_TABLE); + if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1) + xtables_error(PARAMETER_PROBLEM, + "Table name length cannot exceed %d characters", + EBT_TABLE_MAXNAMELEN - 1); + *table = optarg; + break; + case 'i': /* Input interface */ + case 2 : /* Logical input interface */ + case 'o': /* Output interface */ + case 3 : /* Logical output interface */ + case 'j': /* Target */ + case 'p': /* Net family protocol */ + case 's': /* Source mac */ + case 'd': /* Destination mac */ + case 'c': /* Set counters */ + if (!OPT_COMMANDS) + xtables_error(PARAMETER_PROBLEM, + "No command specified"); + if (command != 'A' && command != 'D' && command != 'I' && command != 'C') + xtables_error(PARAMETER_PROBLEM, + "Command and option do not match"); + if (c == 'i') { + ebt_check_option2(&flags, OPT_IN); + if (selected_chain > 2 && selected_chain < NF_BR_BROUTING) + 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; + + 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); + break; + } else if (c == 2) { + ebt_check_option2(&flags, OPT_LOGICALIN); + if (selected_chain > 2 && selected_chain < NF_BR_BROUTING) + 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; + + if (strlen(optarg) >= IFNAMSIZ) + goto big_iface_length; + strcpy(fw.logical_in, optarg); + if (parse_iface(fw.logical_in, "--logical-in")) + return -1; + break; + } else if (c == 'o') { + ebt_check_option2(&flags, OPT_OUT); + if (selected_chain < 2 || selected_chain == NF_BR_BROUTING) + xtables_error(PARAMETER_PROBLEM, + "Use -o only in OUTPUT, FORWARD and POSTROUTING chains"); + if (ebt_check_inverse2(optarg, argc, argv)) + fw.invflags |= EBT_IOUT; + + if (strlen(optarg) >= IFNAMSIZ) + goto big_iface_length; + + xtables_parse_interface(optarg, fw.out, fw.out_mask); + break; + } else if (c == 3) { + ebt_check_option2(&flags, OPT_LOGICALOUT); + if (selected_chain < 2 || selected_chain == NF_BR_BROUTING) + 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; + + if (strlen(optarg) >= IFNAMSIZ) + goto big_iface_length; + strcpy(fw.logical_out, optarg); + if (parse_iface(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); + break; + } else if (c == 's') { + ebt_check_option2(&flags, OPT_SOURCE); + if (ebt_check_inverse2(optarg, argc, argv)) + fw.invflags |= EBT_ISOURCE; + + if (ebt_get_mac_and_mask(optarg, fw.sourcemac, fw.sourcemsk)) + xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg); + 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; + + if (ebt_get_mac_and_mask(optarg, fw.destmac, fw.destmsk)) + xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg); + fw.bitmask |= EBT_DESTMAC; + break; + } else if (c == 'c') { + ebt_check_option2(&flags, OPT_COUNT); + if (ebt_check_inverse2(optarg, argc, argv)) + xtables_error(PARAMETER_PROBLEM, + "Unexpected '!' after -c"); + if (optind >= argc || optarg[0] == '-' || argv[optind][0] == '-') + xtables_error(PARAMETER_PROBLEM, + "Option -c needs 2 arguments"); + + fw.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); + if (*buffer != '\0') + xtables_error(PARAMETER_PROBLEM, + "Packet counter '%s' invalid", + argv[optind]); + optind++; + break; + } + ebt_check_option2(&flags, OPT_PROTOCOL); + if (ebt_check_inverse2(optarg, argc, argv)) + fw.invflags |= EBT_IPROTO; + + fw.bitmask &= ~((unsigned int)EBT_NOPROTO); + i = strtol(optarg, &buffer, 16); + if (*buffer == '\0' && (i < 0 || i > 0xFFFF)) + xtables_error(PARAMETER_PROBLEM, + "Problem with the specified protocol"); + if (*buffer != '\0') { + struct ethertypeent *ent; + + if (!strcasecmp(optarg, "LENGTH")) { + 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; + } else + fw.ethproto = i; + + if (fw.ethproto < 0x0600) + xtables_error(PARAMETER_PROBLEM, + "Sorry, protocols have values above or equal to 0x0600"); + break; + case 4 : /* Lc */ +#ifdef SILENT_DAEMON + if (exec_style == EXEC_STYLE_DAEMON) + xtables_error(PARAMETER_PROBLEM, + "--Lc is not supported in daemon mode"); +#endif + ebt_check_option2(&flags, LIST_C); + if (command != 'L') + xtables_error(PARAMETER_PROBLEM, + "Use --Lc with -L"); + flags |= LIST_C; + break; + case 5 : /* Ln */ +#ifdef SILENT_DAEMON + if (exec_style == EXEC_STYLE_DAEMON) + xtables_error(PARAMETER_PROBLEM, + "--Ln is not supported in daemon mode"); +#endif + ebt_check_option2(&flags, LIST_N); + if (command != 'L') + xtables_error(PARAMETER_PROBLEM, + "Use --Ln with -L"); + if (flags & LIST_X) + xtables_error(PARAMETER_PROBLEM, + "--Lx is not compatible with --Ln"); + flags |= LIST_N; + break; + case 6 : /* Lx */ +#ifdef SILENT_DAEMON + if (exec_style == EXEC_STYLE_DAEMON) + xtables_error(PARAMETER_PROBLEM, + "--Lx is not supported in daemon mode"); +#endif + ebt_check_option2(&flags, LIST_X); + if (command != 'L') + xtables_error(PARAMETER_PROBLEM, + "Use --Lx with -L"); + if (flags & LIST_N) + xtables_error(PARAMETER_PROBLEM, + "--Lx is not compatible with --Ln"); + flags |= LIST_X; + break; + case 12 : /* Lmac2 */ +#ifdef SILENT_DAEMON + if (exec_style == EXEC_STYLE_DAEMON) + xtables_error(PARAMETER_PROBLEM, + "--Lmac2 is not supported in daemon mode"); +#endif + ebt_check_option2(&flags, LIST_MAC2); + if (command != 'L') + xtables_error(PARAMETER_PROBLEM, + "Use --Lmac2 with -L"); + flags |= LIST_MAC2; + break; + case 8 : /* atomic-commit */ +/* if (exec_style == EXEC_STYLE_DAEMON) + ebt_print_error2("--atomic-commit is not supported in daemon mode"); + replace->command = c; + if (OPT_COMMANDS) + ebt_print_error2("Multiple commands are not allowed"); + replace->flags |= OPT_COMMAND; + if (!replace->filename) + ebt_print_error2("No atomic file specified");*/ + /* Get the information from the file */ + /*ebt_get_table(replace, 0);*/ + /* We don't want the kernel giving us its counters, + * they would overwrite the counters extracted from + * the file */ + /*replace->num_counters = 0;*/ + /* Make sure the table will be written to the kernel */ + /*free(replace->filename); + replace->filename = NULL; + break;*/ + /*case 7 :*/ /* atomic-init */ + /*case 10:*/ /* atomic-save */ + /*case 11:*/ /* init-table */ + /* if (exec_style == EXEC_STYLE_DAEMON) { + if (c == 7) { + ebt_print_error2("--atomic-init is not supported in daemon mode"); + } else if (c == 10) + ebt_print_error2("--atomic-save is not supported in daemon mode"); + ebt_print_error2("--init-table is not supported in daemon mode"); + } + replace->command = c; + if (OPT_COMMANDS) + ebt_print_error2("Multiple commands are not allowed"); + if (c != 11 && !replace->filename) + ebt_print_error2("No atomic file specified"); + replace->flags |= OPT_COMMAND; + { + char *tmp = replace->filename;*/ + + /* Get the kernel table */ + /*replace->filename = NULL; + ebt_get_kernel_table(replace, c == 10 ? 0 : 1); + replace->filename = tmp; + } + break; + case 9 :*/ /* atomic */ + /*if (exec_style == EXEC_STYLE_DAEMON) + ebt_print_error2("--atomic is not supported in daemon mode"); + if (OPT_COMMANDS) + ebt_print_error2("--atomic has to come before the command");*/ + /* A possible memory leak here, but this is not + * executed in daemon mode */ + /*replace->filename = (char *)malloc(strlen(optarg) + 1); + strcpy(replace->filename, optarg); + break; + case 13 : *//* concurrent */ + /*signal(SIGINT, sighandler); + signal(SIGTERM, sighandler); + use_lockfd = 1; + break;*/ + case 1 : + if (!strcmp(optarg, "!")) + ebt_check_inverse2(optarg, argc, argv); + else + xtables_error(PARAMETER_PROBLEM, + "Bad argument : '%s'", optarg); + /* ebt_ebt_check_inverse2() did optind++ */ + optind--; + continue; + default: + /* Is it a target option? */ + /*t = (struct ebt_u_target *)new_entry->t; + if ((t->parse(c - t->option_offset, argv, argc, new_entry, &t->flags, &t->t))) { + if (ebt_errormsg[0] != '\0') + return -1; + goto check_extension; + }*/ + + /* Is it a match_option? */ + /*for (m = ebt_matches; m; m = m->next) + if (m->parse(c - m->option_offset, argv, argc, new_entry, &m->flags, &m->m)) + break; + + if (m != NULL) { + if (ebt_errormsg[0] != '\0') + return -1; + if (m->used == 0) { + ebt_add_match(new_entry, m); + m->used = 1; + } + goto check_extension; + }*/ + + /* Is it a watcher option? */ + /*for (w = ebt_watchers; w; w = w->next) + if (w->parse(c - w->option_offset, argv, argc, new_entry, &w->flags, &w->w)) + break; + + if (w == NULL && c == '?') + ebt_print_error2("Unknown argument: '%s'", argv[optind - 1], (char)optopt, (char)c); + else if (w == NULL) { + if (!strcmp(t->name, "standard")) + ebt_print_error2("Unknown argument: don't forget the -t option"); + else + ebt_print_error2("Target-specific option does not correspond with specified target"); + } + if (ebt_errormsg[0] != '\0') + return -1; + if (w->used == 0) { + ebt_add_watcher(new_entry, w); + w->used = 1; + } +check_extension: */ + if (command != 'A' && command != 'I' && + command != 'D' && command != 'C') + xtables_error(PARAMETER_PROBLEM, + "Extensions only for -A, -I, -D and -C"); + } + ebt_invert = 0; + } + + /* Just in case we didn't catch an error */ + /*if (ebt_errormsg[0] != '\0') + return -1; + + if (!(table = ebt_find_table(replace->name))) + ebt_print_error2("Bad table name");*/ + + if (command == 'h' && !(flags & OPT_ZERO)) { + print_help(fw.target, fw.matches, *table); + if (exec_style == EXEC_STYLE_PRG) + exit(0); + } + + /* Do the final checks */ + /*if (replace->command == 'A' || replace->command == 'I' || + replace->command == 'D' || replace->command == 'C') {*/ + /* This will put the hook_mask right for the chains */ + /*ebt_check_for_loops(replace); + if (ebt_errormsg[0] != '\0') + return -1; + entries = ebt_to_chain(replace); + m_l = new_entry->m_list; + w_l = new_entry->w_list; + t = (struct ebt_u_target *)new_entry->t; + while (m_l) { + m = (struct ebt_u_match *)(m_l->m); + m->final_check(new_entry, m->m, replace->name, + entries->hook_mask, 0); + if (ebt_errormsg[0] != '\0') + return -1; + m_l = m_l->next; + } + while (w_l) { + w = (struct ebt_u_watcher *)(w_l->w); + w->final_check(new_entry, w->w, replace->name, + entries->hook_mask, 0); + if (ebt_errormsg[0] != '\0') + return -1; + w_l = w_l->next; + } + t->final_check(new_entry, t->t, replace->name, + entries->hook_mask, 0); + if (ebt_errormsg[0] != '\0') + return -1; + }*/ + /* So, the extensions can work with the host endian. + * The kernel does not have to do this of course */ + fw.ethproto = htons(fw.ethproto); + + if (command == 'P') { + if (selected_chain < NF_BR_NUMHOOKS && strcmp(policy, "RETURN")==0) + xtables_error(PARAMETER_PROBLEM, + "Policy RETURN only allowed for user defined chains"); + ret = nft_chain_set(h, *table, chain, policy, NULL); + if (ret < 0) + xtables_error(PARAMETER_PROBLEM, "Wrong policy"); + } else if (command == 'L') { + ret = list_rules(h, chain, *table, rule_nr, + flags&OPT_VERBOSE, + flags&OPT_NUMERIC, + /*flags&OPT_EXPANDED*/0, + flags&LIST_N); + if (!(flags & OPT_ZERO) && exec_style == EXEC_STYLE_PRG) + exit(0); + } + if (flags & OPT_ZERO) { + selected_chain = zerochain; + ret = nft_chain_zero_counters(h, chain, *table); + } else if (command == 'F') { + ret = nft_rule_flush(h, chain, *table); + } else if (command == 'A') { + ret = append_entry(h, chain, *table, &fw, 0, + flags&OPT_VERBOSE, true); + } else if (command == 'I') { + ret = append_entry(h, chain, *table, &fw, rule_nr - 1, + flags&OPT_VERBOSE, false); + } else if (command == 'D') { + ret = delete_entry(h, chain, *table, &fw, 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); + if (ebt_errormsg[0] != '\0') + return -1; + }*/ + /* Commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save, + * --init-table fall through */ + + /*if (ebt_errormsg[0] != '\0') + return -1; + if (table->check) + table->check(replace); + + if (exec_style == EXEC_STYLE_PRG) {*//* Implies ebt_errormsg[0] == '\0' */ + /*ebt_deliver_table(replace); + + if (replace->nentries) + ebt_deliver_counters(replace);*/ + return ret; +} diff --git a/iptables/xtables-ebtables.h b/iptables/xtables-ebtables.h new file mode 100644 index 00000000..1e479b1b --- /dev/null +++ b/iptables/xtables-ebtables.h @@ -0,0 +1,49 @@ +#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 diff --git a/iptables/xtables-multi.c b/iptables/xtables-multi.c index 5f487355..30391e7f 100644 --- a/iptables/xtables-multi.c +++ b/iptables/xtables-multi.c @@ -43,6 +43,7 @@ static const struct subcommand multi_subcommands[] = { {"xtables-config", xtables_config_main}, {"xtables-events", xtables_events_main}, {"xtables-arp", xtables_arp_main}, + {"xtables-ebtables", xtables_eb_main}, #endif {NULL}, }; diff --git a/iptables/xtables-multi.h b/iptables/xtables-multi.h index e706894b..21e60b2b 100644 --- a/iptables/xtables-multi.h +++ b/iptables/xtables-multi.h @@ -10,6 +10,7 @@ extern int xtables_ip6_main(int, char **); extern int xtables_ip6_save_main(int, char **); extern int xtables_ip6_restore_main(int, char **); extern int xtables_arp_main(int, char **); +extern int xtables_eb_main(int, char **); extern int xtables_config_main(int, char **); extern int xtables_events_main(int, char **); #endif -- cgit v1.2.3 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 --- 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 ----------- 8 files changed, 252 insertions(+), 191 deletions(-) create mode 100644 iptables/nft-bridge.h delete mode 100644 iptables/xtables-ebtables.h (limited to 'iptables') 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 From 51e83a4deb4849152a29c160893f0823846d47a0 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Thu, 16 Oct 2014 16:29:51 +0200 Subject: ebtables-compat: fix print_header This prints the header like ebtables. Signed-off-by: Giuseppe Longo Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 9 +++++++-- iptables/nft-shared.h | 1 + iptables/nft.c | 3 +++ 3 files changed, 11 insertions(+), 2 deletions(-) (limited to 'iptables') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index ab97881d..0e21b468 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -357,13 +357,17 @@ static void print_iface(const char *iface) *c = IF_WILDCARD; } +static void nft_bridge_print_table_header(const char *tablename) +{ + printf("Bridge table: %s\n\n", tablename); +} + static void nft_bridge_print_header(unsigned int format, const char *chain, const char *pol, const struct xt_counters *counters, bool basechain, uint32_t refs) { - /* FIXME: Giuseppe replace this with ebtables format */ - print_header(format, chain, pol, counters, basechain, refs); + printf("Bridge chain: %s, entries: %u, policy: %s\n", chain, refs, pol); } static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, @@ -564,6 +568,7 @@ struct nft_family_ops nft_family_ops_bridge = { .parse_payload = nft_bridge_parse_payload, .parse_immediate = nft_bridge_parse_immediate, .parse_target = nft_bridge_parse_target, + .print_table_header = nft_bridge_print_table_header, .print_header = nft_bridge_print_header, .print_firewall = nft_bridge_print_firewall, .save_firewall = NULL, diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 361e9566..feef24f9 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -84,6 +84,7 @@ struct nft_family_ops { void *data); void (*parse_immediate)(const char *jumpto, bool nft_goto, void *data); + void (*print_table_header)(const char *tablename); void (*print_header)(unsigned int format, const char *chain, const char *pol, const struct xt_counters *counters, bool basechain, diff --git a/iptables/nft.c b/iptables/nft.c index 804ebe97..7cd56efa 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -2019,6 +2019,9 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, if (iter == NULL) goto err; + if (ops->print_table_header) + ops->print_table_header(table); + c = nft_chain_list_iter_next(iter); while (c != NULL) { const char *chain_table = -- cgit v1.2.3 From 04ff786c7a42f3ad16535fa5d7aa20346217917b Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Sat, 8 Nov 2014 22:40:37 +0100 Subject: nft-bridge: fix printing of inverted protocols, addresses Previous to this patch, no '!' is printed in payload comparisions. This patch solves it, so we can print for example inverted protocols: % ebtables-compat -L [...] -p ! 0x800 -j ACCEPT Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'iptables') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 0e21b468..3ed62398 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -268,15 +268,21 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, get_cmp_data(e, addr, sizeof(addr), &inv); for (i = 0; i < ETH_ALEN; i++) fw->destmac[i] = addr[i]; + if (inv) + fw->invflags |= EBT_IDEST; break; case offsetof(struct ethhdr, h_source): get_cmp_data(e, addr, sizeof(addr), &inv); for (i = 0; i < ETH_ALEN; i++) fw->sourcemac[i] = addr[i]; + if (inv) + fw->invflags |= EBT_ISOURCE; break; case offsetof(struct ethhdr, h_proto): get_cmp_data(e, ðproto, sizeof(ethproto), &inv); fw->ethproto = ethproto; + if (inv) + fw->invflags |= EBT_IPROTO; break; } } -- cgit v1.2.3 From 29b5492b339efe4635c18ac9f61873a590139c51 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Wed, 12 Nov 2014 17:10:25 +0100 Subject: nft-bridge: fix inversion of builtin matches This patch fixes inversion of builtin matches by updating the use of add_*() functions and using nft_invflags2cmp() as well. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 67 +++++++++++++++++++-------------------------------- 1 file changed, 25 insertions(+), 42 deletions(-) (limited to 'iptables') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 3ed62398..b5aec001 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -64,22 +64,6 @@ static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char } } -static uint8_t ebt_to_ipt_flags(uint16_t invflags) -{ - uint8_t result = 0; - - if (invflags & EBT_IIN) - result |= IPT_INV_VIA_IN; - - if (invflags & EBT_IOUT) - result |= IPT_INV_VIA_OUT; - - if (invflags & EBT_IPROTO) - result |= IPT_INV_PROTO; - - return result; -} - static uint16_t ipt_to_ebt_flags(uint8_t invflags) { uint16_t result = 0; @@ -96,18 +80,12 @@ static uint16_t ipt_to_ebt_flags(uint8_t invflags) return result; } -static void add_logical_iniface(struct nft_rule *r, char *iface, int invflags) +static void add_logical_iniface(struct nft_rule *r, char *iface, uint32_t op) { int iface_len; - uint32_t op; iface_len = strlen(iface); - if (invflags & EBT_ILOGICALIN) - op = NFT_CMP_NEQ; - else - op = NFT_CMP_EQ; - add_meta(r, NFT_META_BRI_IIFNAME); if (iface[iface_len - 1] == '+') add_cmp_ptr(r, op, iface, iface_len - 1); @@ -115,18 +93,12 @@ static void add_logical_iniface(struct nft_rule *r, char *iface, int invflags) add_cmp_ptr(r, op, iface, iface_len + 1); } -static void add_logical_outiface(struct nft_rule *r, char *iface, int invflags) +static void add_logical_outiface(struct nft_rule *r, char *iface, uint32_t op) { int iface_len; - uint32_t op; iface_len = strlen(iface); - if (invflags & EBT_ILOGICALOUT) - op = NFT_CMP_NEQ; - else - op = NFT_CMP_EQ; - add_meta(r, NFT_META_BRI_OIFNAME); if (iface[iface_len - 1] == '+') add_cmp_ptr(r, op, iface, iface_len - 1); @@ -164,36 +136,47 @@ static int nft_bridge_add(struct nft_rule *r, void *data) { struct ebtables_command_state *cs = data; struct ebt_entry *fw = &cs->fw; - uint8_t flags = ebt_to_ipt_flags(fw->invflags); + uint32_t op; char *addr; - if (fw->in[0] != '\0') - add_iniface(r, fw->in, flags); + if (fw->in[0] != '\0') { + op = nft_invflags2cmp(fw->invflags, EBT_IIN); + add_iniface(r, fw->in, op); + } - if (fw->out[0] != '\0') - add_outiface(r, fw->out, flags); + if (fw->out[0] != '\0') { + op = nft_invflags2cmp(fw->invflags, EBT_IOUT); + add_outiface(r, fw->out, op); + } - if (fw->logical_in[0] != '\0') - add_logical_iniface(r, fw->logical_in, flags); + if (fw->logical_in[0] != '\0') { + op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALIN); + add_logical_iniface(r, fw->logical_in, op); + } - if (fw->logical_out[0] != '\0') - add_logical_outiface(r, fw->logical_out, flags); + if (fw->logical_out[0] != '\0') { + op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALOUT); + add_logical_outiface(r, fw->logical_out, op); + } addr = ether_ntoa((struct ether_addr *) fw->sourcemac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { + op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE); add_payload(r, offsetof(struct ethhdr, h_source), 6); - add_cmp_ptr(r, NFT_CMP_EQ, fw->sourcemac, 6); + add_cmp_ptr(r, op, fw->sourcemac, 6); } addr = ether_ntoa((struct ether_addr *) fw->destmac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { + op = nft_invflags2cmp(fw->invflags, EBT_IDEST); add_payload(r, offsetof(struct ethhdr, h_dest), 6); - add_cmp_ptr(r, NFT_CMP_EQ, fw->destmac, 6); + add_cmp_ptr(r, op, fw->destmac, 6); } if (fw->ethproto != 0) { + op = nft_invflags2cmp(fw->invflags, EBT_IPROTO); add_payload(r, offsetof(struct ethhdr, h_proto), 2); - add_cmp_u16(r, fw->ethproto, NFT_CMP_EQ); + add_cmp_u16(r, fw->ethproto, op); } return _add_action(r, cs); -- cgit v1.2.3 From aadc93b1988a80a6b15dbefc57387fe65fb98870 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 17 Nov 2014 12:09:33 +0100 Subject: iptables: xtables-eb: delete extra 'policy' printf This message doesn't exist in the original ebtables tool. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/xtables-eb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'iptables') diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 99d930e5..917bca22 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -670,7 +670,6 @@ handle_P: for (i = 0; i < NUM_STANDARD_TARGETS; i++) if (!strcmp(argv[optind], ebt_standard_targets[i])) { policy = argv[optind]; - printf("policy: %s\n", policy); if (-i-1 == EBT_CONTINUE) xtables_error(PARAMETER_PROBLEM, "Wrong policy '%s'", -- cgit v1.2.3 From 4a48ec94c233a125a371eced5dc161df557576d9 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 24 Nov 2014 10:52:04 +0100 Subject: iptables: xtables-eb: user-defined chains default policy is always RETURN The RETURN default policy is mandatory in user-defined chains. Builtin chains must have one of ACCEPT or DROP. So, with this patch, ebtables-compat ends with: Command: Result: -L Always RETURN for user-defined chains -P builtin RETURN Policy RETURN only allowed for user defined chains -P builtin ACCEPT|DROP ok -P userdefined RETURN|ACCEPT|DROP Policy XYZ not allowed for user defined chains -N userdefined ok -N userdefined -P RETURN|ACCEPT|DROP Policy XYZ not allowed for user defined chains Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 3 ++- iptables/xtables-eb.c | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'iptables') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index b5aec001..a1bd9065 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -356,7 +356,8 @@ static void nft_bridge_print_header(unsigned int format, const char *chain, const struct xt_counters *counters, bool basechain, uint32_t refs) { - printf("Bridge chain: %s, entries: %u, policy: %s\n", chain, refs, pol); + printf("Bridge chain: %s, entries: %u, policy: %s\n", + chain, refs, basechain ? pol : "RETURN"); } static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 917bca22..47af78f9 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -616,6 +616,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) case 'E': /* Rename chain */ case 'X': /* Delete chain */ /* We allow -N chainname -P policy */ + /* XXX: Not in ebtables-compat */ if (command == 'N' && c == 'P') { command = c; optind--; /* No table specified */ @@ -1146,9 +1147,15 @@ check_extension: */ cs.fw.ethproto = htons(cs.fw.ethproto); if (command == 'P') { - if (selected_chain < NF_BR_NUMHOOKS && strcmp(policy, "RETURN")==0) + if (selected_chain < 0) { + xtables_error(PARAMETER_PROBLEM, + "Policy %s not allowed for user defined chains", + policy); + } + if (strcmp(policy, "RETURN") == 0) { xtables_error(PARAMETER_PROBLEM, "Policy RETURN only allowed for user defined chains"); + } ret = nft_chain_set(h, *table, chain, policy, NULL); if (ret < 0) xtables_error(PARAMETER_PROBLEM, "Wrong policy"); -- cgit v1.2.3 From 84b69ea462eb2159ce6bde83d6bcf2eac0098f87 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 24 Nov 2014 19:43:05 +0100 Subject: iptables: xtables-eb: fix renaming of chains Renaming of chains is not working. and ebtables-compat gets: libnftnl: attribute 0 assertion failed in chain.c:159 This patch brings back the parser code of the original ebtables tool: http://git.netfilter.org/ebtables.old-history/tree/userspace/ebtables2/ebtables.c#n652 I adapted the original parser code to fit in the new environment. Also tried to keep original error messages as much as possible. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/xtables-eb.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'iptables') diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 47af78f9..b924daf9 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -21,6 +21,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include @@ -32,6 +33,7 @@ #include #include +#include #include #include "xshared.h" #include "nft.h" @@ -582,7 +584,6 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) struct ebtables_command_state cs; char command = 'h'; const char *chain = NULL; - const char *newname = NULL; const char *policy = NULL; int exec_style = EXEC_STYLE_PRG; int selected_chain = -1; @@ -643,7 +644,21 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) } if (c == 'E') { - ret = nft_chain_user_rename(h, chain, *table, newname); + if (optind >= argc) + xtables_error(PARAMETER_PROBLEM, "No new chain name specified"); + else if (optind < argc - 1) + xtables_error(PARAMETER_PROBLEM, "No extra options allowed with -E"); + else if (strlen(argv[optind]) >= NFT_CHAIN_MAXNAMELEN) + xtables_error(PARAMETER_PROBLEM, "Chain name length can't exceed %d"" characters", NFT_CHAIN_MAXNAMELEN - 1); + else if (strchr(argv[optind], ' ') != NULL) + xtables_error(PARAMETER_PROBLEM, "Use of ' ' not allowed in chain names"); + + ret = nft_chain_user_rename(h, chain, *table, + argv[optind]); + if (ret != 0 && errno == ENOENT) + xtables_error(PARAMETER_PROBLEM, "Chain '%s' doesn't exists", chain); + + optind++; break; } else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) { if (optind != argc - 1) -- cgit v1.2.3 From 6aa7d1c26d0a3b0c909bbf13aa0ef6b179615433 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Wed, 17 Dec 2014 12:06:56 +0100 Subject: extensions: add ebt 802_3 extension This patch adds the first ebtables extension to ebtables-compat. The original 802_3 code is adapted to the xtables environment. I tried to mimic as much as possible the original ebtables code paths. With this patch, ebtables-compat is able to send the 802_3 match to the kernel, but the kernel-to-userspace path is not tested and should be adjusted in follow-up patches. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/Makefile.am | 4 +- iptables/nft-bridge.c | 6 ++ iptables/nft-bridge.h | 6 ++ iptables/xtables-eb-standalone.c | 32 ++---- iptables/xtables-eb.c | 208 ++++++++++++++++++++++++++++----------- 5 files changed, 171 insertions(+), 85 deletions(-) (limited to 'iptables') diff --git a/iptables/Makefile.am b/iptables/Makefile.am index b3e417bf..c66e5337 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -29,7 +29,7 @@ xtables_multi_LDADD += ../libxtables/libxtables.la -lm if ENABLE_NFTABLES xtables_compat_multi_SOURCES = xtables-compat-multi.c iptables-xml.c xtables_compat_multi_CFLAGS = ${AM_CFLAGS} -xtables_compat_multi_LDADD = ../extensions/libext.a +xtables_compat_multi_LDADD = ../extensions/libext.a ../extensions/libext_ebt.a if ENABLE_STATIC xtables_compat_multi_CFLAGS += -DALL_INCLUSIVE endif @@ -42,7 +42,7 @@ xtables_compat_multi_SOURCES += xtables-save.c xtables-restore.c \ xtables-arp-standalone.c xtables-arp.c \ getethertype.c nft-bridge.c \ xtables-eb-standalone.c xtables-eb.c -xtables_compat_multi_LDADD += ${libmnl_LIBS} ${libnftnl_LIBS} ../extensions/libext4.a ../extensions/libext6.a +xtables_compat_multi_LDADD += ${libmnl_LIBS} ${libnftnl_LIBS} ../extensions/libext4.a ../extensions/libext6.a ../extensions/libext_ebt.a # yacc and lex generate dirty code xtables_compat_multi-xtables-config-parser.o xtables_compat_multi-xtables-config-syntax.o: AM_CFLAGS += -Wno-missing-prototypes -Wno-missing-declarations -Wno-implicit-function-declaration -Wno-nested-externs -Wno-undef -Wno-redundant-decls xtables_compat_multi_SOURCES += xshared.c diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index a1bd9065..9772b5fe 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -135,6 +135,7 @@ static int _add_action(struct nft_rule *r, struct ebtables_command_state *cs) static int nft_bridge_add(struct nft_rule *r, void *data) { struct ebtables_command_state *cs = data; + struct xtables_rule_match *matchp; struct ebt_entry *fw = &cs->fw; uint32_t op; char *addr; @@ -179,6 +180,11 @@ static int nft_bridge_add(struct nft_rule *r, void *data) add_cmp_u16(r, fw->ethproto, op); } + for (matchp = cs->matches; matchp; matchp = matchp->next) { + if (add_match(r, matchp->match->m) < 0) + break; + } + return _add_action(r, cs); } diff --git a/iptables/nft-bridge.h b/iptables/nft-bridge.h index 1e3f0a16..fd8bc9f1 100644 --- a/iptables/nft-bridge.h +++ b/iptables/nft-bridge.h @@ -90,6 +90,12 @@ struct ebtables_command_state { struct xtables_rule_match *matches; const char *jumpto; struct xt_counters counters; + int invert; + int c; + char **argv; + int proto_used; + char *protocol; + unsigned int options; }; void nft_rule_to_ebtables_command_state(struct nft_rule *r, diff --git a/iptables/xtables-eb-standalone.c b/iptables/xtables-eb-standalone.c index 1c3cbf07..914d137b 100644 --- a/iptables/xtables-eb-standalone.c +++ b/iptables/xtables-eb-standalone.c @@ -36,22 +36,12 @@ #include #include #include +#include #include "nft.h" #include "xtables-multi.h" -extern struct xtables_globals xtables_globals; -extern const char *program_version, *program_name; - -static const struct xtables_afinfo afinfo_bridge = { - .kmod = "eb_tables", - .proc_exists = "/proc/net/eb_tables_names", - .libprefix = "libeb_", - .family = NFPROTO_BRIDGE, - .ipproto = IPPROTO_IP, - .so_rev_match = -1, - .so_rev_target = -1, -}; +extern struct xtables_globals ebtables_globals; int xtables_eb_main(int argc, char *argv[]) { @@ -61,24 +51,18 @@ int xtables_eb_main(int argc, char *argv[]) .family = NFPROTO_BRIDGE, }; - xtables_globals.program_name = "ebtables"; - /* This code below could be replaced by xtables_init_all, which - * doesn't support NFPROTO_BRIDGE yet. - */ - xtables_init(); - afinfo = &afinfo_bridge; - ret = xtables_set_params(&xtables_globals); + ebtables_globals.program_name = "ebtables"; + ret = xtables_init_all(&ebtables_globals, NFPROTO_BRIDGE); if (ret < 0) { - fprintf(stderr, "%s/%s Failed to initialize xtables\n", - xtables_globals.program_name, - xtables_globals.program_version); + fprintf(stderr, "%s/%s Failed to initialize ebtables-compat\n", + ebtables_globals.program_name, + ebtables_globals.program_version); exit(1); } #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) - init_extensions(); + init_extensionsb(); #endif - ret = do_commandeb(&h, argc, argv, &table); if (ret) ret = nft_commit(&h); diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index b924daf9..22ae4fdf 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -39,10 +40,6 @@ #include "nft.h" #include "nft-bridge.h" -extern struct xtables_globals xtables_globals; -#define prog_name xtables_globals.program_name -#define prog_vers xtables_globals.program_version - /* * From include/ebtables_u.h */ @@ -140,44 +137,6 @@ static int ebt_check_inverse2(const char option[], int argc, char **argv) return ebt_invert; } -/* - * From libebtc.c - */ - -/* The four target names, from libebtc.c */ -const char* ebt_standard_targets[NUM_STANDARD_TARGETS] = -{ - "ACCEPT", - "DROP", - "CONTINUE", - "RETURN", -}; - -/* Prints all registered extensions */ -static void ebt_list_extensions(const struct xtables_target *t, - const struct xtables_rule_match *m) -{ - printf("%s v%s\n", prog_name, prog_vers); - printf("Loaded userspace extensions:\n"); - /*printf("\nLoaded tables:\n"); - while (tbl) { - printf("%s\n", tbl->name); - tbl = tbl->next; - }*/ - printf("\nLoaded targets:\n"); - for (t = xtables_targets; t; t = t->next) { - printf("%s\n", t->name); - } - printf("\nLoaded matches:\n"); - for (; m != NULL; m = m->next) - printf("%s\n", m->match->name); - /*printf("\nLoaded watchers:\n"); - while (w) { - printf("%s\n", w->name); - w = w->next; - }*/ -} - /* * Glue code to use libxtables */ @@ -341,8 +300,92 @@ static struct option ebt_original_options[] = { 0 } }; +void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); + static struct option *ebt_options = ebt_original_options; +struct xtables_globals ebtables_globals = { + .option_offset = 0, + .program_version = IPTABLES_VERSION, + .orig_opts = ebt_original_options, + .exit_err = xtables_exit_error, + .compat_rev = nft_compatible_revision, +}; + +#define opts ebtables_globals.opts +#define prog_name ebtables_globals.program_name +#define prog_vers ebtables_globals.program_version + +/* + * From libebtc.c + */ + +/* The four target names, from libebtc.c */ +const char* ebt_standard_targets[NUM_STANDARD_TARGETS] = +{ + "ACCEPT", + "DROP", + "CONTINUE", + "RETURN", +}; + +/* Prints all registered extensions */ +static void ebt_list_extensions(const struct xtables_target *t, + const struct xtables_rule_match *m) +{ + printf("%s v%s\n", prog_name, prog_vers); + printf("Loaded userspace extensions:\n"); + /*printf("\nLoaded tables:\n"); + while (tbl) { + printf("%s\n", tbl->name); + tbl = tbl->next; + }*/ + printf("\nLoaded targets:\n"); + for (t = xtables_targets; t; t = t->next) { + printf("%s\n", t->name); + } + printf("\nLoaded matches:\n"); + for (; m != NULL; m = m->next) + printf("%s\n", m->match->name); + /*printf("\nLoaded watchers:\n"); + while (w) { + printf("%s\n", w->name); + w = w->next; + }*/ +} + +#define OPTION_OFFSET 256 +static struct option *merge_options(struct option *oldopts, + const struct option *newopts, + unsigned int *options_offset) +{ + unsigned int num_old, num_new, i; + struct option *merge; + + if (!newopts || !oldopts || !options_offset) + xtables_error(OTHER_PROBLEM, "merge wrong"); + for (num_old = 0; oldopts[num_old].name; num_old++); + for (num_new = 0; newopts[num_new].name; num_new++); + + ebtables_globals.option_offset += OPTION_OFFSET; + *options_offset = ebtables_globals.option_offset; + + merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); + if (!merge) + return NULL; + memcpy(merge, oldopts, num_old * sizeof(struct option)); + for (i = 0; i < num_new; i++) { + merge[num_old + i] = newopts[i]; + merge[num_old + i].val += *options_offset; + } + memset(merge + num_old + num_new, 0, sizeof(struct option)); + /* Only free dynamically allocated stuff */ + if (oldopts != ebt_original_options) + free(oldopts); + + return merge; +} + /* * More glue code. */ @@ -370,11 +413,11 @@ static struct xtables_target *command_jump(struct ebtables_command_state *cs, xs_init_target(target); if (target->x6_options != NULL) - ebt_options = xtables_options_xfrm(xtables_globals.orig_opts, + ebt_options = xtables_options_xfrm(ebtables_globals.orig_opts, ebt_options, target->x6_options, &target->option_offset); else - ebt_options = xtables_merge_options(xtables_globals.orig_opts, + ebt_options = xtables_merge_options(ebtables_globals.orig_opts, ebt_options, target->extra_opts, &target->option_offset); @@ -569,6 +612,42 @@ static int parse_iface(char *iface, char *option) return 0; } +/* This code is very similar to iptables/xtables.c:command_match() */ +static void ebt_load_match(const char *name) +{ + struct xtables_match *m; + size_t size; + opts = ebt_original_options; + + m = xtables_find_match(name, XTF_LOAD_MUST_SUCCEED, NULL); + if (m == NULL) + xtables_error(OTHER_PROBLEM, "Unable to load %s match", name); + + size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size; + m->m = xtables_calloc(1, size); + m->m->u.match_size = size; + strcpy(m->m->u.user.name, m->name); + m->m->u.user.revision = m->revision; + xs_init_match(m); + + opts = merge_options(opts, m->extra_opts, &m->option_offset); + if (opts == NULL) + xtables_error(OTHER_PROBLEM, "Can't alloc memory"); +} + +static void ebt_load_matches(void) +{ + ebt_load_match("802_3"); +} + +static void ebt_add_match(struct xtables_match *m, + struct xtables_rule_match **rule_matches) +{ + if (xtables_find_match(m->name, XTF_LOAD_MUST_SUCCEED, rule_matches) == NULL) + xtables_error(OTHER_PROBLEM, + "Unable to add match %s", m->name); +} + /* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) { @@ -581,6 +660,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_match *m; struct ebtables_command_state cs; char command = 'h'; const char *chain = NULL; @@ -589,6 +669,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) int selected_chain = -1; memset(&cs, 0, sizeof(cs)); + cs.argv = argv; if (nft_init(h, xtables_bridge) < 0) xtables_error(OTHER_PROBLEM, @@ -598,14 +679,30 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) if (h->ops == NULL) xtables_error(PARAMETER_PROBLEM, "Unknown family"); + /* manually registering ebt matches, given the original ebtables parser + * don't use '-m matchname' and the match can't loaded dinamically when + * the user calls it. + */ + ebt_load_matches(); + + /* clear mflags in case do_commandeb gets called a second time + * (we clear the global list of all matches for security)*/ + for (m = xtables_matches; m; m = m->next) + m->mflags = 0; + for (t = xtables_targets; t; t = t->next) { t->tflags = 0; t->used = 0; } + /* prevent getopt to spoil our error reporting */ + opterr = false; + /* Getopt saves the day */ while ((c = getopt_long(argc, argv, - "-A:D:C:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", ebt_options, NULL)) != -1) { + "-A:D:C:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) { + cs.c = c; + cs.invert = ebt_invert; switch (c) { case 'A': /* Add a rule */ @@ -1070,19 +1167,12 @@ big_iface_length: }*/ /* Is it a match_option? */ - /*for (m = ebt_matches; m; m = m->next) - if (m->parse(c - m->option_offset, argv, argc, new_entry, &m->flags, &m->m)) - break; - - if (m != NULL) { - if (ebt_errormsg[0] != '\0') - return -1; - if (m->used == 0) { - ebt_add_match(new_entry, m); - m->used = 1; + for (m = xtables_matches; m; m = m->next) { + if (m->parse(c - m->option_offset, argv, ebt_invert, &m->mflags, NULL, &m->m)) { + ebt_add_match(m, &cs.matches); + goto check_extension; } - goto check_extension; - }*/ + } /* Is it a watcher option? */ /*for (w = ebt_watchers; w; w = w->next) @@ -1102,8 +1192,8 @@ big_iface_length: if (w->used == 0) { ebt_add_watcher(new_entry, w); w->used = 1; - } -check_extension: */ + }*/ +check_extension: if (command != 'A' && command != 'I' && command != 'D' && command != 'C') xtables_error(PARAMETER_PROBLEM, -- cgit v1.2.3 From 0e65c922fc0d51a8dff1a779863d4ae559aa9a4a Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Tue, 23 Dec 2014 13:24:26 +0100 Subject: ebtables-compat: fix counter listing With this patch: % sudo ebtables-compat -L --Lc Bridge table: filter Bridge chain: INPUT, entries: 0, policy: ACCEPT -j ACCEPT , pcnt = 123 -- bcnt = 123 Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 5 +++++ iptables/xtables-eb.c | 12 +++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'iptables') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 9772b5fe..807c4da0 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -470,6 +471,10 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, } } + if (!(format & FMT_NOCOUNTS)) + printf(" , pcnt = %"PRIu64" -- bcnt = %"PRIu64"", + (uint64_t)cs.counters.pcnt, (uint64_t)cs.counters.bcnt); + if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); } diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 22ae4fdf..d0f6a3e3 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -486,14 +486,12 @@ static void print_help(const struct xtables_target *t, /* Execute command L */ static int list_rules(struct nft_handle *h, const char *chain, const char *table, int rule_nr, int verbose, int numeric, int expanded, - int linenumbers) + int linenumbers, int counters) { unsigned int format; format = FMT_OPTIONS; - if (!verbose) - format |= FMT_NOCOUNTS; - else + if (verbose) format |= FMT_VIA; if (numeric) @@ -505,6 +503,9 @@ static int list_rules(struct nft_handle *h, const char *chain, const char *table if (linenumbers) format |= FMT_LINENUMBERS; + if (!counters) + format |= FMT_NOCOUNTS; + return nft_rule_list(h, chain, table, rule_nr, format); } @@ -1269,7 +1270,8 @@ check_extension: flags&OPT_VERBOSE, flags&OPT_NUMERIC, /*flags&OPT_EXPANDED*/0, - flags&LIST_N); + flags&LIST_N, + flags&LIST_C); if (!(flags & OPT_ZERO) && exec_style == EXEC_STYLE_PRG) exit(0); } -- cgit v1.2.3 From 42cfeee024d0ba0c6b15645f829273ee3dcfa5c6 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Fri, 26 Dec 2014 13:49:52 +0100 Subject: ebtables-compat: fix printing of extension This patch fix printing of ebt extensions: % sudo ebtables-compat -L [...] Bridge chain: FORWARD, entries: 1, policy: ACCEPT --802_3-type 0x0012 -j ACCEPT [...] Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 23 +++++++---------------- iptables/nft-bridge.h | 1 + iptables/nft-shared.c | 18 +++++++++++++++++- 3 files changed, 25 insertions(+), 17 deletions(-) (limited to 'iptables') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 807c4da0..90bcd63d 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -370,6 +370,7 @@ static void nft_bridge_print_header(unsigned int format, const char *chain, static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, unsigned int format) { + struct xtables_rule_match *matchp; struct ebtables_command_state cs = {}; char *addr; @@ -443,23 +444,13 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, print_iface(cs.fw.out); } - /* old code to adapt - m_l = hlp->m_list; - while (m_l) { - m = ebt_find_match(m_l->m->u.name); - if (!m) - ebt_print_bug("Match not found"); - m->print(hlp, m_l->m); - m_l = m_l->next; + for (matchp = cs.matches; matchp; matchp = matchp->next) { + if (matchp->match->print != NULL) { + matchp->match->print(&cs.fw, matchp->match->m, + format & FMT_NUMERIC); + } } - w_l = hlp->w_list; - while (w_l) { - w = ebt_find_watcher(w_l->w->u.name); - if (!w) - ebt_print_bug("Watcher not found"); - w->print(hlp, w_l->w); - w_l = w_l->next; - }*/ + printf("-j "); if (!(format & FMT_NOTARGET)) printf("%s", cs.jumpto); diff --git a/iptables/nft-bridge.h b/iptables/nft-bridge.h index fd8bc9f1..83575432 100644 --- a/iptables/nft-bridge.h +++ b/iptables/nft-bridge.h @@ -4,6 +4,7 @@ #include //#include #include +#include /* We use replace->flags, so we can't use the following values: * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO */ diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 71c44763..dd1dfca2 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -26,6 +26,7 @@ #include #include "nft-shared.h" +#include "nft-bridge.h" #include "xshared.h" #include "nft.h" @@ -326,9 +327,24 @@ void nft_parse_match(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) const char *mt_name = nft_rule_expr_get_str(e, NFT_EXPR_MT_NAME); const void *mt_info = nft_rule_expr_get(e, NFT_EXPR_MT_INFO, &mt_len); struct xtables_match *match; + struct xtables_rule_match **matches; struct xt_entry_match *m; - match = xtables_find_match(mt_name, XTF_TRY_LOAD, &ctx->state.cs->matches); + switch (ctx->family) { + case NFPROTO_IPV4: + case NFPROTO_IPV6: + matches = &ctx->state.cs->matches; + break; + case NFPROTO_BRIDGE: + matches = &ctx->state.cs_eb->matches; + break; + default: + fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n", + ctx->family); + exit(EXIT_FAILURE); + } + + match = xtables_find_match(mt_name, XTF_TRY_LOAD, matches); if (match == NULL) return; -- cgit v1.2.3 From bc543af074cf4372162eb330b914d2b0fdb6b6c7 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 5 Jan 2015 15:28:46 +0100 Subject: ebtables-compat: fix segfault in rules w/o target This patch fixes a segfault in rules without target. Now, these two rules are allowed: % ebtables-compat -A FORWARD -p 0x0600 -j CONTINUE % ebtables-compat -A FORWARD -p 0x0600 And both are printed: Bridge chain: FORWARD, entries: 1, policy: ACCEPT -p 0x600 -j CONTINUE Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'iptables') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 90bcd63d..fd9554eb 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -114,6 +114,9 @@ static int _add_action(struct nft_rule *r, struct ebtables_command_state *cs) { int ret = 0; + if (cs->jumpto == NULL || strcmp(cs->jumpto, "CONTINUE") == 0) + return 0; + /* If no target at all, add nothing (default to continue) */ if (cs->target != NULL) { /* Standard target? */ @@ -452,14 +455,16 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, } printf("-j "); - if (!(format & FMT_NOTARGET)) - printf("%s", cs.jumpto); - if (cs.target != NULL) { if (cs.target->print != NULL) { cs.target->print(&cs.fw, cs.target->t, format & FMT_NUMERIC); } + } else { + if (strcmp(cs.jumpto, "") == 0) + printf("CONTINUE"); + else + printf("%s", cs.jumpto); } if (!(format & FMT_NOCOUNTS)) -- cgit v1.2.3 From 457ed5e1231cf433b239fd10ccf3d976805eb4d8 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Tue, 13 Jan 2015 18:36:10 +0100 Subject: ebtables-compat: fix ACCEPT printing by simplifying logic The commit bc543af ("ebtables-compat: fix segfault in rules w/o target") doesn't handle all possible cases of target printing, and ACCEPT is left behind. BTW, the logic of target (-j XXX) printing is a bit weird. This patch simplifies it. I assume: * cs->jumpto is only filled by nft_immediate. * cs->target is only filled by nft_target. So we end with these cases: * nft_immediate contains a 'standard' target (ACCEPT, DROP, CONTINUE, RETURN, chain) Then cs->jumpto contains the target already. We have the rule. * No standard target. If nft_target contains a target, try to load it. * Neither nft_target nor nft_immediate exist. Then, assume CONTINUE. The printing path is then straight forward: either cs.jumpto or cs.target contains the target. As there isn't support for target extensions yet, there is no way to test the nft_target (cs.target) path. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'iptables') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index fd9554eb..9747405e 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -337,12 +337,13 @@ void nft_rule_to_ebtables_command_state(struct nft_rule *r, nft_rule_expr_iter_destroy(iter); - if (cs->target != NULL) - cs->jumpto = cs->target->name; - else if (cs->jumpto != NULL) - cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); + if (cs->jumpto != NULL) + return; + + if (cs->target != NULL && cs->target->name != NULL) + cs->target = xtables_find_target(cs->target->name, XTF_TRY_LOAD); else - cs->jumpto = ""; + cs->jumpto = "CONTINUE"; } static void print_iface(const char *iface) @@ -455,17 +456,11 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, } printf("-j "); - if (cs.target != NULL) { - if (cs.target->print != NULL) { - cs.target->print(&cs.fw, cs.target->t, - format & FMT_NUMERIC); - } - } else { - if (strcmp(cs.jumpto, "") == 0) - printf("CONTINUE"); - else - printf("%s", cs.jumpto); - } + + if (cs.jumpto != NULL) + printf("%s", cs.jumpto); + else if (cs.target != NULL && cs.target->print != NULL) + cs.target->print(&cs.fw, cs.target->t, format & FMT_NUMERIC); if (!(format & FMT_NOCOUNTS)) printf(" , pcnt = %"PRIu64" -- bcnt = %"PRIu64"", -- cgit v1.2.3 From 4143a08819a076507abaee0ee18e291b65e5997c Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 19 Jan 2015 14:27:41 +0100 Subject: ebtables-compat: add nft rule compat information to bridge rules The compat information is required by some ebtables extensions to properly work. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'iptables') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 9747405e..af67a5af 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -184,6 +184,8 @@ static int nft_bridge_add(struct nft_rule *r, void *data) add_cmp_u16(r, fw->ethproto, op); } + add_compat(r, fw->ethproto, fw->invflags); + for (matchp = cs->matches; matchp; matchp = matchp->next) { if (add_match(r, matchp->match->m) < 0) break; -- cgit v1.2.3 From 16331e1a3f592a6cb2d5e8eb64ea2e112d997e97 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 19 Jan 2015 14:27:46 +0100 Subject: ebtables-compat: prevent options overwrite Parsing options will be overwritten if every time we load a match the extension options are merged to the original options. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/xtables-eb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'iptables') diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index d0f6a3e3..b559a533 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -618,7 +618,6 @@ static void ebt_load_match(const char *name) { struct xtables_match *m; size_t size; - opts = ebt_original_options; m = xtables_find_match(name, XTF_LOAD_MUST_SUCCEED, NULL); if (m == NULL) @@ -638,6 +637,7 @@ static void ebt_load_match(const char *name) static void ebt_load_matches(void) { + opts = ebt_original_options; ebt_load_match("802_3"); } -- cgit v1.2.3 From c5c011a13395ceab661eb2d5774487e1215ca9e7 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 19 Jan 2015 14:27:51 +0100 Subject: ebtables-compat: prevent same matches to be included multiple times Using two matches options results in two copies of the match being included in the nft rule. Example before this patch: % ebtables-compat -A FORWARD -p 0x0800 --ip-src 10.0.0.1 --ip-dst 10.0.0.2 -j ACCEPT % ebtables-compat -L [...] -p 0x0800 --ip-src 10.0.0.1 --ip-dst 10.0.0.2 --ip-src 10.0.0.1 --ip-dst 10.0.0.2 -j ACCEPT Example with this patch: % ebtables-compat -A FORWARD -p 0x0800 --ip-src 10.0.0.1 --ip-dst 10.0.0.2 -j ACCEPT % ebtables-compat -L [...] % -p 0x0800 --ip-src 10.0.0.1 --ip-dst 10.0.0.2 -j ACCEPT [Note: the br_ip extension comes in a follow-up patch] Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/xtables-eb.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'iptables') diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index b559a533..a0786794 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -644,6 +644,14 @@ static void ebt_load_matches(void) static void ebt_add_match(struct xtables_match *m, struct xtables_rule_match **rule_matches) { + struct xtables_rule_match *i; + + /* match already in rule_matches, skip inclusion */ + for (i = *rule_matches; i; i = i->next) { + if (strcmp(m->name, i->match->name) == 0) + return; + } + if (xtables_find_match(m->name, XTF_LOAD_MUST_SUCCEED, rule_matches) == NULL) xtables_error(OTHER_PROBLEM, "Unable to add match %s", m->name); -- cgit v1.2.3 From cd414abfd21dae0288f53669672f057c0630c78a Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 19 Jan 2015 14:27:57 +0100 Subject: ebtables-compat: include rule counters in ebtables rules Counters are missing in ebtables rules. This patch includes them just before the target, so counters are incremented when the rule is about to take his action. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'iptables') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index af67a5af..3ef13570 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -191,6 +191,9 @@ static int nft_bridge_add(struct nft_rule *r, void *data) break; } + if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0) + return -1; + return _add_action(r, cs); } -- cgit v1.2.3 From 8acf8315a44fbee8227433daabb262b6de1e70f6 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 19 Jan 2015 14:28:02 +0100 Subject: ebtables-compat: fix nft payload bases ebtables should use NFT_PAYLOAD_LL_HEADER to fetch basic payload information from packets in the bridge family. Let's allow the add_payload() function to know in which base it should work. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-arp.c | 15 ++++++++++----- iptables/nft-bridge.c | 9 ++++++--- iptables/nft-ipv4.c | 3 ++- iptables/nft-shared.c | 9 ++++----- iptables/nft-shared.h | 2 +- 5 files changed, 23 insertions(+), 15 deletions(-) (limited to 'iptables') diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index b10b45f1..24b31c5a 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -156,13 +156,15 @@ static int nft_arp_add(struct nft_rule *r, void *data) if (fw->arp.arhrd != 0) { op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPHRD); - add_payload(r, offsetof(struct arphdr, ar_hrd), 2); + add_payload(r, offsetof(struct arphdr, ar_hrd), 2, + NFT_PAYLOAD_NETWORK_HEADER); add_cmp_u16(r, fw->arp.arhrd, op); } if (fw->arp.arpro != 0) { op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPPRO); - add_payload(r, offsetof(struct arphdr, ar_pro), 2); + add_payload(r, offsetof(struct arphdr, ar_pro), 2, + NFT_PAYLOAD_NETWORK_HEADER); add_cmp_u16(r, fw->arp.arpro, op); } @@ -176,13 +178,15 @@ static int nft_arp_add(struct nft_rule *r, void *data) if (fw->arp.arpop != 0) { op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPOP); - add_payload(r, offsetof(struct arphdr, ar_op), 2); + add_payload(r, offsetof(struct arphdr, ar_op), 2, + NFT_PAYLOAD_NETWORK_HEADER); add_cmp_u16(r, fw->arp.arpop, op); } if (fw->arp.src_devaddr.addr[0] != '\0') { op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_SRCDEVADDR); - add_payload(r, sizeof(struct arphdr), fw->arp.arhln); + add_payload(r, sizeof(struct arphdr), fw->arp.arhln, + NFT_PAYLOAD_NETWORK_HEADER); add_cmp_ptr(r, op, fw->arp.src_devaddr.addr, fw->arp.arhln); } @@ -195,7 +199,8 @@ static int nft_arp_add(struct nft_rule *r, void *data) if (fw->arp.tgt_devaddr.addr[0] != '\0') { op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_TGTDEVADDR); - add_payload(r, sizeof(struct arphdr) + fw->arp.arhln + 4, fw->arp.arhln); + add_payload(r, sizeof(struct arphdr) + fw->arp.arhln + 4, + fw->arp.arhln, NFT_PAYLOAD_NETWORK_HEADER); add_cmp_ptr(r, op, fw->arp.tgt_devaddr.addr, fw->arp.arhln); } diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 3ef13570..62aab041 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -167,20 +167,23 @@ static int nft_bridge_add(struct nft_rule *r, void *data) addr = ether_ntoa((struct ether_addr *) fw->sourcemac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE); - add_payload(r, offsetof(struct ethhdr, h_source), 6); + add_payload(r, offsetof(struct ethhdr, h_source), 6, + NFT_PAYLOAD_LL_HEADER); add_cmp_ptr(r, op, fw->sourcemac, 6); } addr = ether_ntoa((struct ether_addr *) fw->destmac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { op = nft_invflags2cmp(fw->invflags, EBT_IDEST); - add_payload(r, offsetof(struct ethhdr, h_dest), 6); + add_payload(r, offsetof(struct ethhdr, h_dest), 6, + NFT_PAYLOAD_LL_HEADER); add_cmp_ptr(r, op, fw->destmac, 6); } if (fw->ethproto != 0) { op = nft_invflags2cmp(fw->invflags, EBT_IPROTO); - add_payload(r, offsetof(struct ethhdr, h_proto), 2); + add_payload(r, offsetof(struct ethhdr, h_proto), 2, + NFT_PAYLOAD_LL_HEADER); add_cmp_u16(r, fw->ethproto, op); } diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 1b0dc2a1..ed309207 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -60,7 +60,8 @@ static int nft_ipv4_add(struct nft_rule *r, void *data) sizeof(struct in_addr), op); } if (cs->fw.ip.flags & IPT_F_FRAG) { - add_payload(r, offsetof(struct iphdr, frag_off), 2); + add_payload(r, offsetof(struct iphdr, frag_off), 2, + NFT_PAYLOAD_NETWORK_HEADER); /* get the 13 bits that contain the fragment offset */ add_bitwise_u16(r, 0x1fff, !0x1fff); diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index dd1dfca2..76984e81 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -49,7 +49,7 @@ void add_meta(struct nft_rule *r, uint32_t key) nft_rule_add_expr(r, expr); } -void add_payload(struct nft_rule *r, int offset, int len) +void add_payload(struct nft_rule *r, int offset, int len, uint32_t base) { struct nft_rule_expr *expr; @@ -57,8 +57,7 @@ void add_payload(struct nft_rule *r, int offset, int len) if (expr == NULL) return; - nft_rule_expr_set_u32(expr, NFT_EXPR_PAYLOAD_BASE, - NFT_PAYLOAD_NETWORK_HEADER); + nft_rule_expr_set_u32(expr, NFT_EXPR_PAYLOAD_BASE, base); nft_rule_expr_set_u32(expr, NFT_EXPR_PAYLOAD_DREG, NFT_REG_1); nft_rule_expr_set_u32(expr, NFT_EXPR_PAYLOAD_OFFSET, offset); nft_rule_expr_set_u32(expr, NFT_EXPR_PAYLOAD_LEN, len); @@ -161,7 +160,7 @@ void add_outiface(struct nft_rule *r, char *iface, uint32_t op) void add_addr(struct nft_rule *r, int offset, void *data, void *mask, size_t len, uint32_t op) { - add_payload(r, offset, len); + add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER); add_bitwise(r, mask, len); add_cmp_ptr(r, op, data, len); @@ -170,7 +169,7 @@ void add_addr(struct nft_rule *r, int offset, void add_proto(struct nft_rule *r, int offset, size_t len, uint8_t proto, uint32_t op) { - add_payload(r, offset, len); + add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER); add_cmp_u8(r, proto, op); } diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index feef24f9..33582aaa 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -103,7 +103,7 @@ struct nft_family_ops { }; void add_meta(struct nft_rule *r, uint32_t key); -void add_payload(struct nft_rule *r, int offset, int len); +void add_payload(struct nft_rule *r, int offset, int len, uint32_t base); void add_bitwise_u16(struct nft_rule *r, int mask, int xor); void add_cmp_ptr(struct nft_rule *r, uint32_t op, void *data, size_t len); void add_cmp_u8(struct nft_rule *r, uint8_t val, uint32_t op); -- cgit v1.2.3 From 49479aa12a158001bf1e4104b248e533f5038cf3 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 19 Jan 2015 14:28:07 +0100 Subject: ebtables-compat: add 'ip' match extension This patch adds the 'ip' match extension to ebtables-compat. It involves adapting old ebtables extension code to the xtables-compat environment. For testing: % sudo ebtables-compat -p 0x0800 --ip-src 1.1.1.1 -j ACCEPT The patch includes a cached copy of the extension kernel header. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/xtables-eb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'iptables') diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index a0786794..27a1c168 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -639,6 +639,7 @@ static void ebt_load_matches(void) { opts = ebt_original_options; ebt_load_match("802_3"); + ebt_load_match("ip"); } static void ebt_add_match(struct xtables_match *m, -- cgit v1.2.3 From 535ede97cd78a10ea4aaad249a6576fbf37aebc3 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Fri, 30 Jan 2015 12:43:08 +0100 Subject: ebtables-compat: add mark_m match extension Translate mark_m match extension to the xtables-compat environment. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/xtables-eb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'iptables') diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 27a1c168..0ac39d0f 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -640,6 +640,7 @@ static void ebt_load_matches(void) opts = ebt_original_options; ebt_load_match("802_3"); ebt_load_match("ip"); + ebt_load_match("mark_m"); } static void ebt_add_match(struct xtables_match *m, -- cgit v1.2.3 From 936e65d472ca9f9bc64bff835d00877a3c6e2d17 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Tue, 3 Feb 2015 16:26:39 +0100 Subject: ebtables-compat: call extensions final checks Let's call extensions final checks. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/xtables-eb.c | 50 +++++++++++++++++--------------------------------- 1 file changed, 17 insertions(+), 33 deletions(-) (limited to 'iptables') diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 0ac39d0f..c30a2e53 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -647,16 +647,22 @@ static void ebt_add_match(struct xtables_match *m, struct xtables_rule_match **rule_matches) { struct xtables_rule_match *i; + struct xtables_match *newm; /* match already in rule_matches, skip inclusion */ for (i = *rule_matches; i; i = i->next) { - if (strcmp(m->name, i->match->name) == 0) + if (strcmp(m->name, i->match->name) == 0) { + i->match->mflags |= m->mflags; return; + } } - if (xtables_find_match(m->name, XTF_LOAD_MUST_SUCCEED, rule_matches) == NULL) + newm = xtables_find_match(m->name, XTF_LOAD_MUST_SUCCEED, rule_matches); + if (newm == NULL) xtables_error(OTHER_PROBLEM, "Unable to add match %s", m->name); + + newm->mflags = m->mflags; } /* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */ @@ -678,6 +684,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) const char *policy = NULL; int exec_style = EXEC_STYLE_PRG; int selected_chain = -1; + struct xtables_rule_match *xtrm_i; memset(&cs, 0, sizeof(cs)); cs.argv = argv; @@ -1227,37 +1234,14 @@ check_extension: } /* Do the final checks */ - /*if (replace->command == 'A' || replace->command == 'I' || - replace->command == 'D' || replace->command == 'C') {*/ - /* This will put the hook_mask right for the chains */ - /*ebt_check_for_loops(replace); - if (ebt_errormsg[0] != '\0') - return -1; - entries = ebt_to_chain(replace); - m_l = new_entry->m_list; - w_l = new_entry->w_list; - t = (struct ebt_u_target *)new_entry->t; - while (m_l) { - m = (struct ebt_u_match *)(m_l->m); - m->final_check(new_entry, m->m, replace->name, - entries->hook_mask, 0); - if (ebt_errormsg[0] != '\0') - return -1; - m_l = m_l->next; - } - while (w_l) { - w = (struct ebt_u_watcher *)(w_l->w); - w->final_check(new_entry, w->w, replace->name, - entries->hook_mask, 0); - if (ebt_errormsg[0] != '\0') - return -1; - w_l = w_l->next; - } - t->final_check(new_entry, t->t, replace->name, - entries->hook_mask, 0); - if (ebt_errormsg[0] != '\0') - return -1; - }*/ + if (command == 'A' || command == 'I' || + command == 'D' || command == 'C') { + for (xtrm_i = cs.matches; xtrm_i; xtrm_i = xtrm_i->next) + xtables_option_mfcall(xtrm_i->match); + + if (cs.target != NULL) + xtables_option_tfcall(cs.target); + } /* So, the extensions can work with the host endian. * The kernel does not have to do this of course */ cs.fw.ethproto = htons(cs.fw.ethproto); -- cgit v1.2.3 From db0e29a96982806c98eb5525e2b5edf48935c857 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Tue, 3 Feb 2015 17:58:17 +0100 Subject: ebtables-compat: finish target infrastructure Signed-off-by: Arturo Borrero Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++ iptables/xtables-eb.c | 57 +++++++++++++++------------------------------------ 2 files changed, 70 insertions(+), 40 deletions(-) (limited to 'iptables') diff --git a/iptables/nft-bridge.h b/iptables/nft-bridge.h index 83575432..cd63c11a 100644 --- a/iptables/nft-bridge.h +++ b/iptables/nft-bridge.h @@ -4,7 +4,9 @@ #include //#include #include +#include #include +#include /* We use replace->flags, so we can't use the following values: * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO */ @@ -62,6 +64,12 @@ int ebt_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mas #define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \ | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST) +/* 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 + /* Fake ebt_entry */ struct ebt_entry { /* this needs to be the first field */ @@ -102,4 +110,49 @@ struct ebtables_command_state { void nft_rule_to_ebtables_command_state(struct nft_rule *r, struct ebtables_command_state *cs); +static const char *ebt_standard_targets[NUM_STANDARD_TARGETS] = { + "ACCEPT", + "DROP", + "CONTINUE", + "RETURN", +}; + +static inline const char *nft_ebt_standard_target(unsigned int num) +{ + if (num > NUM_STANDARD_TARGETS) + return NULL; + + return ebt_standard_targets[num]; +} + +static inline int ebt_fill_target(const char *str, unsigned int *verdict) +{ + int i, ret = 0; + + for (i = 0; i < NUM_STANDARD_TARGETS; i++) { + if (!strcmp(str, nft_ebt_standard_target(i))) { + *verdict = -i - 1; + break; + } + } + + if (i == NUM_STANDARD_TARGETS) + ret = 1; + + return ret; +} + +static inline const char *ebt_target_name(unsigned int verdict) +{ + return nft_ebt_standard_target(-verdict - 1); +} + +#define EBT_CHECK_OPTION(flags, mask) ({ \ + if (*flags & mask) \ + xtables_error(PARAMETER_PROBLEM, \ + "Multiple use of same " \ + "option not allowed"); \ + *flags |= mask; \ +}) \ + #endif diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index c30a2e53..db1717c9 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -21,6 +21,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include @@ -36,6 +37,7 @@ #include #include #include +#include #include "xshared.h" #include "nft.h" #include "nft-bridge.h" @@ -46,6 +48,8 @@ #define EXEC_STYLE_PRG 0 #define EXEC_STYLE_DAEMON 1 +#define ebt_check_option2(flags, mask) EBT_CHECK_OPTION(flags, mask) + /* * From useful_functions.c */ @@ -105,19 +109,6 @@ int ebt_get_mac_and_mask(const char *from, unsigned char *to, return 0; } -/* This is a replacement for the ebt_check_option2() macro. - * - * Make sure the same option wasn't specified twice. This is used in the parse - * functions of the extensions and ebtables.c. - */ -static void ebt_check_option2(unsigned int *flags, unsigned int mask) -{ - if (*flags & mask) - xtables_error(PARAMETER_PROBLEM, - "Multiple use of same option not allowed"); - *flags |= mask; -} - static int ebt_check_inverse2(const char option[], int argc, char **argv) { if (!option) @@ -302,8 +293,6 @@ static struct option ebt_original_options[] = void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); -static struct option *ebt_options = ebt_original_options; - struct xtables_globals ebtables_globals = { .option_offset = 0, .program_version = IPTABLES_VERSION, @@ -320,15 +309,6 @@ struct xtables_globals ebtables_globals = { * From libebtc.c */ -/* The four target names, from libebtc.c */ -const char* ebt_standard_targets[NUM_STANDARD_TARGETS] = -{ - "ACCEPT", - "DROP", - "CONTINUE", - "RETURN", -}; - /* Prints all registered extensions */ static void ebt_list_extensions(const struct xtables_target *t, const struct xtables_rule_match *m) @@ -363,7 +343,7 @@ static struct option *merge_options(struct option *oldopts, struct option *merge; if (!newopts || !oldopts || !options_offset) - xtables_error(OTHER_PROBLEM, "merge wrong"); + return oldopts; for (num_old = 0; oldopts[num_old].name; num_old++); for (num_new = 0; newopts[num_new].name; num_new++); @@ -412,14 +392,9 @@ static struct xtables_target *command_jump(struct ebtables_command_state *cs, xs_init_target(target); - if (target->x6_options != NULL) - ebt_options = xtables_options_xfrm(ebtables_globals.orig_opts, - ebt_options, target->x6_options, - &target->option_offset); - else - ebt_options = xtables_merge_options(ebtables_globals.orig_opts, - ebt_options, target->extra_opts, - &target->option_offset); + opts = merge_options(opts, target->extra_opts, &target->option_offset); + if (opts == NULL) + xtables_error(OTHER_PROBLEM, "Can't alloc memory"); return target; } @@ -799,7 +774,7 @@ handle_P: xtables_error(PARAMETER_PROBLEM, "No policy specified"); for (i = 0; i < NUM_STANDARD_TARGETS; i++) - if (!strcmp(argv[optind], ebt_standard_targets[i])) { + if (!strcmp(argv[optind], nft_ebt_standard_target(i))) { policy = argv[optind]; if (-i-1 == EBT_CONTINUE) xtables_error(PARAMETER_PROBLEM, @@ -1177,12 +1152,14 @@ big_iface_length: continue; default: /* Is it a target option? */ - /*t = (struct ebt_u_target *)new_entry->t; - if ((t->parse(c - t->option_offset, argv, argc, new_entry, &t->flags, &t->t))) { - if (ebt_errormsg[0] != '\0') - return -1; - goto check_extension; - }*/ + if (cs.target != NULL && cs.target->parse != NULL) { + int opt_offset = cs.target->option_offset; + if (cs.target->parse(c - opt_offset, + argv, ebt_invert, + &cs.target->tflags, + NULL, &cs.target->t)) + goto check_extension; + } /* Is it a match_option? */ for (m = xtables_matches; m; m = m->next) { -- cgit v1.2.3 From fe97f60e5d2a968638286036db67e3a4e17f095d Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 9 Feb 2015 13:16:12 +0100 Subject: ebtables-compat: add watchers support ebtables watchers are targets which always return EBT_CONTINUE. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 86 ++++++++++++++++++++++++++++++++++++----- iptables/nft-bridge.h | 13 +++++++ iptables/nft-shared.c | 5 +++ iptables/nft-shared.h | 1 + iptables/xtables-eb.c | 104 +++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 190 insertions(+), 19 deletions(-) (limited to 'iptables') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 62aab041..e3ab667f 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -22,6 +22,21 @@ #include "nft-bridge.h" #include "nft.h" +void ebt_cs_clean(struct ebtables_command_state *cs) +{ + struct ebt_match *m, *nm; + + xtables_rule_matches_free(&cs->matches); + + for (m = cs->match_list; m;) { + nm = m->next; + if (!m->ismatch) + free(m->u.watcher->t); + free(m); + m = nm; + } +} + /* 0: default, print only 2 digits if necessary * 2: always print 2 digits, a printed mac address * then always has the same length @@ -139,7 +154,7 @@ static int _add_action(struct nft_rule *r, struct ebtables_command_state *cs) static int nft_bridge_add(struct nft_rule *r, void *data) { struct ebtables_command_state *cs = data; - struct xtables_rule_match *matchp; + struct ebt_match *iter; struct ebt_entry *fw = &cs->fw; uint32_t op; char *addr; @@ -189,9 +204,14 @@ static int nft_bridge_add(struct nft_rule *r, void *data) add_compat(r, fw->ethproto, fw->invflags); - for (matchp = cs->matches; matchp; matchp = matchp->next) { - if (add_match(r, matchp->match->m) < 0) - break; + for (iter = cs->match_list; iter; iter = iter->next) { + if (iter->ismatch) { + if (add_match(r, iter->u.match->m)) + break; + } else { + if (add_target(r, iter->u.watcher->t)) + break; + } } if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0) @@ -296,10 +316,44 @@ static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto, cs->jumpto = jumpto; } +static void parse_watcher(void *object, struct ebt_match **match_list, + bool ismatch) +{ + struct ebt_match *m; + + m = calloc(1, sizeof(struct ebt_match)); + if (m == NULL) + xtables_error(OTHER_PROBLEM, "Can't allocate memory"); + + if (ismatch) + m->u.match = object; + else + m->u.watcher = object; + + m->ismatch = ismatch; + if (*match_list == NULL) + *match_list = m; + else + (*match_list)->next = m; +} + +static void nft_bridge_parse_match(struct xtables_match *m, void *data) +{ + struct ebtables_command_state *cs = data; + + parse_watcher(m, &cs->match_list, true); +} + static void nft_bridge_parse_target(struct xtables_target *t, void *data) { struct ebtables_command_state *cs = data; + /* harcoded names :-( */ + if (strcmp(t->name, "log") == 0) { + parse_watcher(t, &cs->match_list, false); + return; + } + cs->target = t; } @@ -382,7 +436,9 @@ static void nft_bridge_print_header(unsigned int format, const char *chain, static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, unsigned int format) { - struct xtables_rule_match *matchp; + struct xtables_match *matchp; + struct xtables_target *watcherp; + struct ebt_match *m; struct ebtables_command_state cs = {}; char *addr; @@ -456,10 +512,19 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, print_iface(cs.fw.out); } - for (matchp = cs.matches; matchp; matchp = matchp->next) { - if (matchp->match->print != NULL) { - matchp->match->print(&cs.fw, matchp->match->m, - format & FMT_NUMERIC); + for (m = cs.match_list; m; m = m->next) { + if (m->ismatch) { + matchp = m->u.match; + if (matchp->print != NULL) { + matchp->print(&cs.fw, matchp->m, + format & FMT_NUMERIC); + } + } else { + watcherp = m->u.watcher; + if (watcherp->print != NULL) { + watcherp->print(&cs.fw, watcherp->t, + format & FMT_NUMERIC); + } } } @@ -476,6 +541,8 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); + + ebt_cs_clean(&cs); } static bool nft_bridge_is_same(const void *data_a, const void *data_b) @@ -567,6 +634,7 @@ 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_match = nft_bridge_parse_match, .parse_target = nft_bridge_parse_target, .print_table_header = nft_bridge_print_table_header, .print_header = nft_bridge_print_header, diff --git a/iptables/nft-bridge.h b/iptables/nft-bridge.h index cd63c11a..1c4a96ea 100644 --- a/iptables/nft-bridge.h +++ b/iptables/nft-bridge.h @@ -93,10 +93,21 @@ struct ebt_entry { unsigned char out_mask[IFNAMSIZ]; }; +/* trick for ebtables-compat, since watchers are targets */ +struct ebt_match { + struct ebt_match *next; + union { + struct xtables_match *match; + struct xtables_target *watcher; + } u; + bool ismatch; +}; + struct ebtables_command_state { struct ebt_entry fw; struct xtables_target *target; struct xtables_rule_match *matches; + struct ebt_match *match_list; const char *jumpto; struct xt_counters counters; int invert; @@ -155,4 +166,6 @@ static inline const char *ebt_target_name(unsigned int verdict) *flags |= mask; \ }) \ +void ebt_cs_clean(struct ebtables_command_state *cs); + #endif diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 76984e81..620da3e7 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -328,6 +328,7 @@ void nft_parse_match(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) struct xtables_match *match; struct xtables_rule_match **matches; struct xt_entry_match *m; + struct nft_family_ops *ops; switch (ctx->family) { case NFPROTO_IPV4: @@ -359,6 +360,10 @@ void nft_parse_match(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) strcpy(m->u.user.name, match->name); match->m = m; + + ops = nft_family_ops_lookup(ctx->family); + if (ops->parse_match != NULL) + ops->parse_match(match, nft_get_data(ctx)); } void print_proto(uint16_t proto, int invert) diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 33582aaa..fbce5b5d 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -97,6 +97,7 @@ struct nft_family_ops { struct xtables_args *args); void (*post_parse)(int command, struct iptables_command_state *cs, struct xtables_args *args); + void (*parse_match)(struct xtables_match *m, void *data); void (*parse_target)(struct xtables_target *t, void *data); bool (*rule_find)(struct nft_family_ops *ops, struct nft_rule *r, void *data); diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index db1717c9..efbb3cd0 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -610,19 +610,49 @@ static void ebt_load_match(const char *name) xtables_error(OTHER_PROBLEM, "Can't alloc memory"); } -static void ebt_load_matches(void) +static void ebt_load_watcher(const char *name) +{ + struct xtables_target *watcher; + size_t size; + + watcher = xtables_find_target(name, XTF_LOAD_MUST_SUCCEED); + if (!watcher) + xtables_error(OTHER_PROBLEM, + "Unable to load %s watcher", name); + + size = XT_ALIGN(sizeof(struct xt_entry_target)) + watcher->size; + + watcher->t = xtables_calloc(1, size); + watcher->t->u.target_size = size; + strncpy(watcher->t->u.user.name, name, + sizeof(watcher->t->u.user.name)); + watcher->t->u.user.name[sizeof(watcher->t->u.user.name)-1] = '\0'; + watcher->t->u.user.revision = watcher->revision; + + xs_init_target(watcher); + + opts = merge_options(opts, watcher->extra_opts, + &watcher->option_offset); + if (opts == NULL) + xtables_error(OTHER_PROBLEM, "Can't alloc memory"); +} + +static void ebt_load_match_extensions(void) { opts = ebt_original_options; ebt_load_match("802_3"); ebt_load_match("ip"); ebt_load_match("mark_m"); + + ebt_load_watcher("log"); } static void ebt_add_match(struct xtables_match *m, - struct xtables_rule_match **rule_matches) + struct ebtables_command_state *cs) { - struct xtables_rule_match *i; + struct xtables_rule_match *i, **rule_matches = &cs->matches; struct xtables_match *newm; + struct ebt_match *newnode; /* match already in rule_matches, skip inclusion */ for (i = *rule_matches; i; i = i->next) { @@ -638,6 +668,45 @@ static void ebt_add_match(struct xtables_match *m, "Unable to add match %s", m->name); newm->mflags = m->mflags; + + /* glue code for watchers */ + newnode = calloc(1, sizeof(struct ebt_match)); + if (newnode == NULL) + xtables_error(OTHER_PROBLEM, "Unable to alloc memory"); + + newnode->ismatch = true; + newnode->u.match = newm; + + if (cs->match_list == NULL) + cs->match_list = newnode; + else + cs->match_list->next = newnode; +} + +static void ebt_add_watcher(struct xtables_target *watcher, + struct ebtables_command_state *cs) +{ + struct ebt_match *i, *newnode; + + for (i = cs->match_list; i; i = i->next) { + if (i->ismatch) + continue; + if (strcmp(i->u.watcher->name, watcher->name) == 0) { + i->u.watcher->tflags |= watcher->tflags; + return; + } + } + + newnode = calloc(1, sizeof(struct ebt_match)); + if (newnode == NULL) + xtables_error(OTHER_PROBLEM, "Unable to alloc memory"); + + newnode->u.watcher = watcher; + + if (cs->match_list == NULL) + cs->match_list = newnode; + else + cs->match_list->next = newnode; } /* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */ @@ -651,7 +720,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) int rule_nr_end = 0; int ret = 0; unsigned int flags = 0; - struct xtables_target *t; + struct xtables_target *t, *w; struct xtables_match *m; struct ebtables_command_state cs; char command = 'h'; @@ -660,6 +729,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) int exec_style = EXEC_STYLE_PRG; int selected_chain = -1; struct xtables_rule_match *xtrm_i; + struct ebt_match *match; memset(&cs, 0, sizeof(cs)); cs.argv = argv; @@ -676,7 +746,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) * don't use '-m matchname' and the match can't loaded dinamically when * the user calls it. */ - ebt_load_matches(); + ebt_load_match_extensions(); /* clear mflags in case do_commandeb gets called a second time * (we clear the global list of all matches for security)*/ @@ -1164,16 +1234,21 @@ big_iface_length: /* Is it a match_option? */ for (m = xtables_matches; m; m = m->next) { if (m->parse(c - m->option_offset, argv, ebt_invert, &m->mflags, NULL, &m->m)) { - ebt_add_match(m, &cs.matches); + ebt_add_match(m, &cs); goto check_extension; } } /* Is it a watcher option? */ - /*for (w = ebt_watchers; w; w = w->next) - if (w->parse(c - w->option_offset, argv, argc, new_entry, &w->flags, &w->w)) - break; - + for (w = xtables_targets; w; w = w->next) { + if (w->parse(c - w->option_offset, argv, + ebt_invert, &w->tflags, + NULL, &w->t)) { + ebt_add_watcher(w, &cs); + goto check_extension; + } + } + /* if (w == NULL && c == '?') ebt_print_error2("Unknown argument: '%s'", argv[optind - 1], (char)optopt, (char)c); else if (w == NULL) { @@ -1216,6 +1291,13 @@ check_extension: for (xtrm_i = cs.matches; xtrm_i; xtrm_i = xtrm_i->next) xtables_option_mfcall(xtrm_i->match); + for (match = cs.match_list; match; match = match->next) { + if (match->ismatch) + continue; + + xtables_option_tfcall(match->u.watcher); + } + if (cs.target != NULL) xtables_option_tfcall(cs.target); } @@ -1278,5 +1360,7 @@ check_extension: if (replace->nentries) ebt_deliver_counters(replace);*/ + + ebt_cs_clean(&cs); return ret; } -- cgit v1.2.3