Blame extensions/libebt_among.c

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