xref: /illumos-gate/usr/src/man/man4i/ipnat.4i (revision fc910014e8a32a65612105835a10995f2c13d942)
1.\" Copyright (c) 2008, Sun Microsystems, Inc.  All Rights Reserved
2.\" Copyright (c) 2017, Joyent, Inc.
3.\" The contents of this file are subject to the terms of the
4.\" Common Development and Distribution License (the "License").
5.\" You may not use this file except in compliance with the License.
6.\"
7.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
8.\" or http://www.opensolaris.org/os/licensing.
9.\" See the License for the specific language governing permissions
10.\" and limitations under the License.
11.\"
12.\" When distributing Covered Code, include this CDDL HEADER in each
13.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
14.\" If applicable, add the following below this CDDL HEADER, with the
15.\" fields enclosed by brackets "[]" replaced with your own identifying
16.\" information: Portions Copyright [yyyy] [name of copyright owner]
17.Dd March 13, 2022
18.Dt IPNAT 4I
19.Os
20.Sh NAME
21.Nm ipnat
22.Nd IP Filter/NAT module interface
23.Sh DESCRIPTION
24The
25.Sy ipnat
26device provides interaction with the NAT features of the Solaris IPFilter.
27.Sh APPLICATION PROGRAMMING INTERFACE
28The NAT features programming model is a component of the Solaris IP Filter and
29is accessed via the NAT device file
30.Pa /dev/ipnat .
31Opening the device for
32reading or writing determines which ioctl calls can be successfully made.
33.Sh IOCTLS
34The caller must construct a
35.Vt ipfobj
36structure when issuing a
37.Sy SIOCGNATL
38or
39SIOCSTPUT
40ioctl.
41The
42.Vt ipfobj
43structure is then passed
44to the ioctl call and is filled out with
45.Fa ipfo_type
46set to
47.Dv IPFOBJ_ Ns value .
48.Dv IPFOBJ_ Ns value
49provides a matching name for the structure, while
50.Fa ipfo_size
51is set to the total size of the structure being passed and
52.Fa ipfo_ptr
53is set to the structure address.
54The
55.Fa ipfo_rev
56structure should be set to the current value of
57.Dv IPFILTER_VERSION ,
58while
59.Fa ipfo_offset
60and
61.Fa ipfo_xxxpad
62should be set to 0.
63.Bd -literal -offset 2n
64/*
65 * Structure used with SIOCGNATL/SIOCSTPUT.
66 */
67
68/*
69 * Object structure description.  For passing through in ioctls.
70 */
71typedef struct  ipfobj  {
72     u_32_t  ipfo_rev;         /* IPFilter version (IPFILTER_VERSION) */
73     u_32_t  ipfo_size;        /* size of object at ipfo_ptr */
74     void    *ipfo_ptr;        /* pointer to object */
75     int     ipfo_type;        /* type of object being pointed to */
76     int     ipfo_offset;      /* bytes from ipfo_ptr where to start */
77     u_char  ipfo_xxxpad[32];  /* reserved for future use */
78} ipfobj_t;
79
80#define IPFILTER_VERSION        4010901 /* IPFilter version */
81#define IPFOBJ_NATSAVE          8       /* struct nat_save */
82#define IPFOBJ_NATLOOKUP        9       /* struct natlookup */
83.Ed
84.Pp
85The following
86.Xr ioctl 2
87calls may be used to manipulate the ipnat sub-system inside of ipf.
88Note that the ipnat driver only accept calls from applications
89using the same data model as the kernel.
90In other words, 64-bit kernels can only accept calls from 64-bit applications.
91Calls from 32-bit applications fail
92with
93.Er EINVAL .
94.Bl -tag -width SIOCSTLCK
95.It Dv SIOCSTLCK
96Set or clear the NAT lock to prevent table updates attributable to packet
97flow-through.
98.It Dv SIOCGNATL
99Search the NAT table for the rdr entry that matches the fields in the natlookup
100structure.
101The caller must populate the structure with the address/port
102information of the accepted TCP connection
103.Pq Fa nl_inip , Fa nl_inport
104and the
105address/port information of the peer
106.Pq Fa nl_outip , Fa nl_outport .
107The
108.Fa nl_flags
109field must have the
110.Dv IPN_TCP
111option set.
112All other fields must be set to 0.
113If the call succeeds,
114.Fa nl_realip
115and
116.Fa nl_realport
117are set to the real destination address and port, respectively.
118The
119.Fa nl_inport
120and
121.Fa nl_outport
122fields must be in host byte order.
123If
124.Dv IPN_FINDFORWARD
125is set in
126.Fa nl_flags ,
127a check is made to see if it is
128possible to create an outgoing NAT session by checking if a packet coming from
129.Pq Fa nl_realip , Fa nl_realport
130and destined for
131.Pq Fa nl_outip , Fa nl_outport
132can be translated.
133If translation is possible, the flag remains set, otherwise it is
134cleared in the structure returned to the caller.
135.Bd -literal -offset indent
136/*
137 * Structure used with SIOCGNATL.
138 */
139typedef struct natlookup {
140     i6addr_t  nl_inipaddr;
141     i6addr_t  nl_outipaddr;
142     i6addr_t  nl_realipaddr;
143     int       nl_v;
144     int       nl_flags;
145     u_short   nl_inport;
146     u_short   nl_outport;
147     u_short   nl_realport;
148} natlookup_t
149
150#define nl_inip       nl_inipaddr.in4
151#define nl_outip      nl_outipaddr.in4
152#define nl_realip     nl_realipaddr.in4
153#define nl_inip6      nl_inipaddr.in6
154#define nl_outip6     nl_outipaddr.in6
155#define nl_realip6    nl_realipaddr.in6
156
157/*
158 * Accepted values for nl_flags
159 */
160#define   IPN_TCP         0x00001
161#define   IPN_FINDFORWARD 0x400000
162.Ed
163.It Dv SIOCSTPUT
164Move a NAT mapping structure from user space into the kernel.
165This ioctl is used by
166.Xr ipfs 8
167to restore NAT sessions saved in
168.Pa /var/db/ipf/ipnat.ipf .
169The
170.Vt nat_save
171structure must have its
172.Fa ipn_nat
173and
174.Fa ipn_ipnat
175structures filled out correctly.
176Fields not assigned a value must be initialised to 0.
177All pointer fields are adjusted, as appropriate, once the
178structure is passed into the kernel and none are preserved.
179.Pp
180To create a translation, the following fields must be set:
181.\" Force item bodies to next line using 2n width
182.Bl -tag -width 2n
183.It "Interface name"
184The interface name on which the host is to be exited must be
185set in
186.Fa nat_ifnames[0] .
187.It "Local IP address and port number"
188The connection's local IP address and port
189number are stored in network byte order using
190.Fa nat_inip Ns / Ns Fa nat_inport .
191.It "Destination address/port"
192The destination address/port are stored in
193.Fa nat_oip Ns / Ns Fa nat_oport .
194.It "Target address/port"
195The translation's target address/port is stored in
196.Fa nat_outip Ns / Ns Fa nat_outport .
197.El
198.Pp
199The caller must also precalculate the checksum adjustments necessary to
200complete the translation and store those values in
201.Fa nat_sumd
202(delta required for TCP  header) and
203.Fa nat_ipsumd
204(delta required for IP header).
205.Bd -literal -offset indent
206/*
207 * Structures used with SIOCSTPUT.
208 */
209typedef struct  nat_save {
210     void            *ipn_next;
211     struct  nat     ipn_nat;
212     struct  ipnat   ipn_ipnat;
213     struct  frentry ipn_fr;
214     int             ipn_dsize;
215     char            ipn_data[4];
216} nat_save_t;
217
218typedef struct  nat {
219     ipfmutex_t      nat_lock;
220     struct  nat     *nat_next;
221     struct  nat     **nat_pnext;
222     struct  nat     *nat_hnext[2];
223     struct  nat     **nat_phnext[2];
224     struct  hostmap *nat_hm;
225     void            *nat_data;
226     struct  nat     **nat_me;
227     struct  ipstate *nat_state;
228     struct  ap_session      *nat_aps;
229     frentry_t       *nat_fr;
230     struct  ipnat   *nat_ptr;
231     void            *nat_ifps[2];
232     void            *nat_sync;
233     ipftqent_t      nat_tqe;
234     u_32_t          nat_flags;
235     u_32_t          nat_sumd[2];
236     u_32_t          nat_ipsumd;
237     u_32_t          nat_mssclamp;
238     i6addr_t        nat_inip6;
239     i6addr_t        nat_outip6;
240     i6addr_t        nat_oip6;
241     U_QUAD_T        nat_pkts[2];
242     U_QUAD_T        nat_bytes[2];
243     union   {
244          udpinfo_t       nat_unu;
245          tcpinfo_t       nat_unt;
246          icmpinfo_t      nat_uni;
247          greinfo_t       nat_ugre;
248     } nat_un;
249     u_short         nat_oport;
250     u_short         nat_use;
251     u_char          nat_p;
252     int             nat_dir;
253     int             nat_ref;
254     int             nat_hv[2];
255     char            nat_ifnames[2][LIFNAMSIZ];
256     int             nat_rev;
257     int             nat_v;
258} nat_t;
259
260#define nat_inip        nat_inip6.in4
261#define nat_outip       nat_outip6.in4
262#define nat_oip         nat_oip6.in4
263#define nat_inport      nat_un.nat_unt.ts_sport
264#define nat_outport     nat_un.nat_unt.ts_dport
265/*
266 * Values for nat_dir
267 */
268#define NAT_INBOUND     0
269#define NAT_OUTBOUND    1
270/*
271 * Definitions for nat_flags
272 */
273#define NAT_TCP         0x0001  /* IPN_TCP */
274.Ed
275.El
276.Sh EXAMPLES
277The following example shows how to prepare and use
278.Fa SIOCSTPUT
279to insert a NAT session directly into the table.
280Note that the usual TCP/IP code is omitted is this example.
281.Pp
282In the code segment below,
283.Fa incoming_fd
284is the TCP connection file descriptor
285that is accepted as part of the redirect process, while
286.Fa remote_fd
287is the outgoing TCP connection to the remote server being translated back to the
288original IP address/port pair.
289.Pp
290Note \(em
291The following ipnat headers must be included before you can use the code shown
292in this example:
293.Bd -literal -offset 2n
294#include <netinet/in.h>
295#include <arpa/inet.h>
296#include <net/if.h>
297#include <netinet/ipl.h>
298#include <netinet/ip_compat.h>
299#include <netinet/ip_fil.h>
300#include <netinet/ip_nat.h>
301#include <string.h>
302#include <fcntl.h>
303.Ed
304.Pp
305Note \(em
306In the example below, various code fragments have been excluded to enhance
307clarity.
308.Bd -literal -offset 2n
309int
310translate_connection(int incoming_fd)
311{
312     struct sockaddr_in usin;
313     struct natlookup nlp;
314     struct nat_save ns;
315     struct ipfobj obj;
316     struct nat *nat;
317     int remote_fd;
318     int nat_fd;
319     int onoff;
320
321     memset(&ns, 0, sizeof(ns));
322     nat = &ns.ipn_nat
323
324     namelen = sizeof(usin);
325     getsockname(remote_fd, (struct sockaddr *)&usin, &namelen);
326
327     namelen = sizeof(sin);
328     getpeername(incoming_fd, (struct sockaddr *) &sin, &namelen);
329
330     namelen = sizeof(sloc);
331     getsockname(incoming_fd, (struct sockaddr *) &sloc, &namelen);
332
333     bzero((char *) &obi, sizeof(obj));
334     obj.ipfo_rev = IPFILTER_VERSION;
335     obj.ipfo_size = sizeof(nlp);
336     obj.ipfo_ptr = &nip;
337     obj.ipfo_type = IPFOBJ_NATLOOKUP;
338
339     /*
340      * Build up the NAT natlookup structure.
341      */
342     bzero((char *) &nlp, sizeof(nlp));
343     nlp.nl_outip = sin.sin_addr;
344     nlp.nl_inip = sloc.sin_addr;
345     nlp.nl_flags = IPN_TCP;
346     nlp.nl_outport = ntohs(sin.sin_port);
347     nlp.nl_inport = ntohs(sloc.sin_port);
348
349     /*
350      * Open the NAT device and lookup the mapping pair.
351      */
352     nat_fd = open(IPNAT_NAME, O_RDWR);
353     if (ioctl(nat_fd, SIOCGNATL, &obj) != 0)
354          return -1;
355
356     nat->nat_inip = usin.sin_addr;
357     nat->nat_outip = nlp.nl_outip;
358     nat->nat_oip = nlp.nl_realip;
359
360     sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)) +
361            ntohs(usin.sin_port);
362     sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)) +
363            ntohs(nlp.nl_outport);
364     CALC_SUMD(sum1, sum2, sumd);
365     nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
366     nat->nat_sumd[1] = nat->nat_sumd[0];
367
368     sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr));
369     sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr));
370     CALC_SUMD(sum1, sum2, sumd);
371     nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
372
373     nat->nat_inport = usin.sin_port;
374     nat->nat_outport = nlp.nl_outport;
375     nat->nat_oport = nlp.nl_realport;
376
377     nat->nat_flags = IPN_TCPUDP;
378
379     /*
380      * Prepare the ipfobj structure, accordingly.
381      */
382     bzero((char *)&obi, sizeof(obj));
383     obj.ipfo_rev = IPFILTER_VERSION;
384     obj.ipfo_size = sizeof(*nsp);
385     obj.ipfo_ptr = nsp;
386     obj.ipfo_type = IPFOBJ_NATSAVE;
387
388     onoff = 1;
389     if (ioctl(nat_fd, SIOCSTPUT, &obj) != 0)
390          fprintf(stderr, "Error occurred\en");
391
392     return connect(rem_fd, (struct sockaddr)&usin, sizeof(usin));
393}
394.Ed
395.Sh ERRORS
396.Bl -tag -width Er
397.It Er EPERM
398The device has been opened for reading only.
399To succeed, the ioctl call must be opened for both reading and writing.
400The call may be returned if it is
401privileged and the calling process did not assert
402.Brq Sy PRIV_SYS_NET_CONFIG
403in the effective set.
404.It Er ENOMEM
405More memory was allocated than the kernel can provide.
406The call may also be returned if the application inserts a NAT entry that
407exceeds the hash bucket chain's maximum length.
408.It Er EFAULT
409The calling process specified an invalid pointer in the ipfobj structure.
410.It Er EINVAL
411The calling process detected a parameter or field set to an unacceptable value.
412.It Er EEXIST
413The calling process, via
414.Dv SIOCSTPUT ,
415attempted to add a NAT entry that already exists in the NAT table.
416.It Er ESRCH
417The calling process called
418.Dv SIOCSTPUT
419before setting the
420.Dv SI_NEWFR
421flag and providing a pointer in the
422.Fa nat_fr
423field that cannot  be found in the current rule set.
424.It Er EACCES
425The calling process issued a
426.Dv SIOCSTPUT
427before issuing a
428.Dv SIOCSTLCK .
429.El
430.Sh INTERFACE STABILITY
431Committed
432.Sh SEE ALSO
433.Xr ioctl 2 ,
434.Xr attributes 7 ,
435.Xr ipfs 8 ,
436.Xr ipnat 8
437