libxt_physdev.c revision d09b6d591ca7d7d7575cb6aa20384c9830f777ab
1/* Shared library add-on to iptables to add bridge port matching support. */ 2#include <stdbool.h> 3#include <stdio.h> 4#include <string.h> 5#include <stdlib.h> 6#include <getopt.h> 7#include <ctype.h> 8#include <xtables.h> 9#include <linux/netfilter/xt_physdev.h> 10#if defined(__GLIBC__) && __GLIBC__ == 2 11#include <net/ethernet.h> 12#else 13#include <linux/if_ether.h> 14#endif 15 16static void physdev_help(void) 17{ 18 printf( 19"physdev match options:\n" 20" [!] --physdev-in inputname[+] bridge port name ([+] for wildcard)\n" 21" [!] --physdev-out outputname[+] bridge port name ([+] for wildcard)\n" 22" [!] --physdev-is-in arrived on a bridge device\n" 23" [!] --physdev-is-out will leave on a bridge device\n" 24" [!] --physdev-is-bridged it's a bridged packet\n"); 25} 26 27static const struct option physdev_opts[] = { 28 {.name = "physdev-in", .has_arg = true, .val = '1'}, 29 {.name = "physdev-out", .has_arg = true, .val = '2'}, 30 {.name = "physdev-is-in", .has_arg = false, .val = '3'}, 31 {.name = "physdev-is-out", .has_arg = false, .val = '4'}, 32 {.name = "physdev-is-bridged", .has_arg = false, .val = '5'}, 33 XT_GETOPT_TABLEEND, 34}; 35 36static int 37physdev_parse(int c, char **argv, int invert, unsigned int *flags, 38 const void *entry, struct xt_entry_match **match) 39{ 40 struct xt_physdev_info *info = 41 (struct xt_physdev_info*)(*match)->data; 42 43 switch (c) { 44 case '1': 45 if (*flags & XT_PHYSDEV_OP_IN) 46 goto multiple_use; 47 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 48 xtables_parse_interface(optarg, info->physindev, 49 (unsigned char *)info->in_mask); 50 if (invert) 51 info->invert |= XT_PHYSDEV_OP_IN; 52 info->bitmask |= XT_PHYSDEV_OP_IN; 53 *flags |= XT_PHYSDEV_OP_IN; 54 break; 55 56 case '2': 57 if (*flags & XT_PHYSDEV_OP_OUT) 58 goto multiple_use; 59 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 60 xtables_parse_interface(optarg, info->physoutdev, 61 (unsigned char *)info->out_mask); 62 if (invert) 63 info->invert |= XT_PHYSDEV_OP_OUT; 64 info->bitmask |= XT_PHYSDEV_OP_OUT; 65 *flags |= XT_PHYSDEV_OP_OUT; 66 break; 67 68 case '3': 69 if (*flags & XT_PHYSDEV_OP_ISIN) 70 goto multiple_use; 71 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 72 info->bitmask |= XT_PHYSDEV_OP_ISIN; 73 if (invert) 74 info->invert |= XT_PHYSDEV_OP_ISIN; 75 *flags |= XT_PHYSDEV_OP_ISIN; 76 break; 77 78 case '4': 79 if (*flags & XT_PHYSDEV_OP_ISOUT) 80 goto multiple_use; 81 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 82 info->bitmask |= XT_PHYSDEV_OP_ISOUT; 83 if (invert) 84 info->invert |= XT_PHYSDEV_OP_ISOUT; 85 *flags |= XT_PHYSDEV_OP_ISOUT; 86 break; 87 88 case '5': 89 if (*flags & XT_PHYSDEV_OP_BRIDGED) 90 goto multiple_use; 91 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 92 if (invert) 93 info->invert |= XT_PHYSDEV_OP_BRIDGED; 94 *flags |= XT_PHYSDEV_OP_BRIDGED; 95 info->bitmask |= XT_PHYSDEV_OP_BRIDGED; 96 break; 97 } 98 99 return 1; 100multiple_use: 101 xtables_error(PARAMETER_PROBLEM, 102 "multiple use of the same physdev option is not allowed"); 103 104} 105 106static void physdev_check(unsigned int flags) 107{ 108 if (flags == 0) 109 xtables_error(PARAMETER_PROBLEM, "PHYSDEV: no physdev option specified"); 110} 111 112static void 113physdev_print(const void *ip, const struct xt_entry_match *match, int numeric) 114{ 115 const struct xt_physdev_info *info = (const void *)match->data; 116 117 printf("PHYSDEV match"); 118 if (info->bitmask & XT_PHYSDEV_OP_ISIN) 119 printf("%s --physdev-is-in", 120 info->invert & XT_PHYSDEV_OP_ISIN ? " !":""); 121 if (info->bitmask & XT_PHYSDEV_OP_IN) 122 printf("%s --physdev-in %s", 123 (info->invert & XT_PHYSDEV_OP_IN) ? " !":"", info->physindev); 124 125 if (info->bitmask & XT_PHYSDEV_OP_ISOUT) 126 printf("%s --physdev-is-out", 127 info->invert & XT_PHYSDEV_OP_ISOUT ? " !":""); 128 if (info->bitmask & XT_PHYSDEV_OP_OUT) 129 printf("%s --physdev-out %s", 130 (info->invert & XT_PHYSDEV_OP_OUT) ? " !":"", info->physoutdev); 131 if (info->bitmask & XT_PHYSDEV_OP_BRIDGED) 132 printf("%s --physdev-is-bridged", 133 info->invert & XT_PHYSDEV_OP_BRIDGED ? " !":""); 134 printf(" "); 135} 136 137static void physdev_save(const void *ip, const struct xt_entry_match *match) 138{ 139 const struct xt_physdev_info *info = (const void *)match->data; 140 141 if (info->bitmask & XT_PHYSDEV_OP_ISIN) 142 printf("%s--physdev-is-in ", 143 (info->invert & XT_PHYSDEV_OP_ISIN) ? "! " : ""); 144 if (info->bitmask & XT_PHYSDEV_OP_IN) 145 printf("%s--physdev-in %s ", 146 (info->invert & XT_PHYSDEV_OP_IN) ? "! " : "", 147 info->physindev); 148 149 if (info->bitmask & XT_PHYSDEV_OP_ISOUT) 150 printf("%s--physdev-is-out ", 151 (info->invert & XT_PHYSDEV_OP_ISOUT) ? "! " : ""); 152 if (info->bitmask & XT_PHYSDEV_OP_OUT) 153 printf("%s--physdev-out %s ", 154 (info->invert & XT_PHYSDEV_OP_OUT) ? "! " : "", 155 info->physoutdev); 156 if (info->bitmask & XT_PHYSDEV_OP_BRIDGED) 157 printf("%s--physdev-is-bridged ", 158 (info->invert & XT_PHYSDEV_OP_BRIDGED) ? "! " : ""); 159} 160 161static struct xtables_match physdev_match = { 162 .family = NFPROTO_UNSPEC, 163 .name = "physdev", 164 .version = XTABLES_VERSION, 165 .size = XT_ALIGN(sizeof(struct xt_physdev_info)), 166 .userspacesize = XT_ALIGN(sizeof(struct xt_physdev_info)), 167 .help = physdev_help, 168 .parse = physdev_parse, 169 .final_check = physdev_check, 170 .print = physdev_print, 171 .save = physdev_save, 172 .extra_opts = physdev_opts, 173}; 174 175void _init(void) 176{ 177 xtables_register_match(&physdev_match); 178} 179