xref: /aosp_15_r20/external/iptables/extensions/libxt_NAT.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
1 /*
2  * Copyright (c) 2011 Patrick McHardy <[email protected]>
3  *
4  * Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT
5  * funded by Astaro.
6  */
7 
8 #include <stdio.h>
9 #include <netdb.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <xtables.h>
13 #include <iptables.h> /* get_kernel_version */
14 #include <limits.h> /* INT_MAX in ip_tables.h */
15 #include <arpa/inet.h>
16 #include <linux/netfilter_ipv4/ip_tables.h>
17 #include <linux/netfilter_ipv6/ip6_tables.h>
18 #include <linux/netfilter/nf_nat.h>
19 
20 #define TO_IPV4_MRC(ptr) ((const struct nf_nat_ipv4_multi_range_compat *)(ptr))
21 #define RANGE2_INIT_FROM_IPV4_MRC(ptr) {			\
22 	.flags		= TO_IPV4_MRC(ptr)->range[0].flags,	\
23 	.min_addr.ip	= TO_IPV4_MRC(ptr)->range[0].min_ip,	\
24 	.max_addr.ip	= TO_IPV4_MRC(ptr)->range[0].max_ip,	\
25 	.min_proto	= TO_IPV4_MRC(ptr)->range[0].min,	\
26 	.max_proto	= TO_IPV4_MRC(ptr)->range[0].max,	\
27 };
28 #define TO_NF_NAT_RANGE(ptr) ((const struct nf_nat_range *)(ptr))
29 #define RANGE2_INIT_FROM_RANGE(ptr) {				\
30 	.flags		= TO_NF_NAT_RANGE(ptr)->flags,		\
31 	.min_addr	= TO_NF_NAT_RANGE(ptr)->min_addr,	\
32 	.max_addr	= TO_NF_NAT_RANGE(ptr)->max_addr,	\
33 	.min_proto	= TO_NF_NAT_RANGE(ptr)->min_proto,	\
34 	.max_proto	= TO_NF_NAT_RANGE(ptr)->max_proto,	\
35 };
36 
37 enum {
38 	O_TO_DEST = 0,
39 	O_TO_SRC,
40 	O_TO_PORTS,
41 	O_RANDOM,
42 	O_RANDOM_FULLY,
43 	O_PERSISTENT,
44 };
45 
SNAT_help(void)46 static void SNAT_help(void)
47 {
48 	printf(
49 "SNAT target options:\n"
50 " --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
51 "				Address to map source to.\n"
52 "[--random] [--random-fully] [--persistent]\n");
53 }
54 
MASQUERADE_help(void)55 static void MASQUERADE_help(void)
56 {
57 	printf(
58 "MASQUERADE target options:\n"
59 " --to-ports <port>[-<port>]\n"
60 "				Port (range) to map to.\n"
61 " --random\n"
62 "				Randomize source port.\n"
63 " --random-fully\n"
64 "				Fully randomize source port.\n");
65 }
66 
DNAT_help(void)67 static void DNAT_help(void)
68 {
69 	printf(
70 "DNAT target options:\n"
71 " --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
72 "				Address to map destination to.\n"
73 "[--random] [--persistent]\n");
74 }
75 
DNAT_help_v2(void)76 static void DNAT_help_v2(void)
77 {
78 	printf(
79 "DNAT target options:\n"
80 " --to-destination [<ipaddr>[-<ipaddr>]][:port[-port[/port]]]\n"
81 "				Address to map destination to.\n"
82 "[--random] [--persistent]\n");
83 }
84 
REDIRECT_help(void)85 static void REDIRECT_help(void)
86 {
87 	printf(
88 "REDIRECT target options:\n"
89 " --to-ports <port>[-<port>]\n"
90 "				Port (range) to map to.\n"
91 " [--random]\n");
92 }
93 
94 static const struct xt_option_entry SNAT_opts[] = {
95 	{.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING,
96 	 .flags = XTOPT_MAND},
97 	{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
98 	{.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE},
99 	{.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
100 	XTOPT_TABLEEND,
101 };
102 
103 static const struct xt_option_entry MASQUERADE_opts[] = {
104 	{.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
105 	{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
106 	{.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE},
107 	XTOPT_TABLEEND,
108 };
109 
110 static const struct xt_option_entry DNAT_opts[] = {
111 	{.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING,
112 	 .flags = XTOPT_MAND},
113 	{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
114 	{.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
115 	XTOPT_TABLEEND,
116 };
117 
118 static const struct xt_option_entry REDIRECT_opts[] = {
119 	{.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
120 	{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
121 	XTOPT_TABLEEND,
122 };
123 
124 /* Parses ports */
125 static void
parse_ports(const char * arg,bool portok,struct nf_nat_range2 * range)126 parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range)
127 {
128 	unsigned int port, maxport, baseport;
129 	char *end = NULL;
130 
131 	if (!portok)
132 		xtables_error(PARAMETER_PROBLEM,
133 			      "Need TCP, UDP, SCTP or DCCP with port specification");
134 
135 	range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
136 
137 	if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) {
138 		port = xtables_service_to_port(arg, NULL);
139 		if (port == (unsigned)-1)
140 			xtables_error(PARAMETER_PROBLEM,
141 				      "Port `%s' not valid", arg);
142 		end = "";
143 	}
144 
145 	switch (*end) {
146 	case '\0':
147 		range->min_proto.tcp.port
148 			= range->max_proto.tcp.port
149 			= htons(port);
150 		return;
151 	case '-':
152 		arg = end + 1;
153 		break;
154 	case ':':
155 		xtables_error(PARAMETER_PROBLEM,
156 			      "Invalid port:port syntax - use dash");
157 	default:
158 		xtables_error(PARAMETER_PROBLEM,
159 			      "Garbage after port value: `%s'", end);
160 	}
161 
162 	/* it is a range, don't allow service names here */
163 	if (!xtables_strtoui(arg, &end, &maxport, 0, UINT16_MAX))
164 		xtables_error(PARAMETER_PROBLEM, "Port `%s' not valid", arg);
165 
166 	if (maxport < port)
167 		/* People are stupid. */
168 		xtables_error(PARAMETER_PROBLEM,
169 			   "Port range `%s' funky", arg);
170 
171 	range->min_proto.tcp.port = htons(port);
172 	range->max_proto.tcp.port = htons(maxport);
173 
174 	switch (*end) {
175 	case '\0':
176 		return;
177 	case '/':
178 		arg = end + 1;
179 		break;
180 	default:
181 		xtables_error(PARAMETER_PROBLEM,
182 			      "Garbage after port range: `%s'", end);
183 	}
184 
185 	if (!xtables_strtoui(arg, &end, &baseport, 1, UINT16_MAX)) {
186 		baseport = xtables_service_to_port(arg, NULL);
187 		if (baseport == (unsigned)-1)
188 			xtables_error(PARAMETER_PROBLEM,
189 				      "Port `%s' not valid", arg);
190 	}
191 
192 	range->flags |= NF_NAT_RANGE_PROTO_OFFSET;
193 	range->base_proto.tcp.port = htons(baseport);
194 }
195 
196 /* Ranges expected in network order. */
197 static void
parse_to(const char * orig_arg,bool portok,struct nf_nat_range2 * range,int family)198 parse_to(const char *orig_arg, bool portok,
199 	 struct nf_nat_range2 *range, int family)
200 {
201 	char *arg, *start, *end, *colon, *dash;
202 
203 	arg = xtables_strdup(orig_arg);
204 	start = strchr(arg, '[');
205 	if (!start) {
206 		start = arg;
207 		/* Lets assume one colon is port information.
208 		 * Otherwise its an IPv6 address */
209 		colon = strchr(arg, ':');
210 		if (colon && strchr(colon + 1, ':'))
211 			colon = NULL;
212 	} else {
213 		start++;
214 		end = strchr(start, ']');
215 		if (end == NULL || family == AF_INET)
216 			xtables_error(PARAMETER_PROBLEM,
217 				      "Invalid address format");
218 
219 		*end = '\0';
220 		colon = strchr(end + 1, ':');
221 	}
222 
223 	if (colon) {
224 		parse_ports(colon + 1, portok, range);
225 
226 		/* Starts with colon or [] colon? No IP info...*/
227 		if (colon == arg || colon == arg + 2) {
228 			free(arg);
229 			return;
230 		}
231 		*colon = '\0';
232 	}
233 
234 	range->flags |= NF_NAT_RANGE_MAP_IPS;
235 	dash = strchr(start, '-');
236 	if (colon && dash && dash > colon)
237 		dash = NULL;
238 
239 	if (dash)
240 		*dash = '\0';
241 
242 	if (!inet_pton(family, start, &range->min_addr))
243 		xtables_error(PARAMETER_PROBLEM,
244 			      "Bad IP address \"%s\"", start);
245 	if (dash) {
246 		if (!inet_pton(family, dash + 1, &range->max_addr))
247 			xtables_error(PARAMETER_PROBLEM,
248 				      "Bad IP address \"%s\"", dash + 1);
249 	} else {
250 		range->max_addr = range->min_addr;
251 	}
252 	free(arg);
253 	return;
254 }
255 
__NAT_parse(struct xt_option_call * cb,__u16 proto,struct nf_nat_range2 * range,int family)256 static void __NAT_parse(struct xt_option_call *cb, __u16 proto,
257 			struct nf_nat_range2 *range, int family)
258 {
259 	bool portok = proto == IPPROTO_TCP ||
260 		      proto == IPPROTO_UDP ||
261 		      proto == IPPROTO_SCTP ||
262 		      proto == IPPROTO_DCCP ||
263 		      proto == IPPROTO_ICMP;
264 
265 	xtables_option_parse(cb);
266 	switch (cb->entry->id) {
267 	case O_TO_DEST:
268 	case O_TO_SRC:
269 		parse_to(cb->arg, portok, range, family);
270 		break;
271 	case O_TO_PORTS:
272 		parse_ports(cb->arg, portok, range);
273 		break;
274 	case O_PERSISTENT:
275 		range->flags |= NF_NAT_RANGE_PERSISTENT;
276 		break;
277 	case O_RANDOM:
278 		range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
279 		break;
280 	case O_RANDOM_FULLY:
281 		range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY;
282 		break;
283 	}
284 }
285 
NAT_parse(struct xt_option_call * cb)286 static void NAT_parse(struct xt_option_call *cb)
287 {
288 	struct nf_nat_ipv4_multi_range_compat *mr = (void *)cb->data;
289 	const struct ipt_entry *entry = cb->xt_entry;
290 	struct nf_nat_range2 range = {};
291 
292 	__NAT_parse(cb, entry->ip.proto, &range, AF_INET);
293 
294 	switch (cb->entry->id) {
295 	case O_TO_DEST:
296 	case O_TO_SRC:
297 		mr->range->min_ip = range.min_addr.ip;
298 		mr->range->max_ip = range.max_addr.ip;
299 		/* fall through */
300 	case O_TO_PORTS:
301 		mr->range->min = range.min_proto;
302 		mr->range->max = range.max_proto;
303 		/* fall through */
304 	case O_PERSISTENT:
305 	case O_RANDOM:
306 	case O_RANDOM_FULLY:
307 		mr->range->flags |= range.flags;
308 		break;
309 	}
310 }
311 
NAT_parse6(struct xt_option_call * cb)312 static void NAT_parse6(struct xt_option_call *cb)
313 {
314 	struct nf_nat_range2 range = RANGE2_INIT_FROM_RANGE(cb->data);
315 	struct nf_nat_range *range_v1 = (void *)cb->data;
316 	const struct ip6t_entry *entry = cb->xt_entry;
317 
318 	__NAT_parse(cb, entry->ipv6.proto, &range, AF_INET6);
319 	memcpy(range_v1, &range, sizeof(*range_v1));
320 }
321 
DNAT_parse_v2(struct xt_option_call * cb)322 static void DNAT_parse_v2(struct xt_option_call *cb)
323 {
324 	const struct ipt_entry *entry = cb->xt_entry;
325 
326 	__NAT_parse(cb, entry->ip.proto, cb->data, AF_INET);
327 }
328 
DNAT_parse6_v2(struct xt_option_call * cb)329 static void DNAT_parse6_v2(struct xt_option_call *cb)
330 {
331 	const struct ip6t_entry *entry = cb->xt_entry;
332 
333 	__NAT_parse(cb, entry->ipv6.proto, cb->data, AF_INET6);
334 }
335 
SNAT_fcheck(struct xt_fcheck_call * cb)336 static void SNAT_fcheck(struct xt_fcheck_call *cb)
337 {
338 	struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
339 
340 	mr->rangesize = 1;
341 }
342 
DNAT_fcheck(struct xt_fcheck_call * cb)343 static void DNAT_fcheck(struct xt_fcheck_call *cb)
344 {
345 	struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
346 
347 	mr->rangesize = 1;
348 
349 	if (mr->range[0].flags & NF_NAT_RANGE_PROTO_OFFSET)
350 		xtables_error(PARAMETER_PROBLEM,
351 			      "Shifted portmap ranges not supported with this kernel");
352 }
353 
DNAT_fcheck6(struct xt_fcheck_call * cb)354 static void DNAT_fcheck6(struct xt_fcheck_call *cb)
355 {
356 	struct nf_nat_range *range = (void *)cb->data;
357 
358 	if (range->flags & NF_NAT_RANGE_PROTO_OFFSET)
359 		xtables_error(PARAMETER_PROBLEM,
360 			      "Shifted portmap ranges not supported with this kernel");
361 }
362 
sprint_range(const struct nf_nat_range2 * r,int family)363 static char *sprint_range(const struct nf_nat_range2 *r, int family)
364 {
365 	bool brackets = family == AF_INET6 &&
366 			r->flags & NF_NAT_RANGE_PROTO_SPECIFIED;
367 	static char buf[INET6_ADDRSTRLEN * 2 + 3 + 6 * 3];
368 
369 	buf[0] = '\0';
370 
371 	if (r->flags & NF_NAT_RANGE_MAP_IPS) {
372 		if (brackets)
373 			strcat(buf, "[");
374 		inet_ntop(family, &r->min_addr,
375 			  buf + strlen(buf), INET6_ADDRSTRLEN);
376 		if (memcmp(&r->min_addr, &r->max_addr, sizeof(r->min_addr))) {
377 			strcat(buf, "-");
378 			inet_ntop(family, &r->max_addr,
379 				  buf + strlen(buf), INET6_ADDRSTRLEN);
380 		}
381 		if (brackets)
382 			strcat(buf, "]");
383 	}
384 	if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
385 		sprintf(buf + strlen(buf), ":%hu",
386 			ntohs(r->min_proto.tcp.port));
387 		if (r->max_proto.tcp.port != r->min_proto.tcp.port)
388 			sprintf(buf + strlen(buf), "-%hu",
389 				ntohs(r->max_proto.tcp.port));
390 		if (r->flags & NF_NAT_RANGE_PROTO_OFFSET)
391 			sprintf(buf + strlen(buf), "/%hu",
392 				ntohs(r->base_proto.tcp.port));
393 	}
394 	return buf;
395 }
396 
__NAT_print(const struct nf_nat_range2 * r,int family,const char * rangeopt,const char * flag_pfx,bool skip_colon)397 static void __NAT_print(const struct nf_nat_range2 *r, int family,
398 			const char *rangeopt, const char *flag_pfx,
399 			bool skip_colon)
400 {
401 	char *range_str = sprint_range(r, family);
402 
403 	if (strlen(range_str)) {
404 		if (range_str[0] == ':' && skip_colon)
405 			range_str++;
406 		printf(" %s%s", rangeopt, range_str);
407 	}
408 	if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
409 		printf(" %srandom", flag_pfx);
410 	if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
411 		printf(" %srandom-fully", flag_pfx);
412 	if (r->flags & NF_NAT_RANGE_PERSISTENT)
413 		printf(" %spersistent", flag_pfx);
414 }
415 
416 static int
__NAT_xlate(struct xt_xlate * xl,const struct nf_nat_range2 * r,int family,const char * tgt)417 __NAT_xlate(struct xt_xlate *xl, const struct nf_nat_range2 *r,
418 	     int family, const char *tgt)
419 {
420 	char *range_str = sprint_range(r, family);
421 	const char *sep = " ";
422 
423 	/* shifted portmap ranges are not supported by nftables */
424 	if (r->flags & NF_NAT_RANGE_PROTO_OFFSET)
425 		return 0;
426 
427 	xt_xlate_add(xl, "%s", tgt);
428 	if (strlen(range_str))
429 		xt_xlate_add(xl, " to %s", range_str);
430 	if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) {
431 		xt_xlate_add(xl, "%srandom", sep);
432 		sep = ",";
433 	}
434 	if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
435 		xt_xlate_add(xl, "%sfully-random", sep);
436 		sep = ",";
437 	}
438 	if (r->flags & NF_NAT_RANGE_PERSISTENT) {
439 		xt_xlate_add(xl, "%spersistent", sep);
440 		sep = ",";
441 	}
442 	return 1;
443 }
444 
445 #define PSX_GEN(name, converter, family,                                       \
446 		print_rangeopt, save_rangeopt, skip_colon, xlate)              \
447 static void name##_print(const void *ip, const struct xt_entry_target *target, \
448 			 int numeric)                                          \
449 {                                                                              \
450 	struct nf_nat_range2 range = converter(target->data);                  \
451 	                                                                       \
452 	__NAT_print(&range, family, print_rangeopt, "", skip_colon);           \
453 }                                                                              \
454 static void name##_save(const void *ip, const struct xt_entry_target *target)  \
455 {                                                                              \
456 	struct nf_nat_range2 range = converter(target->data);                  \
457 	                                                                       \
458 	__NAT_print(&range, family, save_rangeopt, "--", skip_colon);          \
459 }                                                                              \
460 static int name##_xlate(struct xt_xlate *xl,                                   \
461 			const struct xt_xlate_tg_params *params)               \
462 {                                                                              \
463 	struct nf_nat_range2 range = converter(params->target->data);          \
464 	                                                                       \
465 	return __NAT_xlate(xl, &range, family, xlate);                         \
466 }
467 
468 PSX_GEN(DNAT, RANGE2_INIT_FROM_IPV4_MRC, \
469 	AF_INET, "to:", "--to-destination ", false, "dnat")
470 
471 PSX_GEN(DNATv2, *(struct nf_nat_range2 *), \
472 	AF_INET, "to:", "--to-destination ", false, "dnat")
473 
474 PSX_GEN(DNAT6, RANGE2_INIT_FROM_RANGE, \
475 	AF_INET6, "to:", "--to-destination ", false, "dnat")
476 
477 PSX_GEN(DNAT6v2, *(struct nf_nat_range2 *), \
478 	AF_INET6, "to:", "--to-destination ", false, "dnat")
479 
480 PSX_GEN(REDIRECT, RANGE2_INIT_FROM_IPV4_MRC, \
481 	AF_INET, "redir ports ", "--to-ports ", true, "redirect")
482 
483 PSX_GEN(REDIRECT6, RANGE2_INIT_FROM_RANGE, \
484 	AF_INET6, "redir ports ", "--to-ports ", true, "redirect")
485 
486 PSX_GEN(SNAT, RANGE2_INIT_FROM_IPV4_MRC, \
487 	AF_INET, "to:", "--to-source ", false, "snat")
488 
489 PSX_GEN(SNAT6, RANGE2_INIT_FROM_RANGE, \
490 	AF_INET6, "to:", "--to-source ", false, "snat")
491 
492 PSX_GEN(MASQUERADE, RANGE2_INIT_FROM_IPV4_MRC, \
493 	AF_INET, "masq ports: ", "--to-ports ", true, "masquerade")
494 
495 PSX_GEN(MASQUERADE6, RANGE2_INIT_FROM_RANGE, \
496 	AF_INET6, "masq ports: ", "--to-ports ", true, "masquerade")
497 
498 static struct xtables_target nat_tg_reg[] = {
499 	{
500 		.name		= "SNAT",
501 		.version	= XTABLES_VERSION,
502 		.family		= NFPROTO_IPV4,
503 		.size		= XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
504 		.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
505 		.help		= SNAT_help,
506 		.x6_parse	= NAT_parse,
507 		.x6_fcheck	= SNAT_fcheck,
508 		.print		= SNAT_print,
509 		.save		= SNAT_save,
510 		.x6_options	= SNAT_opts,
511 		.xlate		= SNAT_xlate,
512 	},
513 	{
514 		.name		= "DNAT",
515 		.version	= XTABLES_VERSION,
516 		.family		= NFPROTO_IPV4,
517 		.revision	= 0,
518 		.size		= XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
519 		.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
520 		.help		= DNAT_help,
521 		.print		= DNAT_print,
522 		.save		= DNAT_save,
523 		.x6_parse	= NAT_parse,
524 		.x6_fcheck	= DNAT_fcheck,
525 		.x6_options	= DNAT_opts,
526 		.xlate		= DNAT_xlate,
527 	},
528 	{
529 		.name		= "MASQUERADE",
530 		.version	= XTABLES_VERSION,
531 		.family		= NFPROTO_IPV4,
532 		.size		= XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
533 		.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
534 		.help		= MASQUERADE_help,
535 		.x6_parse	= NAT_parse,
536 		.x6_fcheck	= SNAT_fcheck,
537 		.print		= MASQUERADE_print,
538 		.save		= MASQUERADE_save,
539 		.x6_options	= MASQUERADE_opts,
540 		.xlate		= MASQUERADE_xlate,
541 	},
542 	{
543 		.name		= "MASQUERADE",
544 		.version	= XTABLES_VERSION,
545 		.family		= NFPROTO_IPV6,
546 		.size		= XT_ALIGN(sizeof(struct nf_nat_range)),
547 		.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_range)),
548 		.help		= MASQUERADE_help,
549 		.x6_parse	= NAT_parse6,
550 		.print		= MASQUERADE6_print,
551 		.save		= MASQUERADE6_save,
552 		.x6_options	= MASQUERADE_opts,
553 		.xlate		= MASQUERADE6_xlate,
554 	},
555 	{
556 		.name		= "REDIRECT",
557 		.version	= XTABLES_VERSION,
558 		.family		= NFPROTO_IPV4,
559 		.revision	= 0,
560 		.size		= XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
561 		.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
562 		.help		= REDIRECT_help,
563 		.print		= REDIRECT_print,
564 		.save		= REDIRECT_save,
565 		.x6_parse	= NAT_parse,
566 		.x6_fcheck	= DNAT_fcheck,
567 		.x6_options	= REDIRECT_opts,
568 		.xlate		= REDIRECT_xlate,
569 	},
570 	{
571 		.name		= "SNAT",
572 		.version	= XTABLES_VERSION,
573 		.family		= NFPROTO_IPV6,
574 		.revision	= 1,
575 		.size		= XT_ALIGN(sizeof(struct nf_nat_range)),
576 		.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_range)),
577 		.help		= SNAT_help,
578 		.x6_parse	= NAT_parse6,
579 		.print		= SNAT6_print,
580 		.save		= SNAT6_save,
581 		.x6_options	= SNAT_opts,
582 		.xlate		= SNAT6_xlate,
583 	},
584 	{
585 		.name		= "DNAT",
586 		.version	= XTABLES_VERSION,
587 		.family		= NFPROTO_IPV6,
588 		.revision	= 1,
589 		.size		= XT_ALIGN(sizeof(struct nf_nat_range)),
590 		.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_range)),
591 		.help		= DNAT_help,
592 		.print		= DNAT6_print,
593 		.save		= DNAT6_save,
594 		.x6_parse	= NAT_parse6,
595 		.x6_fcheck	= DNAT_fcheck6,
596 		.x6_options	= DNAT_opts,
597 		.xlate		= DNAT6_xlate,
598 	},
599 	{
600 		.name		= "REDIRECT",
601 		.version	= XTABLES_VERSION,
602 		.family		= NFPROTO_IPV6,
603 		.size		= XT_ALIGN(sizeof(struct nf_nat_range)),
604 		.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_range)),
605 		.help		= REDIRECT_help,
606 		.print		= REDIRECT6_print,
607 		.save		= REDIRECT6_save,
608 		.x6_parse	= NAT_parse6,
609 		.x6_fcheck	= DNAT_fcheck6,
610 		.x6_options	= REDIRECT_opts,
611 		.xlate		= REDIRECT6_xlate,
612 	},
613 	{
614 		.name		= "DNAT",
615 		.version	= XTABLES_VERSION,
616 		.family		= NFPROTO_IPV4,
617 		.revision	= 2,
618 		.size		= XT_ALIGN(sizeof(struct nf_nat_range2)),
619 		.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_range2)),
620 		.help		= DNAT_help_v2,
621 		.print		= DNATv2_print,
622 		.save		= DNATv2_save,
623 		.x6_parse	= DNAT_parse_v2,
624 		.x6_options	= DNAT_opts,
625 		.xlate		= DNATv2_xlate,
626 	},
627 	{
628 		.name		= "DNAT",
629 		.version	= XTABLES_VERSION,
630 		.family		= NFPROTO_IPV6,
631 		.revision	= 2,
632 		.size		= XT_ALIGN(sizeof(struct nf_nat_range2)),
633 		.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_range2)),
634 		.help		= DNAT_help_v2,
635 		.print		= DNAT6v2_print,
636 		.save		= DNAT6v2_save,
637 		.x6_parse	= DNAT_parse6_v2,
638 		.x6_options	= DNAT_opts,
639 		.xlate		= DNAT6v2_xlate,
640 	},
641 };
642 
_init(void)643 void _init(void)
644 {
645 	xtables_register_targets(nat_tg_reg, ARRAY_SIZE(nat_tg_reg));
646 }
647