diff options
Diffstat (limited to 'extensions')
-rw-r--r-- | extensions/libebt_among.c | 243 | ||||
-rw-r--r-- | extensions/libebt_among.t | 16 |
2 files changed, 259 insertions, 0 deletions
diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c new file mode 100644 index 00000000..2e87db3b --- /dev/null +++ b/extensions/libebt_among.c @@ -0,0 +1,243 @@ +/* ebt_among + * + * Authors: + * Grzegorz Borowiak <grzes@gnu.univ.gda.pl> + * + * August, 2003 + */ + +#include <ctype.h> +#include <fcntl.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <xtables.h> +#include <arpa/inet.h> +#include <netinet/ether.h> +#include <netinet/in.h> +#include <linux/if_ether.h> +#include <linux/netfilter_bridge/ebt_among.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include "iptables/nft.h" +#include "iptables/nft-bridge.h" + +#define AMONG_DST '1' +#define AMONG_SRC '2' +#define AMONG_DST_F '3' +#define AMONG_SRC_F '4' + +static const struct option bramong_opts[] = { + {"among-dst", required_argument, 0, AMONG_DST}, + {"among-src", required_argument, 0, AMONG_SRC}, + {"among-dst-file", required_argument, 0, AMONG_DST_F}, + {"among-src-file", required_argument, 0, AMONG_SRC_F}, + {0} +}; + +static void bramong_print_help(void) +{ + printf( +"`among' options:\n" +"--among-dst [!] list : matches if ether dst is in list\n" +"--among-src [!] list : matches if ether src is in list\n" +"--among-dst-file [!] file : obtain dst list from file\n" +"--among-src-file [!] file : obtain src list from file\n" +"list has form:\n" +" xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip],yy:yy:yy:yy:yy:yy[=ip.ip.ip.ip]" +",...,zz:zz:zz:zz:zz:zz[=ip.ip.ip.ip][,]\n" +"Things in brackets are optional.\n" +"If you want to allow two (or more) IP addresses to one MAC address, you\n" +"can specify two (or more) pairs with the same MAC, e.g.\n" +" 00:00:00:fa:eb:fe=153.19.120.250,00:00:00:fa:eb:fe=192.168.0.1\n" + ); +} + +static void +parse_nft_among_pair(char *buf, struct nft_among_pair *pair, bool have_ip) +{ + char *sep = index(buf, '='); + struct ether_addr *ether; + + if (have_ip ^ !!sep) + xtables_error(PARAMETER_PROBLEM, + "among: Mixed MAC and MAC=IP not allowed."); + + if (sep) { + *sep = '\0'; + + if (!inet_aton(sep + 1, &pair->in)) + xtables_error(PARAMETER_PROBLEM, + "Invalid IP address '%s'\n", sep + 1); + } + ether = ether_aton(buf); + if (!ether) + xtables_error(PARAMETER_PROBLEM, + "Invalid MAC address '%s'\n", buf); + memcpy(&pair->ether, ether, sizeof(*ether)); +} + +static void +parse_nft_among_pairs(struct nft_among_pair *pairs, char *buf, + size_t cnt, bool have_ip) +{ + size_t tmpcnt = 0; + + buf = strtok(buf, ","); + while (buf) { + struct nft_among_pair pair = {}; + + parse_nft_among_pair(buf, &pair, have_ip); + nft_among_insert_pair(pairs, &tmpcnt, &pair); + buf = strtok(NULL, ","); + } +} + +static size_t count_nft_among_pairs(char *buf) +{ + size_t cnt = 0; + char *p = buf; + + if (!*buf) + return 0; + + do { + cnt++; + p = index(++p, ','); + } while (p); + + return cnt; +} + +static bool nft_among_pairs_have_ip(char *buf) +{ + return !!index(buf, '='); +} + +static int bramong_parse(int c, char **argv, int invert, + unsigned int *flags, const void *entry, + struct xt_entry_match **match) +{ + struct nft_among_data *data = (struct nft_among_data *)(*match)->data; + struct xt_entry_match *new_match; + bool have_ip, dst = false; + size_t new_size, cnt; + struct stat stats; + int fd = -1, poff; + long flen = 0; + + switch (c) { + case AMONG_DST_F: + dst = true; + /* fall through */ + case AMONG_SRC_F: + if ((fd = open(optarg, O_RDONLY)) == -1) + xtables_error(PARAMETER_PROBLEM, + "Couldn't open file '%s'", optarg); + fstat(fd, &stats); + flen = stats.st_size; + /* use mmap because the file will probably be big */ + optarg = mmap(0, flen, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0); + if (optarg == MAP_FAILED) + xtables_error(PARAMETER_PROBLEM, + "Couldn't map file to memory"); + if (optarg[flen-1] != '\n') + xtables_error(PARAMETER_PROBLEM, + "File should end with a newline"); + if (strchr(optarg, '\n') != optarg+flen-1) + xtables_error(PARAMETER_PROBLEM, + "File should only contain one line"); + optarg[flen-1] = '\0'; + /* fall through */ + case AMONG_DST: + if (c == AMONG_DST) + dst = true; + /* fall through */ + case AMONG_SRC: + break; + default: + return 0; + } + + cnt = count_nft_among_pairs(optarg); + if (cnt == 0) + return 0; + + new_size = data->src.cnt + data->dst.cnt + cnt; + new_size *= sizeof(struct nft_among_pair); + new_size += XT_ALIGN(sizeof(struct xt_entry_match)) + + sizeof(struct nft_among_data); + new_match = xtables_calloc(1, new_size); + memcpy(new_match, *match, (*match)->u.match_size); + new_match->u.match_size = new_size; + + data = (struct nft_among_data *)new_match->data; + have_ip = nft_among_pairs_have_ip(optarg); + poff = nft_among_prepare_data(data, dst, cnt, invert, have_ip); + parse_nft_among_pairs(data->pairs + poff, optarg, cnt, have_ip); + + free(*match); + *match = new_match; + + if (c == AMONG_DST_F || c == AMONG_SRC_F) { + munmap(argv, flen); + close(fd); + } + return 1; +} + +static void __bramong_print(struct nft_among_pair *pairs, + int cnt, bool inv, bool have_ip) +{ + const char *isep = inv ? "! " : ""; + int i; + + for (i = 0; i < cnt; i++) { + printf("%s", isep); + isep = ","; + + printf("%s", ether_ntoa(&pairs[i].ether)); + if (have_ip) + printf("=%s", inet_ntoa(pairs[i].in)); + } + printf(" "); +} + +static void bramong_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + struct nft_among_data *data = (struct nft_among_data *)match->data; + + if (data->src.cnt) { + printf("--among-src "); + __bramong_print(data->pairs, + data->src.cnt, data->src.inv, data->src.ip); + } + if (data->dst.cnt) { + printf("--among-dst "); + __bramong_print(data->pairs + data->src.cnt, + data->dst.cnt, data->dst.inv, data->dst.ip); + } +} + +static struct xtables_match bramong_match = { + .name = "among", + .revision = 0, + .version = XTABLES_VERSION, + .family = NFPROTO_BRIDGE, + .size = XT_ALIGN(sizeof(struct nft_among_data)), + .userspacesize = XT_ALIGN(sizeof(struct nft_among_data)), + .help = bramong_print_help, + .parse = bramong_parse, + .print = bramong_print, + .extra_opts = bramong_opts, +}; + +void _init(void) +{ + xtables_register_match(&bramong_match); +} diff --git a/extensions/libebt_among.t b/extensions/libebt_among.t new file mode 100644 index 00000000..56b29916 --- /dev/null +++ b/extensions/libebt_among.t @@ -0,0 +1,16 @@ +:INPUT,FORWARD,OUTPUT +--among-dst de:ad:0:be:ee:ff,c0:ff:ee:0:ba:be;--among-dst c0:ff:ee:0:ba:be,de:ad:0:be:ee:ff;OK +--among-dst ! c0:ff:ee:0:ba:be,de:ad:0:be:ee:ff;=;OK +--among-src be:ef:0:c0:ff:ee,c0:ff:ee:0:ba:be,de:ad:0:be:ee:ff;=;OK +--among-src de:ad:0:be:ee:ff=10.0.0.1,c0:ff:ee:0:ba:be=192.168.1.1;--among-src c0:ff:ee:0:ba:be=192.168.1.1,de:ad:0:be:ee:ff=10.0.0.1;OK +--among-src ! c0:ff:ee:0:ba:be=192.168.1.1,de:ad:0:be:ee:ff=10.0.0.1;=;OK +--among-src de:ad:0:be:ee:ff --among-dst c0:ff:ee:0:ba:be;=;OK +--among-src de:ad:0:be:ee:ff=10.0.0.1 --among-dst c0:ff:ee:0:ba:be=192.168.1.1;=;OK +--among-src ! de:ad:0:be:ee:ff --among-dst c0:ff:ee:0:ba:be;=;OK +--among-src de:ad:0:be:ee:ff=10.0.0.1 --among-dst ! c0:ff:ee:0:ba:be=192.168.1.1;=;OK +--among-src ! de:ad:0:be:ee:ff --among-dst c0:ff:ee:0:ba:be=192.168.1.1;=;OK +--among-src de:ad:0:be:ee:ff=10.0.0.1 --among-dst ! c0:ff:ee:0:ba:be=192.168.1.1;=;OK +--among-src;=;FAIL +--among-src 00:11=10.0.0.1;=;FAIL +--among-src de:ad:0:be:ee:ff=10.256.0.1;=;FAIL +--among-src de:ad:0:be:ee:ff,c0:ff:ee:0:ba:be=192.168.1.1;=;FAIL |