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