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 --- include/ebtables/ethernetdb.h | 58 ++ include/linux/netfilter_bridge.h | 33 + include/linux/netfilter_bridge/ebtables.h | 276 +++++++ 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 + 16 files changed, 2503 insertions(+), 9 deletions(-) create mode 100644 include/ebtables/ethernetdb.h create mode 100644 include/linux/netfilter_bridge.h create mode 100644 include/linux/netfilter_bridge/ebtables.h 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 diff --git a/include/ebtables/ethernetdb.h b/include/ebtables/ethernetdb.h new file mode 100644 index 00000000..46d8bfd1 --- /dev/null +++ b/include/ebtables/ethernetdb.h @@ -0,0 +1,58 @@ +/* +* 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 +*/ + +/* All data returned by the network data base library are supplied in + host order and returned in network order (suitable for use in + system calls). */ + +#ifndef _ETHERNETDB_H +#define _ETHERNETDB_H 1 + +#include +#include +#include + +/* Absolute file name for network data base files. */ +#ifndef _PATH_ETHERTYPES +#define _PATH_ETHERTYPES "/etc/ethertypes" +#endif /* _PATH_ETHERTYPES */ + +struct ethertypeent { + char *e_name; /* Official ethernet type name. */ + char **e_aliases; /* Alias list. */ + int e_ethertype; /* Ethernet type number. */ +}; + +/* Open ethertype data base files and mark them as staying open even + after a later search if STAY_OPEN is non-zero. */ +extern void setethertypeent(int __stay_open) __THROW; + +/* Close ethertype data base files and clear `stay open' flag. */ +extern void endethertypeent(void) __THROW; + +/* Get next entry from ethertype data base file. Open data base if + necessary. */ +extern struct ethertypeent *getethertypeent(void) __THROW; + +/* Return entry from ethertype data base for network with NAME. */ +extern struct ethertypeent *getethertypebyname(__const char *__name) + __THROW; + +/* Return entry from ethertype data base which number is PROTO. */ +extern struct ethertypeent *getethertypebynumber(int __ethertype) __THROW; + + +#endif /* ethernetdb.h */ diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h new file mode 100644 index 00000000..71e9299b --- /dev/null +++ b/include/linux/netfilter_bridge.h @@ -0,0 +1,33 @@ +#ifndef __LINUX_BRIDGE_NETFILTER_H +#define __LINUX_BRIDGE_NETFILTER_H + +/* bridge-specific defines for netfilter. + */ +#include + +/* Bridge Hooks */ +/* After promisc drops, checksum checks. */ +#define NF_BR_PRE_ROUTING 0 +/* If the packet is destined for this box. */ +#define NF_BR_LOCAL_IN 1 +/* If the packet is destined for another interface. */ +#define NF_BR_FORWARD 2 +/* Packets coming from a local process. */ +#define NF_BR_LOCAL_OUT 3 +/* Packets about to hit the wire. */ +#define NF_BR_POST_ROUTING 4 +/* Not really a hook, but used for the ebtables broute table */ +#define NF_BR_BROUTING 5 +#define NF_BR_NUMHOOKS 6 + +enum nf_br_hook_priorities { + NF_BR_PRI_FIRST = INT_MIN, + NF_BR_PRI_FILTER_BRIDGED = -200, + NF_BR_PRI_FILTER_OTHER = 200, + NF_BR_PRI_NAT_DST_BRIDGED = -300, + NF_BR_PRI_NAT_DST_OTHER = 100, + NF_BR_PRI_NAT_SRC = 300, + NF_BR_PRI_LAST = INT_MAX, +}; + +#endif diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h new file mode 100644 index 00000000..f7ed1dcf --- /dev/null +++ b/include/linux/netfilter_bridge/ebtables.h @@ -0,0 +1,276 @@ +/* + * ebtables + * + * Authors: + * Bart De Schuymer + * + * ebtables.c,v 2.0, April, 2002 + * + * This code is stongly inspired on the iptables code which is + * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling + */ + +/* Local copy of the kernel file, needed for Sparc64 support */ +#ifndef __LINUX_BRIDGE_EFF_H +#define __LINUX_BRIDGE_EFF_H +#include +#include +#include + +#define EBT_TABLE_MAXNAMELEN 32 +#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN +#define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN + +/* verdicts >0 are "branches" */ +#define EBT_ACCEPT -1 +#define EBT_DROP -2 +#define EBT_CONTINUE -3 +#define EBT_RETURN -4 +#define NUM_STANDARD_TARGETS 4 +/* ebtables target modules store the verdict inside an int. We can + * reclaim a part of this int for backwards compatible extensions. + * The 4 lsb are more than enough to store the verdict. */ +#define EBT_VERDICT_BITS 0x0000000F + +struct ebt_counter +{ + uint64_t pcnt; + uint64_t bcnt; +}; + +struct ebt_replace +{ + char name[EBT_TABLE_MAXNAMELEN]; + unsigned int valid_hooks; + /* nr of rules in the table */ + unsigned int nentries; + /* total size of the entries */ + unsigned int entries_size; + /* start of the chains */ +#ifdef KERNEL_64_USERSPACE_32 + uint64_t hook_entry[NF_BR_NUMHOOKS]; +#else + struct ebt_entries *hook_entry[NF_BR_NUMHOOKS]; +#endif + /* nr of counters userspace expects back */ + unsigned int num_counters; + /* where the kernel will put the old counters */ +#ifdef KERNEL_64_USERSPACE_32 + uint64_t counters; + uint64_t entries; +#else + struct ebt_counter *counters; + char *entries; +#endif +}; + +struct ebt_entries { + /* this field is always set to zero + * See EBT_ENTRY_OR_ENTRIES. + * Must be same size as ebt_entry.bitmask */ + unsigned int distinguisher; + /* the chain name */ + char name[EBT_CHAIN_MAXNAMELEN]; + /* counter offset for this chain */ + unsigned int counter_offset; + /* one standard (accept, drop, return) per hook */ + int policy; + /* nr. of entries */ + unsigned int nentries; + /* entry list */ + char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); +}; + +/* used for the bitmask of struct ebt_entry */ + +/* This is a hack to make a difference between an ebt_entry struct and an + * ebt_entries struct when traversing the entries from start to end. + * Using this simplifies the code alot, while still being able to use + * ebt_entries. + * Contrary, iptables doesn't use something like ebt_entries and therefore uses + * different techniques for naming the policy and such. So, iptables doesn't + * need a hack like this. + */ +#define EBT_ENTRY_OR_ENTRIES 0x01 +/* these are the normal masks */ +#define EBT_NOPROTO 0x02 +#define EBT_802_3 0x04 +#define EBT_SOURCEMAC 0x08 +#define EBT_DESTMAC 0x10 +#define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \ + | EBT_ENTRY_OR_ENTRIES) + +#define EBT_IPROTO 0x01 +#define EBT_IIN 0x02 +#define EBT_IOUT 0x04 +#define EBT_ISOURCE 0x8 +#define EBT_IDEST 0x10 +#define EBT_ILOGICALIN 0x20 +#define EBT_ILOGICALOUT 0x40 +#define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \ + | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST) + +struct ebt_entry_match +{ + union { + char name[EBT_FUNCTION_MAXNAMELEN]; + struct ebt_match *match; + } u; + /* size of data */ + unsigned int match_size; +#ifdef KERNEL_64_USERSPACE_32 + unsigned int pad; +#endif + unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); +}; + +struct ebt_entry_watcher +{ + union { + char name[EBT_FUNCTION_MAXNAMELEN]; + struct ebt_watcher *watcher; + } u; + /* size of data */ + unsigned int watcher_size; +#ifdef KERNEL_64_USERSPACE_32 + unsigned int pad; +#endif + unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); +}; + +struct ebt_entry_target +{ + union { + char name[EBT_FUNCTION_MAXNAMELEN]; + struct ebt_target *target; + } u; + /* size of data */ + unsigned int target_size; +#ifdef KERNEL_64_USERSPACE_32 + unsigned int pad; +#endif + unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); +}; + +#define EBT_STANDARD_TARGET "standard" +struct ebt_standard_target +{ + struct ebt_entry_target target; + int verdict; +#ifdef KERNEL_64_USERSPACE_32 + unsigned int pad; +#endif +}; + +/* one entry */ +struct ebt_entry { + /* this needs to be the first field */ + unsigned int bitmask; + unsigned int invflags; + uint16_t ethproto; + /* the physical in-dev */ + char in[IFNAMSIZ]; + /* the logical in-dev */ + char logical_in[IFNAMSIZ]; + /* the physical out-dev */ + char out[IFNAMSIZ]; + /* the logical out-dev */ + char logical_out[IFNAMSIZ]; + unsigned char sourcemac[ETH_ALEN]; + unsigned char sourcemsk[ETH_ALEN]; + unsigned char destmac[ETH_ALEN]; + unsigned char destmsk[ETH_ALEN]; + /* sizeof ebt_entry + matches */ + unsigned int watchers_offset; + /* sizeof ebt_entry + matches + watchers */ + unsigned int target_offset; + /* sizeof ebt_entry + matches + watchers + target */ + unsigned int next_offset; + unsigned char elems[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); +}; + +/* {g,s}etsockopt numbers */ +#define EBT_BASE_CTL 128 + +#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL) +#define EBT_SO_SET_COUNTERS (EBT_SO_SET_ENTRIES+1) +#define EBT_SO_SET_MAX (EBT_SO_SET_COUNTERS+1) + +#define EBT_SO_GET_INFO (EBT_BASE_CTL) +#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO+1) +#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES+1) +#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO+1) +#define EBT_SO_GET_MAX (EBT_SO_GET_INIT_ENTRIES+1) + +/* blatently stolen from ip_tables.h + * fn returns 0 to continue iteration */ +#define EBT_MATCH_ITERATE(e, fn, args...) \ +({ \ + unsigned int __i; \ + int __ret = 0; \ + struct ebt_entry_match *__match; \ + \ + for (__i = sizeof(struct ebt_entry); \ + __i < (e)->watchers_offset; \ + __i += __match->match_size + \ + sizeof(struct ebt_entry_match)) { \ + __match = (void *)(e) + __i; \ + \ + __ret = fn(__match , ## args); \ + if (__ret != 0) \ + break; \ + } \ + if (__ret == 0) { \ + if (__i != (e)->watchers_offset) \ + __ret = -EINVAL; \ + } \ + __ret; \ +}) + +#define EBT_WATCHER_ITERATE(e, fn, args...) \ +({ \ + unsigned int __i; \ + int __ret = 0; \ + struct ebt_entry_watcher *__watcher; \ + \ + for (__i = e->watchers_offset; \ + __i < (e)->target_offset; \ + __i += __watcher->watcher_size + \ + sizeof(struct ebt_entry_watcher)) { \ + __watcher = (void *)(e) + __i; \ + \ + __ret = fn(__watcher , ## args); \ + if (__ret != 0) \ + break; \ + } \ + if (__ret == 0) { \ + if (__i != (e)->target_offset) \ + __ret = -EINVAL; \ + } \ + __ret; \ +}) + +#define EBT_ENTRY_ITERATE(entries, size, fn, args...) \ +({ \ + unsigned int __i; \ + int __ret = 0; \ + struct ebt_entry *__entry; \ + \ + for (__i = 0; __i < (size);) { \ + __entry = (void *)(entries) + __i; \ + __ret = fn(__entry , ## args); \ + if (__ret != 0) \ + break; \ + if (__entry->bitmask != 0) \ + __i += __entry->next_offset; \ + else \ + __i += sizeof(struct ebt_entries); \ + } \ + if (__ret == 0) { \ + if (__i != (size)) \ + __ret = -EINVAL; \ + } \ + __ret; \ +}) + +#endif diff --git a/iptables/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 --- include/linux/netfilter_bridge/ebtables.h | 276 ------------------------------ iptables/nft-bridge.c | 177 ++++++++++--------- iptables/nft-bridge.h | 98 +++++++++++ iptables/nft-shared.c | 4 +- iptables/nft-shared.h | 3 +- iptables/nft.h | 9 - iptables/xtables-eb-standalone.c | 3 + iptables/xtables-eb.c | 100 +++++------ iptables/xtables-ebtables.h | 49 ------ 9 files changed, 252 insertions(+), 467 deletions(-) delete mode 100644 include/linux/netfilter_bridge/ebtables.h create mode 100644 iptables/nft-bridge.h delete mode 100644 iptables/xtables-ebtables.h diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h deleted file mode 100644 index f7ed1dcf..00000000 --- a/include/linux/netfilter_bridge/ebtables.h +++ /dev/null @@ -1,276 +0,0 @@ -/* - * ebtables - * - * Authors: - * Bart De Schuymer - * - * ebtables.c,v 2.0, April, 2002 - * - * This code is stongly inspired on the iptables code which is - * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling - */ - -/* Local copy of the kernel file, needed for Sparc64 support */ -#ifndef __LINUX_BRIDGE_EFF_H -#define __LINUX_BRIDGE_EFF_H -#include -#include -#include - -#define EBT_TABLE_MAXNAMELEN 32 -#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN -#define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN - -/* verdicts >0 are "branches" */ -#define EBT_ACCEPT -1 -#define EBT_DROP -2 -#define EBT_CONTINUE -3 -#define EBT_RETURN -4 -#define NUM_STANDARD_TARGETS 4 -/* ebtables target modules store the verdict inside an int. We can - * reclaim a part of this int for backwards compatible extensions. - * The 4 lsb are more than enough to store the verdict. */ -#define EBT_VERDICT_BITS 0x0000000F - -struct ebt_counter -{ - uint64_t pcnt; - uint64_t bcnt; -}; - -struct ebt_replace -{ - char name[EBT_TABLE_MAXNAMELEN]; - unsigned int valid_hooks; - /* nr of rules in the table */ - unsigned int nentries; - /* total size of the entries */ - unsigned int entries_size; - /* start of the chains */ -#ifdef KERNEL_64_USERSPACE_32 - uint64_t hook_entry[NF_BR_NUMHOOKS]; -#else - struct ebt_entries *hook_entry[NF_BR_NUMHOOKS]; -#endif - /* nr of counters userspace expects back */ - unsigned int num_counters; - /* where the kernel will put the old counters */ -#ifdef KERNEL_64_USERSPACE_32 - uint64_t counters; - uint64_t entries; -#else - struct ebt_counter *counters; - char *entries; -#endif -}; - -struct ebt_entries { - /* this field is always set to zero - * See EBT_ENTRY_OR_ENTRIES. - * Must be same size as ebt_entry.bitmask */ - unsigned int distinguisher; - /* the chain name */ - char name[EBT_CHAIN_MAXNAMELEN]; - /* counter offset for this chain */ - unsigned int counter_offset; - /* one standard (accept, drop, return) per hook */ - int policy; - /* nr. of entries */ - unsigned int nentries; - /* entry list */ - char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); -}; - -/* used for the bitmask of struct ebt_entry */ - -/* This is a hack to make a difference between an ebt_entry struct and an - * ebt_entries struct when traversing the entries from start to end. - * Using this simplifies the code alot, while still being able to use - * ebt_entries. - * Contrary, iptables doesn't use something like ebt_entries and therefore uses - * different techniques for naming the policy and such. So, iptables doesn't - * need a hack like this. - */ -#define EBT_ENTRY_OR_ENTRIES 0x01 -/* these are the normal masks */ -#define EBT_NOPROTO 0x02 -#define EBT_802_3 0x04 -#define EBT_SOURCEMAC 0x08 -#define EBT_DESTMAC 0x10 -#define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \ - | EBT_ENTRY_OR_ENTRIES) - -#define EBT_IPROTO 0x01 -#define EBT_IIN 0x02 -#define EBT_IOUT 0x04 -#define EBT_ISOURCE 0x8 -#define EBT_IDEST 0x10 -#define EBT_ILOGICALIN 0x20 -#define EBT_ILOGICALOUT 0x40 -#define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \ - | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST) - -struct ebt_entry_match -{ - union { - char name[EBT_FUNCTION_MAXNAMELEN]; - struct ebt_match *match; - } u; - /* size of data */ - unsigned int match_size; -#ifdef KERNEL_64_USERSPACE_32 - unsigned int pad; -#endif - unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); -}; - -struct ebt_entry_watcher -{ - union { - char name[EBT_FUNCTION_MAXNAMELEN]; - struct ebt_watcher *watcher; - } u; - /* size of data */ - unsigned int watcher_size; -#ifdef KERNEL_64_USERSPACE_32 - unsigned int pad; -#endif - unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); -}; - -struct ebt_entry_target -{ - union { - char name[EBT_FUNCTION_MAXNAMELEN]; - struct ebt_target *target; - } u; - /* size of data */ - unsigned int target_size; -#ifdef KERNEL_64_USERSPACE_32 - unsigned int pad; -#endif - unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); -}; - -#define EBT_STANDARD_TARGET "standard" -struct ebt_standard_target -{ - struct ebt_entry_target target; - int verdict; -#ifdef KERNEL_64_USERSPACE_32 - unsigned int pad; -#endif -}; - -/* one entry */ -struct ebt_entry { - /* this needs to be the first field */ - unsigned int bitmask; - unsigned int invflags; - uint16_t ethproto; - /* the physical in-dev */ - char in[IFNAMSIZ]; - /* the logical in-dev */ - char logical_in[IFNAMSIZ]; - /* the physical out-dev */ - char out[IFNAMSIZ]; - /* the logical out-dev */ - char logical_out[IFNAMSIZ]; - unsigned char sourcemac[ETH_ALEN]; - unsigned char sourcemsk[ETH_ALEN]; - unsigned char destmac[ETH_ALEN]; - unsigned char destmsk[ETH_ALEN]; - /* sizeof ebt_entry + matches */ - unsigned int watchers_offset; - /* sizeof ebt_entry + matches + watchers */ - unsigned int target_offset; - /* sizeof ebt_entry + matches + watchers + target */ - unsigned int next_offset; - unsigned char elems[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); -}; - -/* {g,s}etsockopt numbers */ -#define EBT_BASE_CTL 128 - -#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL) -#define EBT_SO_SET_COUNTERS (EBT_SO_SET_ENTRIES+1) -#define EBT_SO_SET_MAX (EBT_SO_SET_COUNTERS+1) - -#define EBT_SO_GET_INFO (EBT_BASE_CTL) -#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO+1) -#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES+1) -#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO+1) -#define EBT_SO_GET_MAX (EBT_SO_GET_INIT_ENTRIES+1) - -/* blatently stolen from ip_tables.h - * fn returns 0 to continue iteration */ -#define EBT_MATCH_ITERATE(e, fn, args...) \ -({ \ - unsigned int __i; \ - int __ret = 0; \ - struct ebt_entry_match *__match; \ - \ - for (__i = sizeof(struct ebt_entry); \ - __i < (e)->watchers_offset; \ - __i += __match->match_size + \ - sizeof(struct ebt_entry_match)) { \ - __match = (void *)(e) + __i; \ - \ - __ret = fn(__match , ## args); \ - if (__ret != 0) \ - break; \ - } \ - if (__ret == 0) { \ - if (__i != (e)->watchers_offset) \ - __ret = -EINVAL; \ - } \ - __ret; \ -}) - -#define EBT_WATCHER_ITERATE(e, fn, args...) \ -({ \ - unsigned int __i; \ - int __ret = 0; \ - struct ebt_entry_watcher *__watcher; \ - \ - for (__i = e->watchers_offset; \ - __i < (e)->target_offset; \ - __i += __watcher->watcher_size + \ - sizeof(struct ebt_entry_watcher)) { \ - __watcher = (void *)(e) + __i; \ - \ - __ret = fn(__watcher , ## args); \ - if (__ret != 0) \ - break; \ - } \ - if (__ret == 0) { \ - if (__i != (e)->target_offset) \ - __ret = -EINVAL; \ - } \ - __ret; \ -}) - -#define EBT_ENTRY_ITERATE(entries, size, fn, args...) \ -({ \ - unsigned int __i; \ - int __ret = 0; \ - struct ebt_entry *__entry; \ - \ - for (__i = 0; __i < (size);) { \ - __entry = (void *)(entries) + __i; \ - __ret = fn(__entry , ## args); \ - if (__ret != 0) \ - break; \ - if (__entry->bitmask != 0) \ - __i += __entry->next_offset; \ - else \ - __i += sizeof(struct ebt_entries); \ - } \ - if (__ret == 0) { \ - if (__i != (size)) \ - __ret = -EINVAL; \ - } \ - __ret; \ -}) - -#endif diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 66361ee9..ab97881d 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -18,11 +18,13 @@ #include #include "nft-shared.h" +#include "nft-bridge.h" #include "nft.h" /* 0: default, print only 2 digits if necessary * 2: always print 2 digits, a printed mac address - * then always has the same length */ + * then always has the same length + */ int ebt_printstyle_mac; static void ebt_print_mac(const unsigned char *mac) @@ -132,31 +134,36 @@ static void add_logical_outiface(struct nft_rule *r, char *iface, int invflags) add_cmp_ptr(r, op, iface, iface_len + 1); } -static int _add_action(struct nft_rule *r, struct xtables_ebt_entry *fw) +/* TODO: Use generic add_action() once we convert this to use + * iptables_command_state. + */ +static int _add_action(struct nft_rule *r, struct ebtables_command_state *cs) { int ret = 0; - /* If no target at all, add nothing (default to continue) */ - if (fw->target != NULL) { - /* Standard target? */ - if (strcmp(fw->jumpto, XTC_LABEL_ACCEPT) == 0) - ret = add_verdict(r, NF_ACCEPT); - else if (strcmp(fw->jumpto, XTC_LABEL_DROP) == 0) - ret = add_verdict(r, NF_DROP); - else if (strcmp(fw->jumpto, XTC_LABEL_RETURN) == 0) - ret = add_verdict(r, NFT_RETURN); - else - ret = add_target(r, fw->target->t); - } else if (strlen(fw->jumpto) > 0) + /* If no target at all, add nothing (default to continue) */ + if (cs->target != NULL) { + /* Standard target? */ + if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0) + ret = add_verdict(r, NF_ACCEPT); + else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0) + ret = add_verdict(r, NF_DROP); + else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) + ret = add_verdict(r, NFT_RETURN); + else + ret = add_target(r, cs->target->t); + } else if (strlen(cs->jumpto) > 0) { /* Not standard, then it's a jump to chain */ - ret = add_jumpto(r, fw->jumpto, NFT_JUMP); + ret = add_jumpto(r, cs->jumpto, NFT_JUMP); + } - return ret; + return ret; } static int nft_bridge_add(struct nft_rule *r, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; + struct ebt_entry *fw = &cs->fw; uint8_t flags = ebt_to_ipt_flags(fw->invflags); char *addr; @@ -189,13 +196,14 @@ static int nft_bridge_add(struct nft_rule *r, void *data) add_cmp_u16(r, fw->ethproto, NFT_CMP_EQ); } - return _add_action(r, fw); + return _add_action(r, cs); } static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; + struct ebt_entry *fw = &cs->fw; uint8_t flags = 0; int iface = 0; const void *ifname; @@ -214,7 +222,7 @@ static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, memcpy(fw->logical_in, ifname, len); - if (fw->logical_in[len] == '\0') + if (fw->logical_in[len] == '\0') memset(fw->in_mask, 0xff, len); else { fw->logical_in[len] = '+'; @@ -248,7 +256,8 @@ out: static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; + struct ebt_entry *fw = &cs->fw; unsigned char addr[ETH_ALEN]; unsigned short int ethproto; bool inv; @@ -271,28 +280,30 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, break; } } + static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; - fw->jumpto = jumpto; + cs->jumpto = jumpto; } static void nft_bridge_parse_target(struct xtables_target *t, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; - fw->target = t; + cs->target = t; } -void nft_rule_to_xtables_ebt_entry(struct nft_rule *r, struct xtables_ebt_entry *fw) +void nft_rule_to_ebtables_command_state(struct nft_rule *r, + struct ebtables_command_state *cs) { struct nft_rule_expr_iter *iter; struct nft_rule_expr *expr; int family = nft_rule_attr_get_u32(r, NFT_RULE_ATTR_FAMILY); struct nft_xt_ctx ctx = { - .state.ebfw = fw, + .state.cs_eb = cs, .family = family, }; @@ -306,15 +317,19 @@ void nft_rule_to_xtables_ebt_entry(struct nft_rule *r, struct xtables_ebt_entry nft_rule_expr_get_str(expr, NFT_RULE_EXPR_ATTR_NAME); if (strcmp(name, "counter") == 0) - nft_parse_counter(expr, &fw->counters); + nft_parse_counter(expr, &cs->counters); else if (strcmp(name, "payload") == 0) nft_parse_payload(&ctx, expr); else if (strcmp(name, "meta") == 0) nft_parse_meta(&ctx, expr); + else if (strcmp(name, "bitwise") == 0) + nft_parse_bitwise(&ctx, expr); else if (strcmp(name, "cmp") == 0) nft_parse_cmp(&ctx, expr); else if (strcmp(name, "immediate") == 0) nft_parse_immediate(&ctx, expr); + else if (strcmp(name, "match") == 0) + nft_parse_match(&ctx, expr); else if (strcmp(name, "target") == 0) nft_parse_target(&ctx, expr); @@ -323,12 +338,12 @@ void nft_rule_to_xtables_ebt_entry(struct nft_rule *r, struct xtables_ebt_entry nft_rule_expr_iter_destroy(iter); - if (fw->target != NULL) - fw->jumpto = fw->target->name; - else if (fw->jumpto != NULL) - fw->target = xtables_find_target(fw->jumpto, XTF_TRY_LOAD); + if (cs->target != NULL) + cs->jumpto = cs->target->name; + else if (cs->jumpto != NULL) + cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); else - fw->jumpto = ""; + cs->jumpto = ""; } static void print_iface(const char *iface) @@ -351,81 +366,80 @@ static void nft_bridge_print_header(unsigned int format, const char *chain, print_header(format, chain, pol, counters, basechain, refs); } -static void -nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, - unsigned int format) +static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, + unsigned int format) { - struct xtables_ebt_entry fw = {}; + struct ebtables_command_state cs = {}; char *addr; - nft_rule_to_xtables_ebt_entry(r, &fw); + nft_rule_to_ebtables_command_state(r, &cs); if (format & FMT_LINENUMBERS) printf("%d ", num); /* Dont print anything about the protocol if no protocol was * specified, obviously this means any protocol will do. */ - if (fw.ethproto != 0) { + if (cs.fw.ethproto != 0) { printf("-p "); - if (fw.invflags & EBT_IPROTO) + if (cs.fw.invflags & EBT_IPROTO) printf("! "); - if (fw.bitmask & EBT_802_3) + if (cs.fw.bitmask & EBT_802_3) printf("Length "); else { struct ethertypeent *ent; - ent = getethertypebynumber(ntohs(fw.ethproto)); + ent = getethertypebynumber(ntohs(cs.fw.ethproto)); if (!ent) - printf("0x%x ", ntohs(fw.ethproto)); + printf("0x%x ", ntohs(cs.fw.ethproto)); else printf("%s ", ent->e_name); } } - addr = ether_ntoa((struct ether_addr *) fw.sourcemac); + addr = ether_ntoa((struct ether_addr *) cs.fw.sourcemac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { printf("-s "); - if (fw.invflags & EBT_ISOURCE) + if (cs.fw.invflags & EBT_ISOURCE) printf("! "); - ebt_print_mac_and_mask(fw.sourcemac, fw.sourcemsk); + ebt_print_mac_and_mask(cs.fw.sourcemac, cs.fw.sourcemsk); printf(" "); } - addr = ether_ntoa((struct ether_addr *) fw.destmac); + addr = ether_ntoa((struct ether_addr *) cs.fw.destmac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { printf("-d "); - if (fw.invflags & EBT_IDEST) + if (cs.fw.invflags & EBT_IDEST) printf("! "); - ebt_print_mac_and_mask(fw.destmac, fw.destmsk); + ebt_print_mac_and_mask(cs.fw.destmac, cs.fw.destmsk); printf(" "); } - if (fw.in[0] != '\0') { + if (cs.fw.in[0] != '\0') { printf("-i "); - if (fw.invflags & EBT_IIN) + if (cs.fw.invflags & EBT_IIN) printf("! "); - print_iface(fw.in); + print_iface(cs.fw.in); } - if (fw.logical_in[0] != '\0') { + if (cs.fw.logical_in[0] != '\0') { printf("--logical-in "); - if (fw.invflags & EBT_ILOGICALIN) + if (cs.fw.invflags & EBT_ILOGICALIN) printf("! "); - print_iface(fw.logical_in); + print_iface(cs.fw.logical_in); } - if (fw.logical_out[0] != '\0') { + if (cs.fw.logical_out[0] != '\0') { printf("--logical-out "); - if (fw.invflags & EBT_ILOGICALOUT) + if (cs.fw.invflags & EBT_ILOGICALOUT) printf("! "); - print_iface(fw.logical_out); + print_iface(cs.fw.logical_out); } - if (fw.out[0] != '\0') { + if (cs.fw.out[0] != '\0') { printf("-o "); - if (fw.invflags & EBT_IOUT) + if (cs.fw.invflags & EBT_IOUT) printf("! "); - print_iface(fw.out); + print_iface(cs.fw.out); } /* old code to adapt @@ -447,12 +461,12 @@ nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, }*/ printf("-j "); if (!(format & FMT_NOTARGET)) - printf("%s", fw.jumpto); + printf("%s", cs.jumpto); - if (fw.target != NULL) { - if (fw.target->print != NULL) { - fw.target->print(&fw, fw.target->t, - format & FMT_NUMERIC); + if (cs.target != NULL) { + if (cs.target->print != NULL) { + cs.target->print(&cs.fw, cs.target->t, + format & FMT_NUMERIC); } } @@ -460,16 +474,15 @@ nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, fputc('\n', stdout); } -static bool nft_bridge_is_same(const void *data_a, - const void *data_b) +static bool nft_bridge_is_same(const void *data_a, const void *data_b) { - const struct xtables_ebt_entry *a = data_a; - const struct xtables_ebt_entry *b = data_b; + const struct ebt_entry *a = data_a; + const struct ebt_entry *b = data_b; int i; - if (a->ethproto != b->ethproto - /*|| a->flags != b->flags*/ - || a->invflags != b->invflags) { + if (a->ethproto != b->ethproto || + /* FIXME: a->flags != b->flags || */ + a->invflags != b->invflags) { DEBUGP("different proto/flags/invflags\n"); return false; } @@ -515,27 +528,27 @@ static bool nft_bridge_is_same(const void *data_a, static bool nft_bridge_rule_find(struct nft_family_ops *ops, struct nft_rule *r, void *data) { - struct xtables_ebt_entry *fw = data; - struct xtables_ebt_entry this = {}; + struct ebtables_command_state *cs = data; + struct ebtables_command_state this = {}; - nft_rule_to_xtables_ebt_entry(r, &this); + nft_rule_to_ebtables_command_state(r, &this); DEBUGP("comparing with... "); - if (!ops->is_same(fw, &this)) + if (!nft_bridge_is_same(cs, &this)) return false; - if (!compare_matches(fw->matches, this.matches)) { + if (!compare_matches(cs->matches, this.matches)) { DEBUGP("Different matches\n"); return false; } - if (!compare_targets(fw->target, this.target)) { + if (!compare_targets(cs->target, this.target)) { DEBUGP("Different target\n"); return false; } - if (strcmp(fw->jumpto, this.jumpto) != 0) { + if (strcmp(cs->jumpto, this.jumpto) != 0) { DEBUGP("Different verdict\n"); return false; } @@ -550,9 +563,11 @@ struct nft_family_ops nft_family_ops_bridge = { .parse_meta = nft_bridge_parse_meta, .parse_payload = nft_bridge_parse_payload, .parse_immediate = nft_bridge_parse_immediate, + .parse_target = nft_bridge_parse_target, .print_header = nft_bridge_print_header, .print_firewall = nft_bridge_print_firewall, + .save_firewall = NULL, + .save_counters = NULL, .post_parse = NULL, .rule_find = nft_bridge_rule_find, - .parse_target = nft_bridge_parse_target, }; diff --git a/iptables/nft-bridge.h b/iptables/nft-bridge.h new file mode 100644 index 00000000..1e3f0a16 --- /dev/null +++ b/iptables/nft-bridge.h @@ -0,0 +1,98 @@ +#ifndef _NFT_BRIDGE_H_ +#define _NFT_BRIDGE_H_ + +#include +//#include +#include + +/* We use replace->flags, so we can't use the following values: + * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO */ +#define LIST_N 0x04 +#define LIST_C 0x08 +#define LIST_X 0x10 +#define LIST_MAC2 0x20 + +/* Be backwards compatible, so don't use '+' in kernel */ +#define IF_WILDCARD 1 + +extern unsigned char eb_mac_type_unicast[ETH_ALEN]; +extern unsigned char eb_msk_type_unicast[ETH_ALEN]; +extern unsigned char eb_mac_type_multicast[ETH_ALEN]; +extern unsigned char eb_msk_type_multicast[ETH_ALEN]; +extern unsigned char eb_mac_type_broadcast[ETH_ALEN]; +extern unsigned char eb_msk_type_broadcast[ETH_ALEN]; +extern unsigned char eb_mac_type_bridge_group[ETH_ALEN]; +extern unsigned char eb_msk_type_bridge_group[ETH_ALEN]; + +int ebt_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask); + +/* From: include/linux/netfilter_bridge/ebtables.h + * + * Adapted for the need of the ebtables-compat. + */ + +#define EBT_TABLE_MAXNAMELEN 32 +#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN +#define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN + +/* verdicts >0 are "branches" */ +#define EBT_ACCEPT -1 +#define EBT_DROP -2 +#define EBT_CONTINUE -3 +#define EBT_RETURN -4 +#define NUM_STANDARD_TARGETS 4 + +#define EBT_ENTRY_OR_ENTRIES 0x01 +/* these are the normal masks */ +#define EBT_NOPROTO 0x02 +#define EBT_802_3 0x04 +#define EBT_SOURCEMAC 0x08 +#define EBT_DESTMAC 0x10 +#define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \ + | EBT_ENTRY_OR_ENTRIES) + +#define EBT_IPROTO 0x01 +#define EBT_IIN 0x02 +#define EBT_IOUT 0x04 +#define EBT_ISOURCE 0x8 +#define EBT_IDEST 0x10 +#define EBT_ILOGICALIN 0x20 +#define EBT_ILOGICALOUT 0x40 +#define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \ + | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST) + +/* Fake ebt_entry */ +struct ebt_entry { + /* this needs to be the first field */ + unsigned int bitmask; + unsigned int invflags; + uint16_t ethproto; + /* the physical in-dev */ + char in[IFNAMSIZ]; + /* the logical in-dev */ + char logical_in[IFNAMSIZ]; + /* the physical out-dev */ + char out[IFNAMSIZ]; + /* the logical out-dev */ + char logical_out[IFNAMSIZ]; + unsigned char sourcemac[ETH_ALEN]; + unsigned char sourcemsk[ETH_ALEN]; + unsigned char destmac[ETH_ALEN]; + unsigned char destmsk[ETH_ALEN]; + + unsigned char in_mask[IFNAMSIZ]; + unsigned char out_mask[IFNAMSIZ]; +}; + +struct ebtables_command_state { + struct ebt_entry fw; + struct xtables_target *target; + struct xtables_rule_match *matches; + const char *jumpto; + struct xt_counters counters; +}; + +void nft_rule_to_ebtables_command_state(struct nft_rule *r, + struct ebtables_command_state *cs); + +#endif diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 9ca2e35c..71c44763 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -280,7 +280,7 @@ static void *nft_get_data(struct nft_xt_ctx *ctx) case NFPROTO_ARP: return ctx->state.cs_arp; case NFPROTO_BRIDGE: - return ctx->state.ebfw; + return ctx->state.cs_eb; default: /* Should not happen */ return NULL; @@ -320,7 +320,7 @@ void nft_parse_target(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) ops->parse_target(target, data); } -static void nft_parse_match(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) +void nft_parse_match(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) { uint32_t mt_len; const char *mt_name = nft_rule_expr_get_str(e, NFT_EXPR_MT_NAME); diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 97d41df8..361e9566 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -48,7 +48,7 @@ struct nft_xt_ctx { union { struct iptables_command_state *cs; struct arptables_command_state *cs_arp; - struct xtables_ebt_entry *ebfw; + struct ebtables_command_state *cs_eb; } state; struct nft_rule_expr_iter *iter; int family; @@ -130,6 +130,7 @@ void print_proto(uint16_t proto, int invert); void get_cmp_data(struct nft_rule_expr *e, void *data, size_t dlen, bool *inv); void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); +void nft_parse_match(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); void nft_parse_target(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); void nft_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); void nft_parse_payload(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); diff --git a/iptables/nft.h b/iptables/nft.h index 4f0b733c..ab3d64ac 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -170,13 +170,4 @@ int nft_arp_rule_insert(struct nft_handle *h, const char *chain, void nft_rule_to_arpt_entry(struct nft_rule *r, struct arpt_entry *fw); -/* - * BRIDGE - */ - -#include "xtables-ebtables.h" - -struct xtables_ebt_entry; - -void nft_rule_to_xtables_ebt_entry(struct nft_rule *r, struct xtables_ebt_entry *fw); #endif diff --git a/iptables/xtables-eb-standalone.c b/iptables/xtables-eb-standalone.c index 6ec418cb..1c3cbf07 100644 --- a/iptables/xtables-eb-standalone.c +++ b/iptables/xtables-eb-standalone.c @@ -83,5 +83,8 @@ int xtables_eb_main(int argc, char *argv[]) if (ret) ret = nft_commit(&h); + if (!ret) + fprintf(stderr, "%s\n", nft_strerror(errno)); + exit(!ret); } diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 73a38db9..99d930e5 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -31,9 +31,11 @@ #include #include +#include #include #include "xshared.h" #include "nft.h" +#include "nft-bridge.h" extern struct xtables_globals xtables_globals; #define prog_name xtables_globals.program_name @@ -213,16 +215,16 @@ static int append_entry(struct nft_handle *h, const char *chain, const char *table, - struct xtables_ebt_entry *fw, + struct ebtables_command_state *cs, int rule_nr, bool verbose, bool append) { int ret = 1; if (append) - ret = nft_rule_append(h, chain, table, fw, 0, verbose); + ret = nft_rule_append(h, chain, table, cs, 0, verbose); else - ret = nft_rule_insert(h, chain, table, fw, rule_nr, verbose); + ret = nft_rule_insert(h, chain, table, cs, rule_nr, verbose); return ret; } @@ -231,7 +233,7 @@ static int delete_entry(struct nft_handle *h, const char *chain, const char *table, - struct xtables_ebt_entry *fw, + struct ebtables_command_state *cs, int rule_nr, int rule_nr_end, bool verbose) @@ -239,7 +241,7 @@ delete_entry(struct nft_handle *h, int ret = 1; if (rule_nr == -1) - ret = nft_rule_delete(h, chain, table, fw, verbose); + ret = nft_rule_delete(h, chain, table, cs, verbose); else { do { ret = nft_rule_delete_num(h, chain, table, @@ -342,7 +344,7 @@ static struct option *ebt_options = ebt_original_options; /* * More glue code. */ -static struct xtables_target *command_jump(struct xtables_ebt_entry *fw, +static struct xtables_target *command_jump(struct ebtables_command_state *cs, const char *jumpto) { struct xtables_target *target; @@ -490,7 +492,7 @@ static int parse_rule_range(const char *argv, int *rule_nr, int *rule_nr_end) /* Incrementing or decrementing rules in daemon mode is not supported as the * involved code overload is not worth it (too annoying to take the increased * counters in the kernel into account). */ -static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int *rule_nr_end, int exec_style, struct xtables_ebt_entry *fw) +static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int *rule_nr_end, int exec_style, struct ebtables_command_state *cs) { char *buffer; int ret = 0; @@ -515,16 +517,16 @@ daemon_incr: xtables_error(PARAMETER_PROBLEM, "Incrementing rule counters (%s) not allowed in daemon mode", argv[optind]); ret += 1; - fw->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10); + cs->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10); } else if (argv[optind][0] == '-') { if (exec_style == EXEC_STYLE_DAEMON) daemon_decr: xtables_error(PARAMETER_PROBLEM, "Decrementing rule counters (%s) not allowed in daemon mode", argv[optind]); ret += 2; - fw->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10); + cs->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10); } else - fw->counters.pcnt = strtoull(argv[optind], &buffer, 10); + cs->counters.pcnt = strtoull(argv[optind], &buffer, 10); if (*buffer != '\0') goto invalid; @@ -533,14 +535,14 @@ daemon_decr: if (exec_style == EXEC_STYLE_DAEMON) goto daemon_incr; ret += 3; - fw->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10); + cs->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10); } else if (argv[optind][0] == '-') { if (exec_style == EXEC_STYLE_DAEMON) goto daemon_decr; ret += 6; - fw->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10); + cs->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10); } else - fw->counters.bcnt = strtoull(argv[optind], &buffer, 10); + cs->counters.bcnt = strtoull(argv[optind], &buffer, 10); if (*buffer != '\0') goto invalid; @@ -577,7 +579,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) int ret = 0; unsigned int flags = 0; struct xtables_target *t; - struct xtables_ebt_entry fw; + struct ebtables_command_state cs; char command = 'h'; const char *chain = NULL; const char *newname = NULL; @@ -585,7 +587,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) int exec_style = EXEC_STYLE_PRG; int selected_chain = -1; - memset(&fw, 0, sizeof(fw)); + memset(&cs, 0, sizeof(cs)); if (nft_init(h, xtables_bridge) < 0) xtables_error(OTHER_PROBLEM, @@ -651,7 +653,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) "Problem with the specified rule number(s) '%s'", argv[optind]); optind++; } else if (c == 'C') { - if ((chcounter = parse_change_counters_rule(argc, argv, &rule_nr, &rule_nr_end, exec_style, &fw)) == -1) + if ((chcounter = parse_change_counters_rule(argc, argv, &rule_nr, &rule_nr_end, exec_style, &cs)) == -1) return -1; } else if (c == 'I') { if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9'))) @@ -748,7 +750,7 @@ print_zero: struct ebt_u_watcher *w;*/ if (!strcasecmp("list_extensions", argv[optind])) { - ebt_list_extensions(xtables_targets, fw.matches); + ebt_list_extensions(xtables_targets, cs.matches); exit(0); } /*if ((m = ebt_find_match(argv[optind]))) @@ -761,7 +763,7 @@ print_zero: if (flags & OPT_JUMP) xtables_error(PARAMETER_PROBLEM,"Sorry, you can only see help for one target extension at a time"); flags |= OPT_JUMP; - fw.target = t; + cs.target = t; //} optind++; } @@ -798,14 +800,14 @@ print_zero: xtables_error(PARAMETER_PROBLEM, "Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains"); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_IIN; + cs.fw.invflags |= EBT_IIN; if (strlen(optarg) >= IFNAMSIZ) big_iface_length: xtables_error(PARAMETER_PROBLEM, "Interface name length cannot exceed %d characters", IFNAMSIZ - 1); - xtables_parse_interface(optarg, fw.in, fw.in_mask); + xtables_parse_interface(optarg, cs.fw.in, cs.fw.in_mask); break; } else if (c == 2) { ebt_check_option2(&flags, OPT_LOGICALIN); @@ -813,12 +815,12 @@ big_iface_length: xtables_error(PARAMETER_PROBLEM, "Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains"); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_ILOGICALIN; + cs.fw.invflags |= EBT_ILOGICALIN; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; - strcpy(fw.logical_in, optarg); - if (parse_iface(fw.logical_in, "--logical-in")) + strcpy(cs.fw.logical_in, optarg); + if (parse_iface(cs.fw.logical_in, "--logical-in")) return -1; break; } else if (c == 'o') { @@ -827,12 +829,12 @@ big_iface_length: xtables_error(PARAMETER_PROBLEM, "Use -o only in OUTPUT, FORWARD and POSTROUTING chains"); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_IOUT; + cs.fw.invflags |= EBT_IOUT; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; - xtables_parse_interface(optarg, fw.out, fw.out_mask); + xtables_parse_interface(optarg, cs.fw.out, cs.fw.out_mask); break; } else if (c == 3) { ebt_check_option2(&flags, OPT_LOGICALOUT); @@ -840,36 +842,36 @@ big_iface_length: xtables_error(PARAMETER_PROBLEM, "Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains"); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_ILOGICALOUT; + cs.fw.invflags |= EBT_ILOGICALOUT; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; - strcpy(fw.logical_out, optarg); - if (parse_iface(fw.logical_out, "--logical-out")) + strcpy(cs.fw.logical_out, optarg); + if (parse_iface(cs.fw.logical_out, "--logical-out")) return -1; break; } else if (c == 'j') { ebt_check_option2(&flags, OPT_JUMP); - fw.jumpto = parse_target(optarg); - fw.target = command_jump(&fw, fw.jumpto); + cs.jumpto = parse_target(optarg); + cs.target = command_jump(&cs, cs.jumpto); break; } else if (c == 's') { ebt_check_option2(&flags, OPT_SOURCE); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_ISOURCE; + cs.fw.invflags |= EBT_ISOURCE; - if (ebt_get_mac_and_mask(optarg, fw.sourcemac, fw.sourcemsk)) + if (ebt_get_mac_and_mask(optarg, cs.fw.sourcemac, cs.fw.sourcemsk)) xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg); - fw.bitmask |= EBT_SOURCEMAC; + cs.fw.bitmask |= EBT_SOURCEMAC; break; } else if (c == 'd') { ebt_check_option2(&flags, OPT_DEST); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_IDEST; + cs.fw.invflags |= EBT_IDEST; - if (ebt_get_mac_and_mask(optarg, fw.destmac, fw.destmsk)) + if (ebt_get_mac_and_mask(optarg, cs.fw.destmac, cs.fw.destmsk)) xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg); - fw.bitmask |= EBT_DESTMAC; + cs.fw.bitmask |= EBT_DESTMAC; break; } else if (c == 'c') { ebt_check_option2(&flags, OPT_COUNT); @@ -880,12 +882,12 @@ big_iface_length: xtables_error(PARAMETER_PROBLEM, "Option -c needs 2 arguments"); - fw.counters.pcnt = strtoull(optarg, &buffer, 10); + cs.counters.pcnt = strtoull(optarg, &buffer, 10); if (*buffer != '\0') xtables_error(PARAMETER_PROBLEM, "Packet counter '%s' invalid", optarg); - fw.counters.bcnt = strtoull(argv[optind], &buffer, 10); + cs.counters.bcnt = strtoull(argv[optind], &buffer, 10); if (*buffer != '\0') xtables_error(PARAMETER_PROBLEM, "Packet counter '%s' invalid", @@ -895,9 +897,9 @@ big_iface_length: } ebt_check_option2(&flags, OPT_PROTOCOL); if (ebt_check_inverse2(optarg, argc, argv)) - fw.invflags |= EBT_IPROTO; + cs.fw.invflags |= EBT_IPROTO; - fw.bitmask &= ~((unsigned int)EBT_NOPROTO); + cs.fw.bitmask &= ~((unsigned int)EBT_NOPROTO); i = strtol(optarg, &buffer, 16); if (*buffer == '\0' && (i < 0 || i > 0xFFFF)) xtables_error(PARAMETER_PROBLEM, @@ -906,18 +908,18 @@ big_iface_length: struct ethertypeent *ent; if (!strcasecmp(optarg, "LENGTH")) { - fw.bitmask |= EBT_802_3; + cs.fw.bitmask |= EBT_802_3; break; } ent = getethertypebyname(optarg); if (!ent) xtables_error(PARAMETER_PROBLEM, "Problem with the specified Ethernet protocol '%s', perhaps "_PATH_ETHERTYPES " is missing", optarg); - fw.ethproto = ent->e_ethertype; + cs.fw.ethproto = ent->e_ethertype; } else - fw.ethproto = i; + cs.fw.ethproto = i; - if (fw.ethproto < 0x0600) + if (cs.fw.ethproto < 0x0600) xtables_error(PARAMETER_PROBLEM, "Sorry, protocols have values above or equal to 0x0600"); break; @@ -1103,7 +1105,7 @@ check_extension: */ ebt_print_error2("Bad table name");*/ if (command == 'h' && !(flags & OPT_ZERO)) { - print_help(fw.target, fw.matches, *table); + print_help(cs.target, cs.matches, *table); if (exec_style == EXEC_STYLE_PRG) exit(0); } @@ -1142,7 +1144,7 @@ check_extension: */ }*/ /* So, the extensions can work with the host endian. * The kernel does not have to do this of course */ - fw.ethproto = htons(fw.ethproto); + cs.fw.ethproto = htons(cs.fw.ethproto); if (command == 'P') { if (selected_chain < NF_BR_NUMHOOKS && strcmp(policy, "RETURN")==0) @@ -1166,13 +1168,13 @@ check_extension: */ } else if (command == 'F') { ret = nft_rule_flush(h, chain, *table); } else if (command == 'A') { - ret = append_entry(h, chain, *table, &fw, 0, + ret = append_entry(h, chain, *table, &cs, 0, flags&OPT_VERBOSE, true); } else if (command == 'I') { - ret = append_entry(h, chain, *table, &fw, rule_nr - 1, + ret = append_entry(h, chain, *table, &cs, rule_nr - 1, flags&OPT_VERBOSE, false); } else if (command == 'D') { - ret = delete_entry(h, chain, *table, &fw, rule_nr - 1, + ret = delete_entry(h, chain, *table, &cs, rule_nr - 1, rule_nr_end, flags&OPT_VERBOSE); } /*else if (replace->command == 'C') { ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus), chcounter); diff --git a/iptables/xtables-ebtables.h b/iptables/xtables-ebtables.h deleted file mode 100644 index 1e479b1b..00000000 --- a/iptables/xtables-ebtables.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef _XTABLES_EBTABLES_H_ -#define _XTABLES_EBTABLES_H_ - -#include -#include -#include - -/* We use replace->flags, so we can't use the following values: - * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO */ -#define LIST_N 0x04 -#define LIST_C 0x08 -#define LIST_X 0x10 -#define LIST_MAC2 0x20 - -/* Be backwards compatible, so don't use '+' in kernel */ -#define IF_WILDCARD 1 - -extern unsigned char eb_mac_type_unicast[ETH_ALEN]; -extern unsigned char eb_msk_type_unicast[ETH_ALEN]; -extern unsigned char eb_mac_type_multicast[ETH_ALEN]; -extern unsigned char eb_msk_type_multicast[ETH_ALEN]; -extern unsigned char eb_mac_type_broadcast[ETH_ALEN]; -extern unsigned char eb_msk_type_broadcast[ETH_ALEN]; -extern unsigned char eb_mac_type_bridge_group[ETH_ALEN]; -extern unsigned char eb_msk_type_bridge_group[ETH_ALEN]; - -int ebt_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask); - -struct xtables_ebt_entry { - unsigned int bitmask; - unsigned int invflags; - unsigned int flags; - uint16_t ethproto; - char in[IFNAMSIZ]; - char logical_in[IFNAMSIZ]; - unsigned char in_mask[IFNAMSIZ]; - char out[IFNAMSIZ]; - char logical_out[IFNAMSIZ]; - unsigned char out_mask[IFNAMSIZ]; - unsigned char sourcemac[ETH_ALEN]; - unsigned char sourcemsk[ETH_ALEN]; - unsigned char destmac[ETH_ALEN]; - unsigned char destmsk[ETH_ALEN]; - struct xtables_rule_match *matches; - struct xtables_target *target; - struct xt_counters counters; - const char *jumpto; -}; -#endif -- cgit v1.2.3 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(-) 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(+) 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(-) 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(-) 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 df6e630c7e8eeec3045b3b8cee52e9efdbc45b62 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 10 Nov 2014 20:03:08 +0100 Subject: ebtables-compat: build ebtables extensions This permits to build extensions for ebtables-compat layer. Signed-off-by: Giuseppe Longo Signed-off-by: Pablo Neira Ayuso --- extensions/GNUmakefile.in | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index 52915725..7b4f891a 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -39,16 +39,20 @@ endif # Wildcard module list # pfx_build_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(sort $(wildcard ${srcdir}/libxt_*.c))) +pfb_build_mod := $(patsubst ${srcdir}/libebt_%.c,%,$(sort $(wildcard ${srcdir}/libebt_*.c))) pfx_symlinks := NOTRACK state @ENABLE_IPV4_TRUE@ pf4_build_mod := $(patsubst ${srcdir}/libipt_%.c,%,$(sort $(wildcard ${srcdir}/libipt_*.c))) @ENABLE_IPV6_TRUE@ pf6_build_mod := $(patsubst ${srcdir}/libip6t_%.c,%,$(sort $(wildcard ${srcdir}/libip6t_*.c))) pfx_build_mod := $(filter-out @blacklist_modules@,${pfx_build_mod}) +pfb_build_mod := $(filter-out @blacklist_modules@,${pfb_build_mod}) pf4_build_mod := $(filter-out @blacklist_modules@,${pf4_build_mod}) pf6_build_mod := $(filter-out @blacklist_modules@,${pf6_build_mod}) pfx_objs := $(patsubst %,libxt_%.o,${pfx_build_mod}) +pfb_objs := $(patsubst %,libebt_%.o,${pfb_build_mod}) pf4_objs := $(patsubst %,libipt_%.o,${pf4_build_mod}) pf6_objs := $(patsubst %,libip6t_%.o,${pf6_build_mod}) pfx_solibs := $(patsubst %,libxt_%.so,${pfx_build_mod} ${pfx_symlinks}) +pfb_solibs := $(patsubst %,libebt_%.so,${pfb_build_mod}) pf4_solibs := $(patsubst %,libipt_%.so,${pf4_build_mod}) pf6_solibs := $(patsubst %,libip6t_%.so,${pf6_build_mod}) @@ -59,10 +63,11 @@ pf6_solibs := $(patsubst %,libip6t_%.so,${pf6_build_mod}) targets := libext.a libext4.a libext6.a matches.man targets.man targets_install := @ENABLE_STATIC_TRUE@ libext_objs := ${pfx_objs} +@ENABLE_STATIC_TRUE@ libextb_objs := ${pfb_objs} @ENABLE_STATIC_TRUE@ libext4_objs := ${pf4_objs} @ENABLE_STATIC_TRUE@ libext6_objs := ${pf6_objs} -@ENABLE_STATIC_FALSE@ targets += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs} -@ENABLE_STATIC_FALSE@ targets_install += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs} +@ENABLE_STATIC_FALSE@ targets += ${pfx_solibs} ${pfb_solibs} ${pf4_solibs} ${pf6_solibs} +@ENABLE_STATIC_FALSE@ targets_install += ${pfx_solibs} ${pfb_solibs} ${pf4_solibs} ${pf6_solibs} .SECONDARY: @@ -118,6 +123,9 @@ lib%.o: ${srcdir}/lib%.c libext.a: initext.o ${libext_objs} ${AM_VERBOSE_AR} ${AR} crs $@ $^; +libextb.a: initextb.o ${libextb_objs} + ${AM_VERBOSE_AR} ${AR} crs $@ $^; + libext4.a: initext4.o ${libext4_objs} ${AM_VERBOSE_AR} ${AR} crs $@ $^; @@ -125,6 +133,7 @@ libext6.a: initext6.o ${libext6_objs} ${AM_VERBOSE_AR} ${AR} crs $@ $^; initext_func := $(addprefix xt_,${pfx_build_mod}) +initextb_func := $(addprefix ebt_,${pfb_build_mod}) initext4_func := $(addprefix ipt_,${pf4_build_mod}) initext6_func := $(addprefix ip6t_,${pf6_build_mod}) @@ -133,6 +142,11 @@ initext6_func := $(addprefix ip6t_,${pf6_build_mod}) cmp -s $@ $@.tmp || mv $@.tmp $@; \ rm -f $@.tmp; +.initextb.dd: FORCE + @echo "${initextb_func}" >$@.tmp; \ + cmp -s $@ $@.tmp || mv $@.tmp $@; \ + rm -f $@.tmp; + .initext4.dd: FORCE @echo "${initext4_func}" >$@.tmp; \ cmp -s $@ $@.tmp || mv $@.tmp $@; \ @@ -159,6 +173,22 @@ initext.c: .initext.dd echo "}" >>$@; \ ); +initextb.c: .initextb.dd + ${AM_VERBOSE_GEN} + @( \ + echo "" >$@; \ + for i in ${initextb_func}; do \ + echo "extern void lib$${i}_init(void);" >>$@; \ + done; \ + echo "void init_extensions(void);" >>$@; \ + echo "void init_extensions(void)" >>$@; \ + echo "{" >>$@; \ + for i in ${initextb_func}; do \ + echo " ""lib$${i}_init();" >>$@; \ + done; \ + echo "}" >>$@; \ + ); + initext4.c: .initext4.dd ${AM_VERBOSE_GEN} @( \ @@ -219,8 +249,8 @@ man_run = \ fi; \ done >$@; -matches.man: .initext.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man) - $(call man_run,$(call ex_matches,${pfx_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks})) +matches.man: .initext.dd .initextb.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man) + $(call man_run,$(call ex_matches,${pfx_build_mod} ${pfb_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks})) targets.man: .initext.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man) - $(call man_run,$(call ex_targets,${pfx_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks})) + $(call man_run,$(call ex_targets,${pfx_build_mod} ${pfb_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks})) -- 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(-) 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(-) 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 --- extensions/GNUmakefile.in | 12 +-- extensions/libebt_802_3.c | 160 ++++++++++++++++++++++++++++++ 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 ++++++++++++++++++++++++++++----------- libxtables/xtables.c | 13 +++ 8 files changed, 350 insertions(+), 91 deletions(-) create mode 100644 extensions/libebt_802_3.c diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index 7b4f891a..9eb4bf98 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -60,10 +60,10 @@ pf6_solibs := $(patsubst %,libip6t_%.so,${pf6_build_mod}) # # Building blocks # -targets := libext.a libext4.a libext6.a matches.man targets.man +targets := libext.a libext4.a libext6.a libext_ebt.a matches.man targets.man targets_install := @ENABLE_STATIC_TRUE@ libext_objs := ${pfx_objs} -@ENABLE_STATIC_TRUE@ libextb_objs := ${pfb_objs} +@ENABLE_STATIC_TRUE@ libext_ebt_objs := ${pfb_objs} @ENABLE_STATIC_TRUE@ libext4_objs := ${pf4_objs} @ENABLE_STATIC_TRUE@ libext6_objs := ${pf6_objs} @ENABLE_STATIC_FALSE@ targets += ${pfx_solibs} ${pfb_solibs} ${pf4_solibs} ${pf6_solibs} @@ -80,7 +80,7 @@ install: ${targets_install} if test -n "${targets_install}"; then install -pm0755 $^ "${DESTDIR}${xtlibdir}/"; fi; clean: - rm -f *.o *.oo *.so *.a {matches,targets}.man initext.c initext4.c initext6.c; + rm -f *.o *.oo *.so *.a {matches,targets}.man initext.c initext4.c initext6.c initextb.c; rm -f .*.d .*.dd; distclean: clean @@ -123,7 +123,7 @@ lib%.o: ${srcdir}/lib%.c libext.a: initext.o ${libext_objs} ${AM_VERBOSE_AR} ${AR} crs $@ $^; -libextb.a: initextb.o ${libextb_objs} +libext_ebt.a: initextb.o ${libext_ebt_objs} ${AM_VERBOSE_AR} ${AR} crs $@ $^; libext4.a: initext4.o ${libext4_objs} @@ -180,8 +180,8 @@ initextb.c: .initextb.dd for i in ${initextb_func}; do \ echo "extern void lib$${i}_init(void);" >>$@; \ done; \ - echo "void init_extensions(void);" >>$@; \ - echo "void init_extensions(void)" >>$@; \ + echo "void init_extensionsb(void);" >>$@; \ + echo "void init_extensionsb(void)" >>$@; \ echo "{" >>$@; \ for i in ${initextb_func}; do \ echo " ""lib$${i}_init();" >>$@; \ diff --git a/extensions/libebt_802_3.c b/extensions/libebt_802_3.c new file mode 100644 index 00000000..3ca80f77 --- /dev/null +++ b/extensions/libebt_802_3.c @@ -0,0 +1,160 @@ +/* 802_3 + * + * Author: + * Chris Vitale + * + * May 2003 + * + * Adapted by Arturo Borrero Gonzalez + * to use libxtables for ebtables-compat + */ + +#include +#include +#include +#include +#include +#include +#include + +#define _802_3_SAP '1' +#define _802_3_TYPE '2' + +static const struct option br802_3_opts[] = { + { .name = "802_3-sap", .has_arg = true, .val = _802_3_SAP }, + { .name = "802_3-type", .has_arg = true, .val = _802_3_TYPE }, + XT_GETOPT_TABLEEND, +}; + +static void br802_3_print_help(void) +{ + printf( +"802_3 options:\n" +"--802_3-sap [!] protocol : 802.3 DSAP/SSAP- 1 byte value (hex)\n" +" DSAP and SSAP are always the same. One SAP applies to both fields\n" +"--802_3-type [!] protocol : 802.3 SNAP Type- 2 byte value (hex)\n" +" Type implies SAP value 0xaa\n"); +} + +static void br802_3_init(struct xt_entry_match *match) +{ + struct ebt_802_3_info *info = (struct ebt_802_3_info *)match->data; + + info->invflags = 0; + info->bitmask = 0; +} + +/*static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, + unsigned int *flags, struct ebt_entry_match **match)*/ +static int +br802_3_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + struct ebt_802_3_info *info = (struct ebt_802_3_info *) (*match)->data; + unsigned int i; + char *end; + + switch (c) { + case _802_3_SAP: + if (invert) + info->invflags |= EBT_802_3_SAP; + i = strtoul(optarg, &end, 16); + if (i > 255 || *end != '\0') + xtables_error(PARAMETER_PROBLEM, + "Problem with specified " + "sap hex value, %x",i); + info->sap = i; /* one byte, so no byte order worries */ + info->bitmask |= EBT_802_3_SAP; + break; + case _802_3_TYPE: + if (invert) + info->invflags |= EBT_802_3_TYPE; + i = strtoul(optarg, &end, 16); + if (i > 65535 || *end != '\0') { + xtables_error(PARAMETER_PROBLEM, + "Problem with the specified " + "type hex value, %x",i); + } + info->type = htons(i); + info->bitmask |= EBT_802_3_TYPE; + break; + default: + return 0; + } + return 1; +} + +static void +br802_3_final_check(unsigned int flags) +{ + /*if (!(entry->bitmask & EBT_802_3)) + ebt_print_error("For 802.3 DSAP/SSAP filtering the protocol " + "must be LENGTH"); + */ + if (!flags) + xtables_error(PARAMETER_PROBLEM, + "You must specify proper arguments"); +} + +/*static void print(const struct ebt_u_entry *entry, + const struct ebt_entry_match *match)*/ +static void br802_3_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + struct ebt_802_3_info *info = (struct ebt_802_3_info *)match->data; + + if (info->bitmask & EBT_802_3_SAP) { + printf("--802_3-sap "); + if (info->invflags & EBT_802_3_SAP) + printf("! "); + printf("0x%.2x ", info->sap); + } + if (info->bitmask & EBT_802_3_TYPE) { + printf("--802_3-type "); + if (info->invflags & EBT_802_3_TYPE) + printf("! "); + printf("0x%.4x ", ntohs(info->type)); + } +} +/* +static int compare(const struct ebt_entry_match *m1, + const struct ebt_entry_match *m2) +{ + struct ebt_802_3_info *info1 = (struct ebt_802_3_info *)m1->data; + struct ebt_802_3_info *info2 = (struct ebt_802_3_info *)m2->data; + + if (info1->bitmask != info2->bitmask) + return 0; + if (info1->invflags != info2->invflags) + return 0; + if (info1->bitmask & EBT_802_3_SAP) { + if (info1->sap != info2->sap) + return 0; + } + if (info1->bitmask & EBT_802_3_TYPE) { + if (info1->type != info2->type) + return 0; + } + return 1; +} +*/ +static struct xtables_match br802_3_match = +{ + .name = "802_3", + .revision = 0, + .version = XTABLES_VERSION, + .family = NFPROTO_BRIDGE, + .size = XT_ALIGN(sizeof(struct ebt_802_3_info)), + .userspacesize = XT_ALIGN(sizeof(struct ebt_802_3_info)), + .init = br802_3_init, + .help = br802_3_print_help, + .parse = br802_3_parse, + .final_check = br802_3_final_check, + .print = br802_3_print, + .extra_opts = br802_3_opts, +}; + +void _init(void) +{ + xtables_register_match(&br802_3_match); +} 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, diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 68411248..6985a274 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -168,6 +168,16 @@ static const struct xtables_afinfo afinfo_ipv6 = { .so_rev_target = IP6T_SO_GET_REVISION_TARGET, }; +static const struct xtables_afinfo afinfo_bridge = { + .kmod = "eb_tables", + .proc_exists = "/proc/net/eb_tables_names", + .libprefix = "libebt_", + .family = NFPROTO_BRIDGE, + .ipproto = IPPROTO_IP, + .so_rev_match = -1, + .so_rev_target = -1, +}; + const struct xtables_afinfo *afinfo; /* Search path for Xtables .so files */ @@ -224,6 +234,9 @@ void xtables_set_nfproto(uint8_t nfproto) case NFPROTO_IPV6: afinfo = &afinfo_ipv6; break; + case NFPROTO_BRIDGE: + afinfo = &afinfo_bridge; + break; default: fprintf(stderr, "libxtables: unhandled NFPROTO in %s\n", __func__); -- 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(-) 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(-) 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(-) 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 3397fb3be98ff90ff3d6788fe08d81b65d7b027c Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Wed, 7 Jan 2015 17:22:01 +0100 Subject: ebtables-compat: include /etc/ethertypes in tarball The /etc/ethertypes file was originally distributed by the ebtables tarball. So, let's include the file also in ebtables-compat, so users can keep using protocol names instead of the hex code. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- Makefile.am | 5 +++++ etc/ethertypes | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 etc/ethertypes diff --git a/Makefile.am b/Makefile.am index 275ebc35..044f6461 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,6 +16,11 @@ SUBDIRS += extensions # Depends on extensions/libext.a: SUBDIRS += iptables +if ENABLE_NFTABLES +confdir = $(sysconfdir) +dist_conf_DATA = etc/ethertypes +endif + .PHONY: tarball tarball: rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION}; diff --git a/etc/ethertypes b/etc/ethertypes new file mode 100644 index 00000000..813177b7 --- /dev/null +++ b/etc/ethertypes @@ -0,0 +1,39 @@ +# +# Ethernet frame types +# This file describes some of the various Ethernet +# protocol types that are used on Ethernet networks. +# +# This list could be found on: +# http://www.iana.org/assignments/ethernet-numbers +# http://www.iana.org/assignments/ieee-802-numbers +# +# ... #Comment +# +IPv4 0800 ip ip4 # Internet IP (IPv4) +X25 0805 +ARP 0806 ether-arp # +FR_ARP 0808 # Frame Relay ARP [RFC1701] +BPQ 08FF # G8BPQ AX.25 Ethernet Packet +DEC 6000 # DEC Assigned proto +DNA_DL 6001 # DEC DNA Dump/Load +DNA_RC 6002 # DEC DNA Remote Console +DNA_RT 6003 # DEC DNA Routing +LAT 6004 # DEC LAT +DIAG 6005 # DEC Diagnostics +CUST 6006 # DEC Customer use +SCA 6007 # DEC Systems Comms Arch +TEB 6558 # Trans Ether Bridging [RFC1701] +RAW_FR 6559 # Raw Frame Relay [RFC1701] +RARP 8035 # Reverse ARP [RFC903] +AARP 80F3 # Appletalk AARP +ATALK 809B # Appletalk +802_1Q 8100 8021q 1q 802.1q dot1q # 802.1Q Virtual LAN tagged frame +IPX 8137 # Novell IPX +NetBEUI 8191 # NetBEUI +IPv6 86DD ip6 # IP version 6 +PPP 880B # PPP +ATMMPOA 884C # MultiProtocol over ATM +PPP_DISC 8863 # PPPoE discovery messages +PPP_SES 8864 # PPPoE session messages +ATMFATE 8884 # Frame-based ATM Transport over Ethernet +LOOP 9000 loopback # loop proto -- 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(-) 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 e911ef60d225d86bda817244fafa4b399a2d711e Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 19 Jan 2015 14:27:36 +0100 Subject: include: cache copy of Linux header uapi/linux/netfilter_bridge/ebt_802_3.h Cache a copy of Linux header uapi/linux/netfilter_bridge/ebt_802_3.h which contains the struct ebt_802_3_info definition. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter_bridge/ebt_802_3.h | 63 ++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 include/linux/netfilter_bridge/ebt_802_3.h diff --git a/include/linux/netfilter_bridge/ebt_802_3.h b/include/linux/netfilter_bridge/ebt_802_3.h new file mode 100644 index 00000000..f37522aa --- /dev/null +++ b/include/linux/netfilter_bridge/ebt_802_3.h @@ -0,0 +1,63 @@ +#ifndef _UAPI__LINUX_BRIDGE_EBT_802_3_H +#define _UAPI__LINUX_BRIDGE_EBT_802_3_H + +#include +#include + +#define EBT_802_3_SAP 0x01 +#define EBT_802_3_TYPE 0x02 + +#define EBT_802_3_MATCH "802_3" + +/* + * If frame has DSAP/SSAP value 0xaa you must check the SNAP type + * to discover what kind of packet we're carrying. + */ +#define CHECK_TYPE 0xaa + +/* + * Control field may be one or two bytes. If the first byte has + * the value 0x03 then the entire length is one byte, otherwise it is two. + * One byte controls are used in Unnumbered Information frames. + * Two byte controls are used in Numbered Information frames. + */ +#define IS_UI 0x03 + +#define EBT_802_3_MASK (EBT_802_3_SAP | EBT_802_3_TYPE | EBT_802_3) + +/* ui has one byte ctrl, ni has two */ +struct hdr_ui { + __u8 dsap; + __u8 ssap; + __u8 ctrl; + __u8 orig[3]; + __be16 type; +}; + +struct hdr_ni { + __u8 dsap; + __u8 ssap; + __be16 ctrl; + __u8 orig[3]; + __be16 type; +}; + +struct ebt_802_3_hdr { + __u8 daddr[ETH_ALEN]; + __u8 saddr[ETH_ALEN]; + __be16 len; + union { + struct hdr_ui ui; + struct hdr_ni ni; + } llc; +}; + + +struct ebt_802_3_info { + __u8 sap; + __be16 type; + __u8 bitmask; + __u8 invflags; +}; + +#endif /* _UAPI__LINUX_BRIDGE_EBT_802_3_H */ -- 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(+) 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(-) 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(+) 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(+) 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(-) 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 --- extensions/libebt_ip.c | 326 ++++++++++++++++++++++++++++++++ include/linux/netfilter_bridge/ebt_ip.h | 44 +++++ iptables/xtables-eb.c | 1 + 3 files changed, 371 insertions(+) create mode 100644 extensions/libebt_ip.c create mode 100644 include/linux/netfilter_bridge/ebt_ip.h diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c new file mode 100644 index 00000000..ffb7ed66 --- /dev/null +++ b/extensions/libebt_ip.c @@ -0,0 +1,326 @@ +/* ebt_ip + * + * Authors: + * Bart De Schuymer + * + * Changes: + * added ip-sport and ip-dport; parsing of port arguments is + * based on code from iptables-1.2.7a + * Innominate Security Technologies AG + * September, 2002 + * + * Adapted by Arturo Borrero Gonzalez + * to use libxtables for ebtables-compat in 2015. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define IP_SOURCE '1' +#define IP_DEST '2' +#define IP_EBT_TOS '3' /* include/bits/in.h seems to already define IP_TOS */ +#define IP_PROTO '4' +#define IP_SPORT '5' +#define IP_DPORT '6' + +static const struct option brip_opts[] = { + { .name = "ip-source", .has_arg = true, .val = IP_SOURCE }, + { .name = "ip-src", .has_arg = true, .val = IP_SOURCE }, + { .name = "ip-destination", .has_arg = true, .val = IP_DEST }, + { .name = "ip-dst", .has_arg = true, .val = IP_DEST }, + { .name = "ip-tos", .has_arg = true, .val = IP_EBT_TOS }, + { .name = "ip-protocol", .has_arg = true, .val = IP_PROTO }, + { .name = "ip-proto", .has_arg = true, .val = IP_PROTO }, + { .name = "ip-source-port", .has_arg = true, .val = IP_SPORT }, + { .name = "ip-sport", .has_arg = true, .val = IP_SPORT }, + { .name = "ip-destination-port",.has_arg = true, .val = IP_DPORT }, + { .name = "ip-dport", .has_arg = true, .val = IP_DPORT }, + XT_GETOPT_TABLEEND, +}; + +static void brip_print_help(void) +{ + printf( +"ip options:\n" +"--ip-src [!] address[/mask]: ip source specification\n" +"--ip-dst [!] address[/mask]: ip destination specification\n" +"--ip-tos [!] tos : ip tos specification\n" +"--ip-proto [!] protocol : ip protocol specification\n" +"--ip-sport [!] port[:port] : tcp/udp source port or port range\n" +"--ip-dport [!] port[:port] : tcp/udp destination port or port range\n"); +} + +static void brip_init(struct xt_entry_match *match) +{ + struct ebt_ip_info *info = (struct ebt_ip_info *)match->data; + + info->invflags = 0; + info->bitmask = 0; +} + +static void +parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) +{ + char *buffer; + char *cp; + + buffer = strdup(portstring); + if ((cp = strchr(buffer, ':')) == NULL) + ports[0] = ports[1] = xtables_parse_port(buffer, NULL); + else { + *cp = '\0'; + cp++; + + ports[0] = buffer[0] ? xtables_parse_port(buffer, NULL) : 0; + ports[1] = cp[0] ? xtables_parse_port(cp, NULL) : 0xFFFF; + + if (ports[0] > ports[1]) + xtables_error(PARAMETER_PROBLEM, + "invalid portrange (min > max)"); + } + free(buffer); +} + +/* original code from ebtables: useful_functions.c */ +static int undot_ip(char *ip, unsigned char *ip2) +{ + char *p, *q, *end; + long int onebyte; + int i; + char buf[20]; + + strncpy(buf, ip, sizeof(buf) - 1); + + p = buf; + for (i = 0; i < 3; i++) { + if ((q = strchr(p, '.')) == NULL) + return -1; + *q = '\0'; + onebyte = strtol(p, &end, 10); + if (*end != '\0' || onebyte > 255 || onebyte < 0) + return -1; + ip2[i] = (unsigned char)onebyte; + p = q + 1; + } + + onebyte = strtol(p, &end, 10); + if (*end != '\0' || onebyte > 255 || onebyte < 0) + return -1; + ip2[3] = (unsigned char)onebyte; + + return 0; +} + +static int ip_mask(char *mask, unsigned char *mask2) +{ + char *end; + long int bits; + uint32_t mask22; + + if (undot_ip(mask, mask2)) { + /* not the /a.b.c.e format, maybe the /x format */ + bits = strtol(mask, &end, 10); + if (*end != '\0' || bits > 32 || bits < 0) + return -1; + if (bits != 0) { + mask22 = htonl(0xFFFFFFFF << (32 - bits)); + memcpy(mask2, &mask22, 4); + } else { + mask22 = 0xFFFFFFFF; + memcpy(mask2, &mask22, 4); + } + } + return 0; +} + +static void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk) +{ + char *p; + + /* first the mask */ + if ((p = strrchr(address, '/')) != NULL) { + *p = '\0'; + if (ip_mask(p + 1, (unsigned char *)msk)) { + xtables_error(PARAMETER_PROBLEM, + "Problem with the IP mask '%s'", p + 1); + return; + } + } else + *msk = 0xFFFFFFFF; + + if (undot_ip(address, (unsigned char *)addr)) { + xtables_error(PARAMETER_PROBLEM, + "Problem with the IP address '%s'", address); + return; + } + *addr = *addr & *msk; +} + +static int +brip_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + struct ebt_ip_info *info = (struct ebt_ip_info *)(*match)->data; + + switch (c) { + case IP_SOURCE: + if (invert) + info->invflags |= EBT_IP_SOURCE; + ebt_parse_ip_address(optarg, &info->saddr, &info->smsk); + info->bitmask |= EBT_IP_SOURCE; + break; + case IP_DEST: + if (invert) + info->invflags |= EBT_IP_DEST; + ebt_parse_ip_address(optarg, &info->daddr, &info->dmsk); + info->bitmask |= EBT_IP_DEST; + break; + case IP_SPORT: + if (invert) + info->invflags |= EBT_IP_SPORT; + parse_port_range(NULL, optarg, info->sport); + info->bitmask |= EBT_IP_SPORT; + break; + case IP_DPORT: + if (invert) + info->invflags |= EBT_IP_DPORT; + parse_port_range(NULL, optarg, info->dport); + info->bitmask |= EBT_IP_DPORT; + break; + case IP_EBT_TOS: + if (invert) + info->invflags |= EBT_IP_TOS; + if (!xtables_strtoul(optarg, NULL, (uintmax_t *)&info->tos, + 0, 255)) + xtables_error(PARAMETER_PROBLEM, + "Problem with specified IP tos"); + info->bitmask |= EBT_IP_TOS; + break; + case IP_PROTO: + if (invert) + info->invflags |= EBT_IP_PROTO; + info->protocol = xtables_parse_protocol(optarg); + if (info->protocol == -1) + xtables_error(PARAMETER_PROBLEM, + "Unknown specified IP protocol - %s", + optarg); + info->bitmask |= EBT_IP_PROTO; + break; + default: + return 0; + } + return 1; +} + +static void brip_final_check(unsigned int flags) +{ +/* struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data; + + if (entry->ethproto != ETH_P_IP || entry->invflags & EBT_IPROTO) { + ebt_print_error("For IP filtering the protocol must be " + "specified as IPv4"); + } else if (info->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT) && + (!(info->bitmask & EBT_IP_PROTO) || + info->invflags & EBT_IP_PROTO || + (info->protocol!=IPPROTO_TCP && + info->protocol!=IPPROTO_UDP && + info->protocol!=IPPROTO_SCTP && + info->protocol!=IPPROTO_DCCP))) + ebt_print_error("For port filtering the IP protocol must be " + "either 6 (tcp), 17 (udp), 33 (dccp) or " + "132 (sctp)"); +*/ + if (!flags) + xtables_error(PARAMETER_PROBLEM, + "You must specify proper arguments"); +} + +static void print_port_range(uint16_t *ports) +{ + if (ports[0] == ports[1]) + printf("%d ", ports[0]); + else + printf("%d:%d ", ports[0], ports[1]); +} + +static void brip_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + struct ebt_ip_info *info = (struct ebt_ip_info *)match->data; + struct in_addr *addrp, *maskp; + + if (info->bitmask & EBT_IP_SOURCE) { + printf("--ip-src "); + if (info->invflags & EBT_IP_SOURCE) + printf("! "); + addrp = (struct in_addr *)&info->saddr; + maskp = (struct in_addr *)&info->smsk; + printf("%s%s ", xtables_ipaddr_to_numeric(addrp), + xtables_ipmask_to_numeric(maskp)); + } + if (info->bitmask & EBT_IP_DEST) { + printf("--ip-dst "); + if (info->invflags & EBT_IP_DEST) + printf("! "); + addrp = (struct in_addr *)&info->daddr; + maskp = (struct in_addr *)&info->dmsk; + printf("%s%s ", xtables_ipaddr_to_numeric(addrp), + xtables_ipmask_to_numeric(maskp)); + } + if (info->bitmask & EBT_IP_TOS) { + printf("--ip-tos "); + if (info->invflags & EBT_IP_TOS) + printf("! "); + printf("0x%02X ", info->tos); + } + if (info->bitmask & EBT_IP_PROTO) { + struct protoent *pe; + + printf("--ip-proto "); + if (info->invflags & EBT_IP_PROTO) + printf("! "); + pe = getprotobynumber(info->protocol); + if (pe == NULL) { + printf("%d ", info->protocol); + } else { + printf("%s ", pe->p_name); + } + } + if (info->bitmask & EBT_IP_SPORT) { + printf("--ip-sport "); + if (info->invflags & EBT_IP_SPORT) + printf("! "); + print_port_range(info->sport); + } + if (info->bitmask & EBT_IP_DPORT) { + printf("--ip-dport "); + if (info->invflags & EBT_IP_DPORT) + printf("! "); + print_port_range(info->dport); + } +} + +static struct xtables_match brip_match = { + .name = "ip", + .revision = 0, + .version = XTABLES_VERSION, + .family = NFPROTO_BRIDGE, + .size = XT_ALIGN(sizeof(struct ebt_ip_info)), + .userspacesize = XT_ALIGN(sizeof(struct ebt_ip_info)), + .init = brip_init, + .help = brip_print_help, + .parse = brip_parse, + .final_check = brip_final_check, + .print = brip_print, + .extra_opts = brip_opts, +}; + +void _init(void) +{ + xtables_register_match(&brip_match); +} diff --git a/include/linux/netfilter_bridge/ebt_ip.h b/include/linux/netfilter_bridge/ebt_ip.h new file mode 100644 index 00000000..c4bbc41b --- /dev/null +++ b/include/linux/netfilter_bridge/ebt_ip.h @@ -0,0 +1,44 @@ +/* + * ebt_ip + * + * Authors: + * Bart De Schuymer + * + * April, 2002 + * + * Changes: + * added ip-sport and ip-dport + * Innominate Security Technologies AG + * September, 2002 + */ + +#ifndef __LINUX_BRIDGE_EBT_IP_H +#define __LINUX_BRIDGE_EBT_IP_H + +#include + +#define EBT_IP_SOURCE 0x01 +#define EBT_IP_DEST 0x02 +#define EBT_IP_TOS 0x04 +#define EBT_IP_PROTO 0x08 +#define EBT_IP_SPORT 0x10 +#define EBT_IP_DPORT 0x20 +#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\ + EBT_IP_SPORT | EBT_IP_DPORT ) +#define EBT_IP_MATCH "ip" + +/* the same values are used for the invflags */ +struct ebt_ip_info { + __be32 saddr; + __be32 daddr; + __be32 smsk; + __be32 dmsk; + __u8 tos; + __u8 protocol; + __u8 bitmask; + __u8 invflags; + __u16 sport[2]; + __u16 dport[2]; +}; + +#endif 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 --- extensions/libebt_mark_m.c | 116 ++++++++++++++++++++++++++++ include/linux/netfilter_bridge/ebt_mark_m.h | 16 ++++ iptables/xtables-eb.c | 1 + 3 files changed, 133 insertions(+) create mode 100644 extensions/libebt_mark_m.c create mode 100644 include/linux/netfilter_bridge/ebt_mark_m.h diff --git a/extensions/libebt_mark_m.c b/extensions/libebt_mark_m.c new file mode 100644 index 00000000..d806c651 --- /dev/null +++ b/extensions/libebt_mark_m.c @@ -0,0 +1,116 @@ +/* ebt_mark_m + * + * Authors: + * Bart De Schuymer + * + * July, 2002 + * + * Adapted by Arturo Borrero Gonzalez + * to use libxtables for ebtables-compat in 2015. + */ + +#include +#include +#include +#include +#include +#include + +#define MARK '1' + +static struct option brmark_m_opts[] = { + { .name = "mark", .has_arg = true, .val = MARK }, + XT_GETOPT_TABLEEND, +}; + +static void brmark_m_print_help(void) +{ + printf( +"mark option:\n" +"--mark [!] [value][/mask]: Match nfmask value (see man page)\n"); +} + +static void brmark_m_init(struct xt_entry_match *match) +{ + struct ebt_mark_m_info *info = (struct ebt_mark_m_info *)match->data; + + info->mark = 0; + info->mask = 0; + info->invert = 0; + info->bitmask = 0; +} + +#define OPT_MARK 0x01 +static int +brmark_m_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) + (*match)->data; + char *end; + + switch (c) { + case MARK: + if (invert) + info->invert = 1; + info->mark = strtoul(optarg, &end, 0); + info->bitmask = EBT_MARK_AND; + if (*end == '/') { + if (end == optarg) + info->bitmask = EBT_MARK_OR; + info->mask = strtoul(end+1, &end, 0); + } else { + info->mask = 0xffffffff; + } + if (*end != '\0' || end == optarg) + xtables_error(PARAMETER_PROBLEM, "Bad mark value '%s'", + optarg); + break; + default: + return 0; + } + return 1; +} + +static void brmark_m_final_check(unsigned int flags) +{ + if (!flags) + xtables_error(PARAMETER_PROBLEM, + "You must specify proper arguments"); +} + +static void brmark_m_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + struct ebt_mark_m_info *info = (struct ebt_mark_m_info *)match->data; + + printf("--mark "); + if (info->invert) + printf("! "); + if (info->bitmask == EBT_MARK_OR) + printf("/0x%lx ", info->mask); + else if (info->mask != 0xffffffff) + printf("0x%lx/0x%lx ", info->mark, info->mask); + else + printf("0x%lx ", info->mark); +} + +static struct xtables_match brmark_m_match = { + .name = "mark_m", + .revision = 0, + .version = XTABLES_VERSION, + .family = NFPROTO_BRIDGE, + .size = XT_ALIGN(sizeof(struct ebt_mark_m_info)), + .userspacesize = XT_ALIGN(sizeof(struct ebt_mark_m_info)), + .init = brmark_m_init, + .help = brmark_m_print_help, + .parse = brmark_m_parse, + .final_check = brmark_m_final_check, + .print = brmark_m_print, + .extra_opts = brmark_m_opts, +}; + +void _init(void) +{ + xtables_register_match(&brmark_m_match); +} diff --git a/include/linux/netfilter_bridge/ebt_mark_m.h b/include/linux/netfilter_bridge/ebt_mark_m.h new file mode 100644 index 00000000..410f9e5a --- /dev/null +++ b/include/linux/netfilter_bridge/ebt_mark_m.h @@ -0,0 +1,16 @@ +#ifndef __LINUX_BRIDGE_EBT_MARK_M_H +#define __LINUX_BRIDGE_EBT_MARK_M_H + +#include + +#define EBT_MARK_AND 0x01 +#define EBT_MARK_OR 0x02 +#define EBT_MARK_MASK (EBT_MARK_AND | EBT_MARK_OR) +struct ebt_mark_m_info { + unsigned long mark, mask; + __u8 invert; + __u8 bitmask; +}; +#define EBT_MARK_MATCH "mark_m" + +#endif 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 1bad0c75aa5696590d5cc7279ae6a6830f761d16 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Fri, 30 Jan 2015 12:47:16 +0100 Subject: extensions: cleanup commented code in ebtables-compat extensions This code can be cleaned up. No need for validation from userspace, the kernel will reject incorrect options. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- extensions/libebt_802_3.c | 29 ----------------------------- extensions/libebt_ip.c | 16 ---------------- 2 files changed, 45 deletions(-) diff --git a/extensions/libebt_802_3.c b/extensions/libebt_802_3.c index 3ca80f77..e19c21d0 100644 --- a/extensions/libebt_802_3.c +++ b/extensions/libebt_802_3.c @@ -44,8 +44,6 @@ static void br802_3_init(struct xt_entry_match *match) info->bitmask = 0; } -/*static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, - unsigned int *flags, struct ebt_entry_match **match)*/ static int br802_3_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) @@ -87,17 +85,11 @@ br802_3_parse(int c, char **argv, int invert, unsigned int *flags, static void br802_3_final_check(unsigned int flags) { - /*if (!(entry->bitmask & EBT_802_3)) - ebt_print_error("For 802.3 DSAP/SSAP filtering the protocol " - "must be LENGTH"); - */ if (!flags) xtables_error(PARAMETER_PROBLEM, "You must specify proper arguments"); } -/*static void print(const struct ebt_u_entry *entry, - const struct ebt_entry_match *match)*/ static void br802_3_print(const void *ip, const struct xt_entry_match *match, int numeric) { @@ -116,28 +108,7 @@ static void br802_3_print(const void *ip, const struct xt_entry_match *match, printf("0x%.4x ", ntohs(info->type)); } } -/* -static int compare(const struct ebt_entry_match *m1, - const struct ebt_entry_match *m2) -{ - struct ebt_802_3_info *info1 = (struct ebt_802_3_info *)m1->data; - struct ebt_802_3_info *info2 = (struct ebt_802_3_info *)m2->data; - if (info1->bitmask != info2->bitmask) - return 0; - if (info1->invflags != info2->invflags) - return 0; - if (info1->bitmask & EBT_802_3_SAP) { - if (info1->sap != info2->sap) - return 0; - } - if (info1->bitmask & EBT_802_3_TYPE) { - if (info1->type != info2->type) - return 0; - } - return 1; -} -*/ static struct xtables_match br802_3_match = { .name = "802_3", diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c index ffb7ed66..a85810bc 100644 --- a/extensions/libebt_ip.c +++ b/extensions/libebt_ip.c @@ -219,22 +219,6 @@ brip_parse(int c, char **argv, int invert, unsigned int *flags, static void brip_final_check(unsigned int flags) { -/* struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data; - - if (entry->ethproto != ETH_P_IP || entry->invflags & EBT_IPROTO) { - ebt_print_error("For IP filtering the protocol must be " - "specified as IPv4"); - } else if (info->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT) && - (!(info->bitmask & EBT_IP_PROTO) || - info->invflags & EBT_IP_PROTO || - (info->protocol!=IPPROTO_TCP && - info->protocol!=IPPROTO_UDP && - info->protocol!=IPPROTO_SCTP && - info->protocol!=IPPROTO_DCCP))) - ebt_print_error("For port filtering the IP protocol must be " - "either 6 (tcp), 17 (udp), 33 (dccp) or " - "132 (sctp)"); -*/ if (!flags) xtables_error(PARAMETER_PROBLEM, "You must specify proper arguments"); -- cgit v1.2.3 From 417bb65240a7d444a26232b1d8b30fa3ee6ecbf3 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Thu, 29 Jan 2015 17:44:33 +0100 Subject: libxtables: search first for AF-specific extension There are some extension which may name-clash, for example: * libxt_mark.so * liebt_mark.so Let's search first for AF-specific extension and then for the generic libxt_**. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- libxtables/xtables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 6985a274..16e4d969 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -549,7 +549,7 @@ void xtables_parse_interface(const char *arg, char *vianame, static void *load_extension(const char *search_path, const char *af_prefix, const char *name, bool is_target) { - const char *all_prefixes[] = {"libxt_", af_prefix, NULL}; + const char *all_prefixes[] = {af_prefix, "libxt_", NULL}; const char **prefix; const char *dir = search_path, *next; void *ptr = NULL; -- 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 --- extensions/libebt_802_3.c | 2 ++ extensions/libebt_ip.c | 2 ++ extensions/libebt_mark_m.c | 2 ++ iptables/xtables-eb.c | 50 ++++++++++++++++------------------------------ 4 files changed, 23 insertions(+), 33 deletions(-) diff --git a/extensions/libebt_802_3.c b/extensions/libebt_802_3.c index e19c21d0..3c4a1c3c 100644 --- a/extensions/libebt_802_3.c +++ b/extensions/libebt_802_3.c @@ -79,6 +79,8 @@ br802_3_parse(int c, char **argv, int invert, unsigned int *flags, default: return 0; } + + *flags |= info->bitmask; return 1; } diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c index a85810bc..8b628760 100644 --- a/extensions/libebt_ip.c +++ b/extensions/libebt_ip.c @@ -214,6 +214,8 @@ brip_parse(int c, char **argv, int invert, unsigned int *flags, default: return 0; } + + *flags |= info->bitmask; return 1; } diff --git a/extensions/libebt_mark_m.c b/extensions/libebt_mark_m.c index d806c651..ef9eb6a6 100644 --- a/extensions/libebt_mark_m.c +++ b/extensions/libebt_mark_m.c @@ -69,6 +69,8 @@ brmark_m_parse(int c, char **argv, int invert, unsigned int *flags, default: return 0; } + + *flags |= info->bitmask; return 1; } 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(-) 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 4e5ed8d8165b3d4a16a6133cfc1b43118a0e2a3d Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Tue, 3 Feb 2015 16:29:35 +0100 Subject: ebtables-compat: add mark target extension Translate the mark target extension to the xtables-compat environment. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- extensions/libebt_mark.c | 191 ++++++++++++++++++++++++++++ include/linux/netfilter_bridge/ebt_mark_t.h | 23 ++++ 2 files changed, 214 insertions(+) create mode 100644 extensions/libebt_mark.c create mode 100644 include/linux/netfilter_bridge/ebt_mark_t.h diff --git a/extensions/libebt_mark.c b/extensions/libebt_mark.c new file mode 100644 index 00000000..587b4a63 --- /dev/null +++ b/extensions/libebt_mark.c @@ -0,0 +1,191 @@ +/* ebt_mark + * + * Authors: + * Bart De Schuymer + * + * July, 2002, September 2006 + * + * Adapted by Arturo Borrero Gonzalez + * to use libxtables for ebtables-compat in 2015. + */ + +#include +#include +#include +#include +#include +#include +#include "iptables/nft.h" +#include "iptables/nft-bridge.h" + +static int mark_supplied; + +#define MARK_TARGET '1' +#define MARK_SETMARK '2' +#define MARK_ORMARK '3' +#define MARK_ANDMARK '4' +#define MARK_XORMARK '5' +static struct option brmark_opts[] = { + { .name = "mark-target",.has_arg = true, .val = MARK_TARGET }, + /* an oldtime messup, we should have always used the scheme + * -