1aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger/*
2aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
3aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger *
4aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger * Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT
5aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger * funded by Astaro.
6aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger */
7aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
8aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <stdio.h>
9aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <netdb.h>
10aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <string.h>
11aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <stdlib.h>
12aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <xtables.h>
13aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <iptables.h>
14aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <limits.h> /* INT_MAX in ip_tables.h */
15aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <linux/netfilter_ipv6/ip6_tables.h>
16aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger#include <linux/netfilter/nf_nat.h>
17aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
18aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerenum {
19aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	O_TO_DEST = 0,
20aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	O_RANDOM,
21aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	O_PERSISTENT,
22aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	O_X_TO_DEST,
23aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	F_TO_DEST   = 1 << O_TO_DEST,
24aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	F_RANDOM   = 1 << O_RANDOM,
25aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	F_X_TO_DEST = 1 << O_X_TO_DEST,
26aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger};
27aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
28aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerstatic void DNAT_help(void)
29aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
30aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	printf(
31aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger"DNAT target options:\n"
32aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
33aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger"				Address to map destination to.\n"
34aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger"[--random] [--persistent]\n");
35aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
36aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
37aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerstatic const struct xt_option_entry DNAT_opts[] = {
38aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	{.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING,
39aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	 .flags = XTOPT_MAND | XTOPT_MULTI},
40aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
41aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	{.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
42aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	XTOPT_TABLEEND,
43aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger};
44aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
45aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger/* Ranges expected in network order. */
46aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerstatic void
47aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerparse_to(const char *orig_arg, int portok, struct nf_nat_range *range)
48aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
49aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	char *arg, *start, *end = NULL, *colon = NULL, *dash, *error;
50aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	const struct in6_addr *ip;
51aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
52aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	arg = strdup(orig_arg);
53aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (arg == NULL)
54aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		xtables_error(RESOURCE_PROBLEM, "strdup");
55aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
56aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	start = strchr(arg, '[');
57aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (start == NULL) {
58aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		start = arg;
59aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		/* Lets assume one colon is port information. Otherwise its an IPv6 address */
60aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		colon = strchr(arg, ':');
61aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (colon && strchr(colon+1, ':'))
62aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			colon = NULL;
63aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
64aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	else {
65aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		start++;
66aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		end = strchr(start, ']');
67aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (end == NULL)
68aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			xtables_error(PARAMETER_PROBLEM,
69aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				      "Invalid address format");
70aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
71aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		*end = '\0';
72aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		colon = strchr(end + 1, ':');
73aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
74aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
75aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (colon) {
76aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		int port;
77aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
78aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (!portok)
79aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			xtables_error(PARAMETER_PROBLEM,
80aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				   "Need TCP, UDP, SCTP or DCCP with port specification");
81aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
82aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
83aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
84aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		port = atoi(colon+1);
85aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (port <= 0 || port > 65535)
86aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			xtables_error(PARAMETER_PROBLEM,
87aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				   "Port `%s' not valid\n", colon+1);
88aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
89aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		error = strchr(colon+1, ':');
90aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (error)
91aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			xtables_error(PARAMETER_PROBLEM,
92aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				   "Invalid port:port syntax - use dash\n");
93aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
94aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		dash = strchr(colon, '-');
95aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (!dash) {
96aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			range->min_proto.tcp.port
97aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				= range->max_proto.tcp.port
98aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				= htons(port);
99aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		} else {
100aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			int maxport;
101aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
102aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			maxport = atoi(dash + 1);
103aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (maxport <= 0 || maxport > 65535)
104aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				xtables_error(PARAMETER_PROBLEM,
105aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					   "Port `%s' not valid\n", dash+1);
106aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (maxport < port)
107aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				/* People are stupid. */
108aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				xtables_error(PARAMETER_PROBLEM,
109aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					   "Port range `%s' funky\n", colon+1);
110aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			range->min_proto.tcp.port = htons(port);
111aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			range->max_proto.tcp.port = htons(maxport);
112aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
113aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		/* Starts with colon or [] colon? No IP info...*/
114aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (colon == arg || colon == arg+2) {
115aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			free(arg);
116aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			return;
117aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
118aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		*colon = '\0';
119aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
120aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
121aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	range->flags |= NF_NAT_RANGE_MAP_IPS;
122aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	dash = strchr(start, '-');
123aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (colon && dash && dash > colon)
124aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		dash = NULL;
125aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
126aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (dash)
127aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		*dash = '\0';
128aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
129aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	ip = xtables_numeric_to_ip6addr(start);
130aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (!ip)
131aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
132aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			      start);
133aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	range->min_addr.in6 = *ip;
134aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (dash) {
135aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		ip = xtables_numeric_to_ip6addr(dash + 1);
136aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (!ip)
137aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
138aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				      dash+1);
139aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		range->max_addr.in6 = *ip;
140aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	} else
141aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		range->max_addr = range->min_addr;
142aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
143aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	free(arg);
144aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	return;
145aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
146aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
147aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerstatic void DNAT_parse(struct xt_option_call *cb)
148aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
149aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	const struct ip6t_entry *entry = cb->xt_entry;
150aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct nf_nat_range *range = cb->data;
151aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	int portok;
152aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
153aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (entry->ipv6.proto == IPPROTO_TCP ||
154aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	    entry->ipv6.proto == IPPROTO_UDP ||
155aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	    entry->ipv6.proto == IPPROTO_SCTP ||
156aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	    entry->ipv6.proto == IPPROTO_DCCP ||
157aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	    entry->ipv6.proto == IPPROTO_ICMP)
158aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		portok = 1;
159aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	else
160aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		portok = 0;
161aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
162aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	xtables_option_parse(cb);
163aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	switch (cb->entry->id) {
164aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	case O_TO_DEST:
165aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (cb->xflags & F_X_TO_DEST) {
166aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (!kernel_version)
167aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				get_kernel_version();
168aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			if (kernel_version > LINUX_VERSION(2, 6, 10))
169aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger				xtables_error(PARAMETER_PROBLEM,
170aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger					   "DNAT: Multiple --to-destination not supported");
171aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		}
172aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		parse_to(cb->arg, portok, range);
173aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		break;
174aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	case O_PERSISTENT:
175aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		range->flags |= NF_NAT_RANGE_PERSISTENT;
176aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		break;
177aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
178aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
179aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
180aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerstatic void DNAT_fcheck(struct xt_fcheck_call *cb)
181aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
182aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	static const unsigned int f = F_TO_DEST | F_RANDOM;
183aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	struct nf_nat_range *mr = cb->data;
184aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
185aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if ((cb->xflags & f) == f)
186aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		mr->flags |= NF_NAT_RANGE_PROTO_RANDOM;
187aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
188aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
189aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerstatic void print_range(const struct nf_nat_range *range)
190aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
191aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (range->flags & NF_NAT_RANGE_MAP_IPS) {
192aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)
193aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			printf("[");
194aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		printf("%s", xtables_ip6addr_to_numeric(&range->min_addr.in6));
195aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (memcmp(&range->min_addr, &range->max_addr,
196aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			   sizeof(range->min_addr)))
197aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			printf("-%s", xtables_ip6addr_to_numeric(&range->max_addr.in6));
198aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)
199aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			printf("]");
200aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
201aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
202aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		printf(":");
203aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		printf("%hu", ntohs(range->min_proto.tcp.port));
204aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		if (range->max_proto.tcp.port != range->min_proto.tcp.port)
205aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger			printf("-%hu", ntohs(range->max_proto.tcp.port));
206aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	}
207aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
208aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
209aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerstatic void DNAT_print(const void *ip, const struct xt_entry_target *target,
210aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger                       int numeric)
211aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
212aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	const struct nf_nat_range *range = (const void *)target->data;
213aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
214aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	printf(" to:");
215aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	print_range(range);
216aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
217aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		printf(" random");
218aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (range->flags & NF_NAT_RANGE_PERSISTENT)
219aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		printf(" persistent");
220aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
221aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
222aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerstatic void DNAT_save(const void *ip, const struct xt_entry_target *target)
223aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
224aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	const struct nf_nat_range *range = (const void *)target->data;
225aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
226aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	printf(" --to-destination ");
227aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	print_range(range);
228aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
229aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		printf(" --random");
230aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	if (range->flags & NF_NAT_RANGE_PERSISTENT)
231aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger		printf(" --persistent");
232aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
233aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
234aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingerstatic struct xtables_target snat_tg_reg = {
235aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	.name		= "DNAT",
236aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	.version	= XTABLES_VERSION,
237aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	.family		= NFPROTO_IPV6,
238aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	.revision	= 1,
239aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	.size		= XT_ALIGN(sizeof(struct nf_nat_range)),
240aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_range)),
241aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	.help		= DNAT_help,
242aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	.x6_parse	= DNAT_parse,
243aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	.x6_fcheck	= DNAT_fcheck,
244aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	.print		= DNAT_print,
245aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	.save		= DNAT_save,
246aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	.x6_options	= DNAT_opts,
247aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger};
248aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger
249aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemmingervoid _init(void)
250aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger{
251aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger	xtables_register_target(&snat_tg_reg);
252aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger}
253aba5acdfdb347d2c21fc67d613d83d4430ca3937osdl.org!shemminger