libxt_physdev.c revision 73866357e4a7a0fdc1b293bf8863fee2bd56da9e
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} 135 136static void physdev_save(const void *ip, const struct xt_entry_match *match) 137{ 138 const struct xt_physdev_info *info = (const void *)match->data; 139 140 if (info->bitmask & XT_PHYSDEV_OP_ISIN) 141 printf("%s --physdev-is-in", 142 (info->invert & XT_PHYSDEV_OP_ISIN) ? " !" : ""); 143 if (info->bitmask & XT_PHYSDEV_OP_IN) 144 printf("%s --physdev-in %s", 145 (info->invert & XT_PHYSDEV_OP_IN) ? " !" : "", 146 info->physindev); 147 148 if (info->bitmask & XT_PHYSDEV_OP_ISOUT) 149 printf("%s --physdev-is-out", 150 (info->invert & XT_PHYSDEV_OP_ISOUT) ? " !" : ""); 151 if (info->bitmask & XT_PHYSDEV_OP_OUT) 152 printf("%s --physdev-out %s", 153 (info->invert & XT_PHYSDEV_OP_OUT) ? " !" : "", 154 info->physoutdev); 155 if (info->bitmask & XT_PHYSDEV_OP_BRIDGED) 156 printf("%s --physdev-is-bridged", 157 (info->invert & XT_PHYSDEV_OP_BRIDGED) ? " !" : ""); 158} 159 160static struct xtables_match physdev_match = { 161 .family = NFPROTO_UNSPEC, 162 .name = "physdev", 163 .version = XTABLES_VERSION, 164 .size = XT_ALIGN(sizeof(struct xt_physdev_info)), 165 .userspacesize = XT_ALIGN(sizeof(struct xt_physdev_info)), 166 .help = physdev_help, 167 .parse = physdev_parse, 168 .final_check = physdev_check, 169 .print = physdev_print, 170 .save = physdev_save, 171 .extra_opts = physdev_opts, 172}; 173 174void _init(void) 175{ 176 xtables_register_match(&physdev_match); 177} 178