1 /* Shared library add-on to iptables to add destination-NAT support. */
8 #include <linux/netfilter_ipv4/ip_tables.h>
9 #include <linux/netfilter/nf_nat.h>
11 #define IPT_DNAT_OPT_DEST 0x1
12 #define IPT_DNAT_OPT_RANDOM 0x2
14 /* Dest 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-destination <ipaddr>[-<ipaddr>][:port-port]\n"
29 " Address to map destination to.\n"
35 static struct option opts
[] = {
36 { "to-destination", 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-destination");
163 if (*flags
& IPT_DNAT_OPT_DEST
) {
165 get_kernel_version();
166 if (kernel_version
> LINUX_VERSION(2, 6, 10))
167 exit_error(PARAMETER_PROBLEM
,
168 "Multiple --to-destination not supported");
170 *target
= parse_to(optarg
, portok
, info
);
171 /* WTF do we need this for?? */
172 if (*flags
& IPT_DNAT_OPT_RANDOM
)
173 info
->mr
.range
[0].flags
|= IP_NAT_RANGE_PROTO_RANDOM
;
174 *flags
|= IPT_DNAT_OPT_DEST
;
178 if (*flags
& IPT_DNAT_OPT_DEST
) {
179 info
->mr
.range
[0].flags
|= IP_NAT_RANGE_PROTO_RANDOM
;
180 *flags
|= IPT_DNAT_OPT_RANDOM
;
182 *flags
|= IPT_DNAT_OPT_RANDOM
;
189 /* Final check; must have specfied --to-source. */
190 static void final_check(unsigned int flags
)
193 exit_error(PARAMETER_PROBLEM
,
194 "You must specify --to-destination");
197 static void print_range(const struct ip_nat_range
*r
)
199 if (r
->flags
& IP_NAT_RANGE_MAP_IPS
) {
202 a
.s_addr
= r
->min_ip
;
203 printf("%s", addr_to_dotted(&a
));
204 if (r
->max_ip
!= r
->min_ip
) {
205 a
.s_addr
= r
->max_ip
;
206 printf("-%s", addr_to_dotted(&a
));
209 if (r
->flags
& IP_NAT_RANGE_PROTO_SPECIFIED
) {
211 printf("%hu", ntohs(r
->min
.tcp
.port
));
212 if (r
->max
.tcp
.port
!= r
->min
.tcp
.port
)
213 printf("-%hu", ntohs(r
->max
.tcp
.port
));
217 /* Prints out the targinfo. */
219 print(const struct ipt_ip
*ip
,
220 const struct ipt_entry_target
*target
,
223 struct ipt_natinfo
*info
= (void *)target
;
227 for (i
= 0; i
< info
->mr
.rangesize
; i
++) {
228 print_range(&info
->mr
.range
[i
]);
230 if (info
->mr
.range
[i
].flags
& IP_NAT_RANGE_PROTO_RANDOM
)
235 /* Saves the union ipt_targinfo in parsable form to stdout. */
237 save(const struct ipt_ip
*ip
, const struct ipt_entry_target
*target
)
239 struct ipt_natinfo
*info
= (void *)target
;
242 for (i
= 0; i
< info
->mr
.rangesize
; i
++) {
243 printf("--to-destination ");
244 print_range(&info
->mr
.range
[i
]);
246 if (info
->mr
.range
[i
].flags
& IP_NAT_RANGE_PROTO_RANDOM
)
251 static struct iptables_target dnat
= {
254 .version
= IPTABLES_VERSION
,
255 .size
= IPT_ALIGN(sizeof(struct ip_nat_multi_range
)),
256 .userspacesize
= IPT_ALIGN(sizeof(struct ip_nat_multi_range
)),
259 .final_check
= &final_check
,
267 register_target(&dnat
);