|
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 (have_ip ^ !!sep)
|
|
Packit |
7b22a4 |
xtables_error(PARAMETER_PROBLEM,
|
|
Packit |
7b22a4 |
"among: Mixed MAC and MAC=IP not allowed.");
|
|
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 |
7b22a4 |
if (have_ip)
|
|
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 |
}
|