| /* Shared library add-on to ip6tables to add Hop-by-Hop header support. */ | 
 | #include <stdio.h> | 
 | #include <netdb.h> | 
 | #include <string.h> | 
 | #include <stdlib.h> | 
 | #include <getopt.h> | 
 | #include <errno.h> | 
 | #include <xtables.h> | 
 | /*#include <linux/in6.h>*/ | 
 | #include <linux/netfilter_ipv6/ip6t_opts.h> | 
 | #include <sys/types.h> | 
 | #include <sys/socket.h> | 
 | #include <arpa/inet.h> | 
 |  | 
 | #define DEBUG		0 | 
 |  | 
 | static void hbh_help(void) | 
 | { | 
 | 	printf( | 
 | "hbh match options:\n" | 
 | "[!] --hbh-len length            total length of this header\n" | 
 | "  --hbh-opts TYPE[:LEN][,TYPE[:LEN]...] \n" | 
 | "                                Options and its length (list, max: %d)\n", | 
 | IP6T_OPTS_OPTSNR); | 
 | } | 
 |  | 
 | static const struct option hbh_opts[] = { | 
 | 	{ "hbh-len", 1, NULL, '1' }, | 
 | 	{ "hbh-opts", 1, NULL, '2' }, | 
 | 	{ "hbh-not-strict", 1, NULL, '3' }, | 
 | 	{ .name = NULL } | 
 | }; | 
 |  | 
 | static u_int32_t | 
 | parse_opts_num(const char *idstr, const char *typestr) | 
 | { | 
 | 	unsigned long int id; | 
 | 	char* ep; | 
 |  | 
 | 	id =  strtoul(idstr,&ep,0) ; | 
 |  | 
 | 	if ( idstr == ep ) { | 
 | 		xtables_error(PARAMETER_PROBLEM, | 
 | 			   "hbh: no valid digits in %s `%s'", typestr, idstr); | 
 | 	} | 
 | 	if ( id == ULONG_MAX  && errno == ERANGE ) { | 
 | 		xtables_error(PARAMETER_PROBLEM, | 
 | 			   "%s `%s' specified too big: would overflow", | 
 | 			   typestr, idstr); | 
 | 	}	 | 
 | 	if ( *idstr != '\0'  && *ep != '\0' ) { | 
 | 		xtables_error(PARAMETER_PROBLEM, | 
 | 			   "hbh: error parsing %s `%s'", typestr, idstr); | 
 | 	} | 
 | 	return id; | 
 | } | 
 |  | 
 | static int | 
 | parse_options(const char *optsstr, u_int16_t *opts) | 
 | { | 
 |         char *buffer, *cp, *next, *range; | 
 |         unsigned int i; | 
 | 	 | 
 | 	buffer = strdup(optsstr); | 
 | 	if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed"); | 
 | 			 | 
 |         for (cp=buffer, i=0; cp && i<IP6T_OPTS_OPTSNR; cp=next,i++) | 
 |         { | 
 |                 next=strchr(cp, ','); | 
 |                 if (next) *next++='\0'; | 
 |                 range = strchr(cp, ':'); | 
 |                 if (range) { | 
 |                         if (i == IP6T_OPTS_OPTSNR-1) | 
 | 				xtables_error(PARAMETER_PROBLEM, | 
 |                                            "too many ports specified"); | 
 |                         *range++ = '\0'; | 
 |                 } | 
 | 		opts[i] = (parse_opts_num(cp, "opt") & 0xFF) << 8; | 
 |                 if (range) { | 
 | 			if (opts[i] == 0) | 
 | 				xtables_error(PARAMETER_PROBLEM, "PAD0 has not got length"); | 
 | 			opts[i] |= parse_opts_num(range, "length") & 0xFF; | 
 |                 } else { | 
 |                         opts[i] |= (0x00FF); | 
 | 		} | 
 |  | 
 | #if DEBUG | 
 | 		printf("opts str: %s %s\n", cp, range); | 
 | 		printf("opts opt: %04X\n", opts[i]); | 
 | #endif | 
 | 	} | 
 | 	if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified"); | 
 |  | 
 | 	free(buffer); | 
 |  | 
 | #if DEBUG | 
 | 	printf("addr nr: %d\n", i); | 
 | #endif | 
 |  | 
 | 	return i; | 
 | } | 
 |  | 
 | static void hbh_init(struct xt_entry_match *m) | 
 | { | 
 | 	struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data; | 
 |  | 
 | 	optinfo->hdrlen = 0; | 
 | 	optinfo->flags = 0; | 
 | 	optinfo->invflags = 0; | 
 | 	optinfo->optsnr = 0; | 
 | } | 
 |  | 
 | static int hbh_parse(int c, char **argv, int invert, unsigned int *flags, | 
 |                      const void *entry, struct xt_entry_match **match) | 
 | { | 
 | 	struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data; | 
 |  | 
 | 	switch (c) { | 
 | 	case '1': | 
 | 		if (*flags & IP6T_OPTS_LEN) | 
 | 			xtables_error(PARAMETER_PROBLEM, | 
 | 				   "Only one `--hbh-len' allowed"); | 
 | 		xtables_check_inverse(optarg, &invert, &optind, 0); | 
 | 		optinfo->hdrlen = parse_opts_num(argv[optind-1], "length"); | 
 | 		if (invert) | 
 | 			optinfo->invflags |= IP6T_OPTS_INV_LEN; | 
 | 		optinfo->flags |= IP6T_OPTS_LEN; | 
 | 		*flags |= IP6T_OPTS_LEN; | 
 | 		break; | 
 | 	case '2': | 
 | 		if (*flags & IP6T_OPTS_OPTS) | 
 | 			xtables_error(PARAMETER_PROBLEM, | 
 | 				   "Only one `--hbh-opts' allowed"); | 
 |                 xtables_check_inverse(optarg, &invert, &optind, 0); | 
 |                 if (invert) | 
 | 			xtables_error(PARAMETER_PROBLEM, | 
 | 				" '!' not allowed with `--hbh-opts'"); | 
 | 		optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts); | 
 | 		optinfo->flags |= IP6T_OPTS_OPTS; | 
 | 		*flags |= IP6T_OPTS_OPTS; | 
 | 		break; | 
 | 	case '3': | 
 | 		if (*flags & IP6T_OPTS_NSTRICT) | 
 | 			xtables_error(PARAMETER_PROBLEM, | 
 | 				   "Only one `--hbh-not-strict' allowed"); | 
 | 		if ( !(*flags & IP6T_OPTS_OPTS) ) | 
 | 			xtables_error(PARAMETER_PROBLEM, | 
 | 				   "`--hbh-opts ...' required before `--hbh-not-strict'"); | 
 | 		optinfo->flags |= IP6T_OPTS_NSTRICT; | 
 | 		*flags |= IP6T_OPTS_NSTRICT; | 
 | 		break; | 
 | 	default: | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	return 1; | 
 | } | 
 |  | 
 | static void | 
 | print_options(unsigned int optsnr, u_int16_t *optsp) | 
 | { | 
 | 	unsigned int i; | 
 |  | 
 | 	for(i=0; i<optsnr; i++){ | 
 | 		printf("%d", (optsp[i] & 0xFF00)>>8); | 
 | 		if ((optsp[i] & 0x00FF) != 0x00FF){ | 
 | 			printf(":%d", (optsp[i] & 0x00FF)); | 
 | 		}  | 
 | 		printf("%c", (i!=optsnr-1)?',':' '); | 
 | 	} | 
 | } | 
 |  | 
 | static void hbh_print(const void *ip, const struct xt_entry_match *match, | 
 |                       int numeric) | 
 | { | 
 | 	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; | 
 |  | 
 | 	printf("hbh "); | 
 | 	if (optinfo->flags & IP6T_OPTS_LEN) { | 
 | 		printf("length"); | 
 | 		printf(":%s", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : ""); | 
 | 		printf("%u", optinfo->hdrlen); | 
 | 		printf(" "); | 
 | 	} | 
 | 	if (optinfo->flags & IP6T_OPTS_OPTS) printf("opts "); | 
 | 	print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); | 
 | 	if (optinfo->flags & IP6T_OPTS_NSTRICT) printf("not-strict "); | 
 | 	if (optinfo->invflags & ~IP6T_OPTS_INV_MASK) | 
 | 		printf("Unknown invflags: 0x%X ", | 
 | 		       optinfo->invflags & ~IP6T_OPTS_INV_MASK); | 
 | } | 
 |  | 
 | static void hbh_save(const void *ip, const struct xt_entry_match *match) | 
 | { | 
 | 	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; | 
 |  | 
 | 	if (optinfo->flags & IP6T_OPTS_LEN) { | 
 | 		printf("%s--hbh-len %u ", | 
 | 			(optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "",  | 
 | 			optinfo->hdrlen); | 
 | 	} | 
 |  | 
 | 	if (optinfo->flags & IP6T_OPTS_OPTS) | 
 | 		printf("--hbh-opts "); | 
 | 	print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); | 
 | 	if (optinfo->flags & IP6T_OPTS_NSTRICT) | 
 | 		printf("--hbh-not-strict "); | 
 | } | 
 |  | 
 | static struct xtables_match hbh_mt6_reg = { | 
 | 	.name 		= "hbh", | 
 | 	.version	= XTABLES_VERSION, | 
 | 	.family		= NFPROTO_IPV6, | 
 | 	.size		= XT_ALIGN(sizeof(struct ip6t_opts)), | 
 | 	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_opts)), | 
 | 	.help		= hbh_help, | 
 | 	.init		= hbh_init, | 
 | 	.parse		= hbh_parse, | 
 | 	.print		= hbh_print, | 
 | 	.save		= hbh_save, | 
 | 	.extra_opts	= hbh_opts, | 
 | }; | 
 |  | 
 | void | 
 | _init(void) | 
 | { | 
 | 	xtables_register_match(&hbh_mt6_reg); | 
 | } |