From a567dc31731cf920a83be8f73e557e33a5091b53 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 10 Apr 2018 11:54:57 +0200 Subject: ebtables-compat: add 'vlan' match extension Signed-off-by: Florian Westphal --- extensions/libebt_vlan.c | 226 ++++++++++++++++++++++++++++++++++++++++++ extensions/libebt_vlan.txlate | 11 ++ 2 files changed, 237 insertions(+) create mode 100644 extensions/libebt_vlan.c create mode 100644 extensions/libebt_vlan.txlate (limited to 'extensions') diff --git a/extensions/libebt_vlan.c b/extensions/libebt_vlan.c new file mode 100644 index 00000000..4e2ea0fc --- /dev/null +++ b/extensions/libebt_vlan.c @@ -0,0 +1,226 @@ +/* ebt_vlan + * + * Authors: + * Bart De Schuymer + * Nick Fedchik + * June, 2002 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iptables/nft.h" +#include "iptables/nft-bridge.h" + +#define NAME_VLAN_ID "id" +#define NAME_VLAN_PRIO "prio" +#define NAME_VLAN_ENCAP "encap" + +#define VLAN_ID '1' +#define VLAN_PRIO '2' +#define VLAN_ENCAP '3' + +static const struct option brvlan_opts[] = { + {"vlan-id" , required_argument, NULL, VLAN_ID}, + {"vlan-prio" , required_argument, NULL, VLAN_PRIO}, + {"vlan-encap", required_argument, NULL, VLAN_ENCAP}, + XT_GETOPT_TABLEEND, +}; + +/* + * option inverse flags definition + */ +#define OPT_VLAN_ID 0x01 +#define OPT_VLAN_PRIO 0x02 +#define OPT_VLAN_ENCAP 0x04 +#define OPT_VLAN_FLAGS (OPT_VLAN_ID | OPT_VLAN_PRIO | OPT_VLAN_ENCAP) + +static void brvlan_print_help(void) +{ + printf( +"vlan options:\n" +"--vlan-id [!] id : vlan-tagged frame identifier, 0,1-4096 (integer)\n" +"--vlan-prio [!] prio : Priority-tagged frame's user priority, 0-7 (integer)\n" +"--vlan-encap [!] encap : Encapsulated frame protocol (hexadecimal or name)\n"); +} + +static struct ethertypeent *vlan_getethertypeent(FILE *etherf, const char *name) +{ + static struct ethertypeent et_ent; + char *e, *found_name; + char line[1024]; + + while ((e = fgets(line, sizeof(line), etherf))) { + char *endptr, *cp; + + if (*e == '#') + continue; + + cp = strpbrk(e, "#\n"); + if (cp == NULL) + continue; + *cp = '\0'; + found_name = e; + + cp = strpbrk(e, " \t"); + if (cp == NULL) + continue; + + *cp++ = '\0'; + while (*cp == ' ' || *cp == '\t') + cp++; + e = strpbrk(cp, " \t"); + if (e != NULL) + *e++ = '\0'; + + et_ent.e_ethertype = strtol(cp, &endptr, 16); + if (*endptr != '\0' || + (et_ent.e_ethertype < ETH_ZLEN || et_ent.e_ethertype > 0xFFFF)) + continue; // skip invalid etherproto type entry + + if (strcasecmp(found_name, name) == 0) + return (&et_ent); + + if (e != NULL) { + cp = e; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + e = cp; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + if (strcasecmp(e, name) == 0) + return (&et_ent); + e = cp; + } + } + } + + return NULL; +} + +static struct ethertypeent *brvlan_getethertypebyname(const char *name) +{ + struct ethertypeent *e; + FILE *etherf; + + etherf = fopen(_PATH_ETHERTYPES, "r"); + + e = vlan_getethertypeent(etherf, name); + fclose(etherf); + return (e); +} + +static int +brvlan_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) (*match)->data; + struct ethertypeent *ethent; + char *end; + struct ebt_vlan_info local; + + switch (c) { + case VLAN_ID: + EBT_CHECK_OPTION(flags, OPT_VLAN_ID); + if (invert) + vlaninfo->invflags |= EBT_VLAN_ID; + local.id = strtoul(optarg, &end, 10); + if (local.id > 4094 || *end != '\0') + xtables_error(PARAMETER_PROBLEM, "Invalid --vlan-id range ('%s')", optarg); + vlaninfo->id = local.id; + vlaninfo->bitmask |= EBT_VLAN_ID; + break; + case VLAN_PRIO: + EBT_CHECK_OPTION(flags, OPT_VLAN_PRIO); + if (invert) + vlaninfo->invflags |= EBT_VLAN_PRIO; + local.prio = strtoul(optarg, &end, 10); + if (local.prio >= 8 || *end != '\0') + xtables_error(PARAMETER_PROBLEM, "Invalid --vlan-prio range ('%s')", optarg); + vlaninfo->prio = local.prio; + vlaninfo->bitmask |= EBT_VLAN_PRIO; + break; + case VLAN_ENCAP: + EBT_CHECK_OPTION(flags, OPT_VLAN_ENCAP); + if (invert) + vlaninfo->invflags |= EBT_VLAN_ENCAP; + local.encap = strtoul(optarg, &end, 16); + if (*end != '\0') { + ethent = brvlan_getethertypebyname(optarg); + if (ethent == NULL) + xtables_error(PARAMETER_PROBLEM, "Unknown --vlan-encap value ('%s')", optarg); + local.encap = ethent->e_ethertype; + } + if (local.encap < ETH_ZLEN) + xtables_error(PARAMETER_PROBLEM, "Invalid --vlan-encap range ('%s')", optarg); + vlaninfo->encap = htons(local.encap); + vlaninfo->bitmask |= EBT_VLAN_ENCAP; + break; + default: + return 0; + + } + return 1; +} + +static void brvlan_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) match->data; + + if (vlaninfo->bitmask & EBT_VLAN_ID) { + printf("--vlan-id %s%d ", (vlaninfo->invflags & EBT_VLAN_ID) ? "! " : "", vlaninfo->id); + } + if (vlaninfo->bitmask & EBT_VLAN_PRIO) { + printf("--vlan-prio %s%d ", (vlaninfo->invflags & EBT_VLAN_PRIO) ? "! " : "", vlaninfo->prio); + } + if (vlaninfo->bitmask & EBT_VLAN_ENCAP) { + printf("--vlan-encap %s", (vlaninfo->invflags & EBT_VLAN_ENCAP) ? "! " : ""); + printf("%4.4X ", ntohs(vlaninfo->encap)); + } +} + +static int brvlan_xlate(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct ebt_vlan_info *vlaninfo = (const void*)params->match->data; + + if (vlaninfo->bitmask & EBT_VLAN_ID) + xt_xlate_add(xl, "vlan id %s%d ", (vlaninfo->invflags & EBT_VLAN_ID) ? "!= " : "", vlaninfo->id); + + if (vlaninfo->bitmask & EBT_VLAN_PRIO) + xt_xlate_add(xl, "vlan pcp %s%d ", (vlaninfo->invflags & EBT_VLAN_PRIO) ? "!= " : "", vlaninfo->prio); + + if (vlaninfo->bitmask & EBT_VLAN_ENCAP) + xt_xlate_add(xl, "vlan type %s0x%4.4x ", (vlaninfo->invflags & EBT_VLAN_ENCAP) ? "!= " : "", ntohs(vlaninfo->encap)); + + return 1; +} + +static struct xtables_match brvlan_match = { + .name = "vlan", + .version = XTABLES_VERSION, + .family = NFPROTO_BRIDGE, + .size = XT_ALIGN(sizeof(struct ebt_vlan_info)), + .userspacesize = XT_ALIGN(sizeof(struct ebt_vlan_info)), + .help = brvlan_print_help, + .parse = brvlan_parse, + .print = brvlan_print, + .xlate = brvlan_xlate, + .extra_opts = brvlan_opts, +}; + +void _init(void) +{ + xtables_register_match(&brvlan_match); +} diff --git a/extensions/libebt_vlan.txlate b/extensions/libebt_vlan.txlate new file mode 100644 index 00000000..fe1ec141 --- /dev/null +++ b/extensions/libebt_vlan.txlate @@ -0,0 +1,11 @@ +ebtables-translate -A INPUT --vlan-id 42 +nft add rule bridge filter INPUT vlan id 42 counter + +ebtables-translate -A INPUT --vlan-prio ! 1 +nft add rule bridge filter INPUT vlan pcp != 1 counter + +ebtables-translate -A INPUT --vlan-encap ip +nft add rule bridge filter INPUT vlan type 0x0800 counter + +ebtables-translate -A INPUT --vlan-encap ipv6 ! --vlan-id 1 +nft add rule bridge filter INPUT vlan id != 1 vlan type 0x86dd counter -- cgit v1.2.3