blob: 7211f608a2bc1f4b96a5313aa8b69f35b46bf2e2 [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>
Patrick McHardy40d54752007-04-18 07:00:36 +00009#include <linux/netfilter/nf_nat.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"
Eric Leblondae4b0b32007-02-24 15:11:33 +000026" --random\n"
27" Randomize source port\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000028,
Harald Welte80fe35d2002-05-29 13:08:15 +000029IPTABLES_VERSION);
Martin Josefssonf419f752001-02-19 21:55:27 +000030}
31
32static struct option opts[] = {
Harald Welte18f1aff2001-03-25 19:03:23 +000033 { "to", 1, 0, '1' },
Harald Weltecf655eb2001-07-28 18:47:11 +000034 { "nodst", 0, 0, '2'},
Eric Leblondae4b0b32007-02-24 15:11:33 +000035 { "random", 0, 0, '3' },
Martin Josefssonf419f752001-02-19 21:55:27 +000036 { 0 }
37};
38
39/* Initialize the target. */
40static void
41init(struct ipt_entry_target *t, unsigned int *nfcache)
42{
Harald Weltecf655eb2001-07-28 18:47:11 +000043 struct ipt_same_info *mr = (struct ipt_same_info *)t->data;
Martin Josefssonf419f752001-02-19 21:55:27 +000044
Harald Welte05e0b012001-08-26 08:18:25 +000045 /* Set default to 0 */
46 mr->rangesize = 0;
Harald Weltecf655eb2001-07-28 18:47:11 +000047 mr->info = 0;
Harald Welte05e0b012001-08-26 08:18:25 +000048 mr->ipnum = 0;
Harald Weltecf655eb2001-07-28 18:47:11 +000049
Martin Josefssonf419f752001-02-19 21:55:27 +000050}
51
52/* Parses range of IPs */
53static void
54parse_to(char *arg, struct ip_nat_range *range)
55{
56 char *dash;
57 struct in_addr *ip;
58
59 range->flags |= IP_NAT_RANGE_MAP_IPS;
60 dash = strchr(arg, '-');
Harald Welte05e0b012001-08-26 08:18:25 +000061
Martin Josefssonf419f752001-02-19 21:55:27 +000062 if (dash)
63 *dash = '\0';
Martin Josefssonf419f752001-02-19 21:55:27 +000064
65 ip = dotted_to_addr(arg);
66 if (!ip)
67 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
68 arg);
69 range->min_ip = ip->s_addr;
Harald Welte05e0b012001-08-26 08:18:25 +000070
71 if (dash) {
72 ip = dotted_to_addr(dash+1);
73 if (!ip)
74 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
75 dash+1);
76 }
Martin Josefssonf419f752001-02-19 21:55:27 +000077 range->max_ip = ip->s_addr;
Harald Welte05e0b012001-08-26 08:18:25 +000078 if (dash)
79 if (range->min_ip > range->max_ip)
80 exit_error(PARAMETER_PROBLEM, "Bad IP range `%s-%s'\n",
81 arg, dash+1);
Martin Josefssonf419f752001-02-19 21:55:27 +000082}
83
Harald Weltecf655eb2001-07-28 18:47:11 +000084#define IPT_SAME_OPT_TO 0x01
85#define IPT_SAME_OPT_NODST 0x02
Patrick McHardye656e262007-04-18 12:56:05 +000086#define IPT_SAME_OPT_RANDOM 0x04
Harald Weltecf655eb2001-07-28 18:47:11 +000087
Martin Josefssonf419f752001-02-19 21:55:27 +000088/* Function which parses command options; returns true if it
89 ate an option */
90static int
91parse(int c, char **argv, int invert, unsigned int *flags,
92 const struct ipt_entry *entry,
93 struct ipt_entry_target **target)
94{
Harald Weltecf655eb2001-07-28 18:47:11 +000095 struct ipt_same_info *mr
96 = (struct ipt_same_info *)(*target)->data;
Eric Leblondae4b0b32007-02-24 15:11:33 +000097 int count;
Martin Josefssonf419f752001-02-19 21:55:27 +000098
99 switch (c) {
100 case '1':
Harald Welte05e0b012001-08-26 08:18:25 +0000101 if (mr->rangesize == IPT_SAME_MAX_RANGE)
Harald Weltecf655eb2001-07-28 18:47:11 +0000102 exit_error(PARAMETER_PROBLEM,
Harald Welte05e0b012001-08-26 08:18:25 +0000103 "Too many ranges specified, maximum "
104 "is %i ranges.\n",
105 IPT_SAME_MAX_RANGE);
Harald Welteb77f1da2002-03-14 11:35:58 +0000106 if (check_inverse(optarg, &invert, NULL, 0))
Martin Josefssonf419f752001-02-19 21:55:27 +0000107 exit_error(PARAMETER_PROBLEM,
Harald Welte18f1aff2001-03-25 19:03:23 +0000108 "Unexpected `!' after --to");
Martin Josefssonf419f752001-02-19 21:55:27 +0000109
Harald Welte05e0b012001-08-26 08:18:25 +0000110 parse_to(optarg, &mr->range[mr->rangesize]);
Patrick McHardye656e262007-04-18 12:56:05 +0000111 /* WTF do we need this for? */
Eric Leblondae4b0b32007-02-24 15:11:33 +0000112 if (*flags & IPT_SAME_OPT_RANDOM)
113 mr->range[mr->rangesize].flags
114 |= IP_NAT_RANGE_PROTO_RANDOM;
Harald Welte05e0b012001-08-26 08:18:25 +0000115 mr->rangesize++;
Harald Weltecf655eb2001-07-28 18:47:11 +0000116 *flags |= IPT_SAME_OPT_TO;
117 break;
118
119 case '2':
120 if (*flags & IPT_SAME_OPT_NODST)
121 exit_error(PARAMETER_PROBLEM,
122 "Can't specify --nodst twice");
123
124 mr->info |= IPT_SAME_NODST;
125 *flags |= IPT_SAME_OPT_NODST;
126 break;
Eric Leblondae4b0b32007-02-24 15:11:33 +0000127
Eric Leblondae4b0b32007-02-24 15:11:33 +0000128 case '3':
129 *flags |= IPT_SAME_OPT_RANDOM;
130 for (count=0; count < mr->rangesize; count++)
131 mr->range[count].flags |= IP_NAT_RANGE_PROTO_RANDOM;
132 break;
Patrick McHardye656e262007-04-18 12:56:05 +0000133
Martin Josefssonf419f752001-02-19 21:55:27 +0000134 default:
135 return 0;
136 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000137
138 return 1;
Martin Josefssonf419f752001-02-19 21:55:27 +0000139}
140
Harald Welte18f1aff2001-03-25 19:03:23 +0000141/* Final check; need --to. */
Martin Josefssonf419f752001-02-19 21:55:27 +0000142static void final_check(unsigned int flags)
143{
Harald Weltecf655eb2001-07-28 18:47:11 +0000144 if (!(flags & IPT_SAME_OPT_TO))
Martin Josefssonf419f752001-02-19 21:55:27 +0000145 exit_error(PARAMETER_PROBLEM,
Harald Welte18f1aff2001-03-25 19:03:23 +0000146 "SAME needs --to");
Martin Josefssonf419f752001-02-19 21:55:27 +0000147}
148
149/* Prints out the targinfo. */
150static void
151print(const struct ipt_ip *ip,
152 const struct ipt_entry_target *target,
153 int numeric)
154{
Harald Welte05e0b012001-08-26 08:18:25 +0000155 int count;
Harald Weltecf655eb2001-07-28 18:47:11 +0000156 struct ipt_same_info *mr
157 = (struct ipt_same_info *)target->data;
Eric Leblondae4b0b32007-02-24 15:11:33 +0000158 int random = 0;
Harald Welte05e0b012001-08-26 08:18:25 +0000159
160 printf("same:");
161
162 for (count = 0; count < mr->rangesize; count++) {
163 struct ip_nat_range *r = &mr->range[count];
164 struct in_addr a;
Martin Josefssonf419f752001-02-19 21:55:27 +0000165
Harald Welte05e0b012001-08-26 08:18:25 +0000166 a.s_addr = r->min_ip;
Martin Josefssonf419f752001-02-19 21:55:27 +0000167
Harald Welte05e0b012001-08-26 08:18:25 +0000168 printf("%s", addr_to_dotted(&a));
169 a.s_addr = r->max_ip;
170
171 if (r->min_ip == r->max_ip)
172 printf(" ");
173 else
174 printf("-%s ", addr_to_dotted(&a));
Eric Leblondae4b0b32007-02-24 15:11:33 +0000175 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
176 random = 1;
Harald Welte05e0b012001-08-26 08:18:25 +0000177 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000178
179 if (mr->info & IPT_SAME_NODST)
180 printf("nodst ");
Eric Leblondae4b0b32007-02-24 15:11:33 +0000181
Eric Leblondae4b0b32007-02-24 15:11:33 +0000182 if (random)
183 printf("random ");
Martin Josefssonf419f752001-02-19 21:55:27 +0000184}
185
186/* Saves the union ipt_targinfo in parsable form to stdout. */
187static void
188save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
189{
Harald Welte05e0b012001-08-26 08:18:25 +0000190 int count;
Harald Weltecf655eb2001-07-28 18:47:11 +0000191 struct ipt_same_info *mr
192 = (struct ipt_same_info *)target->data;
Patrick McHardy9c67def2007-04-18 14:00:11 +0000193 int random = 0;
Martin Josefssonf419f752001-02-19 21:55:27 +0000194
Harald Welte05e0b012001-08-26 08:18:25 +0000195 for (count = 0; count < mr->rangesize; count++) {
196 struct ip_nat_range *r = &mr->range[count];
197 struct in_addr a;
198
199 a.s_addr = r->min_ip;
200 printf("--to %s", addr_to_dotted(&a));
201 a.s_addr = r->max_ip;
202
203 if (r->min_ip == r->max_ip)
204 printf(" ");
205 else
206 printf("-%s ", addr_to_dotted(&a));
Patrick McHardy9c67def2007-04-18 14:00:11 +0000207 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
208 random = 1;
Harald Welte05e0b012001-08-26 08:18:25 +0000209 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000210
211 if (mr->info & IPT_SAME_NODST)
212 printf("--nodst ");
Patrick McHardy9c67def2007-04-18 14:00:11 +0000213
214 if (random)
215 printf("--random ");
Martin Josefssonf419f752001-02-19 21:55:27 +0000216}
217
Pablo Neira8caee8b2004-12-28 13:11:59 +0000218static struct iptables_target same = {
219 .next = NULL,
220 .name = "SAME",
221 .version = IPTABLES_VERSION,
222 .size = IPT_ALIGN(sizeof(struct ipt_same_info)),
223 .userspacesize = IPT_ALIGN(sizeof(struct ipt_same_info)),
224 .help = &help,
225 .init = &init,
226 .parse = &parse,
227 .final_check = &final_check,
228 .print = &print,
229 .save = &save,
230 .extra_opts = opts
Martin Josefssonf419f752001-02-19 21:55:27 +0000231};
232
233void _init(void)
234{
235 register_target(&same);
236}