1 /* Shared library add-on to iptables to add destination-NAT support. */
8 #include <iptables.h> /* get_kernel_version */
9 #include <limits.h> /* INT_MAX in ip_tables.h */
10 #include <linux/netfilter_ipv4/ip_tables.h>
11 #include <net/netfilter/nf_nat.h>
13 #define IPT_DNAT_OPT_DEST 0x1
14 #define IPT_DNAT_OPT_RANDOM 0x2
16 /* Dest NAT data consists of a multi-range, indicating where to map
20 struct xt_entry_target t
;
21 struct nf_nat_multi_range mr
;
24 static void DNAT_help(void)
27 "DNAT target options:\n"
28 " --to-destination <ipaddr>[-<ipaddr>][:port-port]\n"
29 " Address to map destination to.\n"
30 "[--random] [--persistent]\n");
33 static const struct option DNAT_opts
[] = {
34 { "to-destination", 1, NULL
, '1' },
35 { "random", 0, NULL
, '2' },
36 { "persistent", 0, NULL
, '3' },
40 static struct ipt_natinfo
*
41 append_range(struct ipt_natinfo
*info
, const struct nf_nat_range
*range
)
45 /* One rangesize already in struct ipt_natinfo */
46 size
= XT_ALIGN(sizeof(*info
) + info
->mr
.rangesize
* sizeof(*range
));
48 info
= realloc(info
, size
);
50 xtables_error(OTHER_PROBLEM
, "Out of memory\n");
52 info
->t
.u
.target_size
= size
;
53 info
->mr
.range
[info
->mr
.rangesize
] = *range
;
59 /* Ranges expected in network order. */
60 static struct xt_entry_target
*
61 parse_to(char *arg
, int portok
, struct ipt_natinfo
*info
)
63 struct nf_nat_range range
;
64 char *colon
, *dash
, *error
;
65 const struct in_addr
*ip
;
67 memset(&range
, 0, sizeof(range
));
68 colon
= strchr(arg
, ':');
74 xtables_error(PARAMETER_PROBLEM
,
75 "Need TCP, UDP, SCTP or DCCP with port specification");
77 range
.flags
|= IP_NAT_RANGE_PROTO_SPECIFIED
;
80 if (port
<= 0 || port
> 65535)
81 xtables_error(PARAMETER_PROBLEM
,
82 "Port `%s' not valid\n", colon
+1);
84 error
= strchr(colon
+1, ':');
86 xtables_error(PARAMETER_PROBLEM
,
87 "Invalid port:port syntax - use dash\n");
89 dash
= strchr(colon
, '-');
97 maxport
= atoi(dash
+ 1);
98 if (maxport
<= 0 || maxport
> 65535)
99 xtables_error(PARAMETER_PROBLEM
,
100 "Port `%s' not valid\n", dash
+1);
102 /* People are stupid. */
103 xtables_error(PARAMETER_PROBLEM
,
104 "Port range `%s' funky\n", colon
+1);
105 range
.min
.tcp
.port
= htons(port
);
106 range
.max
.tcp
.port
= htons(maxport
);
108 /* Starts with a colon? No IP info...*/
110 return &(append_range(info
, &range
)->t
);
114 range
.flags
|= IP_NAT_RANGE_MAP_IPS
;
115 dash
= strchr(arg
, '-');
116 if (colon
&& dash
&& dash
> colon
)
122 ip
= xtables_numeric_to_ipaddr(arg
);
124 xtables_error(PARAMETER_PROBLEM
, "Bad IP address \"%s\"\n",
126 range
.min_ip
= ip
->s_addr
;
128 ip
= xtables_numeric_to_ipaddr(dash
+1);
130 xtables_error(PARAMETER_PROBLEM
, "Bad IP address \"%s\"\n",
132 range
.max_ip
= ip
->s_addr
;
134 range
.max_ip
= range
.min_ip
;
136 return &(append_range(info
, &range
)->t
);
139 static int DNAT_parse(int c
, char **argv
, int invert
, unsigned int *flags
,
140 const void *e
, struct xt_entry_target
**target
)
142 const struct ipt_entry
*entry
= e
;
143 struct ipt_natinfo
*info
= (void *)*target
;
146 if (entry
->ip
.proto
== IPPROTO_TCP
147 || entry
->ip
.proto
== IPPROTO_UDP
148 || entry
->ip
.proto
== IPPROTO_SCTP
149 || entry
->ip
.proto
== IPPROTO_DCCP
150 || entry
->ip
.proto
== IPPROTO_ICMP
)
157 if (xtables_check_inverse(optarg
, &invert
, NULL
, 0))
158 xtables_error(PARAMETER_PROBLEM
,
159 "Unexpected `!' after --to-destination");
163 get_kernel_version();
164 if (kernel_version
> LINUX_VERSION(2, 6, 10))
165 xtables_error(PARAMETER_PROBLEM
,
166 "Multiple --to-destination not supported");
168 *target
= parse_to(optarg
, portok
, info
);
169 /* WTF do we need this for?? */
170 if (*flags
& IPT_DNAT_OPT_RANDOM
)
171 info
->mr
.range
[0].flags
|= IP_NAT_RANGE_PROTO_RANDOM
;
172 *flags
|= IPT_DNAT_OPT_DEST
;
176 if (*flags
& IPT_DNAT_OPT_DEST
) {
177 info
->mr
.range
[0].flags
|= IP_NAT_RANGE_PROTO_RANDOM
;
178 *flags
|= IPT_DNAT_OPT_RANDOM
;
180 *flags
|= IPT_DNAT_OPT_RANDOM
;
184 info
->mr
.range
[0].flags
|= IP_NAT_RANGE_PERSISTENT
;
192 static void DNAT_check(unsigned int flags
)
195 xtables_error(PARAMETER_PROBLEM
,
196 "You must specify --to-destination");
199 static void print_range(const struct nf_nat_range
*r
)
201 if (r
->flags
& IP_NAT_RANGE_MAP_IPS
) {
204 a
.s_addr
= r
->min_ip
;
205 printf("%s", xtables_ipaddr_to_numeric(&a
));
206 if (r
->max_ip
!= r
->min_ip
) {
207 a
.s_addr
= r
->max_ip
;
208 printf("-%s", xtables_ipaddr_to_numeric(&a
));
211 if (r
->flags
& IP_NAT_RANGE_PROTO_SPECIFIED
) {
213 printf("%hu", ntohs(r
->min
.tcp
.port
));
214 if (r
->max
.tcp
.port
!= r
->min
.tcp
.port
)
215 printf("-%hu", ntohs(r
->max
.tcp
.port
));
219 static void DNAT_print(const void *ip
, const struct xt_entry_target
*target
,
222 const struct ipt_natinfo
*info
= (const void *)target
;
226 for (i
= 0; i
< info
->mr
.rangesize
; i
++) {
227 print_range(&info
->mr
.range
[i
]);
229 if (info
->mr
.range
[i
].flags
& IP_NAT_RANGE_PROTO_RANDOM
)
231 if (info
->mr
.range
[i
].flags
& IP_NAT_RANGE_PERSISTENT
)
232 printf("persistent ");
236 static void DNAT_save(const void *ip
, const struct xt_entry_target
*target
)
238 const struct ipt_natinfo
*info
= (const void *)target
;
241 for (i
= 0; i
< info
->mr
.rangesize
; i
++) {
242 printf("--to-destination ");
243 print_range(&info
->mr
.range
[i
]);
245 if (info
->mr
.range
[i
].flags
& IP_NAT_RANGE_PROTO_RANDOM
)
247 if (info
->mr
.range
[i
].flags
& IP_NAT_RANGE_PERSISTENT
)
248 printf("--persistent ");
252 static struct xtables_target dnat_tg_reg
= {
254 .version
= XTABLES_VERSION
,
255 .family
= NFPROTO_IPV4
,
256 .size
= XT_ALIGN(sizeof(struct nf_nat_multi_range
)),
257 .userspacesize
= XT_ALIGN(sizeof(struct nf_nat_multi_range
)),
260 .final_check
= DNAT_check
,
263 .extra_opts
= DNAT_opts
,
268 xtables_register_target(&dnat_tg_reg
);