blob: b18351e8feb429834f2fe2d0dfad7ac095ff8e85 [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. */
Jan Engelhardt32b8e612010-07-23 21:16:14 +02002#include <stdbool.h>
Martin Josefssonf419f752001-02-19 21:55:27 +00003#include <stdio.h>
4#include <netdb.h>
5#include <string.h>
6#include <stdlib.h>
7#include <getopt.h>
Jan Engelhardt5d9678a2008-11-20 10:15:35 +01008#include <xtables.h>
Jan Engelhardt978e27e2009-02-21 04:42:32 +01009#include <net/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
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000013static void SAME_help(void)
Martin Josefssonf419f752001-02-19 21:55:27 +000014{
15 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020016"SAME target options:\n"
Harald Welte18f1aff2001-03-25 19:03:23 +000017" --to <ipaddr>-<ipaddr>\n"
Harald Weltecf655eb2001-07-28 18:47:11 +000018" Addresses to map source to.\n"
Harald Welte05e0b012001-08-26 08:18:25 +000019" May be specified more than\n"
20" once for multiple ranges.\n"
Harald Weltecf655eb2001-07-28 18:47:11 +000021" --nodst\n"
22" Don't use destination-ip in\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000023" source selection\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000024" --random\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020025" Randomize source port\n");
Martin Josefssonf419f752001-02-19 21:55:27 +000026}
27
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000028static const struct option SAME_opts[] = {
Jan Engelhardt32b8e612010-07-23 21:16:14 +020029 {.name = "to", .has_arg = true, .val = '1'},
30 {.name = "nodst", .has_arg = false, .val = '2'},
31 {.name = "random", .has_arg = false, .val = '3'},
32 XT_GETOPT_TABLEEND,
Martin Josefssonf419f752001-02-19 21:55:27 +000033};
34
Martin Josefssonf419f752001-02-19 21:55:27 +000035/* Parses range of IPs */
36static void
Jan Engelhardt978e27e2009-02-21 04:42:32 +010037parse_to(char *arg, struct nf_nat_range *range)
Martin Josefssonf419f752001-02-19 21:55:27 +000038{
39 char *dash;
Jan Engelhardtbd943842008-01-20 13:38:08 +000040 const struct in_addr *ip;
Martin Josefssonf419f752001-02-19 21:55:27 +000041
42 range->flags |= IP_NAT_RANGE_MAP_IPS;
43 dash = strchr(arg, '-');
Harald Welte05e0b012001-08-26 08:18:25 +000044
Martin Josefssonf419f752001-02-19 21:55:27 +000045 if (dash)
46 *dash = '\0';
Martin Josefssonf419f752001-02-19 21:55:27 +000047
Jan Engelhardt1e01b0b2009-01-30 04:20:32 +010048 ip = xtables_numeric_to_ipaddr(arg);
Martin Josefssonf419f752001-02-19 21:55:27 +000049 if (!ip)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010050 xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
Martin Josefssonf419f752001-02-19 21:55:27 +000051 arg);
52 range->min_ip = ip->s_addr;
Harald Welte05e0b012001-08-26 08:18:25 +000053
54 if (dash) {
Jan Engelhardt1e01b0b2009-01-30 04:20:32 +010055 ip = xtables_numeric_to_ipaddr(dash+1);
Harald Welte05e0b012001-08-26 08:18:25 +000056 if (!ip)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010057 xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
Harald Welte05e0b012001-08-26 08:18:25 +000058 dash+1);
59 }
Martin Josefssonf419f752001-02-19 21:55:27 +000060 range->max_ip = ip->s_addr;
Harald Welte05e0b012001-08-26 08:18:25 +000061 if (dash)
62 if (range->min_ip > range->max_ip)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010063 xtables_error(PARAMETER_PROBLEM, "Bad IP range \"%s-%s\"\n",
Harald Welte05e0b012001-08-26 08:18:25 +000064 arg, dash+1);
Martin Josefssonf419f752001-02-19 21:55:27 +000065}
66
Harald Weltecf655eb2001-07-28 18:47:11 +000067#define IPT_SAME_OPT_TO 0x01
68#define IPT_SAME_OPT_NODST 0x02
Patrick McHardye656e262007-04-18 12:56:05 +000069#define IPT_SAME_OPT_RANDOM 0x04
Harald Weltecf655eb2001-07-28 18:47:11 +000070
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000071static int SAME_parse(int c, char **argv, int invert, unsigned int *flags,
72 const void *entry, struct xt_entry_target **target)
Martin Josefssonf419f752001-02-19 21:55:27 +000073{
Harald Weltecf655eb2001-07-28 18:47:11 +000074 struct ipt_same_info *mr
75 = (struct ipt_same_info *)(*target)->data;
Jan Engelhardt7a236f42008-03-03 12:30:41 +010076 unsigned int count;
Martin Josefssonf419f752001-02-19 21:55:27 +000077
78 switch (c) {
79 case '1':
Harald Welte05e0b012001-08-26 08:18:25 +000080 if (mr->rangesize == IPT_SAME_MAX_RANGE)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010081 xtables_error(PARAMETER_PROBLEM,
Harald Welte05e0b012001-08-26 08:18:25 +000082 "Too many ranges specified, maximum "
83 "is %i ranges.\n",
84 IPT_SAME_MAX_RANGE);
Jan Engelhardtbf971282009-11-03 19:55:11 +010085 if (xtables_check_inverse(optarg, &invert, NULL, 0, argv))
Jan Engelhardt1829ed42009-02-21 03:29:44 +010086 xtables_error(PARAMETER_PROBLEM,
Harald Welte18f1aff2001-03-25 19:03:23 +000087 "Unexpected `!' after --to");
Martin Josefssonf419f752001-02-19 21:55:27 +000088
Harald Welte05e0b012001-08-26 08:18:25 +000089 parse_to(optarg, &mr->range[mr->rangesize]);
Patrick McHardye656e262007-04-18 12:56:05 +000090 /* WTF do we need this for? */
Eric Leblondae4b0b32007-02-24 15:11:33 +000091 if (*flags & IPT_SAME_OPT_RANDOM)
92 mr->range[mr->rangesize].flags
93 |= IP_NAT_RANGE_PROTO_RANDOM;
Harald Welte05e0b012001-08-26 08:18:25 +000094 mr->rangesize++;
Harald Weltecf655eb2001-07-28 18:47:11 +000095 *flags |= IPT_SAME_OPT_TO;
96 break;
97
98 case '2':
99 if (*flags & IPT_SAME_OPT_NODST)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100100 xtables_error(PARAMETER_PROBLEM,
Harald Weltecf655eb2001-07-28 18:47:11 +0000101 "Can't specify --nodst twice");
102
103 mr->info |= IPT_SAME_NODST;
104 *flags |= IPT_SAME_OPT_NODST;
105 break;
Eric Leblondae4b0b32007-02-24 15:11:33 +0000106
Eric Leblondae4b0b32007-02-24 15:11:33 +0000107 case '3':
108 *flags |= IPT_SAME_OPT_RANDOM;
109 for (count=0; count < mr->rangesize; count++)
110 mr->range[count].flags |= IP_NAT_RANGE_PROTO_RANDOM;
111 break;
Martin Josefssonf419f752001-02-19 21:55:27 +0000112 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000113
114 return 1;
Martin Josefssonf419f752001-02-19 21:55:27 +0000115}
116
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000117static void SAME_check(unsigned int flags)
Martin Josefssonf419f752001-02-19 21:55:27 +0000118{
Harald Weltecf655eb2001-07-28 18:47:11 +0000119 if (!(flags & IPT_SAME_OPT_TO))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100120 xtables_error(PARAMETER_PROBLEM,
Harald Welte18f1aff2001-03-25 19:03:23 +0000121 "SAME needs --to");
Martin Josefssonf419f752001-02-19 21:55:27 +0000122}
123
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000124static void SAME_print(const void *ip, const struct xt_entry_target *target,
125 int numeric)
Martin Josefssonf419f752001-02-19 21:55:27 +0000126{
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100127 unsigned int count;
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200128 const struct ipt_same_info *mr = (const void *)target->data;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100129 int random_selection = 0;
Harald Welte05e0b012001-08-26 08:18:25 +0000130
Jan Engelhardt73866352010-12-18 02:04:59 +0100131 printf(" same:");
132
Harald Welte05e0b012001-08-26 08:18:25 +0000133 for (count = 0; count < mr->rangesize; count++) {
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200134 const struct nf_nat_range *r = &mr->range[count];
Harald Welte05e0b012001-08-26 08:18:25 +0000135 struct in_addr a;
Martin Josefssonf419f752001-02-19 21:55:27 +0000136
Harald Welte05e0b012001-08-26 08:18:25 +0000137 a.s_addr = r->min_ip;
Martin Josefssonf419f752001-02-19 21:55:27 +0000138
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100139 printf("%s", xtables_ipaddr_to_numeric(&a));
Harald Welte05e0b012001-08-26 08:18:25 +0000140 a.s_addr = r->max_ip;
141
Jan Engelhardt73866352010-12-18 02:04:59 +0100142 if (r->min_ip != r->max_ip)
143 printf("-%s", xtables_ipaddr_to_numeric(&a));
Eric Leblondae4b0b32007-02-24 15:11:33 +0000144 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100145 random_selection = 1;
Harald Welte05e0b012001-08-26 08:18:25 +0000146 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000147
148 if (mr->info & IPT_SAME_NODST)
Jan Engelhardt73866352010-12-18 02:04:59 +0100149 printf(" nodst");
Eric Leblondae4b0b32007-02-24 15:11:33 +0000150
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100151 if (random_selection)
Jan Engelhardt73866352010-12-18 02:04:59 +0100152 printf(" random");
Martin Josefssonf419f752001-02-19 21:55:27 +0000153}
154
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000155static void SAME_save(const void *ip, const struct xt_entry_target *target)
Martin Josefssonf419f752001-02-19 21:55:27 +0000156{
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100157 unsigned int count;
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200158 const struct ipt_same_info *mr = (const void *)target->data;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100159 int random_selection = 0;
Martin Josefssonf419f752001-02-19 21:55:27 +0000160
Harald Welte05e0b012001-08-26 08:18:25 +0000161 for (count = 0; count < mr->rangesize; count++) {
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200162 const struct nf_nat_range *r = &mr->range[count];
Harald Welte05e0b012001-08-26 08:18:25 +0000163 struct in_addr a;
164
165 a.s_addr = r->min_ip;
Jan Engelhardt73866352010-12-18 02:04:59 +0100166 printf(" --to %s", xtables_ipaddr_to_numeric(&a));
Harald Welte05e0b012001-08-26 08:18:25 +0000167 a.s_addr = r->max_ip;
168
Jan Engelhardt73866352010-12-18 02:04:59 +0100169 if (r->min_ip != r->max_ip)
170 printf("-%s", xtables_ipaddr_to_numeric(&a));
Patrick McHardy9c67def2007-04-18 14:00:11 +0000171 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100172 random_selection = 1;
Harald Welte05e0b012001-08-26 08:18:25 +0000173 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000174
175 if (mr->info & IPT_SAME_NODST)
Jan Engelhardt73866352010-12-18 02:04:59 +0100176 printf(" --nodst");
Patrick McHardy9c67def2007-04-18 14:00:11 +0000177
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100178 if (random_selection)
Jan Engelhardt73866352010-12-18 02:04:59 +0100179 printf(" --random");
Martin Josefssonf419f752001-02-19 21:55:27 +0000180}
181
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200182static struct xtables_target same_tg_reg = {
Pablo Neira8caee8b2004-12-28 13:11:59 +0000183 .name = "SAME",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200184 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100185 .family = NFPROTO_IPV4,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200186 .size = XT_ALIGN(sizeof(struct ipt_same_info)),
187 .userspacesize = XT_ALIGN(sizeof(struct ipt_same_info)),
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000188 .help = SAME_help,
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000189 .parse = SAME_parse,
190 .final_check = SAME_check,
191 .print = SAME_print,
192 .save = SAME_save,
193 .extra_opts = SAME_opts,
Martin Josefssonf419f752001-02-19 21:55:27 +0000194};
195
196void _init(void)
197{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200198 xtables_register_target(&same_tg_reg);
Martin Josefssonf419f752001-02-19 21:55:27 +0000199}