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