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