ipnat - IP Filter/NAT module interface
The ipnat device provides interfaction with the NAT features of the Solaris IPFilter.
The NAT features programming model is a component of the Solaris IP Filter and is accessed via the NAT device file /dev/ipnat. Opening the device for reading or writing determines which ioctl calls can be successfully made.
The caller must construct a ipfobj structure when issuing a SIOCGNATL or SIOCSTPUT. The ipfobj structure is then passed to the ioctl call and is filled out with ipfo_type set to IPFOBJ_value. IPFOBJ_ value provides a matching name for the structure, while ipfo_size is set to the total size of the structure being passed and ipfo_ptr is set to the structure address. The ipfo_rev structure should be set to the current value of IPFILTER_VERSION, while ipfo_offset and ipfo_xxxpad should be set to 0.
/*
   * Structure used with SIOCGNATL/SIOCSTPUT.
   */
  /*
   * Object structure description.  For passing through in ioctls.
   */
  typedef struct  ipfobj  {
       u_32_t  ipfo_rev;         /* IPFilter version (IPFILTER_VERSION) */
       u_32_t  ipfo_size;        /* size of object at ipfo_ptr */
       void    *ipfo_ptr;        /* pointer to object */
       int     ipfo_type;        /* type of object being pointed to */
       int     ipfo_offset;      /* bytes from ipfo_ptr where to start */
       u_char  ipfo_xxxpad[32];  /* reserved for future use */
  } ipfobj_t;
  #define IPFILTER_VERSION        4010901 /* IPFilter version */
  #define IPFOBJ_NATSAVE          8       /* struct nat_save */
  #define IPFOBJ_NATLOOKUP        9       /* struct natlookup */
The following ioctl() calls may be used to manipulate the ipnat sub-system inside of ipf. Note that the ipnat driver only accept calls from applications using the same data model as the kernel. In other words, 64-bit kernels can only accept calls from 64-bit applications. Calls from 32-bit applications fail with EINVAL.
SIOCSTLCK
SIOCGNATL
If IPN_FINDFORWARD is set in nl_flags, a check is made to see if it is possible to create an outgoing NAT session by checking if a packet coming from (nl_realip,nl_realport) and destined for (nl_outip,nl_outport) can be translated. If translation is possible, the flag remains set, otherwise it is cleared in the structure returned to the caller.
     /*
     * Structure used with SIOCGNATL.
     */
    typedef struct natlookup {
         i6addr_t  nl_inipaddr;
         i6addr_t  nl_outipaddr;
         i6addr_t  nl_realipaddr;
         int       nl_v;          
         int       nl_flags;
         u_short   nl_inport;
         u_short   nl_outport;
         u_short   nl_realport;
    } natlookup_t
   #define nl_inip       nl_inipaddr.in4
   #define nl_outip      nl_outipaddr.in4
   #define nl_realip     nl_realipaddr.in4
   #define nl_inip6      nl_inipaddr.in6
   #define nl_outip6     nl_outipaddr.in6
   #define nl_realip6    nl_realipaddr.in6
    /*
     * Accepted values for nl_flags
     */
    #define   IPN_TCP         0x00001
    #define   IPN_FINDFORWARD 0x400000
SIOCSTPUT
To create a translation, the following fields must be set:
Interface name - The interface name on which the host is to be exited must be set in nat_ifnames[0].
Local IP address and port number - The connection's local IP address and port number are stored in network byte order using  nat_inip/nat_inport.
Destination address/port - The destination address/port  are stored in nat_oip/nat_oport.
Target address/port - The translation's target address/port is stored in nat_outip/nat_outport.
The caller must also precalculate the checksum adjustments necessary to complete the translation and store those values in nat_sumd (delta required for TCP  header) and nat_ipsumd (delta required for IP header). 
/*
     * Structures used with SIOCSTPUT.
     */
    typedef struct  nat_save    {
         void    *ipn_next;
         struct  nat     ipn_nat;
         struct  ipnat   ipn_ipnat;
         struct  frentry ipn_fr;
         int     ipn_dsize;
         char    ipn_data[4];
    } nat_save_t;
    typedef struct  nat     {
         ipfmutex_t      nat_lock;
         struct  nat     *nat_next;
         struct  nat     **nat_pnext;
         struct  nat     *nat_hnext[2];
         struct  nat     **nat_phnext[2];
         struct  hostmap *nat_hm;
         void            *nat_data;
         struct  nat     **nat_me;
         struct  ipstate *nat_state;
         struct  ap_session      *nat_aps;
         frentry_t       *nat_fr;
         struct  ipnat   *nat_ptr;
         void            *nat_ifps[2];
         void            *nat_sync;
         ipftqent_t      nat_tqe;
         u_32_t          nat_flags;
         u_32_t          nat_sumd[2];
         u_32_t          nat_ipsumd;
         u_32_t          nat_mssclamp;
         i6addr_t        nat_inip6;
         i6addr_t        nat_outip6;
         i6addr_t        nat_oip6;
         U_QUAD_T        nat_pkts[2];
         U_QUAD_T        nat_bytes[2];
         union   {
              udpinfo_t       nat_unu;
              tcpinfo_t       nat_unt;
              icmpinfo_t      nat_uni;
              greinfo_t       nat_ugre;
         } nat_un;
         u_short         nat_oport;
         u_short         nat_use;
         u_char          nat_p;
         int             nat_dir;
         int             nat_ref;
         int             nat_hv[2];
         char            nat_ifnames[2][LIFNAMSIZ];
         int             nat_rev;
                 int             nat_v;
    } nat_t;
    #define nat_inip        nat_inip6.in4
    #define nat_outip       nat_outip6.in4
    #define nat_oip         nat_oip6.in4
    #define nat_inport      nat_un.nat_unt.ts_sport
    #define nat_outport     nat_un.nat_unt.ts_dport
    /*
     * Values for nat_dir
     */
    #define NAT_INBOUND     0
    #define NAT_OUTBOUND    1
    /*
     * Definitions for nat_flags
     */
    #define NAT_TCP         0x0001  /* IPN_TCP */
The following example shows how to prepare and use SIOCSTPUT to insert a NAT session directly into the table. Note that the usual TCP/IP code is omitted is this example.
In the code segment below, incoming_fd is the TCP connection file descriptor that is accepted as part of the redirect process, while remote_fd is the outgoing TCP connection to the remote server being translated back to the original IP address/port pair.
Note -
#include <netinet/in.h> #include <arpa/inet.h> #include <net/if.h> #include <netinet/ipl.h> #include <netinet/ip_compat.h> #include <netinet/ip_fil.h> #include <netinet/ip_nat.h> #include <string.h> #include <fcntl.h>
Note -
int
    translate_connection(int incoming_fd)
    {
         struct sockaddr_in usin;
         struct natlookup nlp;
         struct nat_save ns;
         struct ipfobj obj;
         struct nat *nat;
         int remote_fd;
         int nat_fd;
         int onoff;
         memset(&ns, 0, sizeof(ns));
         nat = &ns.ipn_nat
         namelen = sizeof(usin);
         getsockname(remote_fd, (struct sockaddr *)&usin, &namelen);
         namelen = sizeof(sin);
         getpeername(incoming_fd, (struct sockaddr *) &sin, &namelen);
         namelen = sizeof(sloc);
         getsockname(incoming_fd, (struct sockaddr *) &sloc, &namelen);
         bzero((char *) &obi, sizeof(obj));
         obj.ipfo_rev = IPFILTER_VERSION;
         obj.ipfo_size = sizeof(nlp);
         obj.ipfo_ptr = &nip;
         obj.ipfo_type = IPFOBJ_NATLOOKUP;
         /*
          * Build up the NAT natlookup structure.
          */
         bzero((char *) &nlp, sizeof(nlp));
         nlp.nl_outip = sin.sin_addr;
         nlp.nl_inip = sloc.sin_addr;
         nlp.nl_flags = IPN_TCP;
         nlp.nl_outport = ntohs(sin.sin_port);
         nlp.nl_inport = ntohs(sloc.sin_port);
         /*
          * Open the NAT device and lookup the mapping pair.
          */
         nat_fd = open(IPNAT_NAME, O_RDWR);
         if (ioctl(nat_fd, SIOCGNATL, &obj) != 0)
              return -1;
         nat->nat_inip = usin.sin_addr;
         nat->nat_outip = nlp.nl_outip;
         nat->nat_oip = nlp.nl_realip;
         sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)) +
                ntohs(usin.sin_port);
         sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)) +
                ntohs(nlp.nl_outport);
         CALC_SUMD(sum1, sum2, sumd);
         nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
         nat->nat_sumd[1] = nat->nat_sumd[0];
         sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr));
         sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr));
         CALC_SUMD(sum1, sum2, sumd);
         nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
         nat->nat_inport = usin.sin_port;
         nat->nat_outport = nlp.nl_outport;
         nat->nat_oport = nlp.nl_realport;
         nat->nat_flags = IPN_TCPUDP;
         /*
          * Prepare the ipfobj structure, accordingly.
          */
         bzero((char *)&obi, sizeof(obj));
         obj.ipfo_rev = IPFILTER_VERSION;
         obj.ipfo_size = sizeof(*nsp);
         obj.ipfo_ptr = nsp;
         obj.ipfo_type = IPFOBJ_NATSAVE;
         onoff = 1;
         if (ioctl(nat_fd, SIOCSTPUT, &obj) != 0)
              fprintf(stderr, "Error occurred\n");
         return connect(rem_fd, (struct sockaddr ) &usin, sizeof(usin));
    }
EPERM
ENOMEM
EFAULT
EINVAL
EEXIST
ESRCH
EACESS
See attributes(5) for descriptions of the following attributes:
| 
 | ||||||
ipfs(1M), ipnat(1M), ioctl(2), attributes(5)
| Закладки на сайте Проследить за страницей | Created 1996-2025 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |