1 /* ebt_stp
2 *
3 * Authors:
4 * Bart De Schuymer <[email protected]>
5 *
6 * July, 2003
7 */
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <getopt.h>
13 #include <netinet/ether.h>
14 #include <linux/netfilter_bridge/ebt_stp.h>
15 #include <xtables.h>
16
17 #include "iptables/nft.h"
18 #include "iptables/nft-bridge.h"
19
20 #define STP_TYPE 'a'
21 #define STP_FLAGS 'b'
22 #define STP_ROOTPRIO 'c'
23 #define STP_ROOTADDR 'd'
24 #define STP_ROOTCOST 'e'
25 #define STP_SENDERPRIO 'f'
26 #define STP_SENDERADDR 'g'
27 #define STP_PORT 'h'
28 #define STP_MSGAGE 'i'
29 #define STP_MAXAGE 'j'
30 #define STP_HELLOTIME 'k'
31 #define STP_FWDD 'l'
32 #define STP_NUMOPS 12
33
34 static const struct option brstp_opts[] =
35 {
36 { "stp-type" , required_argument, 0, STP_TYPE},
37 { "stp-flags" , required_argument, 0, STP_FLAGS},
38 { "stp-root-prio" , required_argument, 0, STP_ROOTPRIO},
39 { "stp-root-addr" , required_argument, 0, STP_ROOTADDR},
40 { "stp-root-cost" , required_argument, 0, STP_ROOTCOST},
41 { "stp-sender-prio" , required_argument, 0, STP_SENDERPRIO},
42 { "stp-sender-addr" , required_argument, 0, STP_SENDERADDR},
43 { "stp-port" , required_argument, 0, STP_PORT},
44 { "stp-msg-age" , required_argument, 0, STP_MSGAGE},
45 { "stp-max-age" , required_argument, 0, STP_MAXAGE},
46 { "stp-hello-time" , required_argument, 0, STP_HELLOTIME},
47 { "stp-forward-delay", required_argument, 0, STP_FWDD},
48 { 0 }
49 };
50
51 #define BPDU_TYPE_CONFIG 0
52 #define BPDU_TYPE_TCN 0x80
53 #define BPDU_TYPE_CONFIG_STRING "config"
54 #define BPDU_TYPE_TCN_STRING "tcn"
55
56 #define FLAG_TC 0x01
57 #define FLAG_TC_ACK 0x80
58 #define FLAG_TC_STRING "topology-change"
59 #define FLAG_TC_ACK_STRING "topology-change-ack"
60
brstp_print_help(void)61 static void brstp_print_help(void)
62 {
63 printf(
64 "stp options:\n"
65 "--stp-type type : BPDU type\n"
66 "--stp-flags flag : control flag\n"
67 "--stp-root-prio prio[:prio] : root priority (16-bit) range\n"
68 "--stp-root-addr address[/mask] : MAC address of root\n"
69 "--stp-root-cost cost[:cost] : root cost (32-bit) range\n"
70 "--stp-sender-prio prio[:prio] : sender priority (16-bit) range\n"
71 "--stp-sender-addr address[/mask] : MAC address of sender\n"
72 "--stp-port port[:port] : port id (16-bit) range\n"
73 "--stp-msg-age age[:age] : message age timer (16-bit) range\n"
74 "--stp-max-age age[:age] : maximum age timer (16-bit) range\n"
75 "--stp-hello-time time[:time] : hello time timer (16-bit) range\n"
76 "--stp-forward-delay delay[:delay]: forward delay timer (16-bit) range\n"
77 " Recognized BPDU type strings:\n"
78 " \"config\": configuration BPDU (=0)\n"
79 " \"tcn\" : topology change notification BPDU (=0x80)\n"
80 " Recognized control flag strings:\n"
81 " \"topology-change\" : topology change flag (0x01)\n"
82 " \"topology-change-ack\": topology change acknowledgement flag (0x80)");
83 }
84
parse_range(const char * portstring,void * lower,void * upper,int bits,uint32_t min,uint32_t max)85 static int parse_range(const char *portstring, void *lower, void *upper,
86 int bits, uint32_t min, uint32_t max)
87 {
88 char *buffer;
89 char *cp, *end;
90 uint32_t low_nr, upp_nr;
91 int ret = 0;
92
93 buffer = xtables_strdup(portstring);
94
95 if ((cp = strchr(buffer, ':')) == NULL) {
96 low_nr = strtoul(buffer, &end, 10);
97 if (*end || low_nr < min || low_nr > max) {
98 ret = -1;
99 goto out;
100 }
101 if (bits == 2) {
102 *(uint16_t *)lower = low_nr;
103 *(uint16_t *)upper = low_nr;
104 } else {
105 *(uint32_t *)lower = low_nr;
106 *(uint32_t *)upper = low_nr;
107 }
108 } else {
109 *cp = '\0';
110 cp++;
111 if (!*buffer)
112 low_nr = min;
113 else {
114 low_nr = strtoul(buffer, &end, 10);
115 if (*end || low_nr < min) {
116 ret = -1;
117 goto out;
118 }
119 }
120 if (!*cp)
121 upp_nr = max;
122 else {
123 upp_nr = strtoul(cp, &end, 10);
124 if (*end || upp_nr > max) {
125 ret = -1;
126 goto out;
127 }
128 }
129 if (upp_nr < low_nr) {
130 ret = -1;
131 goto out;
132 }
133 if (bits == 2) {
134 *(uint16_t *)lower = low_nr;
135 *(uint16_t *)upper = upp_nr;
136 } else {
137 *(uint32_t *)lower = low_nr;
138 *(uint32_t *)upper = upp_nr;
139 }
140 }
141 out:
142 free(buffer);
143 return ret;
144 }
145
print_range(unsigned int l,unsigned int u)146 static void print_range(unsigned int l, unsigned int u)
147 {
148 if (l == u)
149 printf("%u", l);
150 else
151 printf("%u:%u", l, u);
152 }
153
154 static int
brstp_parse(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_match ** match)155 brstp_parse(int c, char **argv, int invert, unsigned int *flags,
156 const void *entry, struct xt_entry_match **match)
157 {
158 struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)(*match)->data;
159 unsigned int flag;
160 long int i;
161 char *end = NULL;
162
163 if (c < 'a' || c > ('a' + STP_NUMOPS - 1))
164 return 0;
165 flag = 1 << (c - 'a');
166 EBT_CHECK_OPTION(flags, flag);
167 if (invert)
168 stpinfo->invflags |= flag;
169 stpinfo->bitmask |= flag;
170 switch (flag) {
171 case EBT_STP_TYPE:
172 i = strtol(optarg, &end, 0);
173 if (i < 0 || i > 255 || *end != '\0') {
174 if (!strcasecmp(optarg, BPDU_TYPE_CONFIG_STRING))
175 stpinfo->type = BPDU_TYPE_CONFIG;
176 else if (!strcasecmp(optarg, BPDU_TYPE_TCN_STRING))
177 stpinfo->type = BPDU_TYPE_TCN;
178 else
179 xtables_error(PARAMETER_PROBLEM, "Bad --stp-type argument");
180 } else
181 stpinfo->type = i;
182 break;
183 case EBT_STP_FLAGS:
184 i = strtol(optarg, &end, 0);
185 if (i < 0 || i > 255 || *end != '\0') {
186 if (!strcasecmp(optarg, FLAG_TC_STRING))
187 stpinfo->config.flags = FLAG_TC;
188 else if (!strcasecmp(optarg, FLAG_TC_ACK_STRING))
189 stpinfo->config.flags = FLAG_TC_ACK;
190 else
191 xtables_error(PARAMETER_PROBLEM, "Bad --stp-flags argument");
192 } else
193 stpinfo->config.flags = i;
194 break;
195 case EBT_STP_ROOTPRIO:
196 if (parse_range(argv[optind-1], &(stpinfo->config.root_priol),
197 &(stpinfo->config.root_priou), 2, 0, 0xffff))
198 xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-prio range");
199 break;
200 case EBT_STP_ROOTCOST:
201 if (parse_range(argv[optind-1], &(stpinfo->config.root_costl),
202 &(stpinfo->config.root_costu), 4, 0, 0xffffffff))
203 xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-cost range");
204 break;
205 case EBT_STP_SENDERPRIO:
206 if (parse_range(argv[optind-1], &(stpinfo->config.sender_priol),
207 &(stpinfo->config.sender_priou), 2, 0, 0xffff))
208 xtables_error(PARAMETER_PROBLEM, "Bad --stp-sender-prio range");
209 break;
210 case EBT_STP_PORT:
211 if (parse_range(argv[optind-1], &(stpinfo->config.portl),
212 &(stpinfo->config.portu), 2, 0, 0xffff))
213 xtables_error(PARAMETER_PROBLEM, "Bad --stp-port-range");
214 break;
215 case EBT_STP_MSGAGE:
216 if (parse_range(argv[optind-1], &(stpinfo->config.msg_agel),
217 &(stpinfo->config.msg_ageu), 2, 0, 0xffff))
218 xtables_error(PARAMETER_PROBLEM, "Bad --stp-msg-age range");
219 break;
220 case EBT_STP_MAXAGE:
221 if (parse_range(argv[optind-1], &(stpinfo->config.max_agel),
222 &(stpinfo->config.max_ageu), 2, 0, 0xffff))
223 xtables_error(PARAMETER_PROBLEM, "Bad --stp-max-age range");
224 break;
225 case EBT_STP_HELLOTIME:
226 if (parse_range(argv[optind-1], &(stpinfo->config.hello_timel),
227 &(stpinfo->config.hello_timeu), 2, 0, 0xffff))
228 xtables_error(PARAMETER_PROBLEM, "Bad --stp-hello-time range");
229 break;
230 case EBT_STP_FWDD:
231 if (parse_range(argv[optind-1], &(stpinfo->config.forward_delayl),
232 &(stpinfo->config.forward_delayu), 2, 0, 0xffff))
233 xtables_error(PARAMETER_PROBLEM, "Bad --stp-forward-delay range");
234 break;
235 case EBT_STP_ROOTADDR:
236 if (xtables_parse_mac_and_mask(argv[optind-1],
237 stpinfo->config.root_addr,
238 stpinfo->config.root_addrmsk))
239 xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-addr address");
240 break;
241 case EBT_STP_SENDERADDR:
242 if (xtables_parse_mac_and_mask(argv[optind-1],
243 stpinfo->config.sender_addr,
244 stpinfo->config.sender_addrmsk))
245 xtables_error(PARAMETER_PROBLEM, "Bad --stp-sender-addr address");
246 break;
247 default:
248 xtables_error(PARAMETER_PROBLEM, "Unknown stp option");
249 }
250 return 1;
251 }
252
brstp_print(const void * ip,const struct xt_entry_match * match,int numeric)253 static void brstp_print(const void *ip, const struct xt_entry_match *match,
254 int numeric)
255 {
256 const struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)match->data;
257 const struct ebt_stp_config_info *c = &(stpinfo->config);
258 int i;
259
260 for (i = 0; i < STP_NUMOPS; i++) {
261 if (!(stpinfo->bitmask & (1 << i)))
262 continue;
263 printf("--%s %s", brstp_opts[i].name,
264 (stpinfo->invflags & (1 << i)) ? "! " : "");
265 if (EBT_STP_TYPE == (1 << i)) {
266 if (stpinfo->type == BPDU_TYPE_CONFIG)
267 printf("%s", BPDU_TYPE_CONFIG_STRING);
268 else if (stpinfo->type == BPDU_TYPE_TCN)
269 printf("%s", BPDU_TYPE_TCN_STRING);
270 else
271 printf("%d", stpinfo->type);
272 } else if (EBT_STP_FLAGS == (1 << i)) {
273 if (c->flags == FLAG_TC)
274 printf("%s", FLAG_TC_STRING);
275 else if (c->flags == FLAG_TC_ACK)
276 printf("%s", FLAG_TC_ACK_STRING);
277 else
278 printf("%d", c->flags);
279 } else if (EBT_STP_ROOTPRIO == (1 << i))
280 print_range(c->root_priol, c->root_priou);
281 else if (EBT_STP_ROOTADDR == (1 << i))
282 xtables_print_mac_and_mask((unsigned char *)c->root_addr,
283 (unsigned char*)c->root_addrmsk);
284 else if (EBT_STP_ROOTCOST == (1 << i))
285 print_range(c->root_costl, c->root_costu);
286 else if (EBT_STP_SENDERPRIO == (1 << i))
287 print_range(c->sender_priol, c->sender_priou);
288 else if (EBT_STP_SENDERADDR == (1 << i))
289 xtables_print_mac_and_mask((unsigned char *)c->sender_addr,
290 (unsigned char *)c->sender_addrmsk);
291 else if (EBT_STP_PORT == (1 << i))
292 print_range(c->portl, c->portu);
293 else if (EBT_STP_MSGAGE == (1 << i))
294 print_range(c->msg_agel, c->msg_ageu);
295 else if (EBT_STP_MAXAGE == (1 << i))
296 print_range(c->max_agel, c->max_ageu);
297 else if (EBT_STP_HELLOTIME == (1 << i))
298 print_range(c->hello_timel, c->hello_timeu);
299 else if (EBT_STP_FWDD == (1 << i))
300 print_range(c->forward_delayl, c->forward_delayu);
301 printf(" ");
302 }
303 }
304
305 static struct xtables_match brstp_match = {
306 .name = "stp",
307 .version = XTABLES_VERSION,
308 .family = NFPROTO_BRIDGE,
309 .size = sizeof(struct ebt_stp_info),
310 .help = brstp_print_help,
311 .parse = brstp_parse,
312 .print = brstp_print,
313 .extra_opts = brstp_opts,
314 };
315
_init(void)316 void _init(void)
317 {
318 xtables_register_match(&brstp_match);
319 }
320