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