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

Reply via email to