1 /* Shared library add-on to iptables to add source-NAT support. */
8 #include <linux/netfilter_ipv4/ip_tables.h>
9 #include <linux/netfilter_ipv4/ip_nat_rule.h>
11 /* Source NAT data consists of a multi-range, indicating where to map
15 struct ipt_entry_target t
;
16 struct ip_nat_multi_range mr
;
19 /* Function which prints out usage message. */
25 " --to-source <ipaddr>[-<ipaddr>][:port-port]\n"
26 " Address to map source to.\n"
27 " (You can use this more than once)\n\n",
31 static struct option opts
[] = {
32 { "to-source", 1, 0, '1' },
36 static struct ipt_natinfo
*
37 append_range(struct ipt_natinfo
*info
, const struct ip_nat_range
*range
)
41 /* One rangesize already in struct ipt_natinfo */
42 size
= IPT_ALIGN(sizeof(*info
) + info
->mr
.rangesize
* sizeof(*range
));
44 info
= realloc(info
, size
);
46 exit_error(OTHER_PROBLEM
, "Out of memory\n");
48 info
->t
.u
.target_size
= size
;
49 info
->mr
.range
[info
->mr
.rangesize
] = *range
;
55 /* Ranges expected in network order. */
56 static struct ipt_entry_target
*
57 parse_to(char *arg
, int portok
, struct ipt_natinfo
*info
)
59 struct ip_nat_range range
;
60 char *colon
, *dash
, *error
;
63 memset(&range
, 0, sizeof(range
));
64 colon
= strchr(arg
, ':');
70 exit_error(PARAMETER_PROBLEM
,
71 "Need TCP or UDP with port specification");
73 range
.flags
|= IP_NAT_RANGE_PROTO_SPECIFIED
;
76 if (port
<= 0 || port
> 65535)
77 exit_error(PARAMETER_PROBLEM
,
78 "Port `%s' not valid\n", colon
+1);
80 error
= strchr(colon
+1, ':');
82 exit_error(PARAMETER_PROBLEM
,
83 "Invalid port:port syntax - use dash\n");
85 dash
= strchr(colon
, '-');
93 maxport
= atoi(dash
+ 1);
94 if (maxport
<= 0 || maxport
> 65535)
95 exit_error(PARAMETER_PROBLEM
,
96 "Port `%s' not valid\n", dash
+1);
98 /* People are stupid. */
99 exit_error(PARAMETER_PROBLEM
,
100 "Port range `%s' funky\n", colon
+1);
101 range
.min
.tcp
.port
= htons(port
);
102 range
.max
.tcp
.port
= htons(maxport
);
104 /* Starts with a colon? No IP info...*/
106 return &(append_range(info
, &range
)->t
);
110 range
.flags
|= IP_NAT_RANGE_MAP_IPS
;
111 dash
= strchr(arg
, '-');
112 if (colon
&& dash
&& dash
> colon
)
118 ip
= dotted_to_addr(arg
);
120 exit_error(PARAMETER_PROBLEM
, "Bad IP address `%s'\n",
122 range
.min_ip
= ip
->s_addr
;
124 ip
= dotted_to_addr(dash
+1);
126 exit_error(PARAMETER_PROBLEM
, "Bad IP address `%s'\n",
128 range
.max_ip
= ip
->s_addr
;
130 range
.max_ip
= range
.min_ip
;
132 return &(append_range(info
, &range
)->t
);
135 /* Function which parses command options; returns true if it
138 parse(int c
, char **argv
, int invert
, unsigned int *flags
,
139 const struct ipt_entry
*entry
,
140 struct ipt_entry_target
**target
)
142 struct ipt_natinfo
*info
= (void *)*target
;
145 if (entry
->ip
.proto
== IPPROTO_TCP
146 || entry
->ip
.proto
== IPPROTO_UDP
147 || entry
->ip
.proto
== IPPROTO_ICMP
)
154 if (check_inverse(optarg
, &invert
, NULL
, 0))
155 exit_error(PARAMETER_PROBLEM
,
156 "Unexpected `!' after --to-source");
160 get_kernel_version();
161 if (kernel_version
> LINUX_VERSION(2, 6, 10))
162 exit_error(PARAMETER_PROBLEM
,
163 "Multiple --to-source not supported");
165 *target
= parse_to(optarg
, portok
, info
);
174 /* Final check; must have specfied --to-source. */
175 static void final_check(unsigned int flags
)
178 exit_error(PARAMETER_PROBLEM
,
179 "You must specify --to-source");
182 static void print_range(const struct ip_nat_range
*r
)
184 if (r
->flags
& IP_NAT_RANGE_MAP_IPS
) {
187 a
.s_addr
= r
->min_ip
;
188 printf("%s", addr_to_dotted(&a
));
189 if (r
->max_ip
!= r
->min_ip
) {
190 a
.s_addr
= r
->max_ip
;
191 printf("-%s", addr_to_dotted(&a
));
194 if (r
->flags
& IP_NAT_RANGE_PROTO_SPECIFIED
) {
196 printf("%hu", ntohs(r
->min
.tcp
.port
));
197 if (r
->max
.tcp
.port
!= r
->min
.tcp
.port
)
198 printf("-%hu", ntohs(r
->max
.tcp
.port
));
202 /* Prints out the targinfo. */
204 print(const struct ipt_ip
*ip
,
205 const struct ipt_entry_target
*target
,
208 struct ipt_natinfo
*info
= (void *)target
;
212 for (i
= 0; i
< info
->mr
.rangesize
; i
++) {
213 print_range(&info
->mr
.range
[i
]);
218 /* Saves the union ipt_targinfo in parsable form to stdout. */
220 save(const struct ipt_ip
*ip
, const struct ipt_entry_target
*target
)
222 struct ipt_natinfo
*info
= (void *)target
;
225 for (i
= 0; i
< info
->mr
.rangesize
; i
++) {
226 printf("--to-source ");
227 print_range(&info
->mr
.range
[i
]);
232 static struct iptables_target snat
= {
235 .version
= IPTABLES_VERSION
,
236 .size
= IPT_ALIGN(sizeof(struct ip_nat_multi_range
)),
237 .userspacesize
= IPT_ALIGN(sizeof(struct ip_nat_multi_range
)),
240 .final_check
= &final_check
,
248 register_target(&snat
);