Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / iptables / extensions / libipt_DNAT.c
blob44b2968b70d6b6705ccde82785801d231ca10a58
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 <iptables.h>
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
15 to. */
16 struct ipt_natinfo
18 struct ipt_entry_target t;
19 struct ip_nat_multi_range mr;
22 /* Function which prints out usage message. */
23 static void
24 help(void)
26 printf(
27 "DNAT v%s options:\n"
28 " --to-destination <ipaddr>[-<ipaddr>][:port-port]\n"
29 " Address to map destination to.\n"
30 "[--random]\n"
31 "\n",
32 IPTABLES_VERSION);
35 static struct option opts[] = {
36 { "to-destination", 1, 0, '1' },
37 { "random", 0, 0, '2' },
38 { 0 }
41 static struct ipt_natinfo *
42 append_range(struct ipt_natinfo *info, const struct ip_nat_range *range)
44 unsigned int size;
46 /* One rangesize already in struct ipt_natinfo */
47 size = IPT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
49 info = realloc(info, size);
50 if (!info)
51 exit_error(OTHER_PROBLEM, "Out of memory\n");
53 info->t.u.target_size = size;
54 info->mr.range[info->mr.rangesize] = *range;
55 info->mr.rangesize++;
57 return info;
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;
66 struct in_addr *ip;
68 memset(&range, 0, sizeof(range));
69 colon = strchr(arg, ':');
71 if (colon) {
72 int port;
74 if (!portok)
75 exit_error(PARAMETER_PROBLEM,
76 "Need TCP or UDP with port specification");
78 range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
80 port = atoi(colon+1);
81 if (port <= 0 || port > 65535)
82 exit_error(PARAMETER_PROBLEM,
83 "Port `%s' not valid\n", colon+1);
85 error = strchr(colon+1, ':');
86 if (error)
87 exit_error(PARAMETER_PROBLEM,
88 "Invalid port:port syntax - use dash\n");
90 dash = strchr(colon, '-');
91 if (!dash) {
92 range.min.tcp.port
93 = range.max.tcp.port
94 = htons(port);
95 } else {
96 int maxport;
98 maxport = atoi(dash + 1);
99 if (maxport <= 0 || maxport > 65535)
100 exit_error(PARAMETER_PROBLEM,
101 "Port `%s' not valid\n", dash+1);
102 if (maxport < port)
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...*/
110 if (colon == arg)
111 return &(append_range(info, &range)->t);
112 *colon = '\0';
115 range.flags |= IP_NAT_RANGE_MAP_IPS;
116 dash = strchr(arg, '-');
117 if (colon && dash && dash > colon)
118 dash = NULL;
120 if (dash)
121 *dash = '\0';
123 ip = dotted_to_addr(arg);
124 if (!ip)
125 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
126 arg);
127 range.min_ip = ip->s_addr;
128 if (dash) {
129 ip = dotted_to_addr(dash+1);
130 if (!ip)
131 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
132 dash+1);
133 range.max_ip = ip->s_addr;
134 } else
135 range.max_ip = range.min_ip;
137 return &(append_range(info, &range)->t);
140 /* Function which parses command options; returns true if it
141 ate an option */
142 static int
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;
148 int portok;
150 if (entry->ip.proto == IPPROTO_TCP
151 || entry->ip.proto == IPPROTO_UDP
152 || entry->ip.proto == IPPROTO_ICMP)
153 portok = 1;
154 else
155 portok = 0;
157 switch (c) {
158 case '1':
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) {
164 if (!kernel_version)
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;
175 return 1;
177 case '2':
178 if (*flags & IPT_DNAT_OPT_DEST) {
179 info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
180 *flags |= IPT_DNAT_OPT_RANDOM;
181 } else
182 *flags |= IPT_DNAT_OPT_RANDOM;
183 return 1;
184 default:
185 return 0;
189 /* Final check; must have specfied --to-source. */
190 static void final_check(unsigned int flags)
192 if (!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) {
200 struct in_addr a;
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) {
210 printf(":");
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. */
218 static void
219 print(const struct ipt_ip *ip,
220 const struct ipt_entry_target *target,
221 int numeric)
223 struct ipt_natinfo *info = (void *)target;
224 unsigned int i = 0;
226 printf("to:");
227 for (i = 0; i < info->mr.rangesize; i++) {
228 print_range(&info->mr.range[i]);
229 printf(" ");
230 if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM)
231 printf("random ");
235 /* Saves the union ipt_targinfo in parsable form to stdout. */
236 static void
237 save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
239 struct ipt_natinfo *info = (void *)target;
240 unsigned int i = 0;
242 for (i = 0; i < info->mr.rangesize; i++) {
243 printf("--to-destination ");
244 print_range(&info->mr.range[i]);
245 printf(" ");
246 if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM)
247 printf("--random ");
251 static struct iptables_target dnat = {
252 .next = NULL,
253 .name = "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)),
257 .help = &help,
258 .parse = &parse,
259 .final_check = &final_check,
260 .print = &print,
261 .save = &save,
262 .extra_opts = opts
265 void _init(void)
267 register_target(&dnat);