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