blob: 97ad8044bbeb936797ca71d16e8211eeaee632c0 [file] [log] [blame]
/* Shared library add-on to iptables to add addrtype matching support
*
* This program is released under the terms of GNU GPL */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <iptables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_addrtype.h>
/* from linux/rtnetlink.h, must match order of enumeration */
static const char *const rtn_names[] = {
"UNSPEC",
"UNICAST",
"LOCAL",
"BROADCAST",
"ANYCAST",
"MULTICAST",
"BLACKHOLE",
"UNREACHABLE",
"PROHIBIT",
"THROW",
"NAT",
"XRESOLVE",
NULL
};
static void addrtype_help_types(void)
{
int i;
for (i = 0; rtn_names[i]; i++)
printf(" %s\n", rtn_names[i]);
}
static void addrtype_help_v0(void)
{
printf(
"Address type match options:\n"
" [!] --src-type type[,...] Match source address type\n"
" [!] --dst-type type[,...] Match destination address type\n"
"\n"
"Valid types: \n");
addrtype_help_types();
}
static void addrtype_help_v1(void)
{
printf(
"Address type match options:\n"
" [!] --src-type type[,...] Match source address type\n"
" [!] --dst-type type[,...] Match destination address type\n"
" --limit-iface-in Match only on the packet's incoming device\n"
" --limit-iface-out Match only on the packet's incoming device\n"
"\n"
"Valid types: \n");
addrtype_help_types();
}
static int
parse_type(const char *name, size_t len, u_int16_t *mask)
{
int i;
for (i = 0; rtn_names[i]; i++)
if (strncasecmp(name, rtn_names[i], len) == 0) {
/* build up bitmask for kernel module */
*mask |= (1 << i);
return 1;
}
return 0;
}
static void parse_types(const char *arg, u_int16_t *mask)
{
const char *comma;
while ((comma = strchr(arg, ',')) != NULL) {
if (comma == arg || !parse_type(arg, comma-arg, mask))
exit_error(PARAMETER_PROBLEM,
"addrtype: bad type `%s'", arg);
arg = comma + 1;
}
if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask))
exit_error(PARAMETER_PROBLEM, "addrtype: bad type `%s'", arg);
}
#define IPT_ADDRTYPE_OPT_SRCTYPE 0x1
#define IPT_ADDRTYPE_OPT_DSTTYPE 0x2
#define IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN 0x4
#define IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT 0x8
static int
addrtype_parse_v0(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
struct ipt_addrtype_info *info =
(struct ipt_addrtype_info *) (*match)->data;
switch (c) {
case '1':
if (*flags&IPT_ADDRTYPE_OPT_SRCTYPE)
exit_error(PARAMETER_PROBLEM,
"addrtype: can't specify src-type twice");
check_inverse(optarg, &invert, &optind, 0);
parse_types(argv[optind-1], &info->source);
if (invert)
info->invert_source = 1;
*flags |= IPT_ADDRTYPE_OPT_SRCTYPE;
break;
case '2':
if (*flags&IPT_ADDRTYPE_OPT_DSTTYPE)
exit_error(PARAMETER_PROBLEM,
"addrtype: can't specify dst-type twice");
check_inverse(optarg, &invert, &optind, 0);
parse_types(argv[optind-1], &info->dest);
if (invert)
info->invert_dest = 1;
*flags |= IPT_ADDRTYPE_OPT_DSTTYPE;
break;
default:
return 0;
}
return 1;
}
static int
addrtype_parse_v1(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
struct ipt_addrtype_info_v1 *info =
(struct ipt_addrtype_info_v1 *) (*match)->data;
switch (c) {
case '1':
if (*flags & IPT_ADDRTYPE_OPT_SRCTYPE)
exit_error(PARAMETER_PROBLEM,
"addrtype: can't specify src-type twice");
check_inverse(optarg, &invert, &optind, 0);
parse_types(argv[optind-1], &info->source);
if (invert)
info->flags |= IPT_ADDRTYPE_INVERT_SOURCE;
*flags |= IPT_ADDRTYPE_OPT_SRCTYPE;
break;
case '2':
if (*flags & IPT_ADDRTYPE_OPT_DSTTYPE)
exit_error(PARAMETER_PROBLEM,
"addrtype: can't specify dst-type twice");
check_inverse(optarg, &invert, &optind, 0);
parse_types(argv[optind-1], &info->dest);
if (invert)
info->flags |= IPT_ADDRTYPE_INVERT_DEST;
*flags |= IPT_ADDRTYPE_OPT_DSTTYPE;
break;
case '3':
if (*flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN)
exit_error(PARAMETER_PROBLEM,
"addrtype: can't specify limit-iface-in twice");
info->flags |= IPT_ADDRTYPE_LIMIT_IFACE_IN;
*flags |= IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN;
break;
case '4':
if (*flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT)
exit_error(PARAMETER_PROBLEM,
"addrtype: can't specify limit-iface-out twice");
info->flags |= IPT_ADDRTYPE_LIMIT_IFACE_OUT;
*flags |= IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT;
break;
default:
return 0;
}
return 1;
}
static void addrtype_check_v0(unsigned int flags)
{
if (!(flags & (IPT_ADDRTYPE_OPT_SRCTYPE|IPT_ADDRTYPE_OPT_DSTTYPE)))
exit_error(PARAMETER_PROBLEM,
"addrtype: you must specify --src-type or --dst-type");
}
static void addrtype_check_v1(unsigned int flags)
{
if (!(flags & (IPT_ADDRTYPE_OPT_SRCTYPE|IPT_ADDRTYPE_OPT_DSTTYPE)))
exit_error(PARAMETER_PROBLEM,
"addrtype: you must specify --src-type or --dst-type");
if (flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN &&
flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT)
exit_error(PARAMETER_PROBLEM,
"addrtype: you can't specify both --limit-iface-in "
"and --limit-iface-out");
}
static void print_types(u_int16_t mask)
{
const char *sep = "";
int i;
for (i = 0; rtn_names[i]; i++)
if (mask & (1 << i)) {
printf("%s%s", sep, rtn_names[i]);
sep = ",";
}
printf(" ");
}
static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ipt_addrtype_info *info =
(struct ipt_addrtype_info *) match->data;
printf("ADDRTYPE match ");
if (info->source) {
printf("src-type ");
if (info->invert_source)
printf("!");
print_types(info->source);
}
if (info->dest) {
printf("dst-type ");
if (info->invert_dest)
printf("!");
print_types(info->dest);
}
}
static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ipt_addrtype_info_v1 *info =
(struct ipt_addrtype_info_v1 *) match->data;
printf("ADDRTYPE match ");
if (info->source) {
printf("src-type ");
if (info->flags & IPT_ADDRTYPE_INVERT_SOURCE)
printf("!");
print_types(info->source);
}
if (info->dest) {
printf("dst-type ");
if (info->flags & IPT_ADDRTYPE_INVERT_DEST)
printf("!");
print_types(info->dest);
}
if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN) {
printf("limit-in ");
}
if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) {
printf("limit-out ");
}
}
static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match)
{
const struct ipt_addrtype_info *info =
(struct ipt_addrtype_info *) match->data;
if (info->source) {
printf("--src-type ");
if (info->invert_source)
printf("! ");
print_types(info->source);
}
if (info->dest) {
printf("--dst-type ");
if (info->invert_dest)
printf("! ");
print_types(info->dest);
}
}
static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match)
{
const struct ipt_addrtype_info_v1 *info =
(struct ipt_addrtype_info_v1 *) match->data;
if (info->source) {
printf("--src-type ");
if (info->flags & IPT_ADDRTYPE_INVERT_SOURCE)
printf("! ");
print_types(info->source);
}
if (info->dest) {
printf("--dst-type ");
if (info->flags & IPT_ADDRTYPE_INVERT_DEST)
printf("! ");
print_types(info->dest);
}
if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN) {
printf("--limit-iface-in ");
}
if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) {
printf("--limit-iface-out ");
}
}
static const struct option addrtype_opts[] = {
{ "src-type", 1, NULL, '1' },
{ "dst-type", 1, NULL, '2' },
{ .name = NULL }
};
static const struct option addrtype_opts_v0[] = {
{ "src-type", 1, NULL, '1' },
{ "dst-type", 1, NULL, '2' },
{ .name = NULL }
};
static const struct option addrtype_opts_v1[] = {
{ "src-type", 1, NULL, '1' },
{ "dst-type", 1, NULL, '2' },
{ "limit-iface-in", 0, NULL, '3' },
{ "limit-iface-out", 0, NULL, '4' },
{ .name = NULL }
};
static struct xtables_match addrtype_mt_reg_v0 = {
.name = "addrtype",
.version = XTABLES_VERSION,
.family = PF_INET,
.size = XT_ALIGN(sizeof(struct ipt_addrtype_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_addrtype_info)),
.help = addrtype_help_v0,
.parse = addrtype_parse_v0,
.final_check = addrtype_check_v0,
.print = addrtype_print_v0,
.save = addrtype_save_v0,
.extra_opts = addrtype_opts_v0,
};
static struct xtables_match addrtype_mt_reg_v1 = {
.name = "addrtype",
.version = XTABLES_VERSION,
.family = PF_INET,
.size = XT_ALIGN(sizeof(struct ipt_addrtype_info_v1)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_addrtype_info_v1)),
.help = addrtype_help_v1,
.parse = addrtype_parse_v1,
.final_check = addrtype_check_v1,
.print = addrtype_print_v1,
.save = addrtype_save_v1,
.extra_opts = addrtype_opts_v1,
.revision = 1,
};
void _init(void)
{
xtables_register_match(&addrtype_mt_reg_v0);
xtables_register_match(&addrtype_mt_reg_v1);
}