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; } //-------------------------------------------------------------------------------------------------------