diff options
| author | Jacob McDonnell <jacob@jacobmcdonnell.com> | 2026-04-25 14:02:27 -0400 |
|---|---|---|
| committer | Jacob McDonnell <jacob@jacobmcdonnell.com> | 2026-04-25 14:02:27 -0400 |
| commit | 6d8bdc65446a704d0750217efd05532fc641ea7d (patch) | |
| tree | 8ae6d698b3c9801750a8b117b3842fb369872a3a /static/openbsd/man4/divert.4 | |
| parent | 2f467bd7ff8f8db0dafa40426166491d7f57f368 (diff) | |
docs: OpenBSD Man Pages Added
Diffstat (limited to 'static/openbsd/man4/divert.4')
| -rw-r--r-- | static/openbsd/man4/divert.4 | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/static/openbsd/man4/divert.4 b/static/openbsd/man4/divert.4 new file mode 100644 index 00000000..c15772bc --- /dev/null +++ b/static/openbsd/man4/divert.4 @@ -0,0 +1,210 @@ +.\" $OpenBSD: divert.4,v 1.20 2022/09/10 10:22:46 jsg Exp $ +.\" +.\" Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> +.\" Copyright (c) 2012-2014 Lawrence Teo <lteo@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: September 10 2022 $ +.Dt DIVERT 4 +.Os +.Sh NAME +.Nm divert +.Nd kernel packet diversion mechanism +.Sh SYNOPSIS +.In sys/types.h +.In sys/socket.h +.In netinet/in.h +.Ft int +.Fn socket AF_INET SOCK_RAW IPPROTO_DIVERT +.Ft int +.Fn socket AF_INET6 SOCK_RAW IPPROTO_DIVERT +.Sh DESCRIPTION +Divert sockets are part of a mechanism completely integrated with +.Xr pf 4 +that queues raw packets from the kernel stack to userspace applications, +and vice versa. +.Pp +A divert socket must be bound to a divert port through +.Xr bind 2 , +which only the superuser can do. +Divert ports have their own number space, completely separated from +.Xr tcp 4 +and +.Xr udp 4 . +When +.Xr pf 4 +processes a packet that matches a rule with the +.Ar divert-packet +parameter +(see +.Xr pf.conf 5 +for details), it is sent to the divert socket listening on the +divert port specified in the rule. +Note that +.Ar divert-packet +should not be confused with +.Ar divert-to +or +.Ar divert-reply , +which do not use divert sockets. +If there are no divert sockets listening, the packets are dropped. +.Pp +Packets can be read via +.Xr read 2 , +.Xr recv 2 , +or +.Xr recvfrom 2 +from the divert socket. +The application that is processing the packets can then reinject them into the +kernel. +With +.Xr recvfrom 2 , +an interface IP address is passed if it is an inbound packet. +Outbound packets provide the unspecified address. +When reinjecting, use this address as argument to +.Xr sendto 2 . +This allows the kernel to guess the original incoming interface and +process it as an incoming packet. +If no interface IP address is given, the reinjected packet is treated +as an outgoing packet. +Since the userspace application could have modified the packets, upon +reinjection basic sanity checks are done to ensure that the packets are still +valid. +The packets' IPv4 and protocol checksums (TCP, UDP, ICMP, and ICMPv6) are also +recalculated. +.Pp +Writing to a divert socket can be achieved using +.Xr sendto 2 +and it will skip +.Xr pf 4 +filters to avoid loops. +Note that this means that a reinjected inbound packet will also not +run through the pf out rules after being forwarded. +A diverted packet that is not reinjected into the kernel stack is lost. +.Pp +Receive and send divert socket buffer space can be tuned through +.Xr sysctl 8 . +.Xr netstat 1 +shows information relevant to divert sockets. +Note that the default is 64k and too short to handle full sized UDP +packets. +.Sh EXAMPLES +The following PF rule queues outbound IPv4 packets to TCP port 80, +as well as 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/ip.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <stdio.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"); + + memset(&sin, 0, 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[IP_MAXPACKET]; + struct ip *ip; + struct tcphdr *th; + int hlen; + char src[48], dst[48]; + + memset(packet, 0, sizeof(packet)); + n = recvfrom(fd, packet, sizeof(packet), 0, + (struct sockaddr *) &sin, &sin_len); + if (n == -1) { + warn("recvfrom"); + continue; + } + if (n < sizeof(struct ip)) { + warnx("packet is too short"); + continue; + } + + ip = (struct ip *) packet; + hlen = ip->ip_hl << 2; + if (hlen < sizeof(struct ip) || ntohs(ip->ip_len) < hlen || + n < ntohs(ip->ip_len)) { + warnx("invalid IPv4 packet"); + continue; + } + + th = (struct tcphdr *) (packet + hlen); + + if (inet_ntop(AF_INET, &ip->ip_src, src, + sizeof(src)) == NULL) + (void)strlcpy(src, "?", sizeof(src)); + + if (inet_ntop(AF_INET, &ip->ip_dst, dst, + sizeof(dst)) == NULL) + (void)strlcpy(dst, "?", sizeof(dst)); + + printf("%s:%u -> %s:%u\en", + src, + ntohs(th->th_sport), + dst, + ntohs(th->th_dport) + ); + + n = sendto(fd, packet, n, 0, (struct sockaddr *) &sin, + sin_len); + if (n == -1) + warn("sendto"); + } + + return 0; +} +.Ed +.Sh SEE ALSO +.Xr socket 2 , +.Xr ip 4 , +.Xr pf.conf 5 +.Sh HISTORY +The +.Nm +protocol first appeared in +.Ox 4.7 . |
