While working with divert(4), I found that there is a lack of
documentation that describes how to actually use it.
This diff attempts to address that by adding an EXAMPLE section to the
divert(4) manpage. The example consists of a PF rule and a simple
program that uses the divert port. It is designed to be simple enough
that someone can try this on their desktop.
Comments?
Thanks,
Lawrence
Index: divert.4
===================================================================
RCS file: /cvs/src/share/man/man4/divert.4,v
retrieving revision 1.6
diff -u -p -r1.6 divert.4
--- divert.4 6 Dec 2009 18:32:43 -0000 1.6
+++ divert.4 25 Jan 2012 02:37:36 -0000
@@ -77,6 +77,94 @@ Receive and send divert socket buffer sp
.Xr sysctl 8 .
.Xr netstat 1
shows information relevant to divert sockets.
+.Sh EXAMPLE
+The following PF rule queues outbound IPv4 packets to TCP port 80
+(and the return traffic) on the em0 interface to divert port 700:
+.Bd -literal -offset indent
+pass out on em0 inet proto tcp to port 80 divert-packet port 700
+.Ed
+.Pp
+The following program reads packets on divert port 700 and reinjects them
+back into the kernel. This program does not perform any processing of the
+packets, apart from discarding invalid IP packets.
+.Bd -literal
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+
+#define DIVERT_PORT 700
+
+int
+main(int argc, char *argv[])
+{
+ int fd, s;
+ struct sockaddr_in sin;
+ socklen_t sin_len;
+
+ fd = socket(AF_INET, SOCK_RAW, IPPROTO_DIVERT);
+ if (fd == -1)
+ err(1, "socket");
+
+ bzero(&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(DIVERT_PORT);
+ sin.sin_addr.s_addr = 0;
+
+ sin_len = sizeof(struct sockaddr_in);
+
+ s = bind(fd, (struct sockaddr *) &sin, sin_len);
+ if (s == -1)
+ err(1, "bind");
+
+ for (;;) {
+ ssize_t n;
+ char packet[10000];
+ struct ip *ip_hdr;
+ struct tcpiphdr *tcpip_hdr;
+ char srcip[40], dstip[40];
+
+ bzero(packet, sizeof(packet));
+ n = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr *)
&sin,
+ &sin_len);
+
+ tcpip_hdr = (struct tcpiphdr *) packet;
+ ip_hdr = (struct ip *) packet;
+
+ bzero(srcip, sizeof(srcip));
+ bzero(dstip, sizeof(dstip));
+
+ if (inet_ntop(AF_INET, &ip_hdr->ip_src, srcip, sizeof(srcip))
== NULL) {
+ fprintf(stderr, "Invalid IPv4 source packet\en");
+ continue;
+ }
+ if (inet_ntop(AF_INET, &ip_hdr->ip_dst, dstip, sizeof(dstip))
== NULL) {
+ fprintf(stderr, "Invalid IPv4 destination packet\en");
+ continue;
+ }
+
+ printf("%s:%u -> %s:%u\en",
+ srcip,
+ ntohs(tcpip_hdr->ti_sport),
+ dstip,
+ ntohs(tcpip_hdr->ti_dport)
+ );
+
+ n = sendto(fd, packet, n, 0, (struct sockaddr *) &sin, sin_len);
+ }
+
+ return 0;
+}
+.Ed
.Sh SEE ALSO
.Xr socket 2 ,
.Xr ip 4 ,