• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ebt_stp
2  *
3  * Authors:
4  * Bart De Schuymer <bdschuym@pandora.be>
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 = strdup(portstring);
94 	if ((cp = strchr(buffer, ':')) == NULL) {
95 		low_nr = strtoul(buffer, &end, 10);
96 		if (*end || low_nr < min || low_nr > max) {
97 			ret = -1;
98 			goto out;
99 		}
100 		if (bits == 2) {
101 			*(uint16_t *)lower =  low_nr;
102 			*(uint16_t *)upper =  low_nr;
103 		} else {
104 			*(uint32_t *)lower =  low_nr;
105 			*(uint32_t *)upper =  low_nr;
106 		}
107 	} else {
108 		*cp = '\0';
109 		cp++;
110 		if (!*buffer)
111 			low_nr = min;
112 		else {
113 			low_nr = strtoul(buffer, &end, 10);
114 			if (*end || low_nr < min) {
115 				ret = -1;
116 				goto out;
117 			}
118 		}
119 		if (!*cp)
120 			upp_nr = max;
121 		else {
122 			upp_nr = strtoul(cp, &end, 10);
123 			if (*end || upp_nr > max) {
124 				ret = -1;
125 				goto out;
126 			}
127 		}
128 		if (upp_nr < low_nr) {
129 			ret = -1;
130 			goto out;
131 		}
132 		if (bits == 2) {
133 			*(uint16_t *)lower = low_nr;
134 			*(uint16_t *)upper = upp_nr;
135 		} else {
136 			*(uint32_t *)lower = low_nr;
137 			*(uint32_t *)upper = upp_nr;
138 		}
139 	}
140 out:
141 	free(buffer);
142 	return ret;
143 }
144 
print_range(unsigned int l,unsigned int u)145 static void print_range(unsigned int l, unsigned int u)
146 {
147 	if (l == u)
148 		printf("%u ", l);
149 	else
150 		printf("%u:%u ", l, u);
151 }
152 
153 static int
brstp_parse(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_match ** match)154 brstp_parse(int c, char **argv, int invert, unsigned int *flags,
155 	    const void *entry, struct xt_entry_match **match)
156 {
157 	struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)(*match)->data;
158 	unsigned int flag;
159 	long int i;
160 	char *end = NULL;
161 
162 	if (c < 'a' || c > ('a' + STP_NUMOPS - 1))
163 		return 0;
164 	flag = 1 << (c - 'a');
165 	EBT_CHECK_OPTION(flags, flag);
166 	if (invert)
167 		stpinfo->invflags |= flag;
168 	stpinfo->bitmask |= flag;
169 	switch (flag) {
170 	case EBT_STP_TYPE:
171 		i = strtol(optarg, &end, 0);
172 		if (i < 0 || i > 255 || *end != '\0') {
173 			if (!strcasecmp(optarg, BPDU_TYPE_CONFIG_STRING))
174 				stpinfo->type = BPDU_TYPE_CONFIG;
175 			else if (!strcasecmp(optarg, BPDU_TYPE_TCN_STRING))
176 				stpinfo->type = BPDU_TYPE_TCN;
177 			else
178 				xtables_error(PARAMETER_PROBLEM, "Bad --stp-type argument");
179 		} else
180 			stpinfo->type = i;
181 		break;
182 	case EBT_STP_FLAGS:
183 		i = strtol(optarg, &end, 0);
184 		if (i < 0 || i > 255 || *end != '\0') {
185 			if (!strcasecmp(optarg, FLAG_TC_STRING))
186 				stpinfo->config.flags = FLAG_TC;
187 			else if (!strcasecmp(optarg, FLAG_TC_ACK_STRING))
188 				stpinfo->config.flags = FLAG_TC_ACK;
189 			else
190 				xtables_error(PARAMETER_PROBLEM, "Bad --stp-flags argument");
191 		} else
192 			stpinfo->config.flags = i;
193 		break;
194 	case EBT_STP_ROOTPRIO:
195 		if (parse_range(argv[optind-1], &(stpinfo->config.root_priol),
196 		    &(stpinfo->config.root_priou), 2, 0, 0xffff))
197 			xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-prio range");
198 		break;
199 	case EBT_STP_ROOTCOST:
200 		if (parse_range(argv[optind-1], &(stpinfo->config.root_costl),
201 		    &(stpinfo->config.root_costu), 4, 0, 0xffffffff))
202 			xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-cost range");
203 		break;
204 	case EBT_STP_SENDERPRIO:
205 		if (parse_range(argv[optind-1], &(stpinfo->config.sender_priol),
206 		    &(stpinfo->config.sender_priou), 2, 0, 0xffff))
207 			xtables_error(PARAMETER_PROBLEM, "Bad --stp-sender-prio range");
208 		break;
209 	case EBT_STP_PORT:
210 		if (parse_range(argv[optind-1], &(stpinfo->config.portl),
211 		    &(stpinfo->config.portu), 2, 0, 0xffff))
212 			xtables_error(PARAMETER_PROBLEM, "Bad --stp-port-range");
213 		break;
214 	case EBT_STP_MSGAGE:
215 		if (parse_range(argv[optind-1], &(stpinfo->config.msg_agel),
216 		    &(stpinfo->config.msg_ageu), 2, 0, 0xffff))
217 			xtables_error(PARAMETER_PROBLEM, "Bad --stp-msg-age range");
218 		break;
219 	case EBT_STP_MAXAGE:
220 		if (parse_range(argv[optind-1], &(stpinfo->config.max_agel),
221 		    &(stpinfo->config.max_ageu), 2, 0, 0xffff))
222 			xtables_error(PARAMETER_PROBLEM, "Bad --stp-max-age range");
223 		break;
224 	case EBT_STP_HELLOTIME:
225 		if (parse_range(argv[optind-1], &(stpinfo->config.hello_timel),
226 		    &(stpinfo->config.hello_timeu), 2, 0, 0xffff))
227 			xtables_error(PARAMETER_PROBLEM, "Bad --stp-hello-time range");
228 		break;
229 	case EBT_STP_FWDD:
230 		if (parse_range(argv[optind-1], &(stpinfo->config.forward_delayl),
231 		    &(stpinfo->config.forward_delayu), 2, 0, 0xffff))
232 			xtables_error(PARAMETER_PROBLEM, "Bad --stp-forward-delay range");
233 		break;
234 	case EBT_STP_ROOTADDR:
235 		if (xtables_parse_mac_and_mask(argv[optind-1],
236 					       stpinfo->config.root_addr,
237 					       stpinfo->config.root_addrmsk))
238 			xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-addr address");
239 		break;
240 	case EBT_STP_SENDERADDR:
241 		if (xtables_parse_mac_and_mask(argv[optind-1],
242 					       stpinfo->config.sender_addr,
243 					       stpinfo->config.sender_addrmsk))
244 			xtables_error(PARAMETER_PROBLEM, "Bad --stp-sender-addr address");
245 		break;
246 	default:
247 		xtables_error(PARAMETER_PROBLEM, "Unknown stp option");
248 	}
249 	return 1;
250 }
251 
brstp_print(const void * ip,const struct xt_entry_match * match,int numeric)252 static void brstp_print(const void *ip, const struct xt_entry_match *match,
253 			 int numeric)
254 {
255 	const struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)match->data;
256 	const struct ebt_stp_config_info *c = &(stpinfo->config);
257 	int i;
258 
259 	for (i = 0; i < STP_NUMOPS; i++) {
260 		if (!(stpinfo->bitmask & (1 << i)))
261 			continue;
262 		printf("--%s %s", brstp_opts[i].name,
263 		       (stpinfo->invflags & (1 << i)) ? "! " : "");
264 		if (EBT_STP_TYPE == (1 << i)) {
265 			if (stpinfo->type == BPDU_TYPE_CONFIG)
266 				printf("%s", BPDU_TYPE_CONFIG_STRING);
267 			else if (stpinfo->type == BPDU_TYPE_TCN)
268 				printf("%s", BPDU_TYPE_TCN_STRING);
269 			else
270 				printf("%d", stpinfo->type);
271 		} else if (EBT_STP_FLAGS == (1 << i)) {
272 			if (c->flags == FLAG_TC)
273 				printf("%s", FLAG_TC_STRING);
274 			else if (c->flags == FLAG_TC_ACK)
275 				printf("%s", FLAG_TC_ACK_STRING);
276 			else
277 				printf("%d", c->flags);
278 		} else if (EBT_STP_ROOTPRIO == (1 << i))
279 			print_range(c->root_priol, c->root_priou);
280 		else if (EBT_STP_ROOTADDR == (1 << i))
281 			xtables_print_mac_and_mask((unsigned char *)c->root_addr,
282 			   (unsigned char*)c->root_addrmsk);
283 		else if (EBT_STP_ROOTCOST == (1 << i))
284 			print_range(c->root_costl, c->root_costu);
285 		else if (EBT_STP_SENDERPRIO == (1 << i))
286 			print_range(c->sender_priol, c->sender_priou);
287 		else if (EBT_STP_SENDERADDR == (1 << i))
288 			xtables_print_mac_and_mask((unsigned char *)c->sender_addr,
289 			   (unsigned char *)c->sender_addrmsk);
290 		else if (EBT_STP_PORT == (1 << i))
291 			print_range(c->portl, c->portu);
292 		else if (EBT_STP_MSGAGE == (1 << i))
293 			print_range(c->msg_agel, c->msg_ageu);
294 		else if (EBT_STP_MAXAGE == (1 << i))
295 			print_range(c->max_agel, c->max_ageu);
296 		else if (EBT_STP_HELLOTIME == (1 << i))
297 			print_range(c->hello_timel, c->hello_timeu);
298 		else if (EBT_STP_FWDD == (1 << i))
299 			print_range(c->forward_delayl, c->forward_delayu);
300 		printf(" ");
301 	}
302 }
303 
304 static struct xtables_match brstp_match = {
305 	.name		= "stp",
306 	.version	= XTABLES_VERSION,
307 	.family		= NFPROTO_BRIDGE,
308 	.size		= sizeof(struct ebt_stp_info),
309 	.help		= brstp_print_help,
310 	.parse		= brstp_parse,
311 	.print		= brstp_print,
312 	.extra_opts	= brstp_opts,
313 };
314 
_init(void)315 void _init(void)
316 {
317 	xtables_register_match(&brstp_match);
318 }
319