manpages: do not include v4-only modules in ip6tables manpage
[jleu-iptables.git] / extensions / libipt_DNAT.c
blob8b2caecd65b2bcdaefeb5aa190d64e9a82e07b2c
1 /* Shared library add-on to iptables to add destination-NAT 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 <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
17 to. */
18 struct ipt_natinfo
20 struct xt_entry_target t;
21 struct nf_nat_multi_range mr;
24 static void DNAT_help(void)
26 printf(
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' },
37 { .name = NULL }
40 static struct ipt_natinfo *
41 append_range(struct ipt_natinfo *info, const struct nf_nat_range *range)
43 unsigned int size;
45 /* One rangesize already in struct ipt_natinfo */
46 size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
48 info = realloc(info, size);
49 if (!info)
50 xtables_error(OTHER_PROBLEM, "Out of memory\n");
52 info->t.u.target_size = size;
53 info->mr.range[info->mr.rangesize] = *range;
54 info->mr.rangesize++;
56 return info;
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, ':');
70 if (colon) {
71 int port;
73 if (!portok)
74 xtables_error(PARAMETER_PROBLEM,
75 "Need TCP, UDP, SCTP or DCCP with port specification");
77 range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
79 port = atoi(colon+1);
80 if (port <= 0 || port > 65535)
81 xtables_error(PARAMETER_PROBLEM,
82 "Port `%s' not valid\n", colon+1);
84 error = strchr(colon+1, ':');
85 if (error)
86 xtables_error(PARAMETER_PROBLEM,
87 "Invalid port:port syntax - use dash\n");
89 dash = strchr(colon, '-');
90 if (!dash) {
91 range.min.tcp.port
92 = range.max.tcp.port
93 = htons(port);
94 } else {
95 int maxport;
97 maxport = atoi(dash + 1);
98 if (maxport <= 0 || maxport > 65535)
99 xtables_error(PARAMETER_PROBLEM,
100 "Port `%s' not valid\n", dash+1);
101 if (maxport < port)
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...*/
109 if (colon == arg)
110 return &(append_range(info, &range)->t);
111 *colon = '\0';
114 range.flags |= IP_NAT_RANGE_MAP_IPS;
115 dash = strchr(arg, '-');
116 if (colon && dash && dash > colon)
117 dash = NULL;
119 if (dash)
120 *dash = '\0';
122 ip = xtables_numeric_to_ipaddr(arg);
123 if (!ip)
124 xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
125 arg);
126 range.min_ip = ip->s_addr;
127 if (dash) {
128 ip = xtables_numeric_to_ipaddr(dash+1);
129 if (!ip)
130 xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
131 dash+1);
132 range.max_ip = ip->s_addr;
133 } else
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;
144 int portok;
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)
151 portok = 1;
152 else
153 portok = 0;
155 switch (c) {
156 case '1':
157 if (xtables_check_inverse(optarg, &invert, NULL, 0))
158 xtables_error(PARAMETER_PROBLEM,
159 "Unexpected `!' after --to-destination");
161 if (*flags) {
162 if (!kernel_version)
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;
173 return 1;
175 case '2':
176 if (*flags & IPT_DNAT_OPT_DEST) {
177 info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
178 *flags |= IPT_DNAT_OPT_RANDOM;
179 } else
180 *flags |= IPT_DNAT_OPT_RANDOM;
181 return 1;
183 case '3':
184 info->mr.range[0].flags |= IP_NAT_RANGE_PERSISTENT;
185 return 1;
187 default:
188 return 0;
192 static void DNAT_check(unsigned int flags)
194 if (!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) {
202 struct in_addr a;
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) {
212 printf(":");
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,
220 int numeric)
222 const struct ipt_natinfo *info = (const void *)target;
223 unsigned int i = 0;
225 printf("to:");
226 for (i = 0; i < info->mr.rangesize; i++) {
227 print_range(&info->mr.range[i]);
228 printf(" ");
229 if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM)
230 printf("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;
239 unsigned int i = 0;
241 for (i = 0; i < info->mr.rangesize; i++) {
242 printf("--to-destination ");
243 print_range(&info->mr.range[i]);
244 printf(" ");
245 if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM)
246 printf("--random ");
247 if (info->mr.range[i].flags & IP_NAT_RANGE_PERSISTENT)
248 printf("--persistent ");
252 static struct xtables_target dnat_tg_reg = {
253 .name = "DNAT",
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)),
258 .help = DNAT_help,
259 .parse = DNAT_parse,
260 .final_check = DNAT_check,
261 .print = DNAT_print,
262 .save = DNAT_save,
263 .extra_opts = DNAT_opts,
266 void _init(void)
268 xtables_register_target(&dnat_tg_reg);