1 /* Shared library add-on to iptables to add source-NAT support. */
8 #include <linux/netfilter_ipv4/ip_tables.h>
9 #include <linux/netfilter/nf_nat.h>
11 #define IPT_SNAT_OPT_SOURCE 0x01
12 #define IPT_SNAT_OPT_RANDOM 0x02
14 /* Source NAT data consists of a multi-range, indicating where to map
18 struct ipt_entry_target t
;
19 struct ip_nat_multi_range mr
;
22 /* Function which prints out usage message. */
28 " --to-source <ipaddr>[-<ipaddr>][:port-port]\n"
29 " Address to map source to.\n"
35 static struct option opts
[] = {
36 { "to-source", 1, 0, '1' },
37 { "random", 0, 0, '2' },
41 static struct ipt_natinfo
*
42 append_range(struct ipt_natinfo
*info
, const struct ip_nat_range
*range
)
46 /* One rangesize already in struct ipt_natinfo */
47 size
= IPT_ALIGN(sizeof(*info
) + info
->mr
.rangesize
* sizeof(*range
));
49 info
= realloc(info
, size
);
51 exit_error(OTHER_PROBLEM
, "Out of memory\n");
53 info
->t
.u
.target_size
= size
;
54 info
->mr
.range
[info
->mr
.rangesize
] = *range
;
60 /* Ranges expected in network order. */
61 static struct ipt_entry_target
*
62 parse_to(char *arg
, int portok
, struct ipt_natinfo
*info
)
64 struct ip_nat_range range
;
65 char *colon
, *dash
, *error
;
68 memset(&range
, 0, sizeof(range
));
69 colon
= strchr(arg
, ':');
75 exit_error(PARAMETER_PROBLEM
,
76 "Need TCP or UDP with port specification");
78 range
.flags
|= IP_NAT_RANGE_PROTO_SPECIFIED
;
81 if (port
<= 0 || port
> 65535)
82 exit_error(PARAMETER_PROBLEM
,
83 "Port `%s' not valid\n", colon
+1);
85 error
= strchr(colon
+1, ':');
87 exit_error(PARAMETER_PROBLEM
,
88 "Invalid port:port syntax - use dash\n");
90 dash
= strchr(colon
, '-');
98 maxport
= atoi(dash
+ 1);
99 if (maxport
<= 0 || maxport
> 65535)
100 exit_error(PARAMETER_PROBLEM
,
101 "Port `%s' not valid\n", dash
+1);
103 /* People are stupid. */
104 exit_error(PARAMETER_PROBLEM
,
105 "Port range `%s' funky\n", colon
+1);
106 range
.min
.tcp
.port
= htons(port
);
107 range
.max
.tcp
.port
= htons(maxport
);
109 /* Starts with a colon? No IP info...*/
111 return &(append_range(info
, &range
)->t
);
115 range
.flags
|= IP_NAT_RANGE_MAP_IPS
;
116 dash
= strchr(arg
, '-');
117 if (colon
&& dash
&& dash
> colon
)
123 ip
= dotted_to_addr(arg
);
125 exit_error(PARAMETER_PROBLEM
, "Bad IP address `%s'\n",
127 range
.min_ip
= ip
->s_addr
;
129 ip
= dotted_to_addr(dash
+1);
131 exit_error(PARAMETER_PROBLEM
, "Bad IP address `%s'\n",
133 range
.max_ip
= ip
->s_addr
;
135 range
.max_ip
= range
.min_ip
;
137 return &(append_range(info
, &range
)->t
);
140 /* Function which parses command options; returns true if it
143 parse(int c
, char **argv
, int invert
, unsigned int *flags
,
144 const struct ipt_entry
*entry
,
145 struct ipt_entry_target
**target
)
147 struct ipt_natinfo
*info
= (void *)*target
;
150 if (entry
->ip
.proto
== IPPROTO_TCP
151 || entry
->ip
.proto
== IPPROTO_UDP
152 || entry
->ip
.proto
== IPPROTO_ICMP
)
159 if (check_inverse(optarg
, &invert
, NULL
, 0))
160 exit_error(PARAMETER_PROBLEM
,
161 "Unexpected `!' after --to-source");
163 if (*flags
& IPT_SNAT_OPT_SOURCE
) {
165 get_kernel_version();
166 if (kernel_version
> LINUX_VERSION(2, 6, 10))
167 exit_error(PARAMETER_PROBLEM
,
168 "Multiple --to-source not supported");
170 *target
= parse_to(optarg
, portok
, info
);
171 /* WTF do we need this for?? */
172 if (*flags
& IPT_SNAT_OPT_RANDOM
)
173 info
->mr
.range
[0].flags
|= IP_NAT_RANGE_PROTO_RANDOM
;
174 *flags
|= IPT_SNAT_OPT_SOURCE
;
178 if (*flags
& IPT_SNAT_OPT_SOURCE
) {
179 info
->mr
.range
[0].flags
|= IP_NAT_RANGE_PROTO_RANDOM
;
180 *flags
|= IPT_SNAT_OPT_RANDOM
;
182 *flags
|= IPT_SNAT_OPT_RANDOM
;
190 /* Final check; must have specfied --to-source. */
191 static void final_check(unsigned int flags
)
193 if (!(flags
& IPT_SNAT_OPT_SOURCE
))
194 exit_error(PARAMETER_PROBLEM
,
195 "You must specify --to-source");
198 static void print_range(const struct ip_nat_range
*r
)
200 if (r
->flags
& IP_NAT_RANGE_MAP_IPS
) {
203 a
.s_addr
= r
->min_ip
;
204 printf("%s", addr_to_dotted(&a
));
205 if (r
->max_ip
!= r
->min_ip
) {
206 a
.s_addr
= r
->max_ip
;
207 printf("-%s", addr_to_dotted(&a
));
210 if (r
->flags
& IP_NAT_RANGE_PROTO_SPECIFIED
) {
212 printf("%hu", ntohs(r
->min
.tcp
.port
));
213 if (r
->max
.tcp
.port
!= r
->min
.tcp
.port
)
214 printf("-%hu", ntohs(r
->max
.tcp
.port
));
218 /* Prints out the targinfo. */
220 print(const struct ipt_ip
*ip
,
221 const struct ipt_entry_target
*target
,
224 struct ipt_natinfo
*info
= (void *)target
;
228 for (i
= 0; i
< info
->mr
.rangesize
; i
++) {
229 print_range(&info
->mr
.range
[i
]);
231 if (info
->mr
.range
[i
].flags
& IP_NAT_RANGE_PROTO_RANDOM
)
236 /* Saves the union ipt_targinfo in parsable form to stdout. */
238 save(const struct ipt_ip
*ip
, const struct ipt_entry_target
*target
)
240 struct ipt_natinfo
*info
= (void *)target
;
243 for (i
= 0; i
< info
->mr
.rangesize
; i
++) {
244 printf("--to-source ");
245 print_range(&info
->mr
.range
[i
]);
247 if (info
->mr
.range
[i
].flags
& IP_NAT_RANGE_PROTO_RANDOM
)
252 static struct iptables_target snat
= {
255 .version
= IPTABLES_VERSION
,
256 .size
= IPT_ALIGN(sizeof(struct ip_nat_multi_range
)),
257 .userspacesize
= IPT_ALIGN(sizeof(struct ip_nat_multi_range
)),
260 .final_check
= &final_check
,
268 register_target(&snat
);