blob: c0aef9f966206a2470f99c6c8ec5ffbfdd401314 [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 */
Jan Engelhardta2a7f2b2008-09-01 14:20:13 +020011#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. */
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000014static void SAME_help(void)
Martin Josefssonf419f752001-02-19 21:55:27 +000015{
16 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020017"SAME target options:\n"
Harald Welte18f1aff2001-03-25 19:03:23 +000018" --to <ipaddr>-<ipaddr>\n"
Harald Weltecf655eb2001-07-28 18:47:11 +000019" Addresses to map source to.\n"
Harald Welte05e0b012001-08-26 08:18:25 +000020" May be specified more than\n"
21" once for multiple ranges.\n"
Harald Weltecf655eb2001-07-28 18:47:11 +000022" --nodst\n"
23" Don't use destination-ip in\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000024" source selection\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000025" --random\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020026" Randomize source port\n");
Martin Josefssonf419f752001-02-19 21:55:27 +000027}
28
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000029static const struct option SAME_opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000030 { "to", 1, NULL, '1' },
31 { "nodst", 0, NULL, '2'},
32 { "random", 0, NULL, '3' },
Max Kellermann9ee386a2008-01-29 13:48:05 +000033 { .name = NULL }
Martin Josefssonf419f752001-02-19 21:55:27 +000034};
35
36/* Initialize the target. */
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000037static void SAME_init(struct xt_entry_target *t)
Martin Josefssonf419f752001-02-19 21:55:27 +000038{
Harald Weltecf655eb2001-07-28 18:47:11 +000039 struct ipt_same_info *mr = (struct ipt_same_info *)t->data;
Martin Josefssonf419f752001-02-19 21:55:27 +000040
Harald Welte05e0b012001-08-26 08:18:25 +000041 /* Set default to 0 */
42 mr->rangesize = 0;
Harald Weltecf655eb2001-07-28 18:47:11 +000043 mr->info = 0;
Harald Welte05e0b012001-08-26 08:18:25 +000044 mr->ipnum = 0;
Harald Weltecf655eb2001-07-28 18:47:11 +000045
Martin Josefssonf419f752001-02-19 21:55:27 +000046}
47
48/* Parses range of IPs */
49static void
50parse_to(char *arg, struct ip_nat_range *range)
51{
52 char *dash;
Jan Engelhardtbd943842008-01-20 13:38:08 +000053 const struct in_addr *ip;
Martin Josefssonf419f752001-02-19 21:55:27 +000054
55 range->flags |= IP_NAT_RANGE_MAP_IPS;
56 dash = strchr(arg, '-');
Harald Welte05e0b012001-08-26 08:18:25 +000057
Martin Josefssonf419f752001-02-19 21:55:27 +000058 if (dash)
59 *dash = '\0';
Martin Josefssonf419f752001-02-19 21:55:27 +000060
Jan Engelhardtbd943842008-01-20 13:38:08 +000061 ip = numeric_to_ipaddr(arg);
Martin Josefssonf419f752001-02-19 21:55:27 +000062 if (!ip)
63 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
64 arg);
65 range->min_ip = ip->s_addr;
Harald Welte05e0b012001-08-26 08:18:25 +000066
67 if (dash) {
Jan Engelhardtbd943842008-01-20 13:38:08 +000068 ip = numeric_to_ipaddr(dash+1);
Harald Welte05e0b012001-08-26 08:18:25 +000069 if (!ip)
70 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
71 dash+1);
72 }
Martin Josefssonf419f752001-02-19 21:55:27 +000073 range->max_ip = ip->s_addr;
Harald Welte05e0b012001-08-26 08:18:25 +000074 if (dash)
75 if (range->min_ip > range->max_ip)
76 exit_error(PARAMETER_PROBLEM, "Bad IP range `%s-%s'\n",
77 arg, dash+1);
Martin Josefssonf419f752001-02-19 21:55:27 +000078}
79
Harald Weltecf655eb2001-07-28 18:47:11 +000080#define IPT_SAME_OPT_TO 0x01
81#define IPT_SAME_OPT_NODST 0x02
Patrick McHardye656e262007-04-18 12:56:05 +000082#define IPT_SAME_OPT_RANDOM 0x04
Harald Weltecf655eb2001-07-28 18:47:11 +000083
Martin Josefssonf419f752001-02-19 21:55:27 +000084/* Function which parses command options; returns true if it
85 ate an option */
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000086static int SAME_parse(int c, char **argv, int invert, unsigned int *flags,
87 const void *entry, struct xt_entry_target **target)
Martin Josefssonf419f752001-02-19 21:55:27 +000088{
Harald Weltecf655eb2001-07-28 18:47:11 +000089 struct ipt_same_info *mr
90 = (struct ipt_same_info *)(*target)->data;
Jan Engelhardt7a236f42008-03-03 12:30:41 +010091 unsigned int count;
Martin Josefssonf419f752001-02-19 21:55:27 +000092
93 switch (c) {
94 case '1':
Harald Welte05e0b012001-08-26 08:18:25 +000095 if (mr->rangesize == IPT_SAME_MAX_RANGE)
Harald Weltecf655eb2001-07-28 18:47:11 +000096 exit_error(PARAMETER_PROBLEM,
Harald Welte05e0b012001-08-26 08:18:25 +000097 "Too many ranges specified, maximum "
98 "is %i ranges.\n",
99 IPT_SAME_MAX_RANGE);
Harald Welteb77f1da2002-03-14 11:35:58 +0000100 if (check_inverse(optarg, &invert, NULL, 0))
Martin Josefssonf419f752001-02-19 21:55:27 +0000101 exit_error(PARAMETER_PROBLEM,
Harald Welte18f1aff2001-03-25 19:03:23 +0000102 "Unexpected `!' after --to");
Martin Josefssonf419f752001-02-19 21:55:27 +0000103
Harald Welte05e0b012001-08-26 08:18:25 +0000104 parse_to(optarg, &mr->range[mr->rangesize]);
Patrick McHardye656e262007-04-18 12:56:05 +0000105 /* WTF do we need this for? */
Eric Leblondae4b0b32007-02-24 15:11:33 +0000106 if (*flags & IPT_SAME_OPT_RANDOM)
107 mr->range[mr->rangesize].flags
108 |= IP_NAT_RANGE_PROTO_RANDOM;
Harald Welte05e0b012001-08-26 08:18:25 +0000109 mr->rangesize++;
Harald Weltecf655eb2001-07-28 18:47:11 +0000110 *flags |= IPT_SAME_OPT_TO;
111 break;
112
113 case '2':
114 if (*flags & IPT_SAME_OPT_NODST)
115 exit_error(PARAMETER_PROBLEM,
116 "Can't specify --nodst twice");
117
118 mr->info |= IPT_SAME_NODST;
119 *flags |= IPT_SAME_OPT_NODST;
120 break;
Eric Leblondae4b0b32007-02-24 15:11:33 +0000121
Eric Leblondae4b0b32007-02-24 15:11:33 +0000122 case '3':
123 *flags |= IPT_SAME_OPT_RANDOM;
124 for (count=0; count < mr->rangesize; count++)
125 mr->range[count].flags |= IP_NAT_RANGE_PROTO_RANDOM;
126 break;
Patrick McHardye656e262007-04-18 12:56:05 +0000127
Martin Josefssonf419f752001-02-19 21:55:27 +0000128 default:
129 return 0;
130 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000131
132 return 1;
Martin Josefssonf419f752001-02-19 21:55:27 +0000133}
134
Harald Welte18f1aff2001-03-25 19:03:23 +0000135/* Final check; need --to. */
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000136static void SAME_check(unsigned int flags)
Martin Josefssonf419f752001-02-19 21:55:27 +0000137{
Harald Weltecf655eb2001-07-28 18:47:11 +0000138 if (!(flags & IPT_SAME_OPT_TO))
Martin Josefssonf419f752001-02-19 21:55:27 +0000139 exit_error(PARAMETER_PROBLEM,
Harald Welte18f1aff2001-03-25 19:03:23 +0000140 "SAME needs --to");
Martin Josefssonf419f752001-02-19 21:55:27 +0000141}
142
143/* Prints out the targinfo. */
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000144static void SAME_print(const void *ip, const struct xt_entry_target *target,
145 int numeric)
Martin Josefssonf419f752001-02-19 21:55:27 +0000146{
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100147 unsigned int count;
Harald Weltecf655eb2001-07-28 18:47:11 +0000148 struct ipt_same_info *mr
149 = (struct ipt_same_info *)target->data;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100150 int random_selection = 0;
Harald Welte05e0b012001-08-26 08:18:25 +0000151
152 printf("same:");
153
154 for (count = 0; count < mr->rangesize; count++) {
155 struct ip_nat_range *r = &mr->range[count];
156 struct in_addr a;
Martin Josefssonf419f752001-02-19 21:55:27 +0000157
Harald Welte05e0b012001-08-26 08:18:25 +0000158 a.s_addr = r->min_ip;
Martin Josefssonf419f752001-02-19 21:55:27 +0000159
Jan Engelhardt08b16162008-01-20 13:36:08 +0000160 printf("%s", ipaddr_to_numeric(&a));
Harald Welte05e0b012001-08-26 08:18:25 +0000161 a.s_addr = r->max_ip;
162
163 if (r->min_ip == r->max_ip)
164 printf(" ");
165 else
Jan Engelhardt08b16162008-01-20 13:36:08 +0000166 printf("-%s ", ipaddr_to_numeric(&a));
Eric Leblondae4b0b32007-02-24 15:11:33 +0000167 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100168 random_selection = 1;
Harald Welte05e0b012001-08-26 08:18:25 +0000169 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000170
171 if (mr->info & IPT_SAME_NODST)
172 printf("nodst ");
Eric Leblondae4b0b32007-02-24 15:11:33 +0000173
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100174 if (random_selection)
Eric Leblondae4b0b32007-02-24 15:11:33 +0000175 printf("random ");
Martin Josefssonf419f752001-02-19 21:55:27 +0000176}
177
178/* Saves the union ipt_targinfo in parsable form to stdout. */
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000179static void SAME_save(const void *ip, const struct xt_entry_target *target)
Martin Josefssonf419f752001-02-19 21:55:27 +0000180{
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100181 unsigned int count;
Harald Weltecf655eb2001-07-28 18:47:11 +0000182 struct ipt_same_info *mr
183 = (struct ipt_same_info *)target->data;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100184 int random_selection = 0;
Martin Josefssonf419f752001-02-19 21:55:27 +0000185
Harald Welte05e0b012001-08-26 08:18:25 +0000186 for (count = 0; count < mr->rangesize; count++) {
187 struct ip_nat_range *r = &mr->range[count];
188 struct in_addr a;
189
190 a.s_addr = r->min_ip;
Jan Engelhardt08b16162008-01-20 13:36:08 +0000191 printf("--to %s", ipaddr_to_numeric(&a));
Harald Welte05e0b012001-08-26 08:18:25 +0000192 a.s_addr = r->max_ip;
193
194 if (r->min_ip == r->max_ip)
195 printf(" ");
196 else
Jan Engelhardt08b16162008-01-20 13:36:08 +0000197 printf("-%s ", ipaddr_to_numeric(&a));
Patrick McHardy9c67def2007-04-18 14:00:11 +0000198 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100199 random_selection = 1;
Harald Welte05e0b012001-08-26 08:18:25 +0000200 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000201
202 if (mr->info & IPT_SAME_NODST)
203 printf("--nodst ");
Patrick McHardy9c67def2007-04-18 14:00:11 +0000204
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100205 if (random_selection)
Patrick McHardy9c67def2007-04-18 14:00:11 +0000206 printf("--random ");
Martin Josefssonf419f752001-02-19 21:55:27 +0000207}
208
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200209static struct xtables_target same_tg_reg = {
Pablo Neira8caee8b2004-12-28 13:11:59 +0000210 .name = "SAME",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200211 .version = XTABLES_VERSION,
212 .family = PF_INET,
213 .size = XT_ALIGN(sizeof(struct ipt_same_info)),
214 .userspacesize = XT_ALIGN(sizeof(struct ipt_same_info)),
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000215 .help = SAME_help,
216 .init = SAME_init,
217 .parse = SAME_parse,
218 .final_check = SAME_check,
219 .print = SAME_print,
220 .save = SAME_save,
221 .extra_opts = SAME_opts,
Martin Josefssonf419f752001-02-19 21:55:27 +0000222};
223
224void _init(void)
225{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200226 xtables_register_target(&same_tg_reg);
Martin Josefssonf419f752001-02-19 21:55:27 +0000227}