Blame extensions/libebt_stp.c

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