blob: d1e6903a94dcb0f2e2753ba58d0c12d98bcd4267 [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. */
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000014static void SAME_help(void)
Martin Josefssonf419f752001-02-19 21:55:27 +000015{
16 printf(
17"SAME v%s 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"
26" Randomize source port\n"
Eric Leblondae4b0b32007-02-24 15:11:33 +000027,
Harald Welte80fe35d2002-05-29 13:08:15 +000028IPTABLES_VERSION);
Martin Josefssonf419f752001-02-19 21:55:27 +000029}
30
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000031static const struct option SAME_opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000032 { "to", 1, NULL, '1' },
33 { "nodst", 0, NULL, '2'},
34 { "random", 0, NULL, '3' },
Max Kellermann9ee386a2008-01-29 13:48:05 +000035 { .name = NULL }
Martin Josefssonf419f752001-02-19 21:55:27 +000036};
37
38/* Initialize the target. */
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000039static void SAME_init(struct xt_entry_target *t)
Martin Josefssonf419f752001-02-19 21:55:27 +000040{
Harald Weltecf655eb2001-07-28 18:47:11 +000041 struct ipt_same_info *mr = (struct ipt_same_info *)t->data;
Martin Josefssonf419f752001-02-19 21:55:27 +000042
Harald Welte05e0b012001-08-26 08:18:25 +000043 /* Set default to 0 */
44 mr->rangesize = 0;
Harald Weltecf655eb2001-07-28 18:47:11 +000045 mr->info = 0;
Harald Welte05e0b012001-08-26 08:18:25 +000046 mr->ipnum = 0;
Harald Weltecf655eb2001-07-28 18:47:11 +000047
Martin Josefssonf419f752001-02-19 21:55:27 +000048}
49
50/* Parses range of IPs */
51static void
52parse_to(char *arg, struct ip_nat_range *range)
53{
54 char *dash;
Jan Engelhardtbd943842008-01-20 13:38:08 +000055 const struct in_addr *ip;
Martin Josefssonf419f752001-02-19 21:55:27 +000056
57 range->flags |= IP_NAT_RANGE_MAP_IPS;
58 dash = strchr(arg, '-');
Harald Welte05e0b012001-08-26 08:18:25 +000059
Martin Josefssonf419f752001-02-19 21:55:27 +000060 if (dash)
61 *dash = '\0';
Martin Josefssonf419f752001-02-19 21:55:27 +000062
Jan Engelhardtbd943842008-01-20 13:38:08 +000063 ip = numeric_to_ipaddr(arg);
Martin Josefssonf419f752001-02-19 21:55:27 +000064 if (!ip)
65 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
66 arg);
67 range->min_ip = ip->s_addr;
Harald Welte05e0b012001-08-26 08:18:25 +000068
69 if (dash) {
Jan Engelhardtbd943842008-01-20 13:38:08 +000070 ip = numeric_to_ipaddr(dash+1);
Harald Welte05e0b012001-08-26 08:18:25 +000071 if (!ip)
72 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
73 dash+1);
74 }
Martin Josefssonf419f752001-02-19 21:55:27 +000075 range->max_ip = ip->s_addr;
Harald Welte05e0b012001-08-26 08:18:25 +000076 if (dash)
77 if (range->min_ip > range->max_ip)
78 exit_error(PARAMETER_PROBLEM, "Bad IP range `%s-%s'\n",
79 arg, dash+1);
Martin Josefssonf419f752001-02-19 21:55:27 +000080}
81
Harald Weltecf655eb2001-07-28 18:47:11 +000082#define IPT_SAME_OPT_TO 0x01
83#define IPT_SAME_OPT_NODST 0x02
Patrick McHardye656e262007-04-18 12:56:05 +000084#define IPT_SAME_OPT_RANDOM 0x04
Harald Weltecf655eb2001-07-28 18:47:11 +000085
Martin Josefssonf419f752001-02-19 21:55:27 +000086/* Function which parses command options; returns true if it
87 ate an option */
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000088static int SAME_parse(int c, char **argv, int invert, unsigned int *flags,
89 const void *entry, struct xt_entry_target **target)
Martin Josefssonf419f752001-02-19 21:55:27 +000090{
Harald Weltecf655eb2001-07-28 18:47:11 +000091 struct ipt_same_info *mr
92 = (struct ipt_same_info *)(*target)->data;
Jan Engelhardt7a236f42008-03-03 12:30:41 +010093 unsigned int count;
Martin Josefssonf419f752001-02-19 21:55:27 +000094
95 switch (c) {
96 case '1':
Harald Welte05e0b012001-08-26 08:18:25 +000097 if (mr->rangesize == IPT_SAME_MAX_RANGE)
Harald Weltecf655eb2001-07-28 18:47:11 +000098 exit_error(PARAMETER_PROBLEM,
Harald Welte05e0b012001-08-26 08:18:25 +000099 "Too many ranges specified, maximum "
100 "is %i ranges.\n",
101 IPT_SAME_MAX_RANGE);
Harald Welteb77f1da2002-03-14 11:35:58 +0000102 if (check_inverse(optarg, &invert, NULL, 0))
Martin Josefssonf419f752001-02-19 21:55:27 +0000103 exit_error(PARAMETER_PROBLEM,
Harald Welte18f1aff2001-03-25 19:03:23 +0000104 "Unexpected `!' after --to");
Martin Josefssonf419f752001-02-19 21:55:27 +0000105
Harald Welte05e0b012001-08-26 08:18:25 +0000106 parse_to(optarg, &mr->range[mr->rangesize]);
Patrick McHardye656e262007-04-18 12:56:05 +0000107 /* WTF do we need this for? */
Eric Leblondae4b0b32007-02-24 15:11:33 +0000108 if (*flags & IPT_SAME_OPT_RANDOM)
109 mr->range[mr->rangesize].flags
110 |= IP_NAT_RANGE_PROTO_RANDOM;
Harald Welte05e0b012001-08-26 08:18:25 +0000111 mr->rangesize++;
Harald Weltecf655eb2001-07-28 18:47:11 +0000112 *flags |= IPT_SAME_OPT_TO;
113 break;
114
115 case '2':
116 if (*flags & IPT_SAME_OPT_NODST)
117 exit_error(PARAMETER_PROBLEM,
118 "Can't specify --nodst twice");
119
120 mr->info |= IPT_SAME_NODST;
121 *flags |= IPT_SAME_OPT_NODST;
122 break;
Eric Leblondae4b0b32007-02-24 15:11:33 +0000123
Eric Leblondae4b0b32007-02-24 15:11:33 +0000124 case '3':
125 *flags |= IPT_SAME_OPT_RANDOM;
126 for (count=0; count < mr->rangesize; count++)
127 mr->range[count].flags |= IP_NAT_RANGE_PROTO_RANDOM;
128 break;
Patrick McHardye656e262007-04-18 12:56:05 +0000129
Martin Josefssonf419f752001-02-19 21:55:27 +0000130 default:
131 return 0;
132 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000133
134 return 1;
Martin Josefssonf419f752001-02-19 21:55:27 +0000135}
136
Harald Welte18f1aff2001-03-25 19:03:23 +0000137/* Final check; need --to. */
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000138static void SAME_check(unsigned int flags)
Martin Josefssonf419f752001-02-19 21:55:27 +0000139{
Harald Weltecf655eb2001-07-28 18:47:11 +0000140 if (!(flags & IPT_SAME_OPT_TO))
Martin Josefssonf419f752001-02-19 21:55:27 +0000141 exit_error(PARAMETER_PROBLEM,
Harald Welte18f1aff2001-03-25 19:03:23 +0000142 "SAME needs --to");
Martin Josefssonf419f752001-02-19 21:55:27 +0000143}
144
145/* Prints out the targinfo. */
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000146static void SAME_print(const void *ip, const struct xt_entry_target *target,
147 int numeric)
Martin Josefssonf419f752001-02-19 21:55:27 +0000148{
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100149 unsigned int count;
Harald Weltecf655eb2001-07-28 18:47:11 +0000150 struct ipt_same_info *mr
151 = (struct ipt_same_info *)target->data;
Eric Leblondae4b0b32007-02-24 15:11:33 +0000152 int random = 0;
Harald Welte05e0b012001-08-26 08:18:25 +0000153
154 printf("same:");
155
156 for (count = 0; count < mr->rangesize; count++) {
157 struct ip_nat_range *r = &mr->range[count];
158 struct in_addr a;
Martin Josefssonf419f752001-02-19 21:55:27 +0000159
Harald Welte05e0b012001-08-26 08:18:25 +0000160 a.s_addr = r->min_ip;
Martin Josefssonf419f752001-02-19 21:55:27 +0000161
Jan Engelhardt08b16162008-01-20 13:36:08 +0000162 printf("%s", ipaddr_to_numeric(&a));
Harald Welte05e0b012001-08-26 08:18:25 +0000163 a.s_addr = r->max_ip;
164
165 if (r->min_ip == r->max_ip)
166 printf(" ");
167 else
Jan Engelhardt08b16162008-01-20 13:36:08 +0000168 printf("-%s ", ipaddr_to_numeric(&a));
Eric Leblondae4b0b32007-02-24 15:11:33 +0000169 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
170 random = 1;
Harald Welte05e0b012001-08-26 08:18:25 +0000171 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000172
173 if (mr->info & IPT_SAME_NODST)
174 printf("nodst ");
Eric Leblondae4b0b32007-02-24 15:11:33 +0000175
Eric Leblondae4b0b32007-02-24 15:11:33 +0000176 if (random)
177 printf("random ");
Martin Josefssonf419f752001-02-19 21:55:27 +0000178}
179
180/* Saves the union ipt_targinfo in parsable form to stdout. */
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000181static void SAME_save(const void *ip, const struct xt_entry_target *target)
Martin Josefssonf419f752001-02-19 21:55:27 +0000182{
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100183 unsigned int count;
Harald Weltecf655eb2001-07-28 18:47:11 +0000184 struct ipt_same_info *mr
185 = (struct ipt_same_info *)target->data;
Patrick McHardy9c67def2007-04-18 14:00:11 +0000186 int random = 0;
Martin Josefssonf419f752001-02-19 21:55:27 +0000187
Harald Welte05e0b012001-08-26 08:18:25 +0000188 for (count = 0; count < mr->rangesize; count++) {
189 struct ip_nat_range *r = &mr->range[count];
190 struct in_addr a;
191
192 a.s_addr = r->min_ip;
Jan Engelhardt08b16162008-01-20 13:36:08 +0000193 printf("--to %s", ipaddr_to_numeric(&a));
Harald Welte05e0b012001-08-26 08:18:25 +0000194 a.s_addr = r->max_ip;
195
196 if (r->min_ip == r->max_ip)
197 printf(" ");
198 else
Jan Engelhardt08b16162008-01-20 13:36:08 +0000199 printf("-%s ", ipaddr_to_numeric(&a));
Patrick McHardy9c67def2007-04-18 14:00:11 +0000200 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
201 random = 1;
Harald Welte05e0b012001-08-26 08:18:25 +0000202 }
Harald Weltecf655eb2001-07-28 18:47:11 +0000203
204 if (mr->info & IPT_SAME_NODST)
205 printf("--nodst ");
Patrick McHardy9c67def2007-04-18 14:00:11 +0000206
207 if (random)
208 printf("--random ");
Martin Josefssonf419f752001-02-19 21:55:27 +0000209}
210
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000211static struct iptables_target same_target = {
Pablo Neira8caee8b2004-12-28 13:11:59 +0000212 .name = "SAME",
213 .version = IPTABLES_VERSION,
214 .size = IPT_ALIGN(sizeof(struct ipt_same_info)),
215 .userspacesize = IPT_ALIGN(sizeof(struct ipt_same_info)),
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000216 .help = SAME_help,
217 .init = SAME_init,
218 .parse = SAME_parse,
219 .final_check = SAME_check,
220 .print = SAME_print,
221 .save = SAME_save,
222 .extra_opts = SAME_opts,
Martin Josefssonf419f752001-02-19 21:55:27 +0000223};
224
225void _init(void)
226{
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000227 register_target(&same_target);
Martin Josefssonf419f752001-02-19 21:55:27 +0000228}