Home | History | Annotate | Download | only in extensions
      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 #include <errno.h>
      5 #include <xtables.h>
      6 #include <linux/netfilter_ipv6/ip6t_opts.h>
      7 
      8 #define DEBUG		0
      9 
     10 enum {
     11 	O_HBH_LEN = 0,
     12 	O_HBH_OPTS,
     13 };
     14 
     15 static void hbh_help(void)
     16 {
     17 	printf(
     18 "hbh match options:\n"
     19 "[!] --hbh-len length            total length of this header\n"
     20 "  --hbh-opts TYPE[:LEN][,TYPE[:LEN]...] \n"
     21 "                                Options and its length (list, max: %d)\n",
     22 IP6T_OPTS_OPTSNR);
     23 }
     24 
     25 static const struct xt_option_entry hbh_opts[] = {
     26 	{.name = "hbh-len", .id = O_HBH_LEN, .type = XTTYPE_UINT32,
     27 	 .flags = XTOPT_INVERT | XTOPT_PUT,
     28 	 XTOPT_POINTER(struct ip6t_opts, hdrlen)},
     29 	{.name = "hbh-opts", .id = O_HBH_OPTS, .type = XTTYPE_STRING},
     30 	XTOPT_TABLEEND,
     31 };
     32 
     33 static uint32_t
     34 parse_opts_num(const char *idstr, const char *typestr)
     35 {
     36 	unsigned long int id;
     37 	char* ep;
     38 
     39 	id =  strtoul(idstr,&ep,0) ;
     40 
     41 	if ( idstr == ep ) {
     42 		xtables_error(PARAMETER_PROBLEM,
     43 			   "hbh: no valid digits in %s `%s'", typestr, idstr);
     44 	}
     45 	if ( id == ULONG_MAX  && errno == ERANGE ) {
     46 		xtables_error(PARAMETER_PROBLEM,
     47 			   "%s `%s' specified too big: would overflow",
     48 			   typestr, idstr);
     49 	}
     50 	if ( *idstr != '\0'  && *ep != '\0' ) {
     51 		xtables_error(PARAMETER_PROBLEM,
     52 			   "hbh: error parsing %s `%s'", typestr, idstr);
     53 	}
     54 	return id;
     55 }
     56 
     57 static int
     58 parse_options(const char *optsstr, uint16_t *opts)
     59 {
     60         char *buffer, *cp, *next, *range;
     61         unsigned int i;
     62 
     63 	buffer = strdup(optsstr);
     64 	if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
     65 
     66         for (cp=buffer, i=0; cp && i<IP6T_OPTS_OPTSNR; cp=next,i++)
     67         {
     68                 next=strchr(cp, ',');
     69                 if (next) *next++='\0';
     70                 range = strchr(cp, ':');
     71                 if (range) {
     72                         if (i == IP6T_OPTS_OPTSNR-1)
     73 				xtables_error(PARAMETER_PROBLEM,
     74                                            "too many ports specified");
     75                         *range++ = '\0';
     76                 }
     77 		opts[i] = (parse_opts_num(cp, "opt") & 0xFF) << 8;
     78                 if (range) {
     79 			if (opts[i] == 0)
     80 				xtables_error(PARAMETER_PROBLEM, "PAD0 has not got length");
     81 			opts[i] |= parse_opts_num(range, "length") & 0xFF;
     82                 } else {
     83                         opts[i] |= (0x00FF);
     84 		}
     85 
     86 #if DEBUG
     87 		printf("opts str: %s %s\n", cp, range);
     88 		printf("opts opt: %04X\n", opts[i]);
     89 #endif
     90 	}
     91 	if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
     92 
     93 	free(buffer);
     94 
     95 #if DEBUG
     96 	printf("addr nr: %d\n", i);
     97 #endif
     98 
     99 	return i;
    100 }
    101 
    102 static void hbh_parse(struct xt_option_call *cb)
    103 {
    104 	struct ip6t_opts *optinfo = cb->data;
    105 
    106 	xtables_option_parse(cb);
    107 	switch (cb->entry->id) {
    108 	case O_HBH_LEN:
    109 		if (cb->invert)
    110 			optinfo->invflags |= IP6T_OPTS_INV_LEN;
    111 		break;
    112 	case O_HBH_OPTS:
    113 		optinfo->optsnr = parse_options(cb->arg, optinfo->opts);
    114 		optinfo->flags |= IP6T_OPTS_OPTS;
    115 		break;
    116 	}
    117 }
    118 
    119 static void
    120 print_options(unsigned int optsnr, uint16_t *optsp)
    121 {
    122 	unsigned int i;
    123 
    124 	for(i=0; i<optsnr; i++){
    125 		printf("%c", (i==0)?' ':',');
    126 		printf("%d", (optsp[i] & 0xFF00)>>8);
    127 		if ((optsp[i] & 0x00FF) != 0x00FF){
    128 			printf(":%d", (optsp[i] & 0x00FF));
    129 		}
    130 	}
    131 }
    132 
    133 static void hbh_print(const void *ip, const struct xt_entry_match *match,
    134                       int numeric)
    135 {
    136 	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
    137 
    138 	printf(" hbh");
    139 	if (optinfo->flags & IP6T_OPTS_LEN) {
    140 		printf(" length");
    141 		printf(":%s", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "");
    142 		printf("%u", optinfo->hdrlen);
    143 	}
    144 	if (optinfo->flags & IP6T_OPTS_OPTS) printf(" opts");
    145 	print_options(optinfo->optsnr, (uint16_t *)optinfo->opts);
    146 	if (optinfo->invflags & ~IP6T_OPTS_INV_MASK)
    147 		printf(" Unknown invflags: 0x%X",
    148 		       optinfo->invflags & ~IP6T_OPTS_INV_MASK);
    149 }
    150 
    151 static void hbh_save(const void *ip, const struct xt_entry_match *match)
    152 {
    153 	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
    154 
    155 	if (optinfo->flags & IP6T_OPTS_LEN) {
    156 		printf("%s --hbh-len %u",
    157 			(optinfo->invflags & IP6T_OPTS_INV_LEN) ? " !" : "",
    158 			optinfo->hdrlen);
    159 	}
    160 
    161 	if (optinfo->flags & IP6T_OPTS_OPTS)
    162 		printf(" --hbh-opts");
    163 	print_options(optinfo->optsnr, (uint16_t *)optinfo->opts);
    164 }
    165 
    166 static struct xtables_match hbh_mt6_reg = {
    167 	.name 		= "hbh",
    168 	.version	= XTABLES_VERSION,
    169 	.family		= NFPROTO_IPV6,
    170 	.size		= XT_ALIGN(sizeof(struct ip6t_opts)),
    171 	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_opts)),
    172 	.help		= hbh_help,
    173 	.print		= hbh_print,
    174 	.save		= hbh_save,
    175 	.x6_parse	= hbh_parse,
    176 	.x6_options	= hbh_opts,
    177 };
    178 
    179 void
    180 _init(void)
    181 {
    182 	xtables_register_match(&hbh_mt6_reg);
    183 }
    184