/* ebt_stp * * Authors: * Bart De Schuymer * * July, 2003 */ #include #include #include #include #include #include #include #include "iptables/nft.h" #include "iptables/nft-bridge.h" #define STP_TYPE 'a' #define STP_FLAGS 'b' #define STP_ROOTPRIO 'c' #define STP_ROOTADDR 'd' #define STP_ROOTCOST 'e' #define STP_SENDERPRIO 'f' #define STP_SENDERADDR 'g' #define STP_PORT 'h' #define STP_MSGAGE 'i' #define STP_MAXAGE 'j' #define STP_HELLOTIME 'k' #define STP_FWDD 'l' #define STP_NUMOPS 12 static const struct option brstp_opts[] = { { "stp-type" , required_argument, 0, STP_TYPE}, { "stp-flags" , required_argument, 0, STP_FLAGS}, { "stp-root-prio" , required_argument, 0, STP_ROOTPRIO}, { "stp-root-addr" , required_argument, 0, STP_ROOTADDR}, { "stp-root-cost" , required_argument, 0, STP_ROOTCOST}, { "stp-sender-prio" , required_argument, 0, STP_SENDERPRIO}, { "stp-sender-addr" , required_argument, 0, STP_SENDERADDR}, { "stp-port" , required_argument, 0, STP_PORT}, { "stp-msg-age" , required_argument, 0, STP_MSGAGE}, { "stp-max-age" , required_argument, 0, STP_MAXAGE}, { "stp-hello-time" , required_argument, 0, STP_HELLOTIME}, { "stp-forward-delay", required_argument, 0, STP_FWDD}, { 0 } }; #define BPDU_TYPE_CONFIG 0 #define BPDU_TYPE_TCN 0x80 #define BPDU_TYPE_CONFIG_STRING "config" #define BPDU_TYPE_TCN_STRING "tcn" #define FLAG_TC 0x01 #define FLAG_TC_ACK 0x80 #define FLAG_TC_STRING "topology-change" #define FLAG_TC_ACK_STRING "topology-change-ack" static void brstp_print_help(void) { printf( "stp options:\n" "--stp-type type : BPDU type\n" "--stp-flags flag : control flag\n" "--stp-root-prio prio[:prio] : root priority (16-bit) range\n" "--stp-root-addr address[/mask] : MAC address of root\n" "--stp-root-cost cost[:cost] : root cost (32-bit) range\n" "--stp-sender-prio prio[:prio] : sender priority (16-bit) range\n" "--stp-sender-addr address[/mask] : MAC address of sender\n" "--stp-port port[:port] : port id (16-bit) range\n" "--stp-msg-age age[:age] : message age timer (16-bit) range\n" "--stp-max-age age[:age] : maximum age timer (16-bit) range\n" "--stp-hello-time time[:time] : hello time timer (16-bit) range\n" "--stp-forward-delay delay[:delay]: forward delay timer (16-bit) range\n" " Recognized BPDU type strings:\n" " \"config\": configuration BPDU (=0)\n" " \"tcn\" : topology change notification BPDU (=0x80)\n" " Recognized control flag strings:\n" " \"topology-change\" : topology change flag (0x01)\n" " \"topology-change-ack\": topology change acknowledgement flag (0x80)"); } static int parse_range(const char *portstring, void *lower, void *upper, int bits, uint32_t min, uint32_t max) { char *buffer; char *cp, *end; uint32_t low_nr, upp_nr; int ret = 0; buffer = strdup(portstring); if ((cp = strchr(buffer, ':')) == NULL) { low_nr = strtoul(buffer, &end, 10); if (*end || low_nr < min || low_nr > max) { ret = -1; goto out; } if (bits == 2) { *(uint16_t *)lower = low_nr; *(uint16_t *)upper = low_nr; } else { *(uint32_t *)lower = low_nr; *(uint32_t *)upper = low_nr; } } else { *cp = '\0'; cp++; if (!*buffer) low_nr = min; else { low_nr = strtoul(buffer, &end, 10); if (*end || low_nr < min) { ret = -1; goto out; } } if (!*cp) upp_nr = max; else { upp_nr = strtoul(cp, &end, 10); if (*end || upp_nr > max) { ret = -1; goto out; } } if (upp_nr < low_nr) { ret = -1; goto out; } if (bits == 2) { *(uint16_t *)lower = low_nr; *(uint16_t *)upper = upp_nr; } else { *(uint32_t *)lower = low_nr; *(uint32_t *)upper = upp_nr; } } out: free(buffer); return ret; } static void print_range(unsigned int l, unsigned int u) { if (l == u) printf("%u ", l); else printf("%u:%u ", l, u); } static int brstp_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)(*match)->data; unsigned int flag; long int i; char *end = NULL; if (c < 'a' || c > ('a' + STP_NUMOPS - 1)) return 0; flag = 1 << (c - 'a'); EBT_CHECK_OPTION(flags, flag); if (invert) stpinfo->invflags |= flag; stpinfo->bitmask |= flag; switch (flag) { case EBT_STP_TYPE: i = strtol(optarg, &end, 0); if (i < 0 || i > 255 || *end != '\0') { if (!strcasecmp(optarg, BPDU_TYPE_CONFIG_STRING)) stpinfo->type = BPDU_TYPE_CONFIG; else if (!strcasecmp(optarg, BPDU_TYPE_TCN_STRING)) stpinfo->type = BPDU_TYPE_TCN; else xtables_error(PARAMETER_PROBLEM, "Bad --stp-type argument"); } else stpinfo->type = i; break; case EBT_STP_FLAGS: i = strtol(optarg, &end, 0); if (i < 0 || i > 255 || *end != '\0') { if (!strcasecmp(optarg, FLAG_TC_STRING)) stpinfo->config.flags = FLAG_TC; else if (!strcasecmp(optarg, FLAG_TC_ACK_STRING)) stpinfo->config.flags = FLAG_TC_ACK; else xtables_error(PARAMETER_PROBLEM, "Bad --stp-flags argument"); } else stpinfo->config.flags = i; break; case EBT_STP_ROOTPRIO: if (parse_range(argv[optind-1], &(stpinfo->config.root_priol), &(stpinfo->config.root_priou), 2, 0, 0xffff)) xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-prio range"); break; case EBT_STP_ROOTCOST: if (parse_range(argv[optind-1], &(stpinfo->config.root_costl), &(stpinfo->config.root_costu), 4, 0, 0xffffffff)) xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-cost range"); break; case EBT_STP_SENDERPRIO: if (parse_range(argv[optind-1], &(stpinfo->config.sender_priol), &(stpinfo->config.sender_priou), 2, 0, 0xffff)) xtables_error(PARAMETER_PROBLEM, "Bad --stp-sender-prio range"); break; case EBT_STP_PORT: if (parse_range(argv[optind-1], &(stpinfo->config.portl), &(stpinfo->config.portu), 2, 0, 0xffff)) xtables_error(PARAMETER_PROBLEM, "Bad --stp-port-range"); break; case EBT_STP_MSGAGE: if (parse_range(argv[optind-1], &(stpinfo->config.msg_agel), &(stpinfo->config.msg_ageu), 2, 0, 0xffff)) xtables_error(PARAMETER_PROBLEM, "Bad --stp-msg-age range"); break; case EBT_STP_MAXAGE: if (parse_range(argv[optind-1], &(stpinfo->config.max_agel), &(stpinfo->config.max_ageu), 2, 0, 0xffff)) xtables_error(PARAMETER_PROBLEM, "Bad --stp-max-age range"); break; case EBT_STP_HELLOTIME: if (parse_range(argv[optind-1], &(stpinfo->config.hello_timel), &(stpinfo->config.hello_timeu), 2, 0, 0xffff)) xtables_error(PARAMETER_PROBLEM, "Bad --stp-hello-time range"); break; case EBT_STP_FWDD: if (parse_range(argv[optind-1], &(stpinfo->config.forward_delayl), &(stpinfo->config.forward_delayu), 2, 0, 0xffff)) xtables_error(PARAMETER_PROBLEM, "Bad --stp-forward-delay range"); break; case EBT_STP_ROOTADDR: if (xtables_parse_mac_and_mask(argv[optind-1], stpinfo->config.root_addr, stpinfo->config.root_addrmsk)) xtables_error(PARAMETER_PROBLEM, "Bad --stp-root-addr address"); break; case EBT_STP_SENDERADDR: if (xtables_parse_mac_and_mask(argv[optind-1], stpinfo->config.sender_addr, stpinfo->config.sender_addrmsk)) xtables_error(PARAMETER_PROBLEM, "Bad --stp-sender-addr address"); break; default: xtables_error(PARAMETER_PROBLEM, "Unknown stp option"); } return 1; } static void brstp_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)match->data; const struct ebt_stp_config_info *c = &(stpinfo->config); int i; for (i = 0; i < STP_NUMOPS; i++) { if (!(stpinfo->bitmask & (1 << i))) continue; printf("--%s %s", brstp_opts[i].name, (stpinfo->invflags & (1 << i)) ? "! " : ""); if (EBT_STP_TYPE == (1 << i)) { if (stpinfo->type == BPDU_TYPE_CONFIG) printf("%s", BPDU_TYPE_CONFIG_STRING); else if (stpinfo->type == BPDU_TYPE_TCN) printf("%s", BPDU_TYPE_TCN_STRING); else printf("%d", stpinfo->type); } else if (EBT_STP_FLAGS == (1 << i)) { if (c->flags == FLAG_TC) printf("%s", FLAG_TC_STRING); else if (c->flags == FLAG_TC_ACK) printf("%s", FLAG_TC_ACK_STRING); else printf("%d", c->flags); } else if (EBT_STP_ROOTPRIO == (1 << i)) print_range(c->root_priol, c->root_priou); else if (EBT_STP_ROOTADDR == (1 << i)) xtables_print_mac_and_mask((unsigned char *)c->root_addr, (unsigned char*)c->root_addrmsk); else if (EBT_STP_ROOTCOST == (1 << i)) print_range(c->root_costl, c->root_costu); else if (EBT_STP_SENDERPRIO == (1 << i)) print_range(c->sender_priol, c->sender_priou); else if (EBT_STP_SENDERADDR == (1 << i)) xtables_print_mac_and_mask((unsigned char *)c->sender_addr, (unsigned char *)c->sender_addrmsk); else if (EBT_STP_PORT == (1 << i)) print_range(c->portl, c->portu); else if (EBT_STP_MSGAGE == (1 << i)) print_range(c->msg_agel, c->msg_ageu); else if (EBT_STP_MAXAGE == (1 << i)) print_range(c->max_agel, c->max_ageu); else if (EBT_STP_HELLOTIME == (1 << i)) print_range(c->hello_timel, c->hello_timeu); else if (EBT_STP_FWDD == (1 << i)) print_range(c->forward_delayl, c->forward_delayu); printf(" "); } } static struct xtables_match brstp_match = { .name = "stp", .version = XTABLES_VERSION, .family = NFPROTO_BRIDGE, .size = sizeof(struct ebt_stp_info), .help = brstp_print_help, .parse = brstp_parse, .print = brstp_print, .extra_opts = brstp_opts, }; void _init(void) { xtables_register_match(&brstp_match); }