228 lines
5.6 KiB
C
228 lines
5.6 KiB
C
/* Shared library add-on to iptables to add devgroup matching support.
|
|
*
|
|
* Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
|
|
*/
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <xtables.h>
|
|
#include <linux/netfilter/xt_devgroup.h>
|
|
|
|
static void devgroup_help(void)
|
|
{
|
|
printf(
|
|
"devgroup match options:\n"
|
|
"[!] --src-group value[/mask] Match device group of incoming device\n"
|
|
"[!] --dst-group value[/mask] Match device group of outgoing device\n"
|
|
);
|
|
}
|
|
|
|
enum {
|
|
O_SRC_GROUP = 0,
|
|
O_DST_GROUP,
|
|
};
|
|
|
|
static const struct xt_option_entry devgroup_opts[] = {
|
|
{.name = "src-group", .id = O_SRC_GROUP, .type = XTTYPE_STRING,
|
|
.flags = XTOPT_INVERT},
|
|
{.name = "dst-group", .id = O_DST_GROUP, .type = XTTYPE_STRING,
|
|
.flags = XTOPT_INVERT},
|
|
XTOPT_TABLEEND,
|
|
};
|
|
|
|
/* array of devgroups from /etc/iproute2/group */
|
|
static struct xtables_lmap *devgroups;
|
|
|
|
static void devgroup_init(struct xt_entry_match *match)
|
|
{
|
|
const char file[] = "/etc/iproute2/group";
|
|
devgroups = xtables_lmap_init(file);
|
|
if (devgroups == NULL && errno != ENOENT)
|
|
fprintf(stderr, "Warning: %s: %s\n", file, strerror(errno));
|
|
}
|
|
|
|
static void devgroup_parse_groupspec(const char *arg, unsigned int *group,
|
|
unsigned int *mask)
|
|
{
|
|
char *end;
|
|
bool ok;
|
|
|
|
ok = xtables_strtoui(arg, &end, group, 0, UINT32_MAX);
|
|
if (ok && (*end == '/' || *end == '\0')) {
|
|
if (*end == '/')
|
|
ok = xtables_strtoui(end + 1, NULL, mask,
|
|
0, UINT32_MAX);
|
|
else
|
|
*mask = ~0U;
|
|
if (!ok)
|
|
xtables_error(PARAMETER_PROBLEM,
|
|
"Bad group value \"%s\"", arg);
|
|
} else {
|
|
*group = xtables_lmap_name2id(devgroups, arg);
|
|
if (*group == -1)
|
|
xtables_error(PARAMETER_PROBLEM,
|
|
"Device group \"%s\" not found", arg);
|
|
*mask = ~0U;
|
|
}
|
|
}
|
|
|
|
static void devgroup_parse(struct xt_option_call *cb)
|
|
{
|
|
struct xt_devgroup_info *info = cb->data;
|
|
unsigned int id, mask;
|
|
|
|
xtables_option_parse(cb);
|
|
switch (cb->entry->id) {
|
|
case O_SRC_GROUP:
|
|
devgroup_parse_groupspec(cb->arg, &id, &mask);
|
|
info->src_group = id;
|
|
info->src_mask = mask;
|
|
info->flags |= XT_DEVGROUP_MATCH_SRC;
|
|
if (cb->invert)
|
|
info->flags |= XT_DEVGROUP_INVERT_SRC;
|
|
break;
|
|
case O_DST_GROUP:
|
|
devgroup_parse_groupspec(cb->arg, &id, &mask);
|
|
info->dst_group = id;
|
|
info->dst_mask = mask;
|
|
info->flags |= XT_DEVGROUP_MATCH_DST;
|
|
if (cb->invert)
|
|
info->flags |= XT_DEVGROUP_INVERT_DST;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
print_devgroup(unsigned int id, unsigned int mask, int numeric)
|
|
{
|
|
const char *name = NULL;
|
|
|
|
if (mask != 0xffffffff)
|
|
printf("0x%x/0x%x", id, mask);
|
|
else {
|
|
if (numeric == 0)
|
|
name = xtables_lmap_id2name(devgroups, id);
|
|
if (name)
|
|
printf("%s", name);
|
|
else
|
|
printf("0x%x", id);
|
|
}
|
|
}
|
|
|
|
static void devgroup_show(const char *pfx, const struct xt_devgroup_info *info,
|
|
int numeric)
|
|
{
|
|
if (info->flags & XT_DEVGROUP_MATCH_SRC) {
|
|
if (info->flags & XT_DEVGROUP_INVERT_SRC)
|
|
printf(" !");
|
|
printf(" %ssrc-group ", pfx);
|
|
print_devgroup(info->src_group, info->src_mask, numeric);
|
|
}
|
|
|
|
if (info->flags & XT_DEVGROUP_MATCH_DST) {
|
|
if (info->flags & XT_DEVGROUP_INVERT_DST)
|
|
printf(" !");
|
|
printf(" %sdst-group ", pfx);
|
|
print_devgroup(info->dst_group, info->dst_mask, numeric);
|
|
}
|
|
}
|
|
|
|
static void devgroup_print(const void *ip, const struct xt_entry_match *match,
|
|
int numeric)
|
|
{
|
|
const struct xt_devgroup_info *info = (const void *)match->data;
|
|
|
|
devgroup_show("", info, numeric);
|
|
}
|
|
|
|
static void devgroup_save(const void *ip, const struct xt_entry_match *match)
|
|
{
|
|
const struct xt_devgroup_info *info = (const void *)match->data;
|
|
|
|
devgroup_show("--", info, 0);
|
|
}
|
|
|
|
static void devgroup_check(struct xt_fcheck_call *cb)
|
|
{
|
|
if (cb->xflags == 0)
|
|
xtables_error(PARAMETER_PROBLEM,
|
|
"devgroup match: You must specify either "
|
|
"'--src-group' or '--dst-group'");
|
|
}
|
|
|
|
static void
|
|
print_devgroup_xlate(unsigned int id, uint32_t op, unsigned int mask,
|
|
struct xt_xlate *xl, int numeric)
|
|
{
|
|
const char *name = NULL;
|
|
|
|
if (mask != 0xffffffff)
|
|
xt_xlate_add(xl, "and 0x%x %s 0x%x", mask,
|
|
op == XT_OP_EQ ? "==" : "!=", id);
|
|
else {
|
|
if (numeric == 0)
|
|
name = xtables_lmap_id2name(devgroups, id);
|
|
|
|
xt_xlate_add(xl, "%s", op == XT_OP_EQ ? "" : "!= ");
|
|
if (name)
|
|
xt_xlate_add(xl, "%s", name);
|
|
else
|
|
xt_xlate_add(xl, "0x%x", id);
|
|
}
|
|
}
|
|
|
|
static void devgroup_show_xlate(const struct xt_devgroup_info *info,
|
|
struct xt_xlate *xl, int numeric)
|
|
{
|
|
enum xt_op op = XT_OP_EQ;
|
|
char *space = "";
|
|
|
|
if (info->flags & XT_DEVGROUP_MATCH_SRC) {
|
|
if (info->flags & XT_DEVGROUP_INVERT_SRC)
|
|
op = XT_OP_NEQ;
|
|
xt_xlate_add(xl, "iifgroup ");
|
|
print_devgroup_xlate(info->src_group, op,
|
|
info->src_mask, xl, numeric);
|
|
space = " ";
|
|
}
|
|
|
|
if (info->flags & XT_DEVGROUP_MATCH_DST) {
|
|
if (info->flags & XT_DEVGROUP_INVERT_DST)
|
|
op = XT_OP_NEQ;
|
|
xt_xlate_add(xl, "%soifgroup ", space);
|
|
print_devgroup_xlate(info->dst_group, op,
|
|
info->dst_mask, xl, numeric);
|
|
}
|
|
}
|
|
|
|
static int devgroup_xlate(struct xt_xlate *xl,
|
|
const struct xt_xlate_mt_params *params)
|
|
{
|
|
const struct xt_devgroup_info *info = (const void *)params->match->data;
|
|
|
|
devgroup_show_xlate(info, xl, 0);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static struct xtables_match devgroup_mt_reg = {
|
|
.name = "devgroup",
|
|
.version = XTABLES_VERSION,
|
|
.family = NFPROTO_UNSPEC,
|
|
.size = XT_ALIGN(sizeof(struct xt_devgroup_info)),
|
|
.userspacesize = XT_ALIGN(sizeof(struct xt_devgroup_info)),
|
|
.init = devgroup_init,
|
|
.help = devgroup_help,
|
|
.print = devgroup_print,
|
|
.save = devgroup_save,
|
|
.x6_parse = devgroup_parse,
|
|
.x6_fcheck = devgroup_check,
|
|
.x6_options = devgroup_opts,
|
|
.xlate = devgroup_xlate,
|
|
};
|
|
|
|
void _init(void)
|
|
{
|
|
xtables_register_match(&devgroup_mt_reg);
|
|
}
|