libipt_SAME.c revision 40d54756cd8a2705e22b36f7aef03bb2c472a10b
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 <iptables.h>
8#include <linux/netfilter_ipv4/ip_tables.h>
9#include <linux/netfilter/nf_nat.h>
10/* For 64bit kernel / 32bit userspace */
11#include "../include/linux/netfilter_ipv4/ipt_SAME.h"
12
13/* Function which prints out usage message. */
14static void
15help(void)
16{
17	printf(
18"SAME v%s options:\n"
19" --to <ipaddr>-<ipaddr>\n"
20"				Addresses to map source to.\n"
21"				 May be specified more than\n"
22"				  once for multiple ranges.\n"
23" --nodst\n"
24"				Don't use destination-ip in\n"
25"				           source selection\n"
26
27#ifdef IP_NAT_RANGE_PROTO_RANDOM
28" --random\n"
29"				Randomize source port\n"
30#endif
31,
32IPTABLES_VERSION);
33}
34
35static struct option opts[] = {
36	{ "to", 1, 0, '1' },
37	{ "nodst", 0, 0, '2'},
38#ifdef IP_NAT_RANGE_PROTO_RANDOM
39	{ "random", 0, 0, '3' },
40#endif
41	{ 0 }
42};
43
44/* Initialize the target. */
45static void
46init(struct ipt_entry_target *t, unsigned int *nfcache)
47{
48	struct ipt_same_info *mr = (struct ipt_same_info *)t->data;
49
50	/* Set default to 0 */
51	mr->rangesize = 0;
52	mr->info = 0;
53	mr->ipnum = 0;
54
55}
56
57/* Parses range of IPs */
58static void
59parse_to(char *arg, struct ip_nat_range *range)
60{
61	char *dash;
62	struct in_addr *ip;
63
64	range->flags |= IP_NAT_RANGE_MAP_IPS;
65	dash = strchr(arg, '-');
66
67	if (dash)
68		*dash = '\0';
69
70	ip = dotted_to_addr(arg);
71	if (!ip)
72		exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
73			   arg);
74	range->min_ip = ip->s_addr;
75
76	if (dash) {
77		ip = dotted_to_addr(dash+1);
78		if (!ip)
79			exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
80				   dash+1);
81	}
82	range->max_ip = ip->s_addr;
83	if (dash)
84		if (range->min_ip > range->max_ip)
85			exit_error(PARAMETER_PROBLEM, "Bad IP range `%s-%s'\n",
86				   arg, dash+1);
87}
88
89#define IPT_SAME_OPT_TO			0x01
90#define IPT_SAME_OPT_NODST		0x02
91#ifdef IP_NAT_RANGE_PROTO_RANDOM
92#	define IPT_SAME_OPT_RANDOM		0x04
93#endif
94
95/* Function which parses command options; returns true if it
96   ate an option */
97static int
98parse(int c, char **argv, int invert, unsigned int *flags,
99      const struct ipt_entry *entry,
100      struct ipt_entry_target **target)
101{
102	struct ipt_same_info *mr
103		= (struct ipt_same_info *)(*target)->data;
104#ifdef IP_NAT_RANGE_PROTO_RANDOM
105	int count;
106#endif
107
108	switch (c) {
109	case '1':
110		if (mr->rangesize == IPT_SAME_MAX_RANGE)
111			exit_error(PARAMETER_PROBLEM,
112				   "Too many ranges specified, maximum "
113				   "is %i ranges.\n",
114				   IPT_SAME_MAX_RANGE);
115		if (check_inverse(optarg, &invert, NULL, 0))
116			exit_error(PARAMETER_PROBLEM,
117				   "Unexpected `!' after --to");
118
119		parse_to(optarg, &mr->range[mr->rangesize]);
120#ifdef IP_NAT_RANGE_PROTO_RANDOM
121		if (*flags & IPT_SAME_OPT_RANDOM)
122			mr->range[mr->rangesize].flags
123				|= IP_NAT_RANGE_PROTO_RANDOM;
124#endif
125		mr->rangesize++;
126		*flags |= IPT_SAME_OPT_TO;
127		break;
128
129	case '2':
130		if (*flags & IPT_SAME_OPT_NODST)
131			exit_error(PARAMETER_PROBLEM,
132				   "Can't specify --nodst twice");
133
134		mr->info |= IPT_SAME_NODST;
135		*flags |= IPT_SAME_OPT_NODST;
136		break;
137
138#ifdef IP_NAT_RANGE_PROTO_RANDOM
139	case '3':
140		*flags |= IPT_SAME_OPT_RANDOM;
141		for (count=0; count < mr->rangesize; count++)
142			mr->range[count].flags |= IP_NAT_RANGE_PROTO_RANDOM;
143		break;
144#endif
145	default:
146		return 0;
147	}
148
149	return 1;
150}
151
152/* Final check; need --to. */
153static void final_check(unsigned int flags)
154{
155	if (!(flags & IPT_SAME_OPT_TO))
156		exit_error(PARAMETER_PROBLEM,
157			   "SAME needs --to");
158}
159
160/* Prints out the targinfo. */
161static void
162print(const struct ipt_ip *ip,
163      const struct ipt_entry_target *target,
164      int numeric)
165{
166	int count;
167	struct ipt_same_info *mr
168		= (struct ipt_same_info *)target->data;
169#ifdef IP_NAT_RANGE_PROTO_RANDOM
170	int random = 0;
171#endif
172
173	printf("same:");
174
175	for (count = 0; count < mr->rangesize; count++) {
176		struct ip_nat_range *r = &mr->range[count];
177		struct in_addr a;
178
179		a.s_addr = r->min_ip;
180
181		printf("%s", addr_to_dotted(&a));
182		a.s_addr = r->max_ip;
183
184		if (r->min_ip == r->max_ip)
185			printf(" ");
186		else
187			printf("-%s ", addr_to_dotted(&a));
188#ifdef IP_NAT_RANGE_PROTO_RANDOM
189		if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
190			random = 1;
191#endif
192	}
193
194	if (mr->info & IPT_SAME_NODST)
195		printf("nodst ");
196
197#ifdef IP_NAT_RANGE_PROTO_RANDOM
198	if (random)
199		printf("random ");
200#endif
201}
202
203/* Saves the union ipt_targinfo in parsable form to stdout. */
204static void
205save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
206{
207	int count;
208	struct ipt_same_info *mr
209		= (struct ipt_same_info *)target->data;
210
211	for (count = 0; count < mr->rangesize; count++) {
212		struct ip_nat_range *r = &mr->range[count];
213		struct in_addr a;
214
215		a.s_addr = r->min_ip;
216		printf("--to %s", addr_to_dotted(&a));
217		a.s_addr = r->max_ip;
218
219		if (r->min_ip == r->max_ip)
220			printf(" ");
221		else
222			printf("-%s ", addr_to_dotted(&a));
223	}
224
225	if (mr->info & IPT_SAME_NODST)
226		printf("--nodst ");
227}
228
229static struct iptables_target same = {
230	.next		= NULL,
231	.name		= "SAME",
232	.version	= IPTABLES_VERSION,
233	.size		= IPT_ALIGN(sizeof(struct ipt_same_info)),
234	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_same_info)),
235	.help		= &help,
236	.init		= &init,
237	.parse		= &parse,
238	.final_check	= &final_check,
239	.print		= &print,
240	.save		= &save,
241	.extra_opts	= opts
242};
243
244void _init(void)
245{
246	register_target(&same);
247}
248