blob: 625a78a74f06b15775baf285b43c181f2129a739 [file] [log] [blame]
Harald Welte18f1aff2001-03-25 19:03:23 +00001/* Shared library add-on to iptables to add simple non load-balancing SNAT support. */
Martin Josefssonf419f752001-02-19 21:55:27 +00002#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_ipv4/ip_nat_rule.h>
Martin Josefsson1eb00812004-05-26 15:58:07 +000010/* For 64bit kernel / 32bit userspace */
11#include "../include/linux/netfilter_ipv4/ipt_SAME.h"
Martin Josefssonf419f752001-02-19 21:55:27 +000012
Martin Josefssonf419f752001-02-19 21:55:27 +000013/* Function which prints out usage message. */
14static void
15help(void)
16{
17 printf(
18"SAME v%s options:\n"
Harald Welte18f1aff2001-03-25 19:03:23 +000019" --to <ipaddr>-<ipaddr>\n"
Harald Weltecf655eb2001-07-28 18:47:11 +000020" Addresses to map source to.\n"
Harald Welte05e0b012001-08-26 08:18:25 +000021" May be specified more than\n"
22" once for multiple ranges.\n"
Harald Weltecf655eb2001-07-28 18:47:11 +000023" --nodst\n"
24" Don't use destination-ip in\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000025" source selection\n"
26
27#ifdef IP_NAT_RANGE_PROTO_RANDOM
28" --random\n"
29" Randomize source port\n"
30#endif
31,
Harald Welte80fe35d2002-05-29 13:08:15 +000032IPTABLES_VERSION);
Martin Josefssonf419f752001-02-19 21:55:27 +000033}
34
35static struct option opts[] = {
Harald Welte18f1aff2001-03-25 19:03:23 +000036 { "to", 1, 0, '1' },
Harald Weltecf655eb2001-07-28 18:47:11 +000037 { "nodst", 0, 0, '2'},
Eric Leblondae4b0b32007-02-24 15:11:33 +000038#ifdef IP_NAT_RANGE_PROTO_RANDOM
39 { "random", 0, 0, '3' },
40#endif
Martin Josefssonf419f752001-02-19 21:55:27 +000041 { 0 }
42};
43
44/* Initialize the target. */
45static void
46init(struct ipt_entry_target *t, unsigned int *nfcache)
47{
Harald Weltecf655eb2001-07-28 18:47:11 +000048 struct ipt_same_info *mr = (struct ipt_same_info *)t->data;
Martin Josefssonf419f752001-02-19 21:55:27 +000049
Harald Welte05e0b012001-08-26 08:18:25 +000050 /* Set default to 0 */
51 mr->rangesize = 0;
Harald Weltecf655eb2001-07-28 18:47:11 +000052 mr->info = 0;
Harald Welte05e0b012001-08-26 08:18:25 +000053 mr->ipnum = 0;
Harald Weltecf655eb2001-07-28 18:47:11 +000054
Martin Josefssonf419f752001-02-19 21:55:27 +000055}
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, '-');
Harald Welte05e0b012001-08-26 08:18:25 +000066
Martin Josefssonf419f752001-02-19 21:55:27 +000067 if (dash)
68 *dash = '\0';
Martin Josefssonf419f752001-02-19 21:55:27 +000069
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;
Harald Welte05e0b012001-08-26 08:18:25 +000075
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 }
Martin Josefssonf419f752001-02-19 21:55:27 +000082 range->max_ip = ip->s_addr;
Harald Welte05e0b012001-08-26 08:18:25 +000083 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);
Martin Josefssonf419f752001-02-19 21:55:27 +000087}
88
Harald Weltecf655eb2001-07-28 18:47:11 +000089#define IPT_SAME_OPT_TO 0x01
90#define IPT_SAME_OPT_NODST 0x02
Eric Leblondae4b0b32007-02-24 15:11:33 +000091#ifdef IP_NAT_RANGE_PROTO_RANDOM
92# define IPT_SAME_OPT_RANDOM 0x04
93#endif
Harald Weltecf655eb2001-07-28 18:47:11 +000094
Martin Josefssonf419f752001-02-19 21:55:27 +000095/* 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{
Harald Weltecf655eb2001-07-28 18:47:11 +0000102 struct ipt_same_info *mr
103 = (struct ipt_same_info *)(*target)->data;
Eric Leblondae4b0b32007-02-24 15:11:33 +0000104#ifdef IP_NAT_RANGE_PROTO_RANDOM
105 int count;
106#endif
Martin Josefssonf419f752001-02-19 21:55:27 +0000107
108 switch (c) {
109 case '1':
Harald Welte05e0b012001-08-26 08:18:25 +0000110 if (mr->rangesize == IPT_SAME_MAX_RANGE)
Harald Weltecf655eb2001-07-28 18:47:11 +0000111 exit_error(PARAMETER_PROBLEM,
Harald Welte05e0b012001-08-26 08:18:25 +0000112 "Too many ranges specified, maximum "
113 "is %i ranges.\n",
114 IPT_SAME_MAX_RANGE);
Harald Welteb77f1da2002-03-14 11:35:58 +0000115 if (check_inverse(optarg, &invert, NULL, 0))
Martin Josefssonf419f752001-02-19 21:55:27 +0000116 exit_error(PARAMETER_PROBLEM,
Harald Welte18f1aff2001-03-25 19:03:23 +0000117 "Unexpected `!' after --to");
Martin Josefssonf419f752001-02-19 21:55:27 +0000118
Harald Welte05e0b012001-08-26 08:18:25 +0000119 parse_to(optarg, &mr->range[mr->rangesize]);
Eric Leblondae4b0b32007-02-24 15:11:33 +0000120#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
Harald Welte05e0b012001-08-26 08:18:25 +0000125 mr->rangesize++;
Harald Weltecf655eb2001-07-28 18:47:11 +0000126 *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;
Eric Leblondae4b0b32007-02-24 15:11:33 +0000137
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
Martin Josefssonf419f752001-02-19 21:55:27 +0000145 default:
146 return 0;
147 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000148
149 return 1;
Martin Josefssonf419f752001-02-19 21:55:27 +0000150}
151
Harald Welte18f1aff2001-03-25 19:03:23 +0000152/* Final check; need --to. */
Martin Josefssonf419f752001-02-19 21:55:27 +0000153static void final_check(unsigned int flags)
154{
Harald Weltecf655eb2001-07-28 18:47:11 +0000155 if (!(flags & IPT_SAME_OPT_TO))
Martin Josefssonf419f752001-02-19 21:55:27 +0000156 exit_error(PARAMETER_PROBLEM,
Harald Welte18f1aff2001-03-25 19:03:23 +0000157 "SAME needs --to");
Martin Josefssonf419f752001-02-19 21:55:27 +0000158}
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{
Harald Welte05e0b012001-08-26 08:18:25 +0000166 int count;
Harald Weltecf655eb2001-07-28 18:47:11 +0000167 struct ipt_same_info *mr
168 = (struct ipt_same_info *)target->data;
Eric Leblondae4b0b32007-02-24 15:11:33 +0000169#ifdef IP_NAT_RANGE_PROTO_RANDOM
170 int random = 0;
171#endif
Harald Welte05e0b012001-08-26 08:18:25 +0000172
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;
Martin Josefssonf419f752001-02-19 21:55:27 +0000178
Harald Welte05e0b012001-08-26 08:18:25 +0000179 a.s_addr = r->min_ip;
Martin Josefssonf419f752001-02-19 21:55:27 +0000180
Harald Welte05e0b012001-08-26 08:18:25 +0000181 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));
Eric Leblondae4b0b32007-02-24 15:11:33 +0000188#ifdef IP_NAT_RANGE_PROTO_RANDOM
189 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
190 random = 1;
191#endif
Harald Welte05e0b012001-08-26 08:18:25 +0000192 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000193
194 if (mr->info & IPT_SAME_NODST)
195 printf("nodst ");
Eric Leblondae4b0b32007-02-24 15:11:33 +0000196
197#ifdef IP_NAT_RANGE_PROTO_RANDOM
198 if (random)
199 printf("random ");
200#endif
Martin Josefssonf419f752001-02-19 21:55:27 +0000201}
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{
Harald Welte05e0b012001-08-26 08:18:25 +0000207 int count;
Harald Weltecf655eb2001-07-28 18:47:11 +0000208 struct ipt_same_info *mr
209 = (struct ipt_same_info *)target->data;
Martin Josefssonf419f752001-02-19 21:55:27 +0000210
Harald Welte05e0b012001-08-26 08:18:25 +0000211 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 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000224
225 if (mr->info & IPT_SAME_NODST)
226 printf("--nodst ");
Martin Josefssonf419f752001-02-19 21:55:27 +0000227}
228
Pablo Neira8caee8b2004-12-28 13:11:59 +0000229static 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
Martin Josefssonf419f752001-02-19 21:55:27 +0000242};
243
244void _init(void)
245{
246 register_target(&same);
247}