>Synopsis: "pfctl -sI" returns "Bad address" when more than 64 interfaces
are present
>Category: system
>Environment:
System : OpenBSD 7.2
Details : OpenBSD 7.2 (GENERIC.MP) #0: Wed Oct 26 12:01:47 MDT
2022
[email protected]:/usr/src/sys/arch/amd64/compile/
GENERIC.MP
Architecture: OpenBSD.amd64
Machine : amd64
>Description:
I run OpenBSD (stable) on servers with many interfaces.
Since my servers have been upgraded to 7.2 (stable), the command
"pfctl -sI" returns "Bad address" when there are more than 64 interfaces
(interfaces + groups) to retrieve.
In the source code, it seems that :
- pfr_buf_grow() (sbin/pfctl/pfctl_radix.c) allocates a buffer
dimensioned for 64 elements of PFRB_IFACES type
- pfi_get_ifaces() (sbin/pfctl/pfctl_radix.c) : ioctl(dev,
DIOCIGETIFACES, &io) fails when more than 64 interfaces need to be stored
in io.pfiio_buffer
- pfctl_show_ifaces() (sbin/pfctl/pfctl_table.c) : ends on
errx(1, "%s", pf_strerror(errno)), which returns "Bad address"
In the fix proposed below, I choose arbitrarily to set the
pfrb_size to two times the number of interfaces found whith getifaddrs.
Most of the times, it will be too large, but, with this value, we
are sure to handle all the interfaces and interfaces groups.
An other option. The DIOCIGETIFACES ioctl command could behave as
DIOCRGETTABLES when the buffer is too small (cf. man pf) :
"f the buffer is too small, the kernel does not store anything but
just returns the required buffer size, without error".
>Fix:
--- sbin/pfctl/pfctl_table.c Wed Jan 15 23:38:31 2020
+++ sbin/pfctl/pfctl_table.c Fri Nov 18 15:37:23 2022
@@ -42,6 +42,7 @@
#include <ctype.h>
#include <err.h>
#include <errno.h>
+#include <ifaddrs.h>
#include <netdb.h>
#include <stdarg.h>
#include <stdio.h>
@@ -583,19 +584,22 @@ pfctl_show_ifaces(const char *filter, int
opts)
{
struct pfr_buffer b;
struct pfi_kif *p;
- int i = 0;
+ int nbif=1;
+ struct ifaddrs *ifap, *ifa;
+ if (getifaddrs(&ifap) != 0)
+ errx(1, "%s", pf_strerror(errno));
+ for (ifa = ifap; ifa && nbif++; ifa = ifa->ifa_next) {}
+ freeifaddrs(ifap);
+
bzero(&b, sizeof(b));
b.pfrb_type = PFRB_IFACES;
- for (;;) {
- pfr_buf_grow(&b, b.pfrb_size);
- b.pfrb_size = b.pfrb_msize;
- if (pfi_get_ifaces(filter, b.pfrb_caddr,
&b.pfrb_size))
- errx(1, "%s", pf_strerror(errno));
- if (b.pfrb_size <= b.pfrb_msize)
- break;
- i++;
- }
+
+ pfr_buf_grow(&b, nbif*2);
+ b.pfrb_size = b.pfrb_msize;
+ if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size))
+ errx(1, "%s", pf_strerror(errno));
+
if (opts & PF_OPT_SHOWALL)
pfctl_print_title("INTERFACES:");
PFRB_FOREACH(p, &b)
Best regards.
Olivier.