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