Not directly answering about the change to DIOCNATLOOK (I don't know the answer), but that's generally not recommended any more anyway - the preferred option for transparent proxies is to use "divert-to" and then, for TCP, getsockname(2), or for UDP, IP_RECVDSTADDR/IPV6_RECVDSTPORT etc. In particular this is safer because you don't need access to /dev/pf.
On 2024/05/11 01:12, cut wave wrote: > 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; > } > // > -------------------------------------------------------------------------------------------------------