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
8enum {
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
16static 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
31static 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 */
40static 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
74static 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
100static 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
111static 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
142static 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
169static 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
183void _init(void)
184{
185	xtables_register_target(&same_tg_reg);
186}
187