libipt_SAME.c revision 69f564e3890976461de0016cd81171ff8bfa8353
1/* Shared library add-on to iptables to add simple non load-balancing SNAT support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7#include <xtables.h>
8#include <net/netfilter/nf_nat.h>
9/* For 64bit kernel / 32bit userspace */
10#include <linux/netfilter_ipv4/ipt_SAME.h>
11
12static void SAME_help(void)
13{
14	printf(
15"SAME target options:\n"
16" --to <ipaddr>-<ipaddr>\n"
17"				Addresses to map source to.\n"
18"				 May be specified more than\n"
19"				  once for multiple ranges.\n"
20" --nodst\n"
21"				Don't use destination-ip in\n"
22"				           source selection\n"
23" --random\n"
24"				Randomize source port\n");
25}
26
27static const struct option SAME_opts[] = {
28	{ "to", 1, NULL, '1' },
29	{ "nodst", 0, NULL, '2'},
30	{ "random", 0, NULL, '3' },
31	{ .name = NULL }
32};
33
34static void SAME_init(struct xt_entry_target *t)
35{
36	struct ipt_same_info *mr = (struct ipt_same_info *)t->data;
37
38	/* Set default to 0 */
39	mr->rangesize = 0;
40	mr->info = 0;
41	mr->ipnum = 0;
42
43}
44
45/* Parses range of IPs */
46static void
47parse_to(char *arg, struct nf_nat_range *range)
48{
49	char *dash;
50	const struct in_addr *ip;
51
52	range->flags |= IP_NAT_RANGE_MAP_IPS;
53	dash = strchr(arg, '-');
54
55	if (dash)
56		*dash = '\0';
57
58	ip = xtables_numeric_to_ipaddr(arg);
59	if (!ip)
60		xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
61			   arg);
62	range->min_ip = ip->s_addr;
63
64	if (dash) {
65		ip = xtables_numeric_to_ipaddr(dash+1);
66		if (!ip)
67			xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
68				   dash+1);
69	}
70	range->max_ip = ip->s_addr;
71	if (dash)
72		if (range->min_ip > range->max_ip)
73			xtables_error(PARAMETER_PROBLEM, "Bad IP range \"%s-%s\"\n",
74				   arg, dash+1);
75}
76
77#define IPT_SAME_OPT_TO			0x01
78#define IPT_SAME_OPT_NODST		0x02
79#define IPT_SAME_OPT_RANDOM		0x04
80
81static int SAME_parse(int c, char **argv, int invert, unsigned int *flags,
82                      const void *entry, struct xt_entry_target **target)
83{
84	struct ipt_same_info *mr
85		= (struct ipt_same_info *)(*target)->data;
86	unsigned int count;
87
88	switch (c) {
89	case '1':
90		if (mr->rangesize == IPT_SAME_MAX_RANGE)
91			xtables_error(PARAMETER_PROBLEM,
92				   "Too many ranges specified, maximum "
93				   "is %i ranges.\n",
94				   IPT_SAME_MAX_RANGE);
95		if (xtables_check_inverse(optarg, &invert, NULL, 0))
96			xtables_error(PARAMETER_PROBLEM,
97				   "Unexpected `!' after --to");
98
99		parse_to(optarg, &mr->range[mr->rangesize]);
100		/* WTF do we need this for? */
101		if (*flags & IPT_SAME_OPT_RANDOM)
102			mr->range[mr->rangesize].flags
103				|= IP_NAT_RANGE_PROTO_RANDOM;
104		mr->rangesize++;
105		*flags |= IPT_SAME_OPT_TO;
106		break;
107
108	case '2':
109		if (*flags & IPT_SAME_OPT_NODST)
110			xtables_error(PARAMETER_PROBLEM,
111				   "Can't specify --nodst twice");
112
113		mr->info |= IPT_SAME_NODST;
114		*flags |= IPT_SAME_OPT_NODST;
115		break;
116
117	case '3':
118		*flags |= IPT_SAME_OPT_RANDOM;
119		for (count=0; count < mr->rangesize; count++)
120			mr->range[count].flags |= IP_NAT_RANGE_PROTO_RANDOM;
121		break;
122
123	default:
124		return 0;
125	}
126
127	return 1;
128}
129
130static void SAME_check(unsigned int flags)
131{
132	if (!(flags & IPT_SAME_OPT_TO))
133		xtables_error(PARAMETER_PROBLEM,
134			   "SAME needs --to");
135}
136
137static void SAME_print(const void *ip, const struct xt_entry_target *target,
138                       int numeric)
139{
140	unsigned int count;
141	const struct ipt_same_info *mr = (const void *)target->data;
142	int random_selection = 0;
143
144	printf("same:");
145
146	for (count = 0; count < mr->rangesize; count++) {
147		const struct nf_nat_range *r = &mr->range[count];
148		struct in_addr a;
149
150		a.s_addr = r->min_ip;
151
152		printf("%s", xtables_ipaddr_to_numeric(&a));
153		a.s_addr = r->max_ip;
154
155		if (r->min_ip == r->max_ip)
156			printf(" ");
157		else
158			printf("-%s ", xtables_ipaddr_to_numeric(&a));
159		if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
160			random_selection = 1;
161	}
162
163	if (mr->info & IPT_SAME_NODST)
164		printf("nodst ");
165
166	if (random_selection)
167		printf("random ");
168}
169
170static void SAME_save(const void *ip, const struct xt_entry_target *target)
171{
172	unsigned int count;
173	const struct ipt_same_info *mr = (const void *)target->data;
174	int random_selection = 0;
175
176	for (count = 0; count < mr->rangesize; count++) {
177		const struct nf_nat_range *r = &mr->range[count];
178		struct in_addr a;
179
180		a.s_addr = r->min_ip;
181		printf("--to %s", xtables_ipaddr_to_numeric(&a));
182		a.s_addr = r->max_ip;
183
184		if (r->min_ip == r->max_ip)
185			printf(" ");
186		else
187			printf("-%s ", xtables_ipaddr_to_numeric(&a));
188		if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
189			random_selection = 1;
190	}
191
192	if (mr->info & IPT_SAME_NODST)
193		printf("--nodst ");
194
195	if (random_selection)
196		printf("--random ");
197}
198
199static struct xtables_target same_tg_reg = {
200	.name		= "SAME",
201	.version	= XTABLES_VERSION,
202	.family		= NFPROTO_IPV4,
203	.size		= XT_ALIGN(sizeof(struct ipt_same_info)),
204	.userspacesize	= XT_ALIGN(sizeof(struct ipt_same_info)),
205	.help		= SAME_help,
206	.init		= SAME_init,
207	.parse		= SAME_parse,
208	.final_check	= SAME_check,
209	.print		= SAME_print,
210	.save		= SAME_save,
211	.extra_opts	= SAME_opts,
212};
213
214void _init(void)
215{
216	xtables_register_target(&same_tg_reg);
217}
218