====== FreeBSD divert sockets ====== A divert socket is a socket that can be used to alter packets before being processed by the networking stack. When a packet is received by the network interface, it goes to the Kernel delivers it to the firewall which decides what to do with it. When using divert sockets, the firewall module can be configured to transfer the packet to a running process. The program listening on the divert socket can for example change the TCP source port before forwarding the packet to the networking stack. ===== Prerequisites ===== ==== Kernel support for IP Divert sockets ==== The Kernel must support divert sockets. The Kernel support of divert sockets depends on operating systems. The configuration of divert sockets enabled Kernels is not the scope of this document (probably in a future update of the document). ==== IP firewall settings ==== The IP firewall on the host using divert sockets need to be configured to forward packets to the port where the divert socket is binded. In case of FreeBSD, ipfw 'divert' rule can be used for this purpose. ===== Sample code ===== This code uses a divert socket to read TCP packets and display generic information in FreeBDS systems (//This sample code works but could really use some clean up!//) #include "sysdep.h" #include #include #include #include #include #include #ifdef IPSEC #include #endif /*IPSEC*/ #include #include #include #include #include #include #include #include #include #include #include #define BUFSIZE 65535 int main(int argc, char **argv) { int fd, rawfd, fdfw, ret, n; int on = 1; struct sockaddr_in bindPort, sin; int sinlen; int port_nb; struct ip *hdr; unsigned char packet[BUFSIZE]; struct in_addr addr; int i, direction; struct ip_mreq mreq; if (argc != 2) { fprintf(stderr, "Usage: %s \n", argv[0]); exit(1); } bindPort.sin_family = AF_INET; bindPort.sin_port = htons(atol(argv[1])); bindPort.sin_addr.s_addr = 0; fprintf(stderr, "%s:Creating a socket\n", argv[0]); /* open a divert socket */ fd = socket(AF_INET, SOCK_RAW, IPPROTO_DIVERT); if (fd == -1) { fprintf(stderr, "%s:We could not open a divert socket\n", argv[0]); exit(1); } bindPort.sin_family = AF_INET; bindPort.sin_port = htons(atol(argv[1])); bindPort.sin_addr.s_addr = 0; fprintf(stderr, "%s:Binding a socket\n", argv[0]); ret = bind(fd, (struct sockaddr*)&bindPort, sizeof(struct sockaddr_in)); if (ret != 0) { close(fd); fprintf(stderr, "%s: Error bind(): %s", argv[0], strerror(ret)); exit(2); } printf("%s: Waiting for data...\n", argv[0]); /* read data in */ sinlen = sizeof(struct sockaddr_in); while (1) { n = recvfrom(fd, packet, BUFSIZE, 0, (struct sockaddr*)&sin, &sinlen); hdr = (struct ip *) packet; printf("%s: The packet looks like this:\n", argv[0]); for (i = 0; i < 40; i++) { printf("%02x ", (int)*(packet + i)); if (!((i + 1) % 16)) printf("\n"); }; printf("\n"); printf("%s: Source address: %s\n", argv[0], inet_ntoa(hdr->ip_src)); printf("%s: Destination address: %s\n", argv[0], inet_ntoa(hdr->ip_dst)); printf("%s: Receiving IF address: %s\n", argv[0], inet_ntoa(sin.sin_addr)); printf("%s: Protocol number: %i\n", argv[0], hdr->ip_p); } } {{tag>howto coding}}