blob: a07d9f48a3d94d8033acdb9195e41b258ef94ea4 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* Shared library add-on to iptables to add simple non load-balancing SNAT support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7#include <xtables.h>
8#include <net/netfilter/nf_nat.h>
9/* For 64bit kernel / 32bit userspace */
10#include <linux/netfilter_ipv4/ipt_SAME.h>
11
12static void SAME_help(void)
13{
14 printf(
15"SAME target options:\n"
16" --to <ipaddr>-<ipaddr>\n"
17" Addresses to map source to.\n"
18" May be specified more than\n"
19" once for multiple ranges.\n"
20" --nodst\n"
21" Don't use destination-ip in\n"
22" source selection\n"
23" --random\n"
24" Randomize source port\n");
25}
26
27static const struct option SAME_opts[] = {
28 { "to", 1, NULL, '1' },
29 { "nodst", 0, NULL, '2'},
30 { "random", 0, NULL, '3' },
31 { .name = NULL }
32};
33
34static void SAME_init(struct xt_entry_target *t)
35{
36 struct ipt_same_info *mr = (struct ipt_same_info *)t->data;
37
38 /* Set default to 0 */
39 mr->rangesize = 0;
40 mr->info = 0;
41 mr->ipnum = 0;
42
43}
44
45/* Parses range of IPs */
46static void
47parse_to(char *arg, struct nf_nat_range *range)
48{
49 char *dash;
50 const struct in_addr *ip;
51
52 range->flags |= IP_NAT_RANGE_MAP_IPS;
53 dash = strchr(arg, '-');
54
55 if (dash)
56 *dash = '\0';
57
58 ip = xtables_numeric_to_ipaddr(arg);
59 if (!ip)
60 xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
61 arg);
62 range->min_ip = ip->s_addr;
63
64 if (dash) {
65 ip = xtables_numeric_to_ipaddr(dash+1);
66 if (!ip)
67 xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
68 dash+1);
69 }
70 range->max_ip = ip->s_addr;
71 if (dash)
72 if (range->min_ip > range->max_ip)
73 xtables_error(PARAMETER_PROBLEM, "Bad IP range \"%s-%s\"\n",
74 arg, dash+1);
75}
76
77#define IPT_SAME_OPT_TO 0x01
78#define IPT_SAME_OPT_NODST 0x02
79#define IPT_SAME_OPT_RANDOM 0x04
80
81static int SAME_parse(int c, char **argv, int invert, unsigned int *flags,
82 const void *entry, struct xt_entry_target **target)
83{
84 struct ipt_same_info *mr
85 = (struct ipt_same_info *)(*target)->data;
86 unsigned int count;
87
88 switch (c) {
89 case '1':
90 if (mr->rangesize == IPT_SAME_MAX_RANGE)
91 xtables_error(PARAMETER_PROBLEM,
92 "Too many ranges specified, maximum "
93 "is %i ranges.\n",
94 IPT_SAME_MAX_RANGE);
95 if (xtables_check_inverse(optarg, &invert, NULL, 0))
96 xtables_error(PARAMETER_PROBLEM,
97 "Unexpected `!' after --to");
98
99 parse_to(optarg, &mr->range[mr->rangesize]);
100 /* WTF do we need this for? */
101 if (*flags & IPT_SAME_OPT_RANDOM)
102 mr->range[mr->rangesize].flags
103 |= IP_NAT_RANGE_PROTO_RANDOM;
104 mr->rangesize++;
105 *flags |= IPT_SAME_OPT_TO;
106 break;
107
108 case '2':
109 if (*flags & IPT_SAME_OPT_NODST)
110 xtables_error(PARAMETER_PROBLEM,
111 "Can't specify --nodst twice");
112
113 mr->info |= IPT_SAME_NODST;
114 *flags |= IPT_SAME_OPT_NODST;
115 break;
116
117 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;
122
123 default:
124 return 0;
125 }
126
127 return 1;
128}
129
130static void SAME_check(unsigned int flags)
131{
132 if (!(flags & IPT_SAME_OPT_TO))
133 xtables_error(PARAMETER_PROBLEM,
134 "SAME needs --to");
135}
136
137static void SAME_print(const void *ip, const struct xt_entry_target *target,
138 int numeric)
139{
140 unsigned int count;
141 struct ipt_same_info *mr
142 = (struct ipt_same_info *)target->data;
143 int random_selection = 0;
144
145 printf("same:");
146
147 for (count = 0; count < mr->rangesize; count++) {
148 struct nf_nat_range *r = &mr->range[count];
149 struct in_addr a;
150
151 a.s_addr = r->min_ip;
152
153 printf("%s", xtables_ipaddr_to_numeric(&a));
154 a.s_addr = r->max_ip;
155
156 if (r->min_ip == r->max_ip)
157 printf(" ");
158 else
159 printf("-%s ", xtables_ipaddr_to_numeric(&a));
160 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
161 random_selection = 1;
162 }
163
164 if (mr->info & IPT_SAME_NODST)
165 printf("nodst ");
166
167 if (random_selection)
168 printf("random ");
169}
170
171static void SAME_save(const void *ip, const struct xt_entry_target *target)
172{
173 unsigned int count;
174 struct ipt_same_info *mr
175 = (struct ipt_same_info *)target->data;
176 int random_selection = 0;
177
178 for (count = 0; count < mr->rangesize; count++) {
179 struct nf_nat_range *r = &mr->range[count];
180 struct in_addr a;
181
182 a.s_addr = r->min_ip;
183 printf("--to %s", xtables_ipaddr_to_numeric(&a));
184 a.s_addr = r->max_ip;
185
186 if (r->min_ip == r->max_ip)
187 printf(" ");
188 else
189 printf("-%s ", xtables_ipaddr_to_numeric(&a));
190 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
191 random_selection = 1;
192 }
193
194 if (mr->info & IPT_SAME_NODST)
195 printf("--nodst ");
196
197 if (random_selection)
198 printf("--random ");
199}
200
201static struct xtables_target same_tg_reg = {
202 .name = "SAME",
203 .version = XTABLES_VERSION,
204 .family = NFPROTO_IPV4,
205 .size = XT_ALIGN(sizeof(struct ipt_same_info)),
206 .userspacesize = XT_ALIGN(sizeof(struct ipt_same_info)),
207 .help = SAME_help,
208 .init = SAME_init,
209 .parse = SAME_parse,
210 .final_check = SAME_check,
211 .print = SAME_print,
212 .save = SAME_save,
213 .extra_opts = SAME_opts,
214};
215
216void _init(void)
217{
218 xtables_register_target(&same_tg_reg);
219}