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 		optinfo->flags |= IP6T_OPTS_LEN;
    112 		break;
    113 	case O_HBH_OPTS:
    114 		optinfo->optsnr = parse_options(cb->arg, optinfo->opts);
    115 		optinfo->flags |= IP6T_OPTS_OPTS;
    116 		break;
    117 	}
    118 }
    119 
    120 static void
    121 print_options(unsigned int optsnr, uint16_t *optsp)
    122 {
    123 	unsigned int i;
    124 
    125 	for(i=0; i<optsnr; i++){
    126 		printf("%c", (i==0)?' ':',');
    127 		printf("%d", (optsp[i] & 0xFF00)>>8);
    128 		if ((optsp[i] & 0x00FF) != 0x00FF){
    129 			printf(":%d", (optsp[i] & 0x00FF));
    130 		}
    131 	}
    132 }
    133 
    134 static void hbh_print(const void *ip, const struct xt_entry_match *match,
    135                       int numeric)
    136 {
    137 	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
    138 
    139 	printf(" hbh");
    140 	if (optinfo->flags & IP6T_OPTS_LEN) {
    141 		printf(" length");
    142 		printf(":%s", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "");
    143 		printf("%u", optinfo->hdrlen);
    144 	}
    145 	if (optinfo->flags & IP6T_OPTS_OPTS) printf(" opts");
    146 	print_options(optinfo->optsnr, (uint16_t *)optinfo->opts);
    147 	if (optinfo->invflags & ~IP6T_OPTS_INV_MASK)
    148 		printf(" Unknown invflags: 0x%X",
    149 		       optinfo->invflags & ~IP6T_OPTS_INV_MASK);
    150 }
    151 
    152 static void hbh_save(const void *ip, const struct xt_entry_match *match)
    153 {
    154 	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
    155 
    156 	if (optinfo->flags & IP6T_OPTS_LEN) {
    157 		printf("%s --hbh-len %u",
    158 			(optinfo->invflags & IP6T_OPTS_INV_LEN) ? " !" : "",
    159 			optinfo->hdrlen);
    160 	}
    161 
    162 	if (optinfo->flags & IP6T_OPTS_OPTS)
    163 		printf(" --hbh-opts");
    164 	print_options(optinfo->optsnr, (uint16_t *)optinfo->opts);
    165 }
    166 
    167 static int hbh_xlate(struct xt_xlate *xl,
    168 		     const struct xt_xlate_mt_params *params)
    169 {
    170 	const struct ip6t_opts *optinfo =
    171 		(struct ip6t_opts *)params->match->data;
    172 
    173 	if (!(optinfo->flags & IP6T_OPTS_LEN) ||
    174 	    (optinfo->flags & IP6T_OPTS_OPTS))
    175 		return 0;
    176 
    177 	xt_xlate_add(xl, "hbh hdrlength %s%u",
    178 		     (optinfo->invflags & IP6T_OPTS_INV_LEN) ? "!= " : "",
    179 		     optinfo->hdrlen);
    180 
    181 	return 1;
    182 }
    183 
    184 static struct xtables_match hbh_mt6_reg = {
    185 	.name 		= "hbh",
    186 	.version	= XTABLES_VERSION,
    187 	.family		= NFPROTO_IPV6,
    188 	.size		= XT_ALIGN(sizeof(struct ip6t_opts)),
    189 	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_opts)),
    190 	.help		= hbh_help,
    191 	.print		= hbh_print,
    192 	.save		= hbh_save,
    193 	.x6_parse	= hbh_parse,
    194 	.x6_options	= hbh_opts,
    195 	.xlate		= hbh_xlate,
    196 };
    197 
    198 void
    199 _init(void)
    200 {
    201 	xtables_register_match(&hbh_mt6_reg);
    202 }
    203