diff options
Diffstat (limited to 'extensions/libxt_physdev.c')
-rw-r--r-- | extensions/libxt_physdev.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/extensions/libxt_physdev.c b/extensions/libxt_physdev.c new file mode 100644 index 0000000..5382ab6 --- /dev/null +++ b/extensions/libxt_physdev.c @@ -0,0 +1,180 @@ +/* Shared library add-on to iptables to add bridge port matching support. */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> +#include <ctype.h> +#include <xtables.h> +#include <linux/netfilter/xt_physdev.h> +#if defined(__GLIBC__) && __GLIBC__ == 2 +#include <net/ethernet.h> +#else +#include <linux/if_ether.h> +#endif + +static void physdev_help(void) +{ + printf( +"physdev match options:\n" +" [!] --physdev-in inputname[+] bridge port name ([+] for wildcard)\n" +" [!] --physdev-out outputname[+] bridge port name ([+] for wildcard)\n" +" [!] --physdev-is-in arrived on a bridge device\n" +" [!] --physdev-is-out will leave on a bridge device\n" +" [!] --physdev-is-bridged it's a bridged packet\n"); +} + +static const struct option physdev_opts[] = { + { "physdev-in", 1, NULL, '1' }, + { "physdev-out", 1, NULL, '2' }, + { "physdev-is-in", 0, NULL, '3' }, + { "physdev-is-out", 0, NULL, '4' }, + { "physdev-is-bridged", 0, NULL, '5' }, + { .name = NULL } +}; + +static int +physdev_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + struct xt_physdev_info *info = + (struct xt_physdev_info*)(*match)->data; + + switch (c) { + case '1': + if (*flags & XT_PHYSDEV_OP_IN) + goto multiple_use; + xtables_check_inverse(optarg, &invert, &optind, 0, argv); + xtables_parse_interface(optarg, info->physindev, + (unsigned char *)info->in_mask); + if (invert) + info->invert |= XT_PHYSDEV_OP_IN; + info->bitmask |= XT_PHYSDEV_OP_IN; + *flags |= XT_PHYSDEV_OP_IN; + break; + + case '2': + if (*flags & XT_PHYSDEV_OP_OUT) + goto multiple_use; + xtables_check_inverse(optarg, &invert, &optind, 0, argv); + xtables_parse_interface(optarg, info->physoutdev, + (unsigned char *)info->out_mask); + if (invert) + info->invert |= XT_PHYSDEV_OP_OUT; + info->bitmask |= XT_PHYSDEV_OP_OUT; + *flags |= XT_PHYSDEV_OP_OUT; + break; + + case '3': + if (*flags & XT_PHYSDEV_OP_ISIN) + goto multiple_use; + xtables_check_inverse(optarg, &invert, &optind, 0, argv); + info->bitmask |= XT_PHYSDEV_OP_ISIN; + if (invert) + info->invert |= XT_PHYSDEV_OP_ISIN; + *flags |= XT_PHYSDEV_OP_ISIN; + break; + + case '4': + if (*flags & XT_PHYSDEV_OP_ISOUT) + goto multiple_use; + xtables_check_inverse(optarg, &invert, &optind, 0, argv); + info->bitmask |= XT_PHYSDEV_OP_ISOUT; + if (invert) + info->invert |= XT_PHYSDEV_OP_ISOUT; + *flags |= XT_PHYSDEV_OP_ISOUT; + break; + + case '5': + if (*flags & XT_PHYSDEV_OP_BRIDGED) + goto multiple_use; + xtables_check_inverse(optarg, &invert, &optind, 0, argv); + if (invert) + info->invert |= XT_PHYSDEV_OP_BRIDGED; + *flags |= XT_PHYSDEV_OP_BRIDGED; + info->bitmask |= XT_PHYSDEV_OP_BRIDGED; + break; + + default: + return 0; + } + + return 1; +multiple_use: + xtables_error(PARAMETER_PROBLEM, + "multiple use of the same physdev option is not allowed"); + +} + +static void physdev_check(unsigned int flags) +{ + if (flags == 0) + xtables_error(PARAMETER_PROBLEM, "PHYSDEV: no physdev option specified"); +} + +static void +physdev_print(const void *ip, const struct xt_entry_match *match, int numeric) +{ + const struct xt_physdev_info *info = (const void *)match->data; + + printf("PHYSDEV match"); + if (info->bitmask & XT_PHYSDEV_OP_ISIN) + printf("%s --physdev-is-in", + info->invert & XT_PHYSDEV_OP_ISIN ? " !":""); + if (info->bitmask & XT_PHYSDEV_OP_IN) + printf("%s --physdev-in %s", + (info->invert & XT_PHYSDEV_OP_IN) ? " !":"", info->physindev); + + if (info->bitmask & XT_PHYSDEV_OP_ISOUT) + printf("%s --physdev-is-out", + info->invert & XT_PHYSDEV_OP_ISOUT ? " !":""); + if (info->bitmask & XT_PHYSDEV_OP_OUT) + printf("%s --physdev-out %s", + (info->invert & XT_PHYSDEV_OP_OUT) ? " !":"", info->physoutdev); + if (info->bitmask & XT_PHYSDEV_OP_BRIDGED) + printf("%s --physdev-is-bridged", + info->invert & XT_PHYSDEV_OP_BRIDGED ? " !":""); + printf(" "); +} + +static void physdev_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_physdev_info *info = (const void *)match->data; + + if (info->bitmask & XT_PHYSDEV_OP_ISIN) + printf("%s--physdev-is-in ", + (info->invert & XT_PHYSDEV_OP_ISIN) ? "! " : ""); + if (info->bitmask & XT_PHYSDEV_OP_IN) + printf("%s--physdev-in %s ", + (info->invert & XT_PHYSDEV_OP_IN) ? "! " : "", + info->physindev); + + if (info->bitmask & XT_PHYSDEV_OP_ISOUT) + printf("%s--physdev-is-out ", + (info->invert & XT_PHYSDEV_OP_ISOUT) ? "! " : ""); + if (info->bitmask & XT_PHYSDEV_OP_OUT) + printf("%s--physdev-out %s ", + (info->invert & XT_PHYSDEV_OP_OUT) ? "! " : "", + info->physoutdev); + if (info->bitmask & XT_PHYSDEV_OP_BRIDGED) + printf("%s--physdev-is-bridged ", + (info->invert & XT_PHYSDEV_OP_BRIDGED) ? "! " : ""); +} + +static struct xtables_match physdev_match = { + .family = NFPROTO_UNSPEC, + .name = "physdev", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_physdev_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_physdev_info)), + .help = physdev_help, + .parse = physdev_parse, + .final_check = physdev_check, + .print = physdev_print, + .save = physdev_save, + .extra_opts = physdev_opts, +}; + +void _init(void) +{ + xtables_register_match(&physdev_match); +} |