On Mon, Feb 06, 2012 at 09:12:35PM -0500, Lawrence Teo wrote:
> This is a revised version of a diff that sthen@ and I worked on back in
> May 2011. The original thread and history is at
> http://marc.info/?t=130438996800003&r=1&w=2 if anyone is interested.
> 
> To summarize, the current pf(4) man page's example program uses
> DIOCNATLOOK. But Stuart pointed out in the above thread that divert-to
> has existed since OpenBSD 4.4, so the better approach is to fetch the
> destination address using getsockname() instead of DIOCNATLOOK. This
> also does not require access to /dev/pf.
> 
> In this diff, Stuart added a paragraph to the DIOCNATLOOK description in
> the pf(4) man page to mention divert-to, while I replaced the example
> program with one that demonstrates DIOCGETLIMIT instead. I picked
> DIOCGETLIMIT because it will work as-is on any OpenBSD system
> regardless of their PF rules.

Here's another revision that addresses jmc@'s comments (thank you
Jason!). It uses .Dv where appropriate and adds a missing "the" in the
DIOCNATLOOK paragraph. The example program remains unchanged.

Any further comments would be appreciated.

Thank you,
Lawrence


Index: pf.4
===================================================================
RCS file: /cvs/src/share/man/man4/pf.4,v
retrieving revision 1.73
diff -u -p -r1.73 pf.4
--- pf.4        23 Dec 2011 17:00:47 -0000      1.73
+++ pf.4        8 Feb 2012 03:11:39 -0000
@@ -314,6 +314,22 @@ struct pfioc_natlook {
        u_int8_t         direction;
 };
 .Ed
+.Pp
+This was primarily used to support transparent proxies with rdr-to rules.
+New proxies should use divert-to rules instead.
+These do not require access to the privileged
+.Pa /dev/pf
+device and preserve the original destination address for
+.Xr getsockname 2 .
+For
+.Dv SOCK_DGRAM
+sockets, the
+.Xr ip 4
+socket options
+.Dv IP_RECVDSTADDR
+and
+.Dv IP_RECVDSTPORT
+can be used to retrieve the destination address and port.
 .It Dv DIOCSETDEBUG Fa "u_int32_t *level"
 Set the debug level.
 See the
@@ -990,68 +1006,81 @@ packet filtering device.
 .El
 .Sh EXAMPLES
 The following example demonstrates how to use the
-.Dv DIOCNATLOOK
-command to find the internal host/port of a NATed connection:
+.Dv DIOCGETLIMIT
+command to show the hard limit of a memory pool used by the packet filter:
 .Bd -literal
 #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>
+#include <err.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);
-}
+static const struct {
+       const char      *name;
+       int             index;
+} pf_limits[] = {
+       { "states",             PF_LIMIT_STATES },
+       { "src-nodes",          PF_LIMIT_SRC_NODES },
+       { "frags",              PF_LIMIT_FRAGS },
+       { "tables",             PF_LIMIT_TABLES },
+       { "table-entries",      PF_LIMIT_TABLE_ENTRIES },
+       { NULL,                 0 }
+};
 
 void
-print_address(u_int32_t a)
+usage(void)
 {
-       a = ntohl(a);
-       printf("%d.%d.%d.%d", a >> 24 & 255, a >> 16 & 255,
-           a >> 8 & 255, a & 255);
+       extern char *__progname;
+       int i;
+
+       fprintf(stderr, "usage: %s [", __progname);
+       for (i = 0; pf_limits[i].name; i++)
+               fprintf(stderr, "%s%s", (i > 0 ? "|" : ""), pf_limits[i].name);
+       fprintf(stderr, "]\en");
+       exit(1);
 }
 
 int
 main(int argc, char *argv[])
 {
-       struct pfioc_natlook nl;
-       int dev;
-
-       if (argc != 5) {
-               printf("%s <gwy addr> <gwy port> <ext addr> <ext port>\en",
-                   argv[0]);
-               return 1;
+       struct pfioc_limit pl;
+       int i, dev;
+       int pool_index = -1;
+
+       if (argc != 2)
+               usage();
+
+       for (i = 0; pf_limits[i].name; i++)
+               if (!strcmp(argv[1], pf_limits[i].name)) {
+                       pool_index = pf_limits[i].index;
+                       break;
+               }
+
+       if (pool_index == -1) {
+               warnx("no such memory pool: %s", argv[1]);
+               usage();
        }
 
        dev = open("/dev/pf", O_RDWR);
        if (dev == -1)
                err(1, "open(\e"/dev/pf\e") 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_IN;
-
-       if (ioctl(dev, DIOCNATLOOK, &nl))
-               err(1, "DIOCNATLOOK");
-
-       printf("internal host ");
-       print_address(nl.rsaddr.v4.s_addr);
-       printf(":%u\en", ntohs(nl.rsport));
+       bzero(&pl, sizeof(struct pfioc_limit));
+       pl.index = pool_index;
+
+       if (ioctl(dev, DIOCGETLIMIT, &pl))
+               err(1, "DIOCGETLIMIT");
+
+       printf("The %s memory pool has ", pf_limits[i].name);
+       if (pl.limit == UINT_MAX)
+               printf("unlimited entries.\en");
+       else
+               printf("a hard limit of %u entries.\en", pl.limit);
        return 0;
 }
 .Ed

Reply via email to