1c4c9b52bSGleb Smirnoff /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
4c4c9b52bSGleb Smirnoff * Copyright 2005, Gleb Smirnoff <glebius@FreeBSD.org>
5c4c9b52bSGleb Smirnoff * All rights reserved.
6c4c9b52bSGleb Smirnoff *
7c4c9b52bSGleb Smirnoff * Redistribution and use in source and binary forms, with or without
8c4c9b52bSGleb Smirnoff * modification, are permitted provided that the following conditions
9c4c9b52bSGleb Smirnoff * are met:
10c4c9b52bSGleb Smirnoff * 1. Redistributions of source code must retain the above copyright
11c4c9b52bSGleb Smirnoff * notice, this list of conditions and the following disclaimer.
12c4c9b52bSGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright
13c4c9b52bSGleb Smirnoff * notice, this list of conditions and the following disclaimer in the
14c4c9b52bSGleb Smirnoff * documentation and/or other materials provided with the distribution.
15c4c9b52bSGleb Smirnoff *
16c4c9b52bSGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17c4c9b52bSGleb Smirnoff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18c4c9b52bSGleb Smirnoff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19c4c9b52bSGleb Smirnoff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20c4c9b52bSGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21c4c9b52bSGleb Smirnoff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22c4c9b52bSGleb Smirnoff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23c4c9b52bSGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24c4c9b52bSGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25c4c9b52bSGleb Smirnoff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26c4c9b52bSGleb Smirnoff * SUCH DAMAGE.
27c4c9b52bSGleb Smirnoff */
28c4c9b52bSGleb Smirnoff
29c4c9b52bSGleb Smirnoff #include <sys/param.h>
30c4c9b52bSGleb Smirnoff #include <sys/systm.h>
31c4c9b52bSGleb Smirnoff #include <sys/kernel.h>
32c4c9b52bSGleb Smirnoff #include <sys/mbuf.h>
33c4c9b52bSGleb Smirnoff #include <sys/malloc.h>
34c4c9b52bSGleb Smirnoff #include <sys/ctype.h>
35c4c9b52bSGleb Smirnoff #include <sys/errno.h>
36c4c9b52bSGleb Smirnoff #include <sys/syslog.h>
37c4c9b52bSGleb Smirnoff
38c4c9b52bSGleb Smirnoff #include <netinet/in_systm.h>
39c4c9b52bSGleb Smirnoff #include <netinet/in.h>
40c4c9b52bSGleb Smirnoff #include <netinet/ip.h>
413a48a9faSGleb Smirnoff #include <netinet/ip_var.h>
42c4c9b52bSGleb Smirnoff #include <netinet/tcp.h>
433a48a9faSGleb Smirnoff #include <machine/in_cksum.h>
44c4c9b52bSGleb Smirnoff
45b7841ae6SMaxim Sobolev #include <net/dlt.h>
46b7841ae6SMaxim Sobolev #include <net/ethernet.h>
47b7841ae6SMaxim Sobolev
48c4c9b52bSGleb Smirnoff #include <netinet/libalias/alias.h>
49c57e67d0SAndrey V. Elsukov #include <netinet/libalias/alias_local.h>
50c4c9b52bSGleb Smirnoff
51c4c9b52bSGleb Smirnoff #include <netgraph/ng_message.h>
52c4c9b52bSGleb Smirnoff #include <netgraph/ng_parse.h>
53c4c9b52bSGleb Smirnoff #include <netgraph/ng_nat.h>
54c4c9b52bSGleb Smirnoff #include <netgraph/netgraph.h>
55c4c9b52bSGleb Smirnoff
569b8db664SDmitry Lukhtionov #ifdef NG_SEPARATE_MALLOC
579b8db664SDmitry Lukhtionov static MALLOC_DEFINE(M_NETGRAPH_NAT, "netgraph_nat", "netgraph nat node");
589b8db664SDmitry Lukhtionov #else
599b8db664SDmitry Lukhtionov #define M_NETGRAPH_NAT M_NETGRAPH
609b8db664SDmitry Lukhtionov #endif
619b8db664SDmitry Lukhtionov
62c4c9b52bSGleb Smirnoff static ng_constructor_t ng_nat_constructor;
63c4c9b52bSGleb Smirnoff static ng_rcvmsg_t ng_nat_rcvmsg;
64c4c9b52bSGleb Smirnoff static ng_shutdown_t ng_nat_shutdown;
65c4c9b52bSGleb Smirnoff static ng_newhook_t ng_nat_newhook;
66c4c9b52bSGleb Smirnoff static ng_rcvdata_t ng_nat_rcvdata;
67c4c9b52bSGleb Smirnoff static ng_disconnect_t ng_nat_disconnect;
68c4c9b52bSGleb Smirnoff
69e842c540SAlexander Motin static unsigned int ng_nat_translate_flags(unsigned int x);
70e842c540SAlexander Motin
71e842c540SAlexander Motin /* Parse type for struct ng_nat_mode. */
72e842c540SAlexander Motin static const struct ng_parse_struct_field ng_nat_mode_fields[]
73e842c540SAlexander Motin = NG_NAT_MODE_INFO;
74e842c540SAlexander Motin static const struct ng_parse_type ng_nat_mode_type = {
75e842c540SAlexander Motin &ng_parse_struct_type,
76fffba935SAlexander Motin &ng_nat_mode_fields
77fffba935SAlexander Motin };
78fffba935SAlexander Motin
79fffba935SAlexander Motin /* Parse type for 'description' field in structs. */
80fffba935SAlexander Motin static const struct ng_parse_fixedstring_info ng_nat_description_info
81fffba935SAlexander Motin = { NG_NAT_DESC_LENGTH };
82fffba935SAlexander Motin static const struct ng_parse_type ng_nat_description_type = {
83fffba935SAlexander Motin &ng_parse_fixedstring_type,
84fffba935SAlexander Motin &ng_nat_description_info
85fffba935SAlexander Motin };
86fffba935SAlexander Motin
87fffba935SAlexander Motin /* Parse type for struct ng_nat_redirect_port. */
88fffba935SAlexander Motin static const struct ng_parse_struct_field ng_nat_redirect_port_fields[]
89fffba935SAlexander Motin = NG_NAT_REDIRECT_PORT_TYPE_INFO(&ng_nat_description_type);
90fffba935SAlexander Motin static const struct ng_parse_type ng_nat_redirect_port_type = {
91fffba935SAlexander Motin &ng_parse_struct_type,
92fffba935SAlexander Motin &ng_nat_redirect_port_fields
93fffba935SAlexander Motin };
94fffba935SAlexander Motin
95fffba935SAlexander Motin /* Parse type for struct ng_nat_redirect_addr. */
96fffba935SAlexander Motin static const struct ng_parse_struct_field ng_nat_redirect_addr_fields[]
97fffba935SAlexander Motin = NG_NAT_REDIRECT_ADDR_TYPE_INFO(&ng_nat_description_type);
98fffba935SAlexander Motin static const struct ng_parse_type ng_nat_redirect_addr_type = {
99fffba935SAlexander Motin &ng_parse_struct_type,
100fffba935SAlexander Motin &ng_nat_redirect_addr_fields
101fffba935SAlexander Motin };
102fffba935SAlexander Motin
103fffba935SAlexander Motin /* Parse type for struct ng_nat_redirect_proto. */
104fffba935SAlexander Motin static const struct ng_parse_struct_field ng_nat_redirect_proto_fields[]
105fffba935SAlexander Motin = NG_NAT_REDIRECT_PROTO_TYPE_INFO(&ng_nat_description_type);
106fffba935SAlexander Motin static const struct ng_parse_type ng_nat_redirect_proto_type = {
107fffba935SAlexander Motin &ng_parse_struct_type,
108fffba935SAlexander Motin &ng_nat_redirect_proto_fields
109fffba935SAlexander Motin };
110fffba935SAlexander Motin
111fffba935SAlexander Motin /* Parse type for struct ng_nat_add_server. */
112fffba935SAlexander Motin static const struct ng_parse_struct_field ng_nat_add_server_fields[]
113fffba935SAlexander Motin = NG_NAT_ADD_SERVER_TYPE_INFO;
114fffba935SAlexander Motin static const struct ng_parse_type ng_nat_add_server_type = {
115fffba935SAlexander Motin &ng_parse_struct_type,
116fffba935SAlexander Motin &ng_nat_add_server_fields
117fffba935SAlexander Motin };
118fffba935SAlexander Motin
119fffba935SAlexander Motin /* Parse type for one struct ng_nat_listrdrs_entry. */
120fffba935SAlexander Motin static const struct ng_parse_struct_field ng_nat_listrdrs_entry_fields[]
121fffba935SAlexander Motin = NG_NAT_LISTRDRS_ENTRY_TYPE_INFO(&ng_nat_description_type);
122fffba935SAlexander Motin static const struct ng_parse_type ng_nat_listrdrs_entry_type = {
123fffba935SAlexander Motin &ng_parse_struct_type,
124fffba935SAlexander Motin &ng_nat_listrdrs_entry_fields
125fffba935SAlexander Motin };
126fffba935SAlexander Motin
127fffba935SAlexander Motin /* Parse type for 'redirects' array in struct ng_nat_list_redirects. */
128fffba935SAlexander Motin static int
ng_nat_listrdrs_ary_getLength(const struct ng_parse_type * type,const u_char * start,const u_char * buf)129fffba935SAlexander Motin ng_nat_listrdrs_ary_getLength(const struct ng_parse_type *type,
130fffba935SAlexander Motin const u_char *start, const u_char *buf)
131fffba935SAlexander Motin {
132fffba935SAlexander Motin const struct ng_nat_list_redirects *lr;
133fffba935SAlexander Motin
134fffba935SAlexander Motin lr = (const struct ng_nat_list_redirects *)
135fffba935SAlexander Motin (buf - offsetof(struct ng_nat_list_redirects, redirects));
136fffba935SAlexander Motin return lr->total_count;
137fffba935SAlexander Motin }
138fffba935SAlexander Motin
139fffba935SAlexander Motin static const struct ng_parse_array_info ng_nat_listrdrs_ary_info = {
140fffba935SAlexander Motin &ng_nat_listrdrs_entry_type,
141fffba935SAlexander Motin &ng_nat_listrdrs_ary_getLength,
142fffba935SAlexander Motin NULL
143fffba935SAlexander Motin };
144fffba935SAlexander Motin static const struct ng_parse_type ng_nat_listrdrs_ary_type = {
145fffba935SAlexander Motin &ng_parse_array_type,
146fffba935SAlexander Motin &ng_nat_listrdrs_ary_info
147fffba935SAlexander Motin };
148fffba935SAlexander Motin
149fffba935SAlexander Motin /* Parse type for struct ng_nat_list_redirects. */
150fffba935SAlexander Motin static const struct ng_parse_struct_field ng_nat_list_redirects_fields[]
151fffba935SAlexander Motin = NG_NAT_LIST_REDIRECTS_TYPE_INFO(&ng_nat_listrdrs_ary_type);
152fffba935SAlexander Motin static const struct ng_parse_type ng_nat_list_redirects_type = {
153fffba935SAlexander Motin &ng_parse_struct_type,
154fffba935SAlexander Motin &ng_nat_list_redirects_fields
155e842c540SAlexander Motin };
156e842c540SAlexander Motin
1575aedfa32SGleb Smirnoff /* Parse type for struct ng_nat_libalias_info. */
1585aedfa32SGleb Smirnoff static const struct ng_parse_struct_field ng_nat_libalias_info_fields[]
1595aedfa32SGleb Smirnoff = NG_NAT_LIBALIAS_INFO;
1605aedfa32SGleb Smirnoff static const struct ng_parse_type ng_nat_libalias_info_type = {
1615aedfa32SGleb Smirnoff &ng_parse_struct_type,
1625aedfa32SGleb Smirnoff &ng_nat_libalias_info_fields
1635aedfa32SGleb Smirnoff };
1645aedfa32SGleb Smirnoff
165c4c9b52bSGleb Smirnoff /* List of commands and how to convert arguments to/from ASCII. */
166c4c9b52bSGleb Smirnoff static const struct ng_cmdlist ng_nat_cmdlist[] = {
167c4c9b52bSGleb Smirnoff {
168c4c9b52bSGleb Smirnoff NGM_NAT_COOKIE,
169c4c9b52bSGleb Smirnoff NGM_NAT_SET_IPADDR,
170c4c9b52bSGleb Smirnoff "setaliasaddr",
171c4c9b52bSGleb Smirnoff &ng_parse_ipaddr_type,
172c4c9b52bSGleb Smirnoff NULL
173c4c9b52bSGleb Smirnoff },
174e842c540SAlexander Motin {
175e842c540SAlexander Motin NGM_NAT_COOKIE,
176e842c540SAlexander Motin NGM_NAT_SET_MODE,
177e842c540SAlexander Motin "setmode",
178e842c540SAlexander Motin &ng_nat_mode_type,
179e842c540SAlexander Motin NULL
180e842c540SAlexander Motin },
181e842c540SAlexander Motin {
182e842c540SAlexander Motin NGM_NAT_COOKIE,
183e842c540SAlexander Motin NGM_NAT_SET_TARGET,
184e842c540SAlexander Motin "settarget",
185e842c540SAlexander Motin &ng_parse_ipaddr_type,
186e842c540SAlexander Motin NULL
187e842c540SAlexander Motin },
188fffba935SAlexander Motin {
189fffba935SAlexander Motin NGM_NAT_COOKIE,
190fffba935SAlexander Motin NGM_NAT_REDIRECT_PORT,
191fffba935SAlexander Motin "redirectport",
192fffba935SAlexander Motin &ng_nat_redirect_port_type,
193fffba935SAlexander Motin &ng_parse_uint32_type
194fffba935SAlexander Motin },
195fffba935SAlexander Motin {
196fffba935SAlexander Motin NGM_NAT_COOKIE,
197fffba935SAlexander Motin NGM_NAT_REDIRECT_ADDR,
198fffba935SAlexander Motin "redirectaddr",
199fffba935SAlexander Motin &ng_nat_redirect_addr_type,
200fffba935SAlexander Motin &ng_parse_uint32_type
201fffba935SAlexander Motin },
202fffba935SAlexander Motin {
203fffba935SAlexander Motin NGM_NAT_COOKIE,
204fffba935SAlexander Motin NGM_NAT_REDIRECT_PROTO,
205fffba935SAlexander Motin "redirectproto",
206fffba935SAlexander Motin &ng_nat_redirect_proto_type,
207fffba935SAlexander Motin &ng_parse_uint32_type
208fffba935SAlexander Motin },
209fffba935SAlexander Motin {
210fffba935SAlexander Motin NGM_NAT_COOKIE,
211fffba935SAlexander Motin NGM_NAT_REDIRECT_DYNAMIC,
212fffba935SAlexander Motin "redirectdynamic",
213fffba935SAlexander Motin &ng_parse_uint32_type,
214fffba935SAlexander Motin NULL
215fffba935SAlexander Motin },
216fffba935SAlexander Motin {
217fffba935SAlexander Motin NGM_NAT_COOKIE,
218fffba935SAlexander Motin NGM_NAT_REDIRECT_DELETE,
219fffba935SAlexander Motin "redirectdelete",
220fffba935SAlexander Motin &ng_parse_uint32_type,
221fffba935SAlexander Motin NULL
222fffba935SAlexander Motin },
223fffba935SAlexander Motin {
224fffba935SAlexander Motin NGM_NAT_COOKIE,
225fffba935SAlexander Motin NGM_NAT_ADD_SERVER,
226fffba935SAlexander Motin "addserver",
227fffba935SAlexander Motin &ng_nat_add_server_type,
228fffba935SAlexander Motin NULL
229fffba935SAlexander Motin },
230fffba935SAlexander Motin {
231fffba935SAlexander Motin NGM_NAT_COOKIE,
232fffba935SAlexander Motin NGM_NAT_LIST_REDIRECTS,
233fffba935SAlexander Motin "listredirects",
234fffba935SAlexander Motin NULL,
235fffba935SAlexander Motin &ng_nat_list_redirects_type
236fffba935SAlexander Motin },
237fffba935SAlexander Motin {
238fffba935SAlexander Motin NGM_NAT_COOKIE,
239fffba935SAlexander Motin NGM_NAT_PROXY_RULE,
240fffba935SAlexander Motin "proxyrule",
241fffba935SAlexander Motin &ng_parse_string_type,
242fffba935SAlexander Motin NULL
243fffba935SAlexander Motin },
2445aedfa32SGleb Smirnoff {
2455aedfa32SGleb Smirnoff NGM_NAT_COOKIE,
2465aedfa32SGleb Smirnoff NGM_NAT_LIBALIAS_INFO,
2475aedfa32SGleb Smirnoff "libaliasinfo",
2485aedfa32SGleb Smirnoff NULL,
2495aedfa32SGleb Smirnoff &ng_nat_libalias_info_type
2505aedfa32SGleb Smirnoff },
251b7841ae6SMaxim Sobolev {
252b7841ae6SMaxim Sobolev NGM_NAT_COOKIE,
253b7841ae6SMaxim Sobolev NGM_NAT_SET_DLT,
254b7841ae6SMaxim Sobolev "setdlt",
255b7841ae6SMaxim Sobolev &ng_parse_uint8_type,
256b7841ae6SMaxim Sobolev NULL
257b7841ae6SMaxim Sobolev },
258b7841ae6SMaxim Sobolev {
259b7841ae6SMaxim Sobolev NGM_NAT_COOKIE,
260b7841ae6SMaxim Sobolev NGM_NAT_GET_DLT,
261b7841ae6SMaxim Sobolev "getdlt",
262b7841ae6SMaxim Sobolev NULL,
263b7841ae6SMaxim Sobolev &ng_parse_uint8_type
264b7841ae6SMaxim Sobolev },
265c4c9b52bSGleb Smirnoff { 0 }
266c4c9b52bSGleb Smirnoff };
267c4c9b52bSGleb Smirnoff
268c4c9b52bSGleb Smirnoff /* Netgraph node type descriptor. */
269c4c9b52bSGleb Smirnoff static struct ng_type typestruct = {
270c4c9b52bSGleb Smirnoff .version = NG_ABI_VERSION,
271c4c9b52bSGleb Smirnoff .name = NG_NAT_NODE_TYPE,
272c4c9b52bSGleb Smirnoff .constructor = ng_nat_constructor,
273c4c9b52bSGleb Smirnoff .rcvmsg = ng_nat_rcvmsg,
274c4c9b52bSGleb Smirnoff .shutdown = ng_nat_shutdown,
275c4c9b52bSGleb Smirnoff .newhook = ng_nat_newhook,
276c4c9b52bSGleb Smirnoff .rcvdata = ng_nat_rcvdata,
277c4c9b52bSGleb Smirnoff .disconnect = ng_nat_disconnect,
278c4c9b52bSGleb Smirnoff .cmdlist = ng_nat_cmdlist,
279c4c9b52bSGleb Smirnoff };
280c4c9b52bSGleb Smirnoff NETGRAPH_INIT(nat, &typestruct);
281c4c9b52bSGleb Smirnoff MODULE_DEPEND(ng_nat, libalias, 1, 1, 1);
282c4c9b52bSGleb Smirnoff
283fffba935SAlexander Motin /* Element for list of redirects. */
284fffba935SAlexander Motin struct ng_nat_rdr_lst {
285fffba935SAlexander Motin STAILQ_ENTRY(ng_nat_rdr_lst) entries;
286fffba935SAlexander Motin struct alias_link *lnk;
287fffba935SAlexander Motin struct ng_nat_listrdrs_entry rdr;
288fffba935SAlexander Motin };
289fffba935SAlexander Motin STAILQ_HEAD(rdrhead, ng_nat_rdr_lst);
290fffba935SAlexander Motin
291c4c9b52bSGleb Smirnoff /* Information we store for each node. */
292b0dc0083SGleb Smirnoff struct ng_nat_priv {
293c4c9b52bSGleb Smirnoff node_p node; /* back pointer to node */
294c4c9b52bSGleb Smirnoff hook_p in; /* hook for demasquerading */
295c4c9b52bSGleb Smirnoff hook_p out; /* hook for masquerading */
296c4c9b52bSGleb Smirnoff struct libalias *lib; /* libalias handler */
297c4c9b52bSGleb Smirnoff uint32_t flags; /* status flags */
298fffba935SAlexander Motin uint32_t rdrcount; /* number or redirects in list */
299fffba935SAlexander Motin uint32_t nextid; /* for next in turn in list */
300fffba935SAlexander Motin struct rdrhead redirhead; /* redirect list header */
301b7841ae6SMaxim Sobolev uint8_t dlt; /* DLT_XXX from bpf.h */
302c4c9b52bSGleb Smirnoff };
303b0dc0083SGleb Smirnoff typedef struct ng_nat_priv *priv_p;
304c4c9b52bSGleb Smirnoff
305c4c9b52bSGleb Smirnoff /* Values of flags */
306179f56e1SAlexander Motin #define NGNAT_CONNECTED 0x1 /* We have both hooks connected */
307c4c9b52bSGleb Smirnoff #define NGNAT_ADDR_DEFINED 0x2 /* NGM_NAT_SET_IPADDR happened */
308c4c9b52bSGleb Smirnoff
309c4c9b52bSGleb Smirnoff static int
ng_nat_constructor(node_p node)310c4c9b52bSGleb Smirnoff ng_nat_constructor(node_p node)
311c4c9b52bSGleb Smirnoff {
312c4c9b52bSGleb Smirnoff priv_p priv;
313c4c9b52bSGleb Smirnoff
314c4c9b52bSGleb Smirnoff /* Initialize private descriptor. */
3159b8db664SDmitry Lukhtionov priv = malloc(sizeof(*priv), M_NETGRAPH_NAT, M_WAITOK | M_ZERO);
316c4c9b52bSGleb Smirnoff
317c4c9b52bSGleb Smirnoff /* Init aliasing engine. */
318c4c9b52bSGleb Smirnoff priv->lib = LibAliasInit(NULL);
319c4c9b52bSGleb Smirnoff
320c4c9b52bSGleb Smirnoff /* Set same ports on. */
321c4c9b52bSGleb Smirnoff (void )LibAliasSetMode(priv->lib, PKT_ALIAS_SAME_PORTS,
322c4c9b52bSGleb Smirnoff PKT_ALIAS_SAME_PORTS);
323c4c9b52bSGleb Smirnoff
324fffba935SAlexander Motin /* Init redirects housekeeping. */
325fffba935SAlexander Motin priv->rdrcount = 0;
326fffba935SAlexander Motin priv->nextid = 1;
327b7841ae6SMaxim Sobolev priv->dlt = DLT_RAW;
328fffba935SAlexander Motin STAILQ_INIT(&priv->redirhead);
329fffba935SAlexander Motin
330c4c9b52bSGleb Smirnoff /* Link structs together. */
331c4c9b52bSGleb Smirnoff NG_NODE_SET_PRIVATE(node, priv);
332c4c9b52bSGleb Smirnoff priv->node = node;
333c4c9b52bSGleb Smirnoff
334c4c9b52bSGleb Smirnoff /*
335c4c9b52bSGleb Smirnoff * libalias is not thread safe, so our node
336c4c9b52bSGleb Smirnoff * must be single threaded.
337c4c9b52bSGleb Smirnoff */
338c4c9b52bSGleb Smirnoff NG_NODE_FORCE_WRITER(node);
339c4c9b52bSGleb Smirnoff
340c4c9b52bSGleb Smirnoff return (0);
341c4c9b52bSGleb Smirnoff }
342c4c9b52bSGleb Smirnoff
343c4c9b52bSGleb Smirnoff static int
ng_nat_newhook(node_p node,hook_p hook,const char * name)344c4c9b52bSGleb Smirnoff ng_nat_newhook(node_p node, hook_p hook, const char *name)
345c4c9b52bSGleb Smirnoff {
346c4c9b52bSGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(node);
347c4c9b52bSGleb Smirnoff
348c4c9b52bSGleb Smirnoff if (strcmp(name, NG_NAT_HOOK_IN) == 0) {
349c4c9b52bSGleb Smirnoff priv->in = hook;
350c4c9b52bSGleb Smirnoff } else if (strcmp(name, NG_NAT_HOOK_OUT) == 0) {
351c4c9b52bSGleb Smirnoff priv->out = hook;
352c4c9b52bSGleb Smirnoff } else
353c4c9b52bSGleb Smirnoff return (EINVAL);
354c4c9b52bSGleb Smirnoff
355c4c9b52bSGleb Smirnoff if (priv->out != NULL &&
356179f56e1SAlexander Motin priv->in != NULL)
357179f56e1SAlexander Motin priv->flags |= NGNAT_CONNECTED;
358c4c9b52bSGleb Smirnoff
359c4c9b52bSGleb Smirnoff return(0);
360c4c9b52bSGleb Smirnoff }
361c4c9b52bSGleb Smirnoff
362c4c9b52bSGleb Smirnoff static int
ng_nat_rcvmsg(node_p node,item_p item,hook_p lasthook)363c4c9b52bSGleb Smirnoff ng_nat_rcvmsg(node_p node, item_p item, hook_p lasthook)
364c4c9b52bSGleb Smirnoff {
365c4c9b52bSGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(node);
366c4c9b52bSGleb Smirnoff struct ng_mesg *resp = NULL;
367c4c9b52bSGleb Smirnoff struct ng_mesg *msg;
368c4c9b52bSGleb Smirnoff int error = 0;
369c4c9b52bSGleb Smirnoff
370c4c9b52bSGleb Smirnoff NGI_GET_MSG(item, msg);
371c4c9b52bSGleb Smirnoff
372c4c9b52bSGleb Smirnoff switch (msg->header.typecookie) {
373c4c9b52bSGleb Smirnoff case NGM_NAT_COOKIE:
374c4c9b52bSGleb Smirnoff switch (msg->header.cmd) {
375c4c9b52bSGleb Smirnoff case NGM_NAT_SET_IPADDR:
376c4c9b52bSGleb Smirnoff {
377c4c9b52bSGleb Smirnoff struct in_addr *const ia = (struct in_addr *)msg->data;
378c4c9b52bSGleb Smirnoff
379c4c9b52bSGleb Smirnoff if (msg->header.arglen < sizeof(*ia)) {
380c4c9b52bSGleb Smirnoff error = EINVAL;
381c4c9b52bSGleb Smirnoff break;
382c4c9b52bSGleb Smirnoff }
383c4c9b52bSGleb Smirnoff
384c4c9b52bSGleb Smirnoff LibAliasSetAddress(priv->lib, *ia);
385c4c9b52bSGleb Smirnoff
386c4c9b52bSGleb Smirnoff priv->flags |= NGNAT_ADDR_DEFINED;
387c4c9b52bSGleb Smirnoff }
388c4c9b52bSGleb Smirnoff break;
389e842c540SAlexander Motin case NGM_NAT_SET_MODE:
390e842c540SAlexander Motin {
391e842c540SAlexander Motin struct ng_nat_mode *const mode =
392e842c540SAlexander Motin (struct ng_nat_mode *)msg->data;
393e842c540SAlexander Motin
394e842c540SAlexander Motin if (msg->header.arglen < sizeof(*mode)) {
395e842c540SAlexander Motin error = EINVAL;
396e842c540SAlexander Motin break;
397e842c540SAlexander Motin }
398e842c540SAlexander Motin
399e842c540SAlexander Motin if (LibAliasSetMode(priv->lib,
400e842c540SAlexander Motin ng_nat_translate_flags(mode->flags),
401e842c540SAlexander Motin ng_nat_translate_flags(mode->mask)) < 0) {
402e842c540SAlexander Motin error = ENOMEM;
403e842c540SAlexander Motin break;
404e842c540SAlexander Motin }
405e842c540SAlexander Motin }
406e842c540SAlexander Motin break;
407e842c540SAlexander Motin case NGM_NAT_SET_TARGET:
408e842c540SAlexander Motin {
409e842c540SAlexander Motin struct in_addr *const ia = (struct in_addr *)msg->data;
410e842c540SAlexander Motin
411e842c540SAlexander Motin if (msg->header.arglen < sizeof(*ia)) {
412e842c540SAlexander Motin error = EINVAL;
413e842c540SAlexander Motin break;
414e842c540SAlexander Motin }
415e842c540SAlexander Motin
416e842c540SAlexander Motin LibAliasSetTarget(priv->lib, *ia);
417e842c540SAlexander Motin }
418e842c540SAlexander Motin break;
419fffba935SAlexander Motin case NGM_NAT_REDIRECT_PORT:
420fffba935SAlexander Motin {
421fffba935SAlexander Motin struct ng_nat_rdr_lst *entry;
422fffba935SAlexander Motin struct ng_nat_redirect_port *const rp =
423fffba935SAlexander Motin (struct ng_nat_redirect_port *)msg->data;
424fffba935SAlexander Motin
425fffba935SAlexander Motin if (msg->header.arglen < sizeof(*rp)) {
426fffba935SAlexander Motin error = EINVAL;
427fffba935SAlexander Motin break;
428fffba935SAlexander Motin }
429fffba935SAlexander Motin
430fffba935SAlexander Motin if ((entry = malloc(sizeof(struct ng_nat_rdr_lst),
4319b8db664SDmitry Lukhtionov M_NETGRAPH_NAT, M_NOWAIT | M_ZERO)) == NULL) {
432fffba935SAlexander Motin error = ENOMEM;
433fffba935SAlexander Motin break;
434fffba935SAlexander Motin }
435fffba935SAlexander Motin
436fffba935SAlexander Motin /* Try actual redirect. */
437fffba935SAlexander Motin entry->lnk = LibAliasRedirectPort(priv->lib,
438fffba935SAlexander Motin rp->local_addr, htons(rp->local_port),
439fffba935SAlexander Motin rp->remote_addr, htons(rp->remote_port),
440fffba935SAlexander Motin rp->alias_addr, htons(rp->alias_port),
441fffba935SAlexander Motin rp->proto);
442fffba935SAlexander Motin
443fffba935SAlexander Motin if (entry->lnk == NULL) {
444fffba935SAlexander Motin error = ENOMEM;
4459b8db664SDmitry Lukhtionov free(entry, M_NETGRAPH_NAT);
446fffba935SAlexander Motin break;
447fffba935SAlexander Motin }
448fffba935SAlexander Motin
449fffba935SAlexander Motin /* Successful, save info in our internal list. */
450fffba935SAlexander Motin entry->rdr.local_addr = rp->local_addr;
451fffba935SAlexander Motin entry->rdr.alias_addr = rp->alias_addr;
452fffba935SAlexander Motin entry->rdr.remote_addr = rp->remote_addr;
453fffba935SAlexander Motin entry->rdr.local_port = rp->local_port;
454fffba935SAlexander Motin entry->rdr.alias_port = rp->alias_port;
455fffba935SAlexander Motin entry->rdr.remote_port = rp->remote_port;
456fffba935SAlexander Motin entry->rdr.proto = rp->proto;
457fffba935SAlexander Motin bcopy(rp->description, entry->rdr.description,
458fffba935SAlexander Motin NG_NAT_DESC_LENGTH);
459fffba935SAlexander Motin
460fffba935SAlexander Motin /* Safety precaution. */
461fffba935SAlexander Motin entry->rdr.description[NG_NAT_DESC_LENGTH-1] = '\0';
462fffba935SAlexander Motin
463fffba935SAlexander Motin entry->rdr.id = priv->nextid++;
464fffba935SAlexander Motin priv->rdrcount++;
465fffba935SAlexander Motin
466fffba935SAlexander Motin /* Link to list of redirects. */
467fffba935SAlexander Motin STAILQ_INSERT_TAIL(&priv->redirhead, entry, entries);
468fffba935SAlexander Motin
469fffba935SAlexander Motin /* Response with id of newly added entry. */
470fffba935SAlexander Motin NG_MKRESPONSE(resp, msg, sizeof(entry->rdr.id), M_NOWAIT);
471fffba935SAlexander Motin if (resp == NULL) {
472fffba935SAlexander Motin error = ENOMEM;
473fffba935SAlexander Motin break;
474fffba935SAlexander Motin }
475fffba935SAlexander Motin bcopy(&entry->rdr.id, resp->data, sizeof(entry->rdr.id));
476fffba935SAlexander Motin }
477fffba935SAlexander Motin break;
478fffba935SAlexander Motin case NGM_NAT_REDIRECT_ADDR:
479fffba935SAlexander Motin {
480fffba935SAlexander Motin struct ng_nat_rdr_lst *entry;
481fffba935SAlexander Motin struct ng_nat_redirect_addr *const ra =
482fffba935SAlexander Motin (struct ng_nat_redirect_addr *)msg->data;
483fffba935SAlexander Motin
484fffba935SAlexander Motin if (msg->header.arglen < sizeof(*ra)) {
485fffba935SAlexander Motin error = EINVAL;
486fffba935SAlexander Motin break;
487fffba935SAlexander Motin }
488fffba935SAlexander Motin
489fffba935SAlexander Motin if ((entry = malloc(sizeof(struct ng_nat_rdr_lst),
4909b8db664SDmitry Lukhtionov M_NETGRAPH_NAT, M_NOWAIT | M_ZERO)) == NULL) {
491fffba935SAlexander Motin error = ENOMEM;
492fffba935SAlexander Motin break;
493fffba935SAlexander Motin }
494fffba935SAlexander Motin
495fffba935SAlexander Motin /* Try actual redirect. */
496fffba935SAlexander Motin entry->lnk = LibAliasRedirectAddr(priv->lib,
497fffba935SAlexander Motin ra->local_addr, ra->alias_addr);
498fffba935SAlexander Motin
499fffba935SAlexander Motin if (entry->lnk == NULL) {
500fffba935SAlexander Motin error = ENOMEM;
5019b8db664SDmitry Lukhtionov free(entry, M_NETGRAPH_NAT);
502fffba935SAlexander Motin break;
503fffba935SAlexander Motin }
504fffba935SAlexander Motin
505fffba935SAlexander Motin /* Successful, save info in our internal list. */
506fffba935SAlexander Motin entry->rdr.local_addr = ra->local_addr;
507fffba935SAlexander Motin entry->rdr.alias_addr = ra->alias_addr;
508fffba935SAlexander Motin entry->rdr.proto = NG_NAT_REDIRPROTO_ADDR;
509fffba935SAlexander Motin bcopy(ra->description, entry->rdr.description,
510fffba935SAlexander Motin NG_NAT_DESC_LENGTH);
511fffba935SAlexander Motin
512fffba935SAlexander Motin /* Safety precaution. */
513fffba935SAlexander Motin entry->rdr.description[NG_NAT_DESC_LENGTH-1] = '\0';
514fffba935SAlexander Motin
515fffba935SAlexander Motin entry->rdr.id = priv->nextid++;
516fffba935SAlexander Motin priv->rdrcount++;
517fffba935SAlexander Motin
518fffba935SAlexander Motin /* Link to list of redirects. */
519fffba935SAlexander Motin STAILQ_INSERT_TAIL(&priv->redirhead, entry, entries);
520fffba935SAlexander Motin
521fffba935SAlexander Motin /* Response with id of newly added entry. */
522fffba935SAlexander Motin NG_MKRESPONSE(resp, msg, sizeof(entry->rdr.id), M_NOWAIT);
523fffba935SAlexander Motin if (resp == NULL) {
524fffba935SAlexander Motin error = ENOMEM;
525fffba935SAlexander Motin break;
526fffba935SAlexander Motin }
527fffba935SAlexander Motin bcopy(&entry->rdr.id, resp->data, sizeof(entry->rdr.id));
528fffba935SAlexander Motin }
529fffba935SAlexander Motin break;
530fffba935SAlexander Motin case NGM_NAT_REDIRECT_PROTO:
531fffba935SAlexander Motin {
532fffba935SAlexander Motin struct ng_nat_rdr_lst *entry;
533fffba935SAlexander Motin struct ng_nat_redirect_proto *const rp =
534fffba935SAlexander Motin (struct ng_nat_redirect_proto *)msg->data;
535fffba935SAlexander Motin
536fffba935SAlexander Motin if (msg->header.arglen < sizeof(*rp)) {
537fffba935SAlexander Motin error = EINVAL;
538fffba935SAlexander Motin break;
539fffba935SAlexander Motin }
540fffba935SAlexander Motin
541fffba935SAlexander Motin if ((entry = malloc(sizeof(struct ng_nat_rdr_lst),
5429b8db664SDmitry Lukhtionov M_NETGRAPH_NAT, M_NOWAIT | M_ZERO)) == NULL) {
543fffba935SAlexander Motin error = ENOMEM;
544fffba935SAlexander Motin break;
545fffba935SAlexander Motin }
546fffba935SAlexander Motin
547fffba935SAlexander Motin /* Try actual redirect. */
548fffba935SAlexander Motin entry->lnk = LibAliasRedirectProto(priv->lib,
549fffba935SAlexander Motin rp->local_addr, rp->remote_addr,
550fffba935SAlexander Motin rp->alias_addr, rp->proto);
551fffba935SAlexander Motin
552fffba935SAlexander Motin if (entry->lnk == NULL) {
553fffba935SAlexander Motin error = ENOMEM;
5549b8db664SDmitry Lukhtionov free(entry, M_NETGRAPH_NAT);
555fffba935SAlexander Motin break;
556fffba935SAlexander Motin }
557fffba935SAlexander Motin
558fffba935SAlexander Motin /* Successful, save info in our internal list. */
559fffba935SAlexander Motin entry->rdr.local_addr = rp->local_addr;
560fffba935SAlexander Motin entry->rdr.alias_addr = rp->alias_addr;
561fffba935SAlexander Motin entry->rdr.remote_addr = rp->remote_addr;
562fffba935SAlexander Motin entry->rdr.proto = rp->proto;
563fffba935SAlexander Motin bcopy(rp->description, entry->rdr.description,
564fffba935SAlexander Motin NG_NAT_DESC_LENGTH);
565fffba935SAlexander Motin
566fffba935SAlexander Motin /* Safety precaution. */
567fffba935SAlexander Motin entry->rdr.description[NG_NAT_DESC_LENGTH-1] = '\0';
568fffba935SAlexander Motin
569fffba935SAlexander Motin entry->rdr.id = priv->nextid++;
570fffba935SAlexander Motin priv->rdrcount++;
571fffba935SAlexander Motin
572fffba935SAlexander Motin /* Link to list of redirects. */
573fffba935SAlexander Motin STAILQ_INSERT_TAIL(&priv->redirhead, entry, entries);
574fffba935SAlexander Motin
575fffba935SAlexander Motin /* Response with id of newly added entry. */
576fffba935SAlexander Motin NG_MKRESPONSE(resp, msg, sizeof(entry->rdr.id), M_NOWAIT);
577fffba935SAlexander Motin if (resp == NULL) {
578fffba935SAlexander Motin error = ENOMEM;
579fffba935SAlexander Motin break;
580fffba935SAlexander Motin }
581fffba935SAlexander Motin bcopy(&entry->rdr.id, resp->data, sizeof(entry->rdr.id));
582fffba935SAlexander Motin }
583fffba935SAlexander Motin break;
584fffba935SAlexander Motin case NGM_NAT_REDIRECT_DYNAMIC:
585fffba935SAlexander Motin case NGM_NAT_REDIRECT_DELETE:
586fffba935SAlexander Motin {
587fffba935SAlexander Motin struct ng_nat_rdr_lst *entry;
588fffba935SAlexander Motin uint32_t *const id = (uint32_t *)msg->data;
589fffba935SAlexander Motin
590fffba935SAlexander Motin if (msg->header.arglen < sizeof(*id)) {
591fffba935SAlexander Motin error = EINVAL;
592fffba935SAlexander Motin break;
593fffba935SAlexander Motin }
594fffba935SAlexander Motin
595fffba935SAlexander Motin /* Find entry with supplied id. */
596fffba935SAlexander Motin STAILQ_FOREACH(entry, &priv->redirhead, entries) {
597fffba935SAlexander Motin if (entry->rdr.id == *id)
598fffba935SAlexander Motin break;
599fffba935SAlexander Motin }
600fffba935SAlexander Motin
601fffba935SAlexander Motin /* Not found. */
602fffba935SAlexander Motin if (entry == NULL) {
603fffba935SAlexander Motin error = ENOENT;
604fffba935SAlexander Motin break;
605fffba935SAlexander Motin }
606fffba935SAlexander Motin
607fffba935SAlexander Motin if (msg->header.cmd == NGM_NAT_REDIRECT_DYNAMIC) {
608fffba935SAlexander Motin if (LibAliasRedirectDynamic(priv->lib,
609fffba935SAlexander Motin entry->lnk) == -1) {
610fffba935SAlexander Motin error = ENOTTY; /* XXX Something better? */
611fffba935SAlexander Motin break;
612fffba935SAlexander Motin }
613fffba935SAlexander Motin } else { /* NGM_NAT_REDIRECT_DELETE */
614fffba935SAlexander Motin LibAliasRedirectDelete(priv->lib, entry->lnk);
615fffba935SAlexander Motin }
616fffba935SAlexander Motin
617fffba935SAlexander Motin /* Delete entry from our internal list. */
618fffba935SAlexander Motin priv->rdrcount--;
619fffba935SAlexander Motin STAILQ_REMOVE(&priv->redirhead, entry, ng_nat_rdr_lst, entries);
6209b8db664SDmitry Lukhtionov free(entry, M_NETGRAPH_NAT);
621fffba935SAlexander Motin }
622fffba935SAlexander Motin break;
623fffba935SAlexander Motin case NGM_NAT_ADD_SERVER:
624fffba935SAlexander Motin {
625fffba935SAlexander Motin struct ng_nat_rdr_lst *entry;
626fffba935SAlexander Motin struct ng_nat_add_server *const as =
627fffba935SAlexander Motin (struct ng_nat_add_server *)msg->data;
628fffba935SAlexander Motin
629fffba935SAlexander Motin if (msg->header.arglen < sizeof(*as)) {
630fffba935SAlexander Motin error = EINVAL;
631fffba935SAlexander Motin break;
632fffba935SAlexander Motin }
633fffba935SAlexander Motin
634fffba935SAlexander Motin /* Find entry with supplied id. */
635fffba935SAlexander Motin STAILQ_FOREACH(entry, &priv->redirhead, entries) {
636fffba935SAlexander Motin if (entry->rdr.id == as->id)
637fffba935SAlexander Motin break;
638fffba935SAlexander Motin }
639fffba935SAlexander Motin
640fffba935SAlexander Motin /* Not found. */
641fffba935SAlexander Motin if (entry == NULL) {
642fffba935SAlexander Motin error = ENOENT;
643fffba935SAlexander Motin break;
644fffba935SAlexander Motin }
645fffba935SAlexander Motin
646fffba935SAlexander Motin if (LibAliasAddServer(priv->lib, entry->lnk,
647fffba935SAlexander Motin as->addr, htons(as->port)) == -1) {
648fffba935SAlexander Motin error = ENOMEM;
649fffba935SAlexander Motin break;
650fffba935SAlexander Motin }
651fffba935SAlexander Motin
652fffba935SAlexander Motin entry->rdr.lsnat++;
653fffba935SAlexander Motin }
654fffba935SAlexander Motin break;
655fffba935SAlexander Motin case NGM_NAT_LIST_REDIRECTS:
656fffba935SAlexander Motin {
657fffba935SAlexander Motin struct ng_nat_rdr_lst *entry;
658fffba935SAlexander Motin struct ng_nat_list_redirects *ary;
659fffba935SAlexander Motin int i = 0;
660fffba935SAlexander Motin
661fffba935SAlexander Motin NG_MKRESPONSE(resp, msg, sizeof(*ary) +
662fffba935SAlexander Motin (priv->rdrcount) * sizeof(*entry), M_NOWAIT);
663fffba935SAlexander Motin if (resp == NULL) {
664fffba935SAlexander Motin error = ENOMEM;
665fffba935SAlexander Motin break;
666fffba935SAlexander Motin }
667fffba935SAlexander Motin
668fffba935SAlexander Motin ary = (struct ng_nat_list_redirects *)resp->data;
669fffba935SAlexander Motin ary->total_count = priv->rdrcount;
670fffba935SAlexander Motin
671fffba935SAlexander Motin STAILQ_FOREACH(entry, &priv->redirhead, entries) {
672fffba935SAlexander Motin bcopy(&entry->rdr, &ary->redirects[i++],
673fffba935SAlexander Motin sizeof(struct ng_nat_listrdrs_entry));
674fffba935SAlexander Motin }
675fffba935SAlexander Motin }
676fffba935SAlexander Motin break;
677fffba935SAlexander Motin case NGM_NAT_PROXY_RULE:
678fffba935SAlexander Motin {
679fffba935SAlexander Motin char *cmd = (char *)msg->data;
680fffba935SAlexander Motin
681fffba935SAlexander Motin if (msg->header.arglen < 6) {
682fffba935SAlexander Motin error = EINVAL;
683fffba935SAlexander Motin break;
684fffba935SAlexander Motin }
685fffba935SAlexander Motin
686fffba935SAlexander Motin if (LibAliasProxyRule(priv->lib, cmd) != 0)
687fffba935SAlexander Motin error = ENOMEM;
688fffba935SAlexander Motin }
689fffba935SAlexander Motin break;
6905aedfa32SGleb Smirnoff case NGM_NAT_LIBALIAS_INFO:
6915aedfa32SGleb Smirnoff {
6925aedfa32SGleb Smirnoff struct ng_nat_libalias_info *i;
6935aedfa32SGleb Smirnoff
6945aedfa32SGleb Smirnoff NG_MKRESPONSE(resp, msg,
6955aedfa32SGleb Smirnoff sizeof(struct ng_nat_libalias_info), M_NOWAIT);
6965aedfa32SGleb Smirnoff if (resp == NULL) {
6975aedfa32SGleb Smirnoff error = ENOMEM;
6985aedfa32SGleb Smirnoff break;
6995aedfa32SGleb Smirnoff }
7005aedfa32SGleb Smirnoff i = (struct ng_nat_libalias_info *)resp->data;
7015aedfa32SGleb Smirnoff #define COPY(F) do { \
7025aedfa32SGleb Smirnoff if (priv->lib->F >= 0 && priv->lib->F < UINT32_MAX) \
7035aedfa32SGleb Smirnoff i->F = priv->lib->F; \
7045aedfa32SGleb Smirnoff else \
7055aedfa32SGleb Smirnoff i->F = UINT32_MAX; \
7065aedfa32SGleb Smirnoff } while (0)
7075aedfa32SGleb Smirnoff
7085aedfa32SGleb Smirnoff COPY(icmpLinkCount);
7095aedfa32SGleb Smirnoff COPY(udpLinkCount);
7105aedfa32SGleb Smirnoff COPY(tcpLinkCount);
7115aedfa32SGleb Smirnoff COPY(pptpLinkCount);
7125aedfa32SGleb Smirnoff COPY(sctpLinkCount);
7135aedfa32SGleb Smirnoff COPY(protoLinkCount);
7145aedfa32SGleb Smirnoff COPY(fragmentIdLinkCount);
7155aedfa32SGleb Smirnoff COPY(fragmentPtrLinkCount);
7165aedfa32SGleb Smirnoff COPY(sockCount);
7175aedfa32SGleb Smirnoff #undef COPY
7185aedfa32SGleb Smirnoff }
7195aedfa32SGleb Smirnoff break;
720b7841ae6SMaxim Sobolev case NGM_NAT_SET_DLT:
721b7841ae6SMaxim Sobolev if (msg->header.arglen != sizeof(uint8_t)) {
722b7841ae6SMaxim Sobolev error = EINVAL;
723b7841ae6SMaxim Sobolev break;
724b7841ae6SMaxim Sobolev }
725b7841ae6SMaxim Sobolev switch (*(uint8_t *) msg->data) {
726b7841ae6SMaxim Sobolev case DLT_EN10MB:
727b7841ae6SMaxim Sobolev case DLT_RAW:
728b7841ae6SMaxim Sobolev priv->dlt = *(uint8_t *) msg->data;
729b7841ae6SMaxim Sobolev break;
730b7841ae6SMaxim Sobolev default:
731b7841ae6SMaxim Sobolev error = EINVAL;
732b7841ae6SMaxim Sobolev break;
733b7841ae6SMaxim Sobolev }
734b7841ae6SMaxim Sobolev break;
735c4c9b52bSGleb Smirnoff default:
736c4c9b52bSGleb Smirnoff error = EINVAL; /* unknown command */
737c4c9b52bSGleb Smirnoff break;
738c4c9b52bSGleb Smirnoff }
739c4c9b52bSGleb Smirnoff break;
740b7841ae6SMaxim Sobolev case NGM_NAT_GET_DLT:
741b7841ae6SMaxim Sobolev NG_MKRESPONSE(resp, msg, sizeof(uint8_t), M_WAITOK);
742b7841ae6SMaxim Sobolev if (resp == NULL) {
743b7841ae6SMaxim Sobolev error = ENOMEM;
744b7841ae6SMaxim Sobolev break;
745b7841ae6SMaxim Sobolev }
746b7841ae6SMaxim Sobolev *((uint8_t *) resp->data) = priv->dlt;
747b7841ae6SMaxim Sobolev break;
748c4c9b52bSGleb Smirnoff default:
749c4c9b52bSGleb Smirnoff error = EINVAL; /* unknown cookie type */
750c4c9b52bSGleb Smirnoff break;
751c4c9b52bSGleb Smirnoff }
752c4c9b52bSGleb Smirnoff
753c4c9b52bSGleb Smirnoff NG_RESPOND_MSG(error, node, item, resp);
754c4c9b52bSGleb Smirnoff NG_FREE_MSG(msg);
755c4c9b52bSGleb Smirnoff return (error);
756c4c9b52bSGleb Smirnoff }
757c4c9b52bSGleb Smirnoff
758c4c9b52bSGleb Smirnoff static int
ng_nat_rcvdata(hook_p hook,item_p item)759c4c9b52bSGleb Smirnoff ng_nat_rcvdata(hook_p hook, item_p item )
760c4c9b52bSGleb Smirnoff {
761c4c9b52bSGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
762c4c9b52bSGleb Smirnoff struct mbuf *m;
7632046fd5fSGleb Smirnoff struct ip *ip;
764b7841ae6SMaxim Sobolev int rval, ipofs, error = 0;
765c4c9b52bSGleb Smirnoff char *c;
766c4c9b52bSGleb Smirnoff
767179f56e1SAlexander Motin /* We have no required hooks. */
768179f56e1SAlexander Motin if (!(priv->flags & NGNAT_CONNECTED)) {
769c4c9b52bSGleb Smirnoff NG_FREE_ITEM(item);
770c4c9b52bSGleb Smirnoff return (ENXIO);
771c4c9b52bSGleb Smirnoff }
772c4c9b52bSGleb Smirnoff
773179f56e1SAlexander Motin /* We have no alias address yet to do anything. */
774179f56e1SAlexander Motin if (!(priv->flags & NGNAT_ADDR_DEFINED))
775179f56e1SAlexander Motin goto send;
776179f56e1SAlexander Motin
777c4c9b52bSGleb Smirnoff m = NGI_M(item);
778c4c9b52bSGleb Smirnoff
779c4c9b52bSGleb Smirnoff if ((m = m_megapullup(m, m->m_pkthdr.len)) == NULL) {
780c4c9b52bSGleb Smirnoff NGI_M(item) = NULL; /* avoid double free */
781c4c9b52bSGleb Smirnoff NG_FREE_ITEM(item);
782c4c9b52bSGleb Smirnoff return (ENOBUFS);
783c4c9b52bSGleb Smirnoff }
784c4c9b52bSGleb Smirnoff
785c4c9b52bSGleb Smirnoff NGI_M(item) = m;
786c4c9b52bSGleb Smirnoff
787b7841ae6SMaxim Sobolev switch (priv->dlt) {
788b7841ae6SMaxim Sobolev case DLT_RAW:
789b7841ae6SMaxim Sobolev ipofs = 0;
790b7841ae6SMaxim Sobolev break;
791b7841ae6SMaxim Sobolev case DLT_EN10MB:
792b7841ae6SMaxim Sobolev {
793b7841ae6SMaxim Sobolev struct ether_header *eh;
7942046fd5fSGleb Smirnoff
795b7841ae6SMaxim Sobolev if (m->m_pkthdr.len < sizeof(struct ether_header)) {
796b7841ae6SMaxim Sobolev NG_FREE_ITEM(item);
797b7841ae6SMaxim Sobolev return (ENXIO);
798b7841ae6SMaxim Sobolev }
799b7841ae6SMaxim Sobolev eh = mtod(m, struct ether_header *);
800b7841ae6SMaxim Sobolev switch (ntohs(eh->ether_type)) {
801b7841ae6SMaxim Sobolev case ETHERTYPE_IP:
802b7841ae6SMaxim Sobolev ipofs = sizeof(struct ether_header);
803b7841ae6SMaxim Sobolev break;
804b7841ae6SMaxim Sobolev default:
805b7841ae6SMaxim Sobolev goto send;
806b7841ae6SMaxim Sobolev }
807b7841ae6SMaxim Sobolev break;
808b7841ae6SMaxim Sobolev }
809b7841ae6SMaxim Sobolev default:
810b7841ae6SMaxim Sobolev panic("Corrupted priv->dlt: %u", priv->dlt);
811b7841ae6SMaxim Sobolev }
812b7841ae6SMaxim Sobolev
81349f384cbSEugene Grosbein if (m->m_pkthdr.len < ipofs + sizeof(struct ip))
81449f384cbSEugene Grosbein goto send; /* packet too short to hold IP */
81549f384cbSEugene Grosbein
816b7841ae6SMaxim Sobolev c = (char *)mtodo(m, ipofs);
817b7841ae6SMaxim Sobolev ip = (struct ip *)mtodo(m, ipofs);
818b7841ae6SMaxim Sobolev
81949f384cbSEugene Grosbein if (ip->ip_v != IPVERSION)
82049f384cbSEugene Grosbein goto send; /* other IP version, let it pass */
82149f384cbSEugene Grosbein if (m->m_pkthdr.len < ipofs + ntohs(ip->ip_len))
82249f384cbSEugene Grosbein goto send; /* packet too short (i.e. fragmented or broken) */
823cc8c6970SGleb Smirnoff
824c57e67d0SAndrey V. Elsukov /*
825c57e67d0SAndrey V. Elsukov * We drop packet when:
826c57e67d0SAndrey V. Elsukov * 1. libalias returns PKT_ALIAS_ERROR;
827c57e67d0SAndrey V. Elsukov * 2. For incoming packets:
828c57e67d0SAndrey V. Elsukov * a) for unresolved fragments;
829c57e67d0SAndrey V. Elsukov * b) libalias returns PKT_ALIAS_IGNORED and
830c57e67d0SAndrey V. Elsukov * PKT_ALIAS_DENY_INCOMING flag is set.
831c57e67d0SAndrey V. Elsukov */
832c4c9b52bSGleb Smirnoff if (hook == priv->in) {
833b7841ae6SMaxim Sobolev rval = LibAliasIn(priv->lib, c, m->m_len - ipofs +
834b7841ae6SMaxim Sobolev M_TRAILINGSPACE(m));
835c57e67d0SAndrey V. Elsukov if (rval == PKT_ALIAS_ERROR ||
836c57e67d0SAndrey V. Elsukov rval == PKT_ALIAS_UNRESOLVED_FRAGMENT ||
837c57e67d0SAndrey V. Elsukov (rval == PKT_ALIAS_IGNORED &&
838c57e67d0SAndrey V. Elsukov (priv->lib->packetAliasMode &
839c57e67d0SAndrey V. Elsukov PKT_ALIAS_DENY_INCOMING) != 0)) {
840c4c9b52bSGleb Smirnoff NG_FREE_ITEM(item);
841c4c9b52bSGleb Smirnoff return (EINVAL);
842c4c9b52bSGleb Smirnoff }
843c4c9b52bSGleb Smirnoff } else if (hook == priv->out) {
844b7841ae6SMaxim Sobolev rval = LibAliasOut(priv->lib, c, m->m_len - ipofs +
845b7841ae6SMaxim Sobolev M_TRAILINGSPACE(m));
846c57e67d0SAndrey V. Elsukov if (rval == PKT_ALIAS_ERROR) {
847c4c9b52bSGleb Smirnoff NG_FREE_ITEM(item);
848c4c9b52bSGleb Smirnoff return (EINVAL);
849c4c9b52bSGleb Smirnoff }
850c4c9b52bSGleb Smirnoff } else
851c4c9b52bSGleb Smirnoff panic("ng_nat: unknown hook!\n");
852c4c9b52bSGleb Smirnoff
853c57e67d0SAndrey V. Elsukov if (rval == PKT_ALIAS_RESPOND)
854c57e67d0SAndrey V. Elsukov m->m_flags |= M_SKIP_FIREWALL;
855b7841ae6SMaxim Sobolev m->m_pkthdr.len = m->m_len = ntohs(ip->ip_len) + ipofs;
8563a48a9faSGleb Smirnoff
8573a48a9faSGleb Smirnoff if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
8583a48a9faSGleb Smirnoff ip->ip_p == IPPROTO_TCP) {
859e7bf4700SGleb Smirnoff struct tcphdr *th = (struct tcphdr *)((caddr_t)ip +
860e7bf4700SGleb Smirnoff (ip->ip_hl << 2));
8613a48a9faSGleb Smirnoff
8623a48a9faSGleb Smirnoff /*
8633a48a9faSGleb Smirnoff * Here is our terrible HACK.
8643a48a9faSGleb Smirnoff *
8653a48a9faSGleb Smirnoff * Sometimes LibAlias edits contents of TCP packet.
8663a48a9faSGleb Smirnoff * In this case it needs to recompute full TCP
8673a48a9faSGleb Smirnoff * checksum. However, the problem is that LibAlias
8683a48a9faSGleb Smirnoff * doesn't have any idea about checksum offloading
8693a48a9faSGleb Smirnoff * in kernel. To workaround this, we do not do
8703a48a9faSGleb Smirnoff * checksumming in LibAlias, but only mark the
871a8b70cf2SRichard Scheffenegger * packets with TH_RES1 in the th_x2 field. If we
872a8b70cf2SRichard Scheffenegger * receive a marked packet, we calculate correct
873a8b70cf2SRichard Scheffenegger * checksum for it aware of offloading.
8743a48a9faSGleb Smirnoff *
8753a48a9faSGleb Smirnoff * Why do I do such a terrible hack instead of
8763a48a9faSGleb Smirnoff * recalculating checksum for each packet?
8773a48a9faSGleb Smirnoff * Because the previous checksum was not checked!
8783a48a9faSGleb Smirnoff * Recalculating checksums for EVERY packet will
8793a48a9faSGleb Smirnoff * hide ALL transmission errors. Yes, marked packets
8803a48a9faSGleb Smirnoff * still suffer from this problem. But, sigh, natd(8)
8813a48a9faSGleb Smirnoff * has this problem, too.
8823a48a9faSGleb Smirnoff */
8833a48a9faSGleb Smirnoff
884a8b70cf2SRichard Scheffenegger if (tcp_get_flags(th) & TH_RES1) {
88523e9c6dcSGleb Smirnoff uint16_t ip_len = ntohs(ip->ip_len);
88623e9c6dcSGleb Smirnoff
887a8b70cf2SRichard Scheffenegger tcp_set_flags(th, tcp_get_flags(th) & ~TH_RES1);
8883a48a9faSGleb Smirnoff th->th_sum = in_pseudo(ip->ip_src.s_addr,
8893a48a9faSGleb Smirnoff ip->ip_dst.s_addr, htons(IPPROTO_TCP +
89023e9c6dcSGleb Smirnoff ip_len - (ip->ip_hl << 2)));
8913a48a9faSGleb Smirnoff
8923a48a9faSGleb Smirnoff if ((m->m_pkthdr.csum_flags & CSUM_TCP) == 0) {
8933a48a9faSGleb Smirnoff m->m_pkthdr.csum_data = offsetof(struct tcphdr,
8943a48a9faSGleb Smirnoff th_sum);
8953a48a9faSGleb Smirnoff in_delayed_cksum(m);
8963a48a9faSGleb Smirnoff }
8973a48a9faSGleb Smirnoff }
8983a48a9faSGleb Smirnoff }
8993a48a9faSGleb Smirnoff
900179f56e1SAlexander Motin send:
9013a48a9faSGleb Smirnoff if (hook == priv->in)
9023a48a9faSGleb Smirnoff NG_FWD_ITEM_HOOK(error, item, priv->out);
9033a48a9faSGleb Smirnoff else
9043a48a9faSGleb Smirnoff NG_FWD_ITEM_HOOK(error, item, priv->in);
9053a48a9faSGleb Smirnoff
906c4c9b52bSGleb Smirnoff return (error);
907c4c9b52bSGleb Smirnoff }
908c4c9b52bSGleb Smirnoff
909c4c9b52bSGleb Smirnoff static int
ng_nat_shutdown(node_p node)910c4c9b52bSGleb Smirnoff ng_nat_shutdown(node_p node)
911c4c9b52bSGleb Smirnoff {
912c4c9b52bSGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(node);
913c4c9b52bSGleb Smirnoff
914c4c9b52bSGleb Smirnoff NG_NODE_SET_PRIVATE(node, NULL);
915c4c9b52bSGleb Smirnoff NG_NODE_UNREF(node);
916fffba935SAlexander Motin
917fffba935SAlexander Motin /* Free redirects list. */
918fffba935SAlexander Motin while (!STAILQ_EMPTY(&priv->redirhead)) {
919fffba935SAlexander Motin struct ng_nat_rdr_lst *entry = STAILQ_FIRST(&priv->redirhead);
920fffba935SAlexander Motin STAILQ_REMOVE_HEAD(&priv->redirhead, entries);
9219b8db664SDmitry Lukhtionov free(entry, M_NETGRAPH_NAT);
92274b8d63dSPedro F. Giffuni }
923fffba935SAlexander Motin
924fffba935SAlexander Motin /* Final free. */
925c4c9b52bSGleb Smirnoff LibAliasUninit(priv->lib);
9269b8db664SDmitry Lukhtionov free(priv, M_NETGRAPH_NAT);
927c4c9b52bSGleb Smirnoff
928c4c9b52bSGleb Smirnoff return (0);
929c4c9b52bSGleb Smirnoff }
930c4c9b52bSGleb Smirnoff
931c4c9b52bSGleb Smirnoff static int
ng_nat_disconnect(hook_p hook)932c4c9b52bSGleb Smirnoff ng_nat_disconnect(hook_p hook)
933c4c9b52bSGleb Smirnoff {
934c4c9b52bSGleb Smirnoff const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
935c4c9b52bSGleb Smirnoff
936179f56e1SAlexander Motin priv->flags &= ~NGNAT_CONNECTED;
937c4c9b52bSGleb Smirnoff
938c4c9b52bSGleb Smirnoff if (hook == priv->out)
939c4c9b52bSGleb Smirnoff priv->out = NULL;
940c4c9b52bSGleb Smirnoff if (hook == priv->in)
941c4c9b52bSGleb Smirnoff priv->in = NULL;
942c4c9b52bSGleb Smirnoff
943c4c9b52bSGleb Smirnoff if (priv->out == NULL && priv->in == NULL)
944c4c9b52bSGleb Smirnoff ng_rmnode_self(NG_HOOK_NODE(hook));
945c4c9b52bSGleb Smirnoff
946c4c9b52bSGleb Smirnoff return (0);
947c4c9b52bSGleb Smirnoff }
948c4c9b52bSGleb Smirnoff
949e842c540SAlexander Motin static unsigned int
ng_nat_translate_flags(unsigned int x)950e842c540SAlexander Motin ng_nat_translate_flags(unsigned int x)
951e842c540SAlexander Motin {
952e842c540SAlexander Motin unsigned int res = 0;
953e842c540SAlexander Motin
954e842c540SAlexander Motin if (x & NG_NAT_LOG)
955e842c540SAlexander Motin res |= PKT_ALIAS_LOG;
956e842c540SAlexander Motin if (x & NG_NAT_DENY_INCOMING)
957e842c540SAlexander Motin res |= PKT_ALIAS_DENY_INCOMING;
958e842c540SAlexander Motin if (x & NG_NAT_SAME_PORTS)
959e842c540SAlexander Motin res |= PKT_ALIAS_SAME_PORTS;
960e842c540SAlexander Motin if (x & NG_NAT_UNREGISTERED_ONLY)
961e842c540SAlexander Motin res |= PKT_ALIAS_UNREGISTERED_ONLY;
962e842c540SAlexander Motin if (x & NG_NAT_RESET_ON_ADDR_CHANGE)
963e842c540SAlexander Motin res |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
964e842c540SAlexander Motin if (x & NG_NAT_PROXY_ONLY)
965e842c540SAlexander Motin res |= PKT_ALIAS_PROXY_ONLY;
966e842c540SAlexander Motin if (x & NG_NAT_REVERSE)
967e842c540SAlexander Motin res |= PKT_ALIAS_REVERSE;
9685fe433a6SNeel Chauhan if (x & NG_NAT_UNREGISTERED_CGN)
9695fe433a6SNeel Chauhan res |= PKT_ALIAS_UNREGISTERED_CGN;
970*f132be9bSDamjan Jovanovic if (x & NG_NAT_UDP_EIM)
971*f132be9bSDamjan Jovanovic res |= PKT_ALIAS_UDP_EIM;
972e842c540SAlexander Motin
973e842c540SAlexander Motin return (res);
974e842c540SAlexander Motin }
975