Home | History | Annotate | Download | only in extensions
      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 #include <xtables.h>
      5 #include <linux/netfilter/nf_nat.h>
      6 #include <linux/netfilter_ipv4/ipt_SAME.h>
      7 
      8 enum {
      9 	O_TO_ADDR = 0,
     10 	O_NODST,
     11 	O_RANDOM,
     12 	F_TO_ADDR = 1 << O_TO_ADDR,
     13 	F_RANDOM  = 1 << O_RANDOM,
     14 };
     15 
     16 static void SAME_help(void)
     17 {
     18 	printf(
     19 "SAME target options:\n"
     20 " --to <ipaddr>-<ipaddr>\n"
     21 "				Addresses to map source to.\n"
     22 "				 May be specified more than\n"
     23 "				  once for multiple ranges.\n"
     24 " --nodst\n"
     25 "				Don't use destination-ip in\n"
     26 "				           source selection\n"
     27 " --random\n"
     28 "				Randomize source port\n");
     29 }
     30 
     31 static const struct xt_option_entry SAME_opts[] = {
     32 	{.name = "to", .id = O_TO_ADDR, .type = XTTYPE_STRING,
     33 	 .flags = XTOPT_MAND},
     34 	{.name = "nodst", .id = O_NODST, .type = XTTYPE_NONE},
     35 	{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
     36 	XTOPT_TABLEEND,
     37 };
     38 
     39 /* Parses range of IPs */
     40 static void parse_to(const char *orig_arg, struct nf_nat_ipv4_range *range)
     41 {
     42 	char *dash, *arg;
     43 	const struct in_addr *ip;
     44 
     45 	arg = strdup(orig_arg);
     46 	if (arg == NULL)
     47 		xtables_error(RESOURCE_PROBLEM, "strdup");
     48 	range->flags |= NF_NAT_RANGE_MAP_IPS;
     49 	dash = strchr(arg, '-');
     50 
     51 	if (dash)
     52 		*dash = '\0';
     53 
     54 	ip = xtables_numeric_to_ipaddr(arg);
     55 	if (!ip)
     56 		xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
     57 			   arg);
     58 	range->min_ip = ip->s_addr;
     59 
     60 	if (dash) {
     61 		ip = xtables_numeric_to_ipaddr(dash+1);
     62 		if (!ip)
     63 			xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
     64 				   dash+1);
     65 	}
     66 	range->max_ip = ip->s_addr;
     67 	if (dash)
     68 		if (range->min_ip > range->max_ip)
     69 			xtables_error(PARAMETER_PROBLEM, "Bad IP range \"%s-%s\"\n",
     70 				   arg, dash+1);
     71 	free(arg);
     72 }
     73 
     74 static void SAME_parse(struct xt_option_call *cb)
     75 {
     76 	struct ipt_same_info *mr = cb->data;
     77 	unsigned int count;
     78 
     79 	xtables_option_parse(cb);
     80 	switch (cb->entry->id) {
     81 	case O_TO_ADDR:
     82 		if (mr->rangesize == IPT_SAME_MAX_RANGE)
     83 			xtables_error(PARAMETER_PROBLEM,
     84 				   "Too many ranges specified, maximum "
     85 				   "is %i ranges.\n",
     86 				   IPT_SAME_MAX_RANGE);
     87 		parse_to(cb->arg, &mr->range[mr->rangesize]);
     88 		mr->rangesize++;
     89 		break;
     90 	case O_NODST:
     91 		mr->info |= IPT_SAME_NODST;
     92 		break;
     93 	case O_RANDOM:
     94 		for (count=0; count < mr->rangesize; count++)
     95 			mr->range[count].flags |= NF_NAT_RANGE_PROTO_RANDOM;
     96 		break;
     97 	}
     98 }
     99 
    100 static void SAME_fcheck(struct xt_fcheck_call *cb)
    101 {
    102 	static const unsigned int f = F_TO_ADDR | F_RANDOM;
    103 	struct ipt_same_info *mr = cb->data;
    104 	unsigned int count;
    105 
    106 	if ((cb->xflags & f) == f)
    107 		for (count = 0; count < mr->rangesize; ++count)
    108 			mr->range[count].flags |= NF_NAT_RANGE_PROTO_RANDOM;
    109 }
    110 
    111 static void SAME_print(const void *ip, const struct xt_entry_target *target,
    112                        int numeric)
    113 {
    114 	unsigned int count;
    115 	const struct ipt_same_info *mr = (const void *)target->data;
    116 	int random_selection = 0;
    117 
    118 	printf(" same:");
    119 
    120 	for (count = 0; count < mr->rangesize; count++) {
    121 		const struct nf_nat_ipv4_range *r = &mr->range[count];
    122 		struct in_addr a;
    123 
    124 		a.s_addr = r->min_ip;
    125 
    126 		printf("%s", xtables_ipaddr_to_numeric(&a));
    127 		a.s_addr = r->max_ip;
    128 
    129 		if (r->min_ip != r->max_ip)
    130 			printf("-%s", xtables_ipaddr_to_numeric(&a));
    131 		if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
    132 			random_selection = 1;
    133 	}
    134 
    135 	if (mr->info & IPT_SAME_NODST)
    136 		printf(" nodst");
    137 
    138 	if (random_selection)
    139 		printf(" random");
    140 }
    141 
    142 static void SAME_save(const void *ip, const struct xt_entry_target *target)
    143 {
    144 	unsigned int count;
    145 	const struct ipt_same_info *mr = (const void *)target->data;
    146 	int random_selection = 0;
    147 
    148 	for (count = 0; count < mr->rangesize; count++) {
    149 		const struct nf_nat_ipv4_range *r = &mr->range[count];
    150 		struct in_addr a;
    151 
    152 		a.s_addr = r->min_ip;
    153 		printf(" --to %s", xtables_ipaddr_to_numeric(&a));
    154 		a.s_addr = r->max_ip;
    155 
    156 		if (r->min_ip != r->max_ip)
    157 			printf("-%s", xtables_ipaddr_to_numeric(&a));
    158 		if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
    159 			random_selection = 1;
    160 	}
    161 
    162 	if (mr->info & IPT_SAME_NODST)
    163 		printf(" --nodst");
    164 
    165 	if (random_selection)
    166 		printf(" --random");
    167 }
    168 
    169 static struct xtables_target same_tg_reg = {
    170 	.name		= "SAME",
    171 	.version	= XTABLES_VERSION,
    172 	.family		= NFPROTO_IPV4,
    173 	.size		= XT_ALIGN(sizeof(struct ipt_same_info)),
    174 	.userspacesize	= XT_ALIGN(sizeof(struct ipt_same_info)),
    175 	.help		= SAME_help,
    176 	.x6_parse	= SAME_parse,
    177 	.x6_fcheck	= SAME_fcheck,
    178 	.print		= SAME_print,
    179 	.save		= SAME_save,
    180 	.x6_options	= SAME_opts,
    181 };
    182 
    183 void _init(void)
    184 {
    185 	xtables_register_target(&same_tg_reg);
    186 }
    187