fb473470430264eb1832547250781781320de252
[iptables.git] / extensions / libip6t_physdev.c
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 <ip6tables.h>
8 #include <linux/netfilter_ipv6/ip6t_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 ip6t_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 ip6t_entry *entry,
45       unsigned int *nfcache,
46       struct ip6t_entry_match **match)
47 {
48         struct ip6t_physdev_info *info =
49                 (struct ip6t_physdev_info*)(*match)->data;
50
51         switch (c) {
52         case '1':
53                 if (*flags & IP6T_PHYSDEV_OP_IN)
54                         goto multiple_use;
55                 check_inverse(optarg, &invert, &optind, 0);
56                 parse_interface(argv[optind-1], info->physindev, info->in_mask);
57                 if (invert)
58                         info->invert |= IP6T_PHYSDEV_OP_IN;
59                 info->bitmask |= IP6T_PHYSDEV_OP_IN;
60                 *flags |= IP6T_PHYSDEV_OP_IN;
61                 break;
62
63         case '2':
64                 if (*flags & IP6T_PHYSDEV_OP_OUT)
65                         goto multiple_use;
66                 check_inverse(optarg, &invert, &optind, 0);
67                 parse_interface(argv[optind-1], info->physoutdev,
68                                 info->out_mask);
69                 if (invert)
70                         info->invert |= IP6T_PHYSDEV_OP_OUT;
71                 info->bitmask |= IP6T_PHYSDEV_OP_OUT;
72                 *flags |= IP6T_PHYSDEV_OP_OUT;
73                 break;
74
75         case '3':
76                 if (*flags & IP6T_PHYSDEV_OP_ISIN)
77                         goto multiple_use;
78                 check_inverse(optarg, &invert, &optind, 0);
79                 info->bitmask |= IP6T_PHYSDEV_OP_ISIN;
80                 if (invert)
81                         info->invert |= IP6T_PHYSDEV_OP_ISIN;
82                 *flags |= IP6T_PHYSDEV_OP_ISIN;
83                 break;
84
85         case '4':
86                 if (*flags & IP6T_PHYSDEV_OP_ISOUT)
87                         goto multiple_use;
88                 check_inverse(optarg, &invert, &optind, 0);
89                 info->bitmask |= IP6T_PHYSDEV_OP_ISOUT;
90                 if (invert)
91                         info->invert |= IP6T_PHYSDEV_OP_ISOUT;
92                 *flags |= IP6T_PHYSDEV_OP_ISOUT;
93                 break;
94
95         case '5':
96                 if (*flags & IP6T_PHYSDEV_OP_BRIDGED)
97                         goto multiple_use;
98                 check_inverse(optarg, &invert, &optind, 0);
99                 if (invert)
100                         info->invert |= IP6T_PHYSDEV_OP_BRIDGED;
101                 *flags |= IP6T_PHYSDEV_OP_BRIDGED;
102                 info->bitmask |= IP6T_PHYSDEV_OP_BRIDGED;
103                 break;
104
105         default:
106                 return 0;
107         }
108
109         return 1;
110 multiple_use:
111         exit_error(PARAMETER_PROBLEM,
112            "multiple use of the same physdev option is not allowed");
113
114 }
115
116 static void final_check(unsigned int flags)
117 {
118         if (flags == 0)
119                 exit_error(PARAMETER_PROBLEM, "PHYSDEV: no physdev option specified");
120 }
121
122 static void
123 print(const struct ip6t_ip6 *ip,
124       const struct ip6t_entry_match *match,
125       int numeric)
126 {
127         struct ip6t_physdev_info *info =
128                 (struct ip6t_physdev_info*)match->data;
129
130         printf("PHYSDEV match");
131         if (info->bitmask & IP6T_PHYSDEV_OP_ISIN)
132                 printf("%s --physdev-is-in",
133                        info->invert & IP6T_PHYSDEV_OP_ISIN ? " !":"");
134         if (info->bitmask & IP6T_PHYSDEV_OP_IN)
135                 printf("%s --physdev-in %s",
136                 (info->invert & IP6T_PHYSDEV_OP_IN) ? " !":"", info->physindev);
137
138         if (info->bitmask & IP6T_PHYSDEV_OP_ISOUT)
139                 printf("%s --physdev-is-out",
140                        info->invert & IP6T_PHYSDEV_OP_ISOUT ? " !":"");
141         if (info->bitmask & IP6T_PHYSDEV_OP_OUT)
142                 printf("%s --physdev-out %s",
143                 (info->invert & IP6T_PHYSDEV_OP_OUT) ? " !":"", info->physoutdev);
144         if (info->bitmask & IP6T_PHYSDEV_OP_BRIDGED)
145                 printf("%s --physdev-is-bridged",
146                        info->invert & IP6T_PHYSDEV_OP_BRIDGED ? " !":"");
147         printf(" ");
148 }
149
150 static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
151 {
152         struct ip6t_physdev_info *info =
153                 (struct ip6t_physdev_info*)match->data;
154
155         if (info->bitmask & IP6T_PHYSDEV_OP_ISIN)
156                 printf("%s --physdev-is-in",
157                        info->invert & IP6T_PHYSDEV_OP_ISIN ? " !":"");
158         if (info->bitmask & IP6T_PHYSDEV_OP_IN)
159                 printf("%s --physdev-in %s",
160                 (info->invert & IP6T_PHYSDEV_OP_IN) ? " !":"", info->physindev);
161
162         if (info->bitmask & IP6T_PHYSDEV_OP_ISOUT)
163                 printf("%s --physdev-is-out",
164                        info->invert & IP6T_PHYSDEV_OP_ISOUT ? " !":"");
165         if (info->bitmask & IP6T_PHYSDEV_OP_OUT)
166                 printf("%s --physdev-out %s",
167                 (info->invert & IP6T_PHYSDEV_OP_OUT) ? " !":"", info->physoutdev);
168         if (info->bitmask & IP6T_PHYSDEV_OP_BRIDGED)
169                 printf("%s --physdev-is-bridged",
170                        info->invert & IP6T_PHYSDEV_OP_BRIDGED ? " !":"");
171         printf(" ");
172 }
173
174 static struct ip6tables_match physdev = {
175         .name           = "physdev",
176         .version        = IPTABLES_VERSION,
177         .size           = IP6T_ALIGN(sizeof(struct ip6t_physdev_info)),
178         .userspacesize  = IP6T_ALIGN(sizeof(struct ip6t_physdev_info)),
179         .help           = &help,
180         .init           = &init,
181         .parse          = &parse,
182         .final_check    = &final_check,
183         .print          = &print,
184         .save           = &save,
185         .extra_opts     = opts,
186 };
187
188 void _init(void)
189 {
190         register_match6(&physdev);
191 }