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