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