ng_nat.c revision 369375
1189251Ssam/*-
2189251Ssam * Copyright 2005, Gleb Smirnoff <glebius@FreeBSD.org>
3252726Srpaulo * All rights reserved.
4189251Ssam *
5252726Srpaulo * Redistribution and use in source and binary forms, with or without
6252726Srpaulo * modification, are permitted provided that the following conditions
7189251Ssam * are met:
8189251Ssam * 1. Redistributions of source code must retain the above copyright
9189251Ssam *    notice, this list of conditions and the following disclaimer.
10189251Ssam * 2. Redistributions in binary form must reproduce the above copyright
11189251Ssam *    notice, this list of conditions and the following disclaimer in the
12189251Ssam *    documentation and/or other materials provided with the distribution.
13189251Ssam *
14189251Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15189251Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16189251Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17189251Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18189251Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19252726Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20252726Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21252726Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22214734Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23252726Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24252726Srpaulo * SUCH DAMAGE.
25252726Srpaulo *
26252726Srpaulo * $FreeBSD: stable/11/sys/netgraph/ng_nat.c 369375 2021-02-25 10:10:36Z donner $
27189251Ssam */
28189251Ssam
29252726Srpaulo#include <sys/param.h>
30252726Srpaulo#include <sys/systm.h>
31189251Ssam#include <sys/kernel.h>
32189251Ssam#include <sys/mbuf.h>
33252726Srpaulo#include <sys/malloc.h>
34252726Srpaulo#include <sys/ctype.h>
35252726Srpaulo#include <sys/errno.h>
36252726Srpaulo#include <sys/syslog.h>
37252726Srpaulo
38252726Srpaulo#include <netinet/in_systm.h>
39252726Srpaulo#include <netinet/in.h>
40252726Srpaulo#include <netinet/ip.h>
41252726Srpaulo#include <netinet/ip_var.h>
42252726Srpaulo#include <netinet/tcp.h>
43252726Srpaulo#include <machine/in_cksum.h>
44252726Srpaulo
45252726Srpaulo#include <net/dlt.h>
46252726Srpaulo#include <net/ethernet.h>
47252726Srpaulo
48252726Srpaulo#include <netinet/libalias/alias.h>
49252726Srpaulo#include <netinet/libalias/alias_local.h>
50252726Srpaulo
51252726Srpaulo#include <netgraph/ng_message.h>
52252726Srpaulo#include <netgraph/ng_parse.h>
53252726Srpaulo#include <netgraph/ng_nat.h>
54252726Srpaulo#include <netgraph/netgraph.h>
55252726Srpaulo
56252726Srpaulostatic ng_constructor_t	ng_nat_constructor;
57252726Srpaulostatic ng_rcvmsg_t	ng_nat_rcvmsg;
58252726Srpaulostatic ng_shutdown_t	ng_nat_shutdown;
59252726Srpaulostatic ng_newhook_t	ng_nat_newhook;
60252726Srpaulostatic ng_rcvdata_t	ng_nat_rcvdata;
61252726Srpaulostatic ng_disconnect_t	ng_nat_disconnect;
62252726Srpaulo
63252726Srpaulostatic unsigned int	ng_nat_translate_flags(unsigned int x);
64252726Srpaulo
65252726Srpaulo/* Parse type for struct ng_nat_mode. */
66252726Srpaulostatic const struct ng_parse_struct_field ng_nat_mode_fields[]
67252726Srpaulo	= NG_NAT_MODE_INFO;
68252726Srpaulostatic const struct ng_parse_type ng_nat_mode_type = {
69252726Srpaulo	&ng_parse_struct_type,
70252726Srpaulo	&ng_nat_mode_fields
71252726Srpaulo};
72252726Srpaulo
73252726Srpaulo/* Parse type for 'description' field in structs. */
74252726Srpaulostatic const struct ng_parse_fixedstring_info ng_nat_description_info
75252726Srpaulo	= { NG_NAT_DESC_LENGTH };
76252726Srpaulostatic const struct ng_parse_type ng_nat_description_type = {
77252726Srpaulo	&ng_parse_fixedstring_type,
78252726Srpaulo	&ng_nat_description_info
79252726Srpaulo};
80252726Srpaulo
81252726Srpaulo/* Parse type for struct ng_nat_redirect_port. */
82252726Srpaulostatic const struct ng_parse_struct_field ng_nat_redirect_port_fields[]
83252726Srpaulo	= NG_NAT_REDIRECT_PORT_TYPE_INFO(&ng_nat_description_type);
84252726Srpaulostatic const struct ng_parse_type ng_nat_redirect_port_type = {
85252726Srpaulo	&ng_parse_struct_type,
86252726Srpaulo	&ng_nat_redirect_port_fields
87252726Srpaulo};
88252726Srpaulo
89252726Srpaulo/* Parse type for struct ng_nat_redirect_addr. */
90252726Srpaulostatic const struct ng_parse_struct_field ng_nat_redirect_addr_fields[]
91252726Srpaulo	= NG_NAT_REDIRECT_ADDR_TYPE_INFO(&ng_nat_description_type);
92252726Srpaulostatic const struct ng_parse_type ng_nat_redirect_addr_type = {
93252726Srpaulo	&ng_parse_struct_type,
94252726Srpaulo	&ng_nat_redirect_addr_fields
95252726Srpaulo};
96252726Srpaulo
97252726Srpaulo/* Parse type for struct ng_nat_redirect_proto. */
98252726Srpaulostatic const struct ng_parse_struct_field ng_nat_redirect_proto_fields[]
99252726Srpaulo	= NG_NAT_REDIRECT_PROTO_TYPE_INFO(&ng_nat_description_type);
100252726Srpaulostatic const struct ng_parse_type ng_nat_redirect_proto_type = {
101252726Srpaulo	&ng_parse_struct_type,
102252726Srpaulo	&ng_nat_redirect_proto_fields
103252726Srpaulo};
104252726Srpaulo
105252726Srpaulo/* Parse type for struct ng_nat_add_server. */
106252726Srpaulostatic const struct ng_parse_struct_field ng_nat_add_server_fields[]
107252726Srpaulo	= NG_NAT_ADD_SERVER_TYPE_INFO;
108252726Srpaulostatic const struct ng_parse_type ng_nat_add_server_type = {
109252726Srpaulo	&ng_parse_struct_type,
110252726Srpaulo	&ng_nat_add_server_fields
111252726Srpaulo};
112252726Srpaulo
113252726Srpaulo/* Parse type for one struct ng_nat_listrdrs_entry. */
114252726Srpaulostatic const struct ng_parse_struct_field ng_nat_listrdrs_entry_fields[]
115252726Srpaulo	= NG_NAT_LISTRDRS_ENTRY_TYPE_INFO(&ng_nat_description_type);
116252726Srpaulostatic const struct ng_parse_type ng_nat_listrdrs_entry_type = {
117252726Srpaulo	&ng_parse_struct_type,
118252726Srpaulo	&ng_nat_listrdrs_entry_fields
119252726Srpaulo};
120252726Srpaulo
121252726Srpaulo/* Parse type for 'redirects' array in struct ng_nat_list_redirects. */
122252726Srpaulostatic int
123252726Srpaulong_nat_listrdrs_ary_getLength(const struct ng_parse_type *type,
124252726Srpaulo	const u_char *start, const u_char *buf)
125252726Srpaulo{
126252726Srpaulo	const struct ng_nat_list_redirects *lr;
127252726Srpaulo
128252726Srpaulo	lr = (const struct ng_nat_list_redirects *)
129252726Srpaulo	    (buf - offsetof(struct ng_nat_list_redirects, redirects));
130252726Srpaulo	return lr->total_count;
131252726Srpaulo}
132252726Srpaulo
133252726Srpaulostatic const struct ng_parse_array_info ng_nat_listrdrs_ary_info = {
134252726Srpaulo	&ng_nat_listrdrs_entry_type,
135252726Srpaulo	&ng_nat_listrdrs_ary_getLength,
136252726Srpaulo	NULL
137252726Srpaulo};
138252726Srpaulostatic const struct ng_parse_type ng_nat_listrdrs_ary_type = {
139252726Srpaulo	&ng_parse_array_type,
140252726Srpaulo	&ng_nat_listrdrs_ary_info
141252726Srpaulo};
142252726Srpaulo
143252726Srpaulo/* Parse type for struct ng_nat_list_redirects. */
144252726Srpaulostatic const struct ng_parse_struct_field ng_nat_list_redirects_fields[]
145252726Srpaulo	= NG_NAT_LIST_REDIRECTS_TYPE_INFO(&ng_nat_listrdrs_ary_type);
146252726Srpaulostatic const struct ng_parse_type ng_nat_list_redirects_type = {
147252726Srpaulo	&ng_parse_struct_type,
148252726Srpaulo	&ng_nat_list_redirects_fields
149252726Srpaulo};
150252726Srpaulo
151252726Srpaulo/* Parse type for struct ng_nat_libalias_info. */
152252726Srpaulostatic const struct ng_parse_struct_field ng_nat_libalias_info_fields[]
153252726Srpaulo	= NG_NAT_LIBALIAS_INFO;
154252726Srpaulostatic const struct ng_parse_type ng_nat_libalias_info_type = {
155252726Srpaulo	&ng_parse_struct_type,
156252726Srpaulo	&ng_nat_libalias_info_fields
157252726Srpaulo};
158252726Srpaulo
159252726Srpaulo/* List of commands and how to convert arguments to/from ASCII. */
160252726Srpaulostatic const struct ng_cmdlist ng_nat_cmdlist[] = {
161252726Srpaulo	{
162252726Srpaulo	  NGM_NAT_COOKIE,
163252726Srpaulo	  NGM_NAT_SET_IPADDR,
164252726Srpaulo	  "setaliasaddr",
165252726Srpaulo	  &ng_parse_ipaddr_type,
166252726Srpaulo	  NULL
167252726Srpaulo	},
168252726Srpaulo	{
169252726Srpaulo	  NGM_NAT_COOKIE,
170252726Srpaulo	  NGM_NAT_SET_MODE,
171252726Srpaulo	  "setmode",
172252726Srpaulo	  &ng_nat_mode_type,
173252726Srpaulo	  NULL
174252726Srpaulo	},
175252726Srpaulo	{
176252726Srpaulo	  NGM_NAT_COOKIE,
177252726Srpaulo	  NGM_NAT_SET_TARGET,
178252726Srpaulo	  "settarget",
179252726Srpaulo	  &ng_parse_ipaddr_type,
180252726Srpaulo	  NULL
181252726Srpaulo	},
182252726Srpaulo	{
183252726Srpaulo	  NGM_NAT_COOKIE,
184252726Srpaulo	  NGM_NAT_REDIRECT_PORT,
185252726Srpaulo	  "redirectport",
186252726Srpaulo	  &ng_nat_redirect_port_type,
187252726Srpaulo	  &ng_parse_uint32_type
188252726Srpaulo	},
189252726Srpaulo	{
190252726Srpaulo	  NGM_NAT_COOKIE,
191252726Srpaulo	  NGM_NAT_REDIRECT_ADDR,
192252726Srpaulo	  "redirectaddr",
193252726Srpaulo	  &ng_nat_redirect_addr_type,
194252726Srpaulo	  &ng_parse_uint32_type
195252726Srpaulo	},
196252726Srpaulo	{
197252726Srpaulo	  NGM_NAT_COOKIE,
198252726Srpaulo	  NGM_NAT_REDIRECT_PROTO,
199252726Srpaulo	  "redirectproto",
200252726Srpaulo	  &ng_nat_redirect_proto_type,
201252726Srpaulo	  &ng_parse_uint32_type
202252726Srpaulo	},
203252726Srpaulo	{
204252726Srpaulo	  NGM_NAT_COOKIE,
205252726Srpaulo	  NGM_NAT_REDIRECT_DYNAMIC,
206252726Srpaulo	  "redirectdynamic",
207252726Srpaulo	  &ng_parse_uint32_type,
208252726Srpaulo	  NULL
209252726Srpaulo	},
210252726Srpaulo	{
211252726Srpaulo	  NGM_NAT_COOKIE,
212252726Srpaulo	  NGM_NAT_REDIRECT_DELETE,
213252726Srpaulo	  "redirectdelete",
214252726Srpaulo	  &ng_parse_uint32_type,
215252726Srpaulo	  NULL
216252726Srpaulo	},
217252726Srpaulo	{
218252726Srpaulo	  NGM_NAT_COOKIE,
219252726Srpaulo	  NGM_NAT_ADD_SERVER,
220252726Srpaulo	  "addserver",
221252726Srpaulo	  &ng_nat_add_server_type,
222252726Srpaulo	  NULL
223252726Srpaulo	},
224189251Ssam	{
225189251Ssam	  NGM_NAT_COOKIE,
226189251Ssam	  NGM_NAT_LIST_REDIRECTS,
227189251Ssam	  "listredirects",
228189251Ssam	  NULL,
229189251Ssam	  &ng_nat_list_redirects_type
230189251Ssam	},
231189251Ssam	{
232189251Ssam	  NGM_NAT_COOKIE,
233189251Ssam	  NGM_NAT_PROXY_RULE,
234189251Ssam	  "proxyrule",
235189251Ssam	  &ng_parse_string_type,
236189251Ssam	  NULL
237189251Ssam	},
238189251Ssam	{
239189251Ssam	  NGM_NAT_COOKIE,
240189251Ssam	  NGM_NAT_LIBALIAS_INFO,
241189251Ssam	  "libaliasinfo",
242189251Ssam	  NULL,
243189251Ssam	  &ng_nat_libalias_info_type
244189251Ssam	},
245189251Ssam	{
246189251Ssam	  NGM_NAT_COOKIE,
247189251Ssam	  NGM_NAT_SET_DLT,
248189251Ssam	  "setdlt",
249189251Ssam	  &ng_parse_uint8_type,
250189251Ssam	  NULL
251189251Ssam	},
252189251Ssam	{
253189251Ssam	  NGM_NAT_COOKIE,
254252726Srpaulo	  NGM_NAT_GET_DLT,
255252726Srpaulo	  "getdlt",
256252726Srpaulo	  NULL,
257252726Srpaulo	  &ng_parse_uint8_type
258252726Srpaulo	},
259252726Srpaulo	{ 0 }
260252726Srpaulo};
261189251Ssam
262189251Ssam/* Netgraph node type descriptor. */
263189251Ssamstatic struct ng_type typestruct = {
264189251Ssam	.version =	NG_ABI_VERSION,
265189251Ssam	.name =		NG_NAT_NODE_TYPE,
266189251Ssam	.constructor =	ng_nat_constructor,
267189251Ssam	.rcvmsg =	ng_nat_rcvmsg,
268189251Ssam	.shutdown =	ng_nat_shutdown,
269189251Ssam	.newhook =	ng_nat_newhook,
270189251Ssam	.rcvdata =	ng_nat_rcvdata,
271189251Ssam	.disconnect =	ng_nat_disconnect,
272189251Ssam	.cmdlist =	ng_nat_cmdlist,
273189251Ssam};
274189251SsamNETGRAPH_INIT(nat, &typestruct);
275189251SsamMODULE_DEPEND(ng_nat, libalias, 1, 1, 1);
276189251Ssam
277189251Ssam/* Element for list of redirects. */
278189251Ssamstruct ng_nat_rdr_lst {
279189251Ssam	STAILQ_ENTRY(ng_nat_rdr_lst) entries;
280189251Ssam	struct alias_link	*lnk;
281189251Ssam	struct ng_nat_listrdrs_entry rdr;
282189251Ssam};
283189251SsamSTAILQ_HEAD(rdrhead, ng_nat_rdr_lst);
284189251Ssam
285189251Ssam/* Information we store for each node. */
286189251Ssamstruct ng_nat_priv {
287189251Ssam	node_p		node;		/* back pointer to node */
288189251Ssam	hook_p		in;		/* hook for demasquerading */
289189251Ssam	hook_p		out;		/* hook for masquerading */
290189251Ssam	struct libalias	*lib;		/* libalias handler */
291189251Ssam	uint32_t	flags;		/* status flags */
292189251Ssam	uint32_t	rdrcount;	/* number or redirects in list */
293189251Ssam	uint32_t	nextid;		/* for next in turn in list */
294189251Ssam	struct rdrhead	redirhead;	/* redirect list header */
295189251Ssam	uint8_t		dlt;		/* DLT_XXX from bpf.h */
296189251Ssam};
297189251Ssamtypedef struct ng_nat_priv *priv_p;
298189251Ssam
299189251Ssam/* Values of flags */
300189251Ssam#define	NGNAT_CONNECTED		0x1	/* We have both hooks connected */
301189251Ssam#define	NGNAT_ADDR_DEFINED	0x2	/* NGM_NAT_SET_IPADDR happened */
302252726Srpaulo
303252726Srpaulostatic int
304252726Srpaulong_nat_constructor(node_p node)
305252726Srpaulo{
306252726Srpaulo	priv_p priv;
307252726Srpaulo
308252726Srpaulo	/* Initialize private descriptor. */
309252726Srpaulo	priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
310252726Srpaulo
311189251Ssam	/* Init aliasing engine. */
312189251Ssam	priv->lib = LibAliasInit(NULL);
313189251Ssam
314189251Ssam	/* Set same ports on. */
315189251Ssam	(void )LibAliasSetMode(priv->lib, PKT_ALIAS_SAME_PORTS,
316252726Srpaulo	    PKT_ALIAS_SAME_PORTS);
317189251Ssam
318189251Ssam	/* Init redirects housekeeping. */
319189251Ssam	priv->rdrcount = 0;
320189251Ssam	priv->nextid = 1;
321189251Ssam	priv->dlt = DLT_RAW;
322189251Ssam	STAILQ_INIT(&priv->redirhead);
323189251Ssam
324189251Ssam	/* Link structs together. */
325189251Ssam	NG_NODE_SET_PRIVATE(node, priv);
326189251Ssam	priv->node = node;
327189251Ssam
328189251Ssam	/*
329189251Ssam	 * libalias is not thread safe, so our node
330189251Ssam	 * must be single threaded.
331189251Ssam	 */
332189251Ssam	NG_NODE_FORCE_WRITER(node);
333189251Ssam
334189251Ssam	return (0);
335189251Ssam}
336189251Ssam
337189251Ssamstatic int
338189251Ssamng_nat_newhook(node_p node, hook_p hook, const char *name)
339189251Ssam{
340189251Ssam	const priv_p priv = NG_NODE_PRIVATE(node);
341189251Ssam
342189251Ssam	if (strcmp(name, NG_NAT_HOOK_IN) == 0) {
343189251Ssam		priv->in = hook;
344189251Ssam	} else if (strcmp(name, NG_NAT_HOOK_OUT) == 0) {
345189251Ssam		priv->out = hook;
346189251Ssam	} else
347189251Ssam		return (EINVAL);
348189251Ssam
349189251Ssam	if (priv->out != NULL &&
350189251Ssam	    priv->in != NULL)
351189251Ssam		priv->flags |= NGNAT_CONNECTED;
352189251Ssam
353189251Ssam	return(0);
354189251Ssam}
355189251Ssam
356189251Ssamstatic int
357189251Ssamng_nat_rcvmsg(node_p node, item_p item, hook_p lasthook)
358189251Ssam{
359189251Ssam	const priv_p priv = NG_NODE_PRIVATE(node);
360189251Ssam	struct ng_mesg *resp = NULL;
361189251Ssam	struct ng_mesg *msg;
362189251Ssam	int error = 0;
363189251Ssam
364189251Ssam	NGI_GET_MSG(item, msg);
365189251Ssam
366189251Ssam	switch (msg->header.typecookie) {
367189251Ssam	case NGM_NAT_COOKIE:
368189251Ssam		switch (msg->header.cmd) {
369189251Ssam		case NGM_NAT_SET_IPADDR:
370189251Ssam		    {
371189251Ssam			struct in_addr *const ia = (struct in_addr *)msg->data;
372189251Ssam
373189251Ssam			if (msg->header.arglen < sizeof(*ia)) {
374189251Ssam				error = EINVAL;
375189251Ssam				break;
376189251Ssam			}
377189251Ssam
378189251Ssam			LibAliasSetAddress(priv->lib, *ia);
379189251Ssam
380189251Ssam			priv->flags |= NGNAT_ADDR_DEFINED;
381189251Ssam		    }
382189251Ssam			break;
383189251Ssam		case NGM_NAT_SET_MODE:
384189251Ssam		    {
385189251Ssam			struct ng_nat_mode *const mode =
386189251Ssam			    (struct ng_nat_mode *)msg->data;
387189251Ssam
388189251Ssam			if (msg->header.arglen < sizeof(*mode)) {
389189251Ssam				error = EINVAL;
390189251Ssam				break;
391189251Ssam			}
392189251Ssam
393189251Ssam			if (LibAliasSetMode(priv->lib,
394189251Ssam			    ng_nat_translate_flags(mode->flags),
395189251Ssam			    ng_nat_translate_flags(mode->mask)) < 0) {
396189251Ssam				error = ENOMEM;
397189251Ssam				break;
398189251Ssam			}
399189251Ssam		    }
400189251Ssam			break;
401189251Ssam		case NGM_NAT_SET_TARGET:
402189251Ssam		    {
403189251Ssam			struct in_addr *const ia = (struct in_addr *)msg->data;
404189251Ssam
405189251Ssam			if (msg->header.arglen < sizeof(*ia)) {
406189251Ssam				error = EINVAL;
407189251Ssam				break;
408189251Ssam			}
409252726Srpaulo
410252726Srpaulo			LibAliasSetTarget(priv->lib, *ia);
411252726Srpaulo		    }
412252726Srpaulo			break;
413252726Srpaulo		case NGM_NAT_REDIRECT_PORT:
414252726Srpaulo		    {
415252726Srpaulo			struct ng_nat_rdr_lst *entry;
416252726Srpaulo			struct ng_nat_redirect_port *const rp =
417252726Srpaulo			    (struct ng_nat_redirect_port *)msg->data;
418252726Srpaulo
419252726Srpaulo			if (msg->header.arglen < sizeof(*rp)) {
420252726Srpaulo				error = EINVAL;
421252726Srpaulo				break;
422252726Srpaulo			}
423252726Srpaulo
424252726Srpaulo			if ((entry = malloc(sizeof(struct ng_nat_rdr_lst),
425252726Srpaulo			    M_NETGRAPH, M_NOWAIT | M_ZERO)) == NULL) {
426189251Ssam				error = ENOMEM;
427189251Ssam				break;
428189251Ssam			}
429189251Ssam
430189251Ssam			/* Try actual redirect. */
431189251Ssam			entry->lnk = LibAliasRedirectPort(priv->lib,
432189251Ssam				rp->local_addr, htons(rp->local_port),
433189251Ssam				rp->remote_addr, htons(rp->remote_port),
434189251Ssam				rp->alias_addr, htons(rp->alias_port),
435189251Ssam				rp->proto);
436189251Ssam
437189251Ssam			if (entry->lnk == NULL) {
438189251Ssam				error = ENOMEM;
439189251Ssam				free(entry, M_NETGRAPH);
440189251Ssam				break;
441189251Ssam			}
442189251Ssam
443189251Ssam			/* Successful, save info in our internal list. */
444189251Ssam			entry->rdr.local_addr = rp->local_addr;
445189251Ssam			entry->rdr.alias_addr = rp->alias_addr;
446189251Ssam			entry->rdr.remote_addr = rp->remote_addr;
447189251Ssam			entry->rdr.local_port = rp->local_port;
448189251Ssam			entry->rdr.alias_port = rp->alias_port;
449189251Ssam			entry->rdr.remote_port = rp->remote_port;
450189251Ssam			entry->rdr.proto = rp->proto;
451189251Ssam			bcopy(rp->description, entry->rdr.description,
452189251Ssam			    NG_NAT_DESC_LENGTH);
453189251Ssam
454189251Ssam			/* Safety precaution. */
455189251Ssam			entry->rdr.description[NG_NAT_DESC_LENGTH-1] = '\0';
456189251Ssam
457189251Ssam			entry->rdr.id = priv->nextid++;
458189251Ssam			priv->rdrcount++;
459189251Ssam
460189251Ssam			/* Link to list of redirects. */
461189251Ssam			STAILQ_INSERT_TAIL(&priv->redirhead, entry, entries);
462189251Ssam
463189251Ssam			/* Response with id of newly added entry. */
464189251Ssam			NG_MKRESPONSE(resp, msg, sizeof(entry->rdr.id), M_NOWAIT);
465189251Ssam			if (resp == NULL) {
466189251Ssam				error = ENOMEM;
467189251Ssam				break;
468189251Ssam			}
469189251Ssam			bcopy(&entry->rdr.id, resp->data, sizeof(entry->rdr.id));
470189251Ssam		    }
471189251Ssam			break;
472189251Ssam		case NGM_NAT_REDIRECT_ADDR:
473189251Ssam		    {
474189251Ssam			struct ng_nat_rdr_lst *entry;
475189251Ssam			struct ng_nat_redirect_addr *const ra =
476189251Ssam			    (struct ng_nat_redirect_addr *)msg->data;
477189251Ssam
478189251Ssam			if (msg->header.arglen < sizeof(*ra)) {
479189251Ssam				error = EINVAL;
480189251Ssam				break;
481189251Ssam			}
482189251Ssam
483189251Ssam			if ((entry = malloc(sizeof(struct ng_nat_rdr_lst),
484189251Ssam			    M_NETGRAPH, M_NOWAIT | M_ZERO)) == NULL) {
485189251Ssam				error = ENOMEM;
486189251Ssam				break;
487189251Ssam			}
488189251Ssam
489189251Ssam			/* Try actual redirect. */
490189251Ssam			entry->lnk = LibAliasRedirectAddr(priv->lib,
491189251Ssam				ra->local_addr, ra->alias_addr);
492189251Ssam
493189251Ssam			if (entry->lnk == NULL) {
494189251Ssam				error = ENOMEM;
495189251Ssam				free(entry, M_NETGRAPH);
496189251Ssam				break;
497189251Ssam			}
498189251Ssam
499189251Ssam			/* Successful, save info in our internal list. */
500189251Ssam			entry->rdr.local_addr = ra->local_addr;
501189251Ssam			entry->rdr.alias_addr = ra->alias_addr;
502189251Ssam			entry->rdr.proto = NG_NAT_REDIRPROTO_ADDR;
503189251Ssam			bcopy(ra->description, entry->rdr.description,
504189251Ssam			    NG_NAT_DESC_LENGTH);
505189251Ssam
506189251Ssam			/* Safety precaution. */
507189251Ssam			entry->rdr.description[NG_NAT_DESC_LENGTH-1] = '\0';
508189251Ssam
509189251Ssam			entry->rdr.id = priv->nextid++;
510189251Ssam			priv->rdrcount++;
511189251Ssam
512189251Ssam			/* Link to list of redirects. */
513189251Ssam			STAILQ_INSERT_TAIL(&priv->redirhead, entry, entries);
514189251Ssam
515189251Ssam			/* Response with id of newly added entry. */
516252726Srpaulo			NG_MKRESPONSE(resp, msg, sizeof(entry->rdr.id), M_NOWAIT);
517189251Ssam			if (resp == NULL) {
518189251Ssam				error = ENOMEM;
519214734Srpaulo				break;
520214734Srpaulo			}
521214734Srpaulo			bcopy(&entry->rdr.id, resp->data, sizeof(entry->rdr.id));
522252726Srpaulo		    }
523252726Srpaulo			break;
524214734Srpaulo		case NGM_NAT_REDIRECT_PROTO:
525252726Srpaulo		    {
526252726Srpaulo			struct ng_nat_rdr_lst *entry;
527252726Srpaulo			struct ng_nat_redirect_proto *const rp =
528214734Srpaulo			    (struct ng_nat_redirect_proto *)msg->data;
529214734Srpaulo
530214734Srpaulo			if (msg->header.arglen < sizeof(*rp)) {
531214734Srpaulo				error = EINVAL;
532189251Ssam				break;
533189251Ssam			}
534189251Ssam
535189251Ssam			if ((entry = malloc(sizeof(struct ng_nat_rdr_lst),
536189251Ssam			    M_NETGRAPH, M_NOWAIT | M_ZERO)) == NULL) {
537189251Ssam				error = ENOMEM;
538189251Ssam				break;
539189251Ssam			}
540189251Ssam
541189251Ssam			/* Try actual redirect. */
542189251Ssam			entry->lnk = LibAliasRedirectProto(priv->lib,
543189251Ssam				rp->local_addr, rp->remote_addr,
544189251Ssam				rp->alias_addr, rp->proto);
545189251Ssam
546189251Ssam			if (entry->lnk == NULL) {
547189251Ssam				error = ENOMEM;
548189251Ssam				free(entry, M_NETGRAPH);
549189251Ssam				break;
550189251Ssam			}
551189251Ssam
552189251Ssam			/* Successful, save info in our internal list. */
553189251Ssam			entry->rdr.local_addr = rp->local_addr;
554189251Ssam			entry->rdr.alias_addr = rp->alias_addr;
555214734Srpaulo			entry->rdr.remote_addr = rp->remote_addr;
556252726Srpaulo			entry->rdr.proto = rp->proto;
557214734Srpaulo			bcopy(rp->description, entry->rdr.description,
558252726Srpaulo			    NG_NAT_DESC_LENGTH);
559252726Srpaulo
560252726Srpaulo			/* Safety precaution. */
561252726Srpaulo			entry->rdr.description[NG_NAT_DESC_LENGTH-1] = '\0';
562252726Srpaulo
563252726Srpaulo			entry->rdr.id = priv->nextid++;
564252726Srpaulo			priv->rdrcount++;
565252726Srpaulo
566252726Srpaulo			/* Link to list of redirects. */
567252726Srpaulo			STAILQ_INSERT_TAIL(&priv->redirhead, entry, entries);
568252726Srpaulo
569252726Srpaulo			/* Response with id of newly added entry. */
570252726Srpaulo			NG_MKRESPONSE(resp, msg, sizeof(entry->rdr.id), M_NOWAIT);
571252726Srpaulo			if (resp == NULL) {
572252726Srpaulo				error = ENOMEM;
573252726Srpaulo				break;
574252726Srpaulo			}
575252726Srpaulo			bcopy(&entry->rdr.id, resp->data, sizeof(entry->rdr.id));
576252726Srpaulo		    }
577252726Srpaulo			break;
578252726Srpaulo		case NGM_NAT_REDIRECT_DYNAMIC:
579252726Srpaulo		case NGM_NAT_REDIRECT_DELETE:
580252726Srpaulo		    {
581252726Srpaulo			struct ng_nat_rdr_lst *entry;
582252726Srpaulo			uint32_t *const id = (uint32_t *)msg->data;
583252726Srpaulo
584252726Srpaulo			if (msg->header.arglen < sizeof(*id)) {
585252726Srpaulo				error = EINVAL;
586252726Srpaulo				break;
587252726Srpaulo			}
588252726Srpaulo
589252726Srpaulo			/* Find entry with supplied id. */
590252726Srpaulo			STAILQ_FOREACH(entry, &priv->redirhead, entries) {
591252726Srpaulo				if (entry->rdr.id == *id)
592252726Srpaulo					break;
593252726Srpaulo			}
594252726Srpaulo
595252726Srpaulo			/* Not found. */
596252726Srpaulo			if (entry == NULL) {
597252726Srpaulo				error = ENOENT;
598252726Srpaulo				break;
599252726Srpaulo			}
600252726Srpaulo
601214734Srpaulo			if (msg->header.cmd == NGM_NAT_REDIRECT_DYNAMIC) {
602214734Srpaulo				if (LibAliasRedirectDynamic(priv->lib,
603214734Srpaulo				    entry->lnk) == -1) {
604214734Srpaulo					error = ENOTTY;	/* XXX Something better? */
605214734Srpaulo					break;
606252726Srpaulo				}
607252726Srpaulo			} else {	/* NGM_NAT_REDIRECT_DELETE */
608252726Srpaulo				LibAliasRedirectDelete(priv->lib, entry->lnk);
609252726Srpaulo			}
610252726Srpaulo
611252726Srpaulo			/* Delete entry from our internal list. */
612252726Srpaulo			priv->rdrcount--;
613252726Srpaulo			STAILQ_REMOVE(&priv->redirhead, entry, ng_nat_rdr_lst, entries);
614252726Srpaulo			free(entry, M_NETGRAPH);
615252726Srpaulo		    }
616252726Srpaulo			break;
617252726Srpaulo		case NGM_NAT_ADD_SERVER:
618252726Srpaulo		    {
619252726Srpaulo			struct ng_nat_rdr_lst *entry;
620252726Srpaulo			struct ng_nat_add_server *const as =
621252726Srpaulo			    (struct ng_nat_add_server *)msg->data;
622252726Srpaulo
623252726Srpaulo			if (msg->header.arglen < sizeof(*as)) {
624252726Srpaulo				error = EINVAL;
625214734Srpaulo				break;
626214734Srpaulo			}
627214734Srpaulo
628214734Srpaulo			/* Find entry with supplied id. */
629214734Srpaulo			STAILQ_FOREACH(entry, &priv->redirhead, entries) {
630214734Srpaulo				if (entry->rdr.id == as->id)
631252726Srpaulo					break;
632252726Srpaulo			}
633252726Srpaulo
634252726Srpaulo			/* Not found. */
635252726Srpaulo			if (entry == NULL) {
636252726Srpaulo				error = ENOENT;
637252726Srpaulo				break;
638252726Srpaulo			}
639252726Srpaulo
640252726Srpaulo			if (LibAliasAddServer(priv->lib, entry->lnk,
641252726Srpaulo			    as->addr, htons(as->port)) == -1) {
642252726Srpaulo				error = ENOMEM;
643252726Srpaulo				break;
644252726Srpaulo			}
645252726Srpaulo
646252726Srpaulo			entry->rdr.lsnat++;
647252726Srpaulo		    }
648252726Srpaulo			break;
649252726Srpaulo		case NGM_NAT_LIST_REDIRECTS:
650252726Srpaulo		    {
651252726Srpaulo			struct ng_nat_rdr_lst *entry;
652252726Srpaulo			struct ng_nat_list_redirects *ary;
653252726Srpaulo			int i = 0;
654252726Srpaulo
655252726Srpaulo			NG_MKRESPONSE(resp, msg, sizeof(*ary) +
656252726Srpaulo			    (priv->rdrcount) * sizeof(*entry), M_NOWAIT);
657252726Srpaulo			if (resp == NULL) {
658252726Srpaulo				error = ENOMEM;
659252726Srpaulo				break;
660252726Srpaulo			}
661252726Srpaulo
662252726Srpaulo			ary = (struct ng_nat_list_redirects *)resp->data;
663252726Srpaulo			ary->total_count = priv->rdrcount;
664252726Srpaulo
665252726Srpaulo			STAILQ_FOREACH(entry, &priv->redirhead, entries) {
666252726Srpaulo				bcopy(&entry->rdr, &ary->redirects[i++],
667252726Srpaulo				    sizeof(struct ng_nat_listrdrs_entry));
668252726Srpaulo			}
669252726Srpaulo		    }
670252726Srpaulo			break;
671252726Srpaulo		case NGM_NAT_PROXY_RULE:
672252726Srpaulo		    {
673252726Srpaulo			char *cmd = (char *)msg->data;
674252726Srpaulo
675252726Srpaulo			if (msg->header.arglen < 6) {
676252726Srpaulo				error = EINVAL;
677252726Srpaulo				break;
678252726Srpaulo			}
679252726Srpaulo
680252726Srpaulo			if (LibAliasProxyRule(priv->lib, cmd) != 0)
681252726Srpaulo				error = ENOMEM;
682252726Srpaulo		    }
683252726Srpaulo			break;
684252726Srpaulo		case NGM_NAT_LIBALIAS_INFO:
685252726Srpaulo		    {
686252726Srpaulo			struct ng_nat_libalias_info *i;
687252726Srpaulo
688252726Srpaulo			NG_MKRESPONSE(resp, msg,
689252726Srpaulo			    sizeof(struct ng_nat_libalias_info), M_NOWAIT);
690252726Srpaulo			if (resp == NULL) {
691252726Srpaulo				error = ENOMEM;
692252726Srpaulo				break;
693252726Srpaulo			}
694252726Srpaulo			i = (struct ng_nat_libalias_info *)resp->data;
695252726Srpaulo#define	COPY(F)	do {						\
696252726Srpaulo	if (priv->lib->F >= 0 && priv->lib->F < UINT32_MAX)	\
697252726Srpaulo		i->F = priv->lib->F;				\
698252726Srpaulo	else							\
699252726Srpaulo		i->F = UINT32_MAX;				\
700252726Srpaulo} while (0)
701252726Srpaulo
702252726Srpaulo			COPY(icmpLinkCount);
703252726Srpaulo			COPY(udpLinkCount);
704252726Srpaulo			COPY(tcpLinkCount);
705252726Srpaulo			COPY(pptpLinkCount);
706252726Srpaulo			COPY(sctpLinkCount);
707252726Srpaulo			COPY(protoLinkCount);
708252726Srpaulo			COPY(fragmentIdLinkCount);
709252726Srpaulo			COPY(fragmentPtrLinkCount);
710252726Srpaulo			COPY(sockCount);
711252726Srpaulo#undef COPY
712252726Srpaulo		    }
713252726Srpaulo			break;
714252726Srpaulo		case NGM_NAT_SET_DLT:
715252726Srpaulo			if (msg->header.arglen != sizeof(uint8_t)) {
716252726Srpaulo				error = EINVAL;
717252726Srpaulo				break;
718252726Srpaulo			}
719252726Srpaulo			switch (*(uint8_t *) msg->data) {
720252726Srpaulo			case DLT_EN10MB:
721252726Srpaulo			case DLT_RAW:
722252726Srpaulo				priv->dlt = *(uint8_t *) msg->data;
723252726Srpaulo				break;
724252726Srpaulo			default:
725252726Srpaulo				error = EINVAL;
726252726Srpaulo				break;
727252726Srpaulo			}
728252726Srpaulo			break;
729252726Srpaulo		default:
730252726Srpaulo			error = EINVAL;		/* unknown command */
731252726Srpaulo			break;
732252726Srpaulo		}
733252726Srpaulo		break;
734252726Srpaulo		case NGM_NAT_GET_DLT:
735252726Srpaulo			NG_MKRESPONSE(resp, msg, sizeof(uint8_t), M_WAITOK);
736252726Srpaulo                        if (resp == NULL) {
737252726Srpaulo                                error = ENOMEM;
738252726Srpaulo				break;
739252726Srpaulo			}
740252726Srpaulo			*((uint8_t *) resp->data) = priv->dlt;
741252726Srpaulo			break;
742252726Srpaulo	default:
743252726Srpaulo		error = EINVAL;			/* unknown cookie type */
744252726Srpaulo		break;
745252726Srpaulo	}
746252726Srpaulo
747252726Srpaulo	NG_RESPOND_MSG(error, node, item, resp);
748252726Srpaulo	NG_FREE_MSG(msg);
749252726Srpaulo	return (error);
750252726Srpaulo}
751252726Srpaulo
752252726Srpaulostatic int
753252726Srpaulong_nat_rcvdata(hook_p hook, item_p item )
754252726Srpaulo{
755252726Srpaulo	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
756252726Srpaulo	struct mbuf	*m;
757252726Srpaulo	struct ip	*ip;
758252726Srpaulo	int rval, ipofs, error = 0;
759252726Srpaulo	char *c;
760252726Srpaulo
761252726Srpaulo	/* We have no required hooks. */
762252726Srpaulo	if (!(priv->flags & NGNAT_CONNECTED)) {
763252726Srpaulo		NG_FREE_ITEM(item);
764252726Srpaulo		return (ENXIO);
765252726Srpaulo	}
766252726Srpaulo
767252726Srpaulo	/* We have no alias address yet to do anything. */
768252726Srpaulo	if (!(priv->flags & NGNAT_ADDR_DEFINED))
769252726Srpaulo		goto send;
770252726Srpaulo
771252726Srpaulo	m = NGI_M(item);
772252726Srpaulo
773252726Srpaulo	if ((m = m_megapullup(m, m->m_pkthdr.len)) == NULL) {
774252726Srpaulo		NGI_M(item) = NULL;	/* avoid double free */
775252726Srpaulo		NG_FREE_ITEM(item);
776252726Srpaulo		return (ENOBUFS);
777252726Srpaulo	}
778252726Srpaulo
779252726Srpaulo	NGI_M(item) = m;
780252726Srpaulo
781252726Srpaulo	switch (priv->dlt) {
782252726Srpaulo	case DLT_RAW:
783252726Srpaulo		ipofs = 0;
784252726Srpaulo		break;
785252726Srpaulo	case DLT_EN10MB:
786252726Srpaulo	    {
787252726Srpaulo		struct ether_header *eh;
788252726Srpaulo
789252726Srpaulo		if (m->m_pkthdr.len < sizeof(struct ether_header)) {
790252726Srpaulo			NG_FREE_ITEM(item);
791252726Srpaulo			return (ENXIO);
792252726Srpaulo		}
793252726Srpaulo		eh = mtod(m, struct ether_header *);
794252726Srpaulo		switch (ntohs(eh->ether_type)) {
795252726Srpaulo		case ETHERTYPE_IP:
796252726Srpaulo			ipofs = sizeof(struct ether_header);
797252726Srpaulo			break;
798252726Srpaulo		default:
799252726Srpaulo			goto send;
800189251Ssam		}
801189251Ssam		break;
802189251Ssam	    }
803189251Ssam	default:
804189251Ssam		panic("Corrupted priv->dlt: %u", priv->dlt);
805189251Ssam	}
806189251Ssam
807252726Srpaulo	if (m->m_pkthdr.len < ipofs + sizeof(struct ip))
808252726Srpaulo		goto send;		/* packet too short to hold IP */
809252726Srpaulo
810189251Ssam	c = (char *)mtodo(m, ipofs);
811189251Ssam	ip = (struct ip *)mtodo(m, ipofs);
812189251Ssam
813189251Ssam	if (ip->ip_v != IPVERSION)
814189251Ssam		goto send;		/* other IP version, let it pass */
815189251Ssam	if (m->m_pkthdr.len < ipofs + ntohs(ip->ip_len))
816252726Srpaulo		goto send;		/* packet too short (i.e. fragmented or broken) */
817252726Srpaulo
818214734Srpaulo	/*
819189251Ssam	 * We drop packet when:
820189251Ssam	 * 1. libalias returns PKT_ALIAS_ERROR;
821189251Ssam	 * 2. For incoming packets:
822189251Ssam	 *	a) for unresolved fragments;
823189251Ssam	 *	b) libalias returns PKT_ALIAS_IGNORED and
824214734Srpaulo	 *		PKT_ALIAS_DENY_INCOMING flag is set.
825189251Ssam	 */
826189251Ssam	if (hook == priv->in) {
827189251Ssam		rval = LibAliasIn(priv->lib, c, m->m_len - ipofs +
828189251Ssam		    M_TRAILINGSPACE(m));
829189251Ssam		if (rval == PKT_ALIAS_ERROR ||
830189251Ssam		    rval == PKT_ALIAS_UNRESOLVED_FRAGMENT ||
831189251Ssam		    (rval == PKT_ALIAS_IGNORED &&
832252726Srpaulo		     (priv->lib->packetAliasMode &
833252726Srpaulo		      PKT_ALIAS_DENY_INCOMING) != 0)) {
834252726Srpaulo			NG_FREE_ITEM(item);
835252726Srpaulo			return (EINVAL);
836252726Srpaulo		}
837252726Srpaulo	} else if (hook == priv->out) {
838252726Srpaulo		rval = LibAliasOut(priv->lib, c, m->m_len - ipofs +
839189251Ssam		    M_TRAILINGSPACE(m));
840189251Ssam		if (rval == PKT_ALIAS_ERROR) {
841189251Ssam			NG_FREE_ITEM(item);
842189251Ssam			return (EINVAL);
843189251Ssam		}
844189251Ssam	} else
845189251Ssam		panic("ng_nat: unknown hook!\n");
846189251Ssam
847189251Ssam	if (rval == PKT_ALIAS_RESPOND)
848252726Srpaulo		m->m_flags |= M_SKIP_FIREWALL;
849252726Srpaulo	m->m_pkthdr.len = m->m_len = ntohs(ip->ip_len) + ipofs;
850252726Srpaulo
851252726Srpaulo	if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
852189251Ssam	    ip->ip_p == IPPROTO_TCP) {
853189251Ssam		struct tcphdr *th = (struct tcphdr *)((caddr_t)ip +
854189251Ssam		    (ip->ip_hl << 2));
855189251Ssam
856189251Ssam		/*
857189251Ssam		 * Here is our terrible HACK.
858189251Ssam		 *
859189251Ssam		 * Sometimes LibAlias edits contents of TCP packet.
860189251Ssam		 * In this case it needs to recompute full TCP
861189251Ssam		 * checksum. However, the problem is that LibAlias
862189251Ssam		 * doesn't have any idea about checksum offloading
863189251Ssam		 * in kernel. To workaround this, we do not do
864189251Ssam		 * checksumming in LibAlias, but only mark the
865189251Ssam		 * packets in th_x2 field. If we receive a marked
866189251Ssam		 * packet, we calculate correct checksum for it
867189251Ssam		 * aware of offloading.
868189251Ssam		 *
869189251Ssam		 * Why do I do such a terrible hack instead of
870189251Ssam		 * recalculating checksum for each packet?
871189251Ssam		 * Because the previous checksum was not checked!
872189251Ssam		 * Recalculating checksums for EVERY packet will
873189251Ssam		 * hide ALL transmission errors. Yes, marked packets
874189251Ssam		 * still suffer from this problem. But, sigh, natd(8)
875189251Ssam		 * has this problem, too.
876189251Ssam		 */
877189251Ssam
878189251Ssam		if (th->th_x2) {
879189251Ssam			uint16_t ip_len = ntohs(ip->ip_len);
880189251Ssam
881189251Ssam			th->th_x2 = 0;
882189251Ssam			th->th_sum = in_pseudo(ip->ip_src.s_addr,
883189251Ssam			    ip->ip_dst.s_addr, htons(IPPROTO_TCP +
884189251Ssam			    ip_len - (ip->ip_hl << 2)));
885
886			if ((m->m_pkthdr.csum_flags & CSUM_TCP) == 0) {
887				m->m_pkthdr.csum_data = offsetof(struct tcphdr,
888				    th_sum);
889				in_delayed_cksum(m);
890			}
891		}
892	}
893
894send:
895	if (hook == priv->in)
896		NG_FWD_ITEM_HOOK(error, item, priv->out);
897	else
898		NG_FWD_ITEM_HOOK(error, item, priv->in);
899
900	return (error);
901}
902
903static int
904ng_nat_shutdown(node_p node)
905{
906	const priv_p priv = NG_NODE_PRIVATE(node);
907
908	NG_NODE_SET_PRIVATE(node, NULL);
909	NG_NODE_UNREF(node);
910
911	/* Free redirects list. */
912	while (!STAILQ_EMPTY(&priv->redirhead)) {
913		struct ng_nat_rdr_lst *entry = STAILQ_FIRST(&priv->redirhead);
914		STAILQ_REMOVE_HEAD(&priv->redirhead, entries);
915		free(entry, M_NETGRAPH);
916	}
917
918	/* Final free. */
919	LibAliasUninit(priv->lib);
920	free(priv, M_NETGRAPH);
921
922	return (0);
923}
924
925static int
926ng_nat_disconnect(hook_p hook)
927{
928	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
929
930	priv->flags &= ~NGNAT_CONNECTED;
931
932	if (hook == priv->out)
933		priv->out = NULL;
934	if (hook == priv->in)
935		priv->in = NULL;
936
937	if (priv->out == NULL && priv->in == NULL)
938		ng_rmnode_self(NG_HOOK_NODE(hook));
939
940	return (0);
941}
942
943static unsigned int
944ng_nat_translate_flags(unsigned int x)
945{
946	unsigned int	res = 0;
947
948	if (x & NG_NAT_LOG)
949		res |= PKT_ALIAS_LOG;
950	if (x & NG_NAT_DENY_INCOMING)
951		res |= PKT_ALIAS_DENY_INCOMING;
952	if (x & NG_NAT_SAME_PORTS)
953		res |= PKT_ALIAS_SAME_PORTS;
954	if (x & NG_NAT_UNREGISTERED_ONLY)
955		res |= PKT_ALIAS_UNREGISTERED_ONLY;
956	if (x & NG_NAT_RESET_ON_ADDR_CHANGE)
957		res |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
958	if (x & NG_NAT_PROXY_ONLY)
959		res |= PKT_ALIAS_PROXY_ONLY;
960	if (x & NG_NAT_REVERSE)
961		res |= PKT_ALIAS_REVERSE;
962	if (x & NG_NAT_UNREGISTERED_CGN)
963		res |= PKT_ALIAS_UNREGISTERED_CGN;
964
965	return (res);
966}
967