Home | History | Annotate | Download | only in extensions
      1 /* Shared library add-on to iptables to add bridge port matching support. */
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include <stdlib.h>
      5 #include <getopt.h>
      6 #include <ctype.h>
      7 #include <iptables.h>
      8 #include <linux/netfilter_ipv4/ipt_physdev.h>
      9 #if defined(__GLIBC__) && __GLIBC__ == 2
     10 #include <net/ethernet.h>
     11 #else
     12 #include <linux/if_ether.h>
     13 #endif
     14 
     15 static void
     16 help(void)
     17 {
     18 	printf(
     19 "physdev v%s options:\n"
     20 " --physdev-in [!] input name[+]		bridge port name ([+] for wildcard)\n"
     21 " --physdev-out [!] output name[+]	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 "\n", IPTABLES_VERSION);
     26 }
     27 
     28 static struct option opts[] = {
     29 	{ "physdev-in", 1, 0, '1' },
     30 	{ "physdev-out", 1, 0, '2' },
     31 	{ "physdev-is-in", 0, 0, '3' },
     32 	{ "physdev-is-out", 0, 0, '4' },
     33 	{ "physdev-is-bridged", 0, 0, '5' },
     34 	{0}
     35 };
     36 
     37 static void
     38 init(struct ipt_entry_match *m, unsigned int *nfcache)
     39 {
     40 }
     41 
     42 static int
     43 parse(int c, char **argv, int invert, unsigned int *flags,
     44       const struct ipt_entry *entry,
     45       unsigned int *nfcache,
     46       struct ipt_entry_match **match)
     47 {
     48 	struct ipt_physdev_info *info =
     49 		(struct ipt_physdev_info*)(*match)->data;
     50 
     51 	switch (c) {
     52 	case '1':
     53 		if (*flags & IPT_PHYSDEV_OP_IN)
     54 			goto multiple_use;
     55 		check_inverse(optarg, &invert, &optind, 0);
     56 		parse_interface(argv[optind-1], info->physindev,
     57 				(unsigned char *)info->in_mask);
     58 		if (invert)
     59 			info->invert |= IPT_PHYSDEV_OP_IN;
     60 		info->bitmask |= IPT_PHYSDEV_OP_IN;
     61 		*flags |= IPT_PHYSDEV_OP_IN;
     62 		break;
     63 
     64 	case '2':
     65 		if (*flags & IPT_PHYSDEV_OP_OUT)
     66 			goto multiple_use;
     67 		check_inverse(optarg, &invert, &optind, 0);
     68 		parse_interface(argv[optind-1], info->physoutdev,
     69 				(unsigned char *)info->out_mask);
     70 		if (invert)
     71 			info->invert |= IPT_PHYSDEV_OP_OUT;
     72 		info->bitmask |= IPT_PHYSDEV_OP_OUT;
     73 		*flags |= IPT_PHYSDEV_OP_OUT;
     74 		break;
     75 
     76 	case '3':
     77 		if (*flags & IPT_PHYSDEV_OP_ISIN)
     78 			goto multiple_use;
     79 		check_inverse(optarg, &invert, &optind, 0);
     80 		info->bitmask |= IPT_PHYSDEV_OP_ISIN;
     81 		if (invert)
     82 			info->invert |= IPT_PHYSDEV_OP_ISIN;
     83 		*flags |= IPT_PHYSDEV_OP_ISIN;
     84 		break;
     85 
     86 	case '4':
     87 		if (*flags & IPT_PHYSDEV_OP_ISOUT)
     88 			goto multiple_use;
     89 		check_inverse(optarg, &invert, &optind, 0);
     90 		info->bitmask |= IPT_PHYSDEV_OP_ISOUT;
     91 		if (invert)
     92 			info->invert |= IPT_PHYSDEV_OP_ISOUT;
     93 		*flags |= IPT_PHYSDEV_OP_ISOUT;
     94 		break;
     95 
     96 	case '5':
     97 		if (*flags & IPT_PHYSDEV_OP_BRIDGED)
     98 			goto multiple_use;
     99 		check_inverse(optarg, &invert, &optind, 0);
    100 		if (invert)
    101 			info->invert |= IPT_PHYSDEV_OP_BRIDGED;
    102 		*flags |= IPT_PHYSDEV_OP_BRIDGED;
    103 		info->bitmask |= IPT_PHYSDEV_OP_BRIDGED;
    104 		break;
    105 
    106 	default:
    107 		return 0;
    108 	}
    109 
    110 	return 1;
    111 multiple_use:
    112 	exit_error(PARAMETER_PROBLEM,
    113 	   "multiple use of the same physdev option is not allowed");
    114 
    115 }
    116 
    117 static void final_check(unsigned int flags)
    118 {
    119 	if (flags == 0)
    120 		exit_error(PARAMETER_PROBLEM, "PHYSDEV: no physdev option specified");
    121 }
    122 
    123 static void
    124 print(const struct ipt_ip *ip,
    125       const struct ipt_entry_match *match,
    126       int numeric)
    127 {
    128 	struct ipt_physdev_info *info =
    129 		(struct ipt_physdev_info*)match->data;
    130 
    131 	printf("PHYSDEV match");
    132 	if (info->bitmask & IPT_PHYSDEV_OP_ISIN)
    133 		printf("%s --physdev-is-in",
    134 		       info->invert & IPT_PHYSDEV_OP_ISIN ? " !":"");
    135 	if (info->bitmask & IPT_PHYSDEV_OP_IN)
    136 		printf("%s --physdev-in %s",
    137 		(info->invert & IPT_PHYSDEV_OP_IN) ? " !":"", info->physindev);
    138 
    139 	if (info->bitmask & IPT_PHYSDEV_OP_ISOUT)
    140 		printf("%s --physdev-is-out",
    141 		       info->invert & IPT_PHYSDEV_OP_ISOUT ? " !":"");
    142 	if (info->bitmask & IPT_PHYSDEV_OP_OUT)
    143 		printf("%s --physdev-out %s",
    144 		(info->invert & IPT_PHYSDEV_OP_OUT) ? " !":"", info->physoutdev);
    145 	if (info->bitmask & IPT_PHYSDEV_OP_BRIDGED)
    146 		printf("%s --physdev-is-bridged",
    147 		       info->invert & IPT_PHYSDEV_OP_BRIDGED ? " !":"");
    148 	printf(" ");
    149 }
    150 
    151 static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
    152 {
    153 	struct ipt_physdev_info *info =
    154 		(struct ipt_physdev_info*)match->data;
    155 
    156 	if (info->bitmask & IPT_PHYSDEV_OP_ISIN)
    157 		printf("%s --physdev-is-in",
    158 		       info->invert & IPT_PHYSDEV_OP_ISIN ? " !":"");
    159 	if (info->bitmask & IPT_PHYSDEV_OP_IN)
    160 		printf("%s --physdev-in %s",
    161 		(info->invert & IPT_PHYSDEV_OP_IN) ? " !":"", info->physindev);
    162 
    163 	if (info->bitmask & IPT_PHYSDEV_OP_ISOUT)
    164 		printf("%s --physdev-is-out",
    165 		       info->invert & IPT_PHYSDEV_OP_ISOUT ? " !":"");
    166 	if (info->bitmask & IPT_PHYSDEV_OP_OUT)
    167 		printf("%s --physdev-out %s",
    168 		(info->invert & IPT_PHYSDEV_OP_OUT) ? " !":"", info->physoutdev);
    169 	if (info->bitmask & IPT_PHYSDEV_OP_BRIDGED)
    170 		printf("%s --physdev-is-bridged",
    171 		       info->invert & IPT_PHYSDEV_OP_BRIDGED ? " !":"");
    172 	printf(" ");
    173 }
    174 
    175 static struct iptables_match physdev = {
    176 	.next		= NULL,
    177 	.name		= "physdev",
    178 	.version	= IPTABLES_VERSION,
    179 	.size		= IPT_ALIGN(sizeof(struct ipt_physdev_info)),
    180 	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_physdev_info)),
    181 	.help		= &help,
    182 	.init		= &init,
    183 	.parse		= &parse,
    184 	.final_check	= &final_check,
    185 	.print		= &print,
    186 	.save		= &save,
    187 	.extra_opts	= opts
    188 };
    189 
    190 void ipt_physdev_init(void)
    191 {
    192 	register_match(&physdev);
    193 }
    194