Is there any way to examine the in-memory connection tracking table in the in-kernel version of NAT?

In https://docs.freebsd.org/en/books/handbook/firewalls/ it says:

"FreeBSD has three firewalls built into the base system: PF, IPFW, and IPFILTER, also known as IPF."

in section 33.4 it says:

"IPFW is included in the basic FreeBSD install as a kernel loadable module, meaning that a custom kernel is not needed in order to enable IPFW."

In section 33.4.4 it says:

"FreeBSD’s IPFW firewall has two implementations of NAT: the userland implementation natd(8), and the more recent in-kernel NAT implementation."

So, with all of that understood, how is it possible to dump the connection tracking table of IPFW, in-kernel NAT?

With pf, the author renamed it the "state table" (probably just because he dislikes Linux and wanted to cause trouble) and you dump it like this:

pfctl -s state

with natd it's named "lookup table" and to see it you you start natd with logging and a control socket "natd -n fxp0 -l -p /var/run/natd.sock"

then you can allegedly query the control socket and print the lookup table:

natd -s -p /var/run/natd.sock

Although I think this only prints the defined rules - to get the actual in-core state table I think you have to use the API, connect to the socket, and iterate through the in-core rules.

A quick program that AI hacked out of the natd source to do this is:
Code:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define NATD_SOCKET "/var/run/natd.ctl"
#define CMD "show\n"

int main(void) {
    int sock;
    struct sockaddr_un addr;
    char buffer[4096];
    ssize_t n;

    // Create UNIX domain socket
    sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("socket");
        exit(1);
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, NATD_SOCKET, sizeof(addr.sun_path) - 1);

    // Connect to natd control socket
    if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("connect");
        close(sock);
        exit(1);
    }

    // Send "show" command
    if (write(sock, CMD, strlen(CMD)) < 0) {
        perror("write");
        close(sock);
        exit(1);
    }

    // Read and print response
    while ((n = read(sock, buffer, sizeof(buffer) - 1)) > 0) {
        buffer[n] = '\0';
        printf("%s", buffer);
    }

    if (n < 0) {
        perror("read");
    }

    close(sock);
    return 0;
}
FWIW I haven't tried this to see if it would work. It's just an example of how to do it - since there's a socket you can query.

But, with the in-kernel version of libaliases, it appears you can't do squat. You can dump the rules:

ipfw list

you can dump any port forwarding with

ipfw nat show config

but you don't have any way of seeing the in-core state table/lookup table.

The docs talk about creating a logging interface in /etc/rc.conf

sysrc firewall_logif="YES"

Then dumping the log with:

tcpdump -t -n -i ipfw0

but this isn't looking at the state table, lookup table, connection tracking table, whatever you want to call it.

With the Linux iptables they also make it easy

cat /proc/net/nf_conntrack

dumps the connection tracking table.

Is this just a deliberately built restriction with in-kernel libaliases? I know that libaliases is supposed to be primitive and basic - and I know that the userland natd is discouraged because of the multiple copies that have to be made with a packet going from kernelspace to userspace, but it seems that in this regard at least, natd instance is slightly advanced. However, there is a TON of effort that appears to have gone into libaliases - and it seems that it would be TRIVIAL to add the same functionality that is in natd - provide a socket that we could query the kernel for the current state table.
 
Back
Top