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