Blame extensions/libebt_among.c

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