PF's DIOCNATLOOK system call can not obtain correct return data in OpenBSD
7.3-7.5, but this call was normal before OpenBSD 7.3. I tested it on
OpenBSD 7.2 and OpenBSD 6.9 and both returned correct data.

The test code is at the end of the report (from man page of PF with a
little modification), and the following is the test process:

### [Didn't WORK] DIOCNATLOOK didn't work on OpenBSD 7.3, the following are
systeminfo, pf rules and test process

1. os infomation
openbsd# uname -a
OpenBSD openbsd.home.pro 7.3 GENERIC.MP#5 amd64

2. compile the test code
openbsd# cc test.c

3. the pf rdr rule
openbsd# pfctl -sr
pass in quick on em0 inet proto tcp from any to any port = 1234 flags S/SA
rdr-to 127.0.0.1 port 4000

4. connect from a client(192.168.11.74) to openbsd's port 1234, and print
the pf state table on openbsd.
openbsd# pfctl -ss|grep 1234
all tcp 127.0.0.1:4000 (192.168.11.4:1234) <- 192.168.11.74:26244
 ESTABLISHED:ESTABLISHED

5. running test code with: client_ip  client_port  rdr_ip  rdr_port, and
the code get an error message.
openbsd# ./a.out 192.168.11.74 26244 127.0.0.1 4000

a.out: DIOCNATLOOK: No such file or directory


### DIOCNATLOOK works on OpenBSD 7.2, the following are systeminfo, pf
rules and test process

1. os information
obsd# uname -a
OpenBSD obsd.my.domain 7.2 GENERIC.MP#758 amd64

2. compile the test code
openbsd# cc test.c

3. the pf rdr rule
openbsd# pfctl -sr
pass in quick on em0 inet proto tcp from any to any port = 1234 flags S/SA
rdr-to 127.0.0.1 port 4000

4. connect from a client(192.168.11.74) to openbsd's port 1234, and print
the pf state table on openbsd.
obsd# pfctl -ss | grep 1234
all tcp 127.0.0.1:4444 (192.168.11.43:1234) <- 192.168.11.74:38485
 FIN_WAIT_2:ESTABLISHED

5. running test code with: client_ip  client_port  rdr_ip  rdr_port, and
the code get corrent result.
obsd# ./a.out 192.168.11.74 38485 127.0.0.1 4444
internal        host 192.168.11.43:1234


BTW: This code works on FreeBSD 14 and NetBSD 10

I looked at the source code of pf_ioctl.c and pf.c in both OpenBSD 7.2 and
OpenBSD 7.3, I noticed that the call changed from NB_FIND to NBT_FIND in
OpenBSD 7.3, I don't know if this is the cause.

--
xiangbo

Code of test.c:
//-------------------------------------------------------------------------------------------------------
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <net/pfvar.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

        u_int32_t
read_address(const char *s)
{
        int a, b, c, d;

        sscanf(s, "%i.%i.%i.%i",        &a, &b, &c, &d);
        return htonl(a << 24 | b        << 16 | c << 8 | d);
}

void
print_address(u_int32_t a)
{
a = ntohl(a);
printf("%d.%d.%d.%d", a >> 24 & 255, a >> 16 & 255,
a >>    8 & 255, a & 255);
}

int
main(int        argc, char *argv[])
{
struct pfioc_natlook nl;
int dev;

if (argc        != 5) {
printf("%s <client addr> <client port>  <rdr addr> <rdr port>\n",
argv[0]);
return 1;
}

dev = open("/dev/pf", O_RDWR);
if (dev == -1)
err(1, "open(\"/dev/pf\") failed");

memset(&nl, 0, sizeof(struct pfioc_natlook));
nl.saddr.v4.s_addr = read_address(argv[1]);
nl.sport                 = htons(atoi(argv[2]));
nl.daddr.v4.s_addr = read_address(argv[3]);
nl.dport                 = htons(atoi(argv[4]));
nl.af                      = AF_INET;
nl.proto                 = IPPROTO_TCP;
nl.direction            = PF_OUT;

if (ioctl(dev, DIOCNATLOOK, &nl))
err(1, "DIOCNATLOOK");

printf("internal        host ");
print_address(nl.rdaddr.v4.s_addr);
printf(":%u\n", ntohs(nl.rdport));
return 0;
}
//-------------------------------------------------------------------------------------------------------

Reply via email to