blob: ed02ef9503c131e78c7dd66867e6710e88109a3d [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>
Jan Engelhardt5d9678a2008-11-20 10:15:35 +01007#include <xtables.h>
Jan Engelhardt978e27e2009-02-21 04:42:32 +01008#include <net/netfilter/nf_nat.h>
Martin Josefsson1eb00812004-05-26 15:58:07 +00009/* For 64bit kernel / 32bit userspace */
Jan Engelhardta2a7f2b2008-09-01 14:20:13 +020010#include <linux/netfilter_ipv4/ipt_SAME.h>
Martin Josefssonf419f752001-02-19 21:55:27 +000011
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000012static void SAME_help(void)
Martin Josefssonf419f752001-02-19 21:55:27 +000013{
14 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020015"SAME target options:\n"
Harald Welte18f1aff2001-03-25 19:03:23 +000016" --to <ipaddr>-<ipaddr>\n"
Harald Weltecf655eb2001-07-28 18:47:11 +000017" Addresses to map source to.\n"
Harald Welte05e0b012001-08-26 08:18:25 +000018" May be specified more than\n"
19" once for multiple ranges.\n"
Harald Weltecf655eb2001-07-28 18:47:11 +000020" --nodst\n"
21" Don't use destination-ip in\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000022" source selection\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000023" --random\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020024" Randomize source port\n");
Martin Josefssonf419f752001-02-19 21:55:27 +000025}
26
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000027static const struct option SAME_opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000028 { "to", 1, NULL, '1' },
29 { "nodst", 0, NULL, '2'},
30 { "random", 0, NULL, '3' },
Max Kellermann9ee386a2008-01-29 13:48:05 +000031 { .name = NULL }
Martin Josefssonf419f752001-02-19 21:55:27 +000032};
33
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000034static void SAME_init(struct xt_entry_target *t)
Martin Josefssonf419f752001-02-19 21:55:27 +000035{
Harald Weltecf655eb2001-07-28 18:47:11 +000036 struct ipt_same_info *mr = (struct ipt_same_info *)t->data;
Martin Josefssonf419f752001-02-19 21:55:27 +000037
Harald Welte05e0b012001-08-26 08:18:25 +000038 /* Set default to 0 */
39 mr->rangesize = 0;
Harald Weltecf655eb2001-07-28 18:47:11 +000040 mr->info = 0;
Harald Welte05e0b012001-08-26 08:18:25 +000041 mr->ipnum = 0;
Harald Weltecf655eb2001-07-28 18:47:11 +000042
Martin Josefssonf419f752001-02-19 21:55:27 +000043}
44
45/* Parses range of IPs */
46static void
Jan Engelhardt978e27e2009-02-21 04:42:32 +010047parse_to(char *arg, struct nf_nat_range *range)
Martin Josefssonf419f752001-02-19 21:55:27 +000048{
49 char *dash;
Jan Engelhardtbd943842008-01-20 13:38:08 +000050 const struct in_addr *ip;
Martin Josefssonf419f752001-02-19 21:55:27 +000051
52 range->flags |= IP_NAT_RANGE_MAP_IPS;
53 dash = strchr(arg, '-');
Harald Welte05e0b012001-08-26 08:18:25 +000054
Martin Josefssonf419f752001-02-19 21:55:27 +000055 if (dash)
56 *dash = '\0';
Martin Josefssonf419f752001-02-19 21:55:27 +000057
Jan Engelhardt1e01b0b2009-01-30 04:20:32 +010058 ip = xtables_numeric_to_ipaddr(arg);
Martin Josefssonf419f752001-02-19 21:55:27 +000059 if (!ip)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010060 xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
Martin Josefssonf419f752001-02-19 21:55:27 +000061 arg);
62 range->min_ip = ip->s_addr;
Harald Welte05e0b012001-08-26 08:18:25 +000063
64 if (dash) {
Jan Engelhardt1e01b0b2009-01-30 04:20:32 +010065 ip = xtables_numeric_to_ipaddr(dash+1);
Harald Welte05e0b012001-08-26 08:18:25 +000066 if (!ip)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010067 xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
Harald Welte05e0b012001-08-26 08:18:25 +000068 dash+1);
69 }
Martin Josefssonf419f752001-02-19 21:55:27 +000070 range->max_ip = ip->s_addr;
Harald Welte05e0b012001-08-26 08:18:25 +000071 if (dash)
72 if (range->min_ip > range->max_ip)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010073 xtables_error(PARAMETER_PROBLEM, "Bad IP range \"%s-%s\"\n",
Harald Welte05e0b012001-08-26 08:18:25 +000074 arg, dash+1);
Martin Josefssonf419f752001-02-19 21:55:27 +000075}
76
Harald Weltecf655eb2001-07-28 18:47:11 +000077#define IPT_SAME_OPT_TO 0x01
78#define IPT_SAME_OPT_NODST 0x02
Patrick McHardye656e262007-04-18 12:56:05 +000079#define IPT_SAME_OPT_RANDOM 0x04
Harald Weltecf655eb2001-07-28 18:47:11 +000080
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000081static int SAME_parse(int c, char **argv, int invert, unsigned int *flags,
82 const void *entry, struct xt_entry_target **target)
Martin Josefssonf419f752001-02-19 21:55:27 +000083{
Harald Weltecf655eb2001-07-28 18:47:11 +000084 struct ipt_same_info *mr
85 = (struct ipt_same_info *)(*target)->data;
Jan Engelhardt7a236f42008-03-03 12:30:41 +010086 unsigned int count;
Martin Josefssonf419f752001-02-19 21:55:27 +000087
88 switch (c) {
89 case '1':
Harald Welte05e0b012001-08-26 08:18:25 +000090 if (mr->rangesize == IPT_SAME_MAX_RANGE)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010091 xtables_error(PARAMETER_PROBLEM,
Harald Welte05e0b012001-08-26 08:18:25 +000092 "Too many ranges specified, maximum "
93 "is %i ranges.\n",
94 IPT_SAME_MAX_RANGE);
Jan Engelhardtbf971282009-11-03 19:55:11 +010095 if (xtables_check_inverse(optarg, &invert, NULL, 0, argv))
Jan Engelhardt1829ed42009-02-21 03:29:44 +010096 xtables_error(PARAMETER_PROBLEM,
Harald Welte18f1aff2001-03-25 19:03:23 +000097 "Unexpected `!' after --to");
Martin Josefssonf419f752001-02-19 21:55:27 +000098
Harald Welte05e0b012001-08-26 08:18:25 +000099 parse_to(optarg, &mr->range[mr->rangesize]);
Patrick McHardye656e262007-04-18 12:56:05 +0000100 /* WTF do we need this for? */
Eric Leblondae4b0b32007-02-24 15:11:33 +0000101 if (*flags & IPT_SAME_OPT_RANDOM)
102 mr->range[mr->rangesize].flags
103 |= IP_NAT_RANGE_PROTO_RANDOM;
Harald Welte05e0b012001-08-26 08:18:25 +0000104 mr->rangesize++;
Harald Weltecf655eb2001-07-28 18:47:11 +0000105 *flags |= IPT_SAME_OPT_TO;
106 break;
107
108 case '2':
109 if (*flags & IPT_SAME_OPT_NODST)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100110 xtables_error(PARAMETER_PROBLEM,
Harald Weltecf655eb2001-07-28 18:47:11 +0000111 "Can't specify --nodst twice");
112
113 mr->info |= IPT_SAME_NODST;
114 *flags |= IPT_SAME_OPT_NODST;
115 break;
Eric Leblondae4b0b32007-02-24 15:11:33 +0000116
Eric Leblondae4b0b32007-02-24 15:11:33 +0000117 case '3':
118 *flags |= IPT_SAME_OPT_RANDOM;
119 for (count=0; count < mr->rangesize; count++)
120 mr->range[count].flags |= IP_NAT_RANGE_PROTO_RANDOM;
121 break;
Patrick McHardye656e262007-04-18 12:56:05 +0000122
Martin Josefssonf419f752001-02-19 21:55:27 +0000123 default:
124 return 0;
125 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000126
127 return 1;
Martin Josefssonf419f752001-02-19 21:55:27 +0000128}
129
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000130static void SAME_check(unsigned int flags)
Martin Josefssonf419f752001-02-19 21:55:27 +0000131{
Harald Weltecf655eb2001-07-28 18:47:11 +0000132 if (!(flags & IPT_SAME_OPT_TO))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100133 xtables_error(PARAMETER_PROBLEM,
Harald Welte18f1aff2001-03-25 19:03:23 +0000134 "SAME needs --to");
Martin Josefssonf419f752001-02-19 21:55:27 +0000135}
136
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000137static void SAME_print(const void *ip, const struct xt_entry_target *target,
138 int numeric)
Martin Josefssonf419f752001-02-19 21:55:27 +0000139{
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100140 unsigned int count;
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200141 const struct ipt_same_info *mr = (const void *)target->data;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100142 int random_selection = 0;
Harald Welte05e0b012001-08-26 08:18:25 +0000143
144 printf("same:");
145
146 for (count = 0; count < mr->rangesize; count++) {
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200147 const struct nf_nat_range *r = &mr->range[count];
Harald Welte05e0b012001-08-26 08:18:25 +0000148 struct in_addr a;
Martin Josefssonf419f752001-02-19 21:55:27 +0000149
Harald Welte05e0b012001-08-26 08:18:25 +0000150 a.s_addr = r->min_ip;
Martin Josefssonf419f752001-02-19 21:55:27 +0000151
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100152 printf("%s", xtables_ipaddr_to_numeric(&a));
Harald Welte05e0b012001-08-26 08:18:25 +0000153 a.s_addr = r->max_ip;
154
155 if (r->min_ip == r->max_ip)
156 printf(" ");
157 else
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100158 printf("-%s ", xtables_ipaddr_to_numeric(&a));
Eric Leblondae4b0b32007-02-24 15:11:33 +0000159 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100160 random_selection = 1;
Harald Welte05e0b012001-08-26 08:18:25 +0000161 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000162
163 if (mr->info & IPT_SAME_NODST)
164 printf("nodst ");
Eric Leblondae4b0b32007-02-24 15:11:33 +0000165
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100166 if (random_selection)
Eric Leblondae4b0b32007-02-24 15:11:33 +0000167 printf("random ");
Martin Josefssonf419f752001-02-19 21:55:27 +0000168}
169
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000170static void SAME_save(const void *ip, const struct xt_entry_target *target)
Martin Josefssonf419f752001-02-19 21:55:27 +0000171{
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100172 unsigned int count;
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200173 const struct ipt_same_info *mr = (const void *)target->data;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100174 int random_selection = 0;
Martin Josefssonf419f752001-02-19 21:55:27 +0000175
Harald Welte05e0b012001-08-26 08:18:25 +0000176 for (count = 0; count < mr->rangesize; count++) {
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200177 const struct nf_nat_range *r = &mr->range[count];
Harald Welte05e0b012001-08-26 08:18:25 +0000178 struct in_addr a;
179
180 a.s_addr = r->min_ip;
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100181 printf("--to %s", xtables_ipaddr_to_numeric(&a));
Harald Welte05e0b012001-08-26 08:18:25 +0000182 a.s_addr = r->max_ip;
183
184 if (r->min_ip == r->max_ip)
185 printf(" ");
186 else
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100187 printf("-%s ", xtables_ipaddr_to_numeric(&a));
Patrick McHardy9c67def2007-04-18 14:00:11 +0000188 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100189 random_selection = 1;
Harald Welte05e0b012001-08-26 08:18:25 +0000190 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000191
192 if (mr->info & IPT_SAME_NODST)
193 printf("--nodst ");
Patrick McHardy9c67def2007-04-18 14:00:11 +0000194
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100195 if (random_selection)
Patrick McHardy9c67def2007-04-18 14:00:11 +0000196 printf("--random ");
Martin Josefssonf419f752001-02-19 21:55:27 +0000197}
198
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200199static struct xtables_target same_tg_reg = {
Pablo Neira8caee8b2004-12-28 13:11:59 +0000200 .name = "SAME",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200201 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100202 .family = NFPROTO_IPV4,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200203 .size = XT_ALIGN(sizeof(struct ipt_same_info)),
204 .userspacesize = XT_ALIGN(sizeof(struct ipt_same_info)),
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000205 .help = SAME_help,
206 .init = SAME_init,
207 .parse = SAME_parse,
208 .final_check = SAME_check,
209 .print = SAME_print,
210 .save = SAME_save,
211 .extra_opts = SAME_opts,
Martin Josefssonf419f752001-02-19 21:55:27 +0000212};
213
214void _init(void)
215{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200216 xtables_register_target(&same_tg_reg);
Martin Josefssonf419f752001-02-19 21:55:27 +0000217}