IPNAT(4)

✨ IPNAT(4) β€” the ipnat manual page, bestie edition ✨

okay so you opened the manual for ipnat β€” aka the Network Address Translation kernel interface β€” from the Kernel Interfaces Manual section 4. sit down, grab a strawberry πŸ“, and let's get into it, because this one is genuinely iconic.


🌸 NAME 🌸

ipnat β€” Network Address Translation kernel interface. that's the whole name. short, sweet, does exactly what it says πŸ’…


πŸ¦‹ SYNOPSIS πŸ¦‹

so before you can do literally anything, you gotta include these. all four. no skipping:

#include <netinet/ip_compat.h>
#include <netinet/ip_fil.h>
#include <netinet/ip_proxy.h>
#include <netinet/ip_nat.h>

it's giving "i need my whole friend group with me" energy 🫢


πŸ‘‘ IOCTLS πŸ‘‘

to add and delete rules from the NAT list, there are two 'basic' ioctls you get to use. and they get called like this:

ioctl(fd, SIOCADNAT, struct ipnat **)
ioctl(fd, SIOCRMNAT, struct ipnat **)
ioctl(fd, SIOCGNATS, struct natstat **)
ioctl(fd, SIOCGNATL, struct natlookup **)

now, heads up: unlike ipf(4), the kernel NAT interface supports only a single list. there is not an inactive list that you can swap to. not currently supported, bestie, so don't go looking for one πŸ™ˆ

these ioctls are implemented as being routing ioctls, which means the same rules that apply to the various routing ioctls also apply to the file descriptor. the big one: the fd must be that of the device associated with the module, i.e. /dev/ipl. that part matters, fr fr.


πŸŽ€ the structure πŸŽ€

here's the structure the NAT interface uses, described below, verbatim, don't touch anything:

typedef struct  ipnat   {
        struct  ipnat   *in_next;
        void    *in_ifp;
        u_short in_flags;
        u_short in_pnext;
        u_short in_port[2];
        struct  in_addr in_in[2];
        struct  in_addr in_out[2];
        struct  in_addr in_nextip;
        int     in_space;
        int     in_redir; /* 0 if it's a mapping, 1 if it's a hard redir */
        char    in_ifname[IFNAMSIZ];
} ipnat_t;

#define in_pmin         in_port[0]      /* Also holds static redir port */
#define in_pmax         in_port[1]
#define in_nip          in_nextip.s_addr
#define in_inip         in_in[0].s_addr
#define in_inmsk        in_in[1].s_addr
#define in_outip        in_out[0].s_addr
#define in_outmsk       in_out[1].s_addr

and the recognised values for in_redir are:

#define NAT_MAP         0
#define NAT_REDIRECT    1
not me reading that comment in in_redir like 0 = it's a mapping, 1 = it's a hard redir. that's it, that's the tea β˜•

πŸ“Š NAT statistics πŸ“Š

so the kernel keeps stats for you. what's being counted?

  • the number of packets mapped, going in and out
  • the number of times a new entry gets added and deleted (through expiration) to the NAT table
  • the current usage level of the NAT table

you also get pointers to the NAT table inside the kernel, plus pointers to the top of the internal NAT lists constructed with the SIOCADNAT ioctls. and the table itself? it's a hash table of size NAT_SIZE β€” default size is 367 ⭐

to retrieve the statistics, you must use the SIOCGNATS ioctl, with the appropriate structure passed by reference, like so:

ioctl(fd, SIOCGNATS, struct natstat *)

and here's that structure, again, exact, no edits:

typedef struct  natstat {
        u_long  ns_mapped[2];
        u_long  ns_added;
        u_long  ns_expire;
        u_long  ns_inuse;
        nat_t   ***ns_table;
        ipnat_t *ns_list;
} natstat_t;

πŸ’€ BUGS πŸ’€

okay the actual bug note, and it's a whole mood: it would be nice if there were more flexibility when adding and deleting filter rules. that's the entire bug report. relatable, honestly. 😭


πŸ“ FILES πŸ“

  • /dev/ipnat

that's the one. go say hi to it.


🌈 SEE ALSO 🌈

go read these next, bestie, they're the rest of the lore:


and that's the page!! πŸ’– it came from the IPNAT(4) manual β€” Kernel Interfaces Manual, section 4, page IPNAT(4) β€” so if you cite it, that's the whole flex. now go configure something responsibly, mwah πŸŽ€βœ¨πŸ’…

πŸ“¦ where this page comes from