From owner-freebsd-net@FreeBSD.ORG Wed Jan 16 19:51:51 2013 Return-Path: Delivered-To: freebsd-net@FreeBSD.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 7946C144 for ; Wed, 16 Jan 2013 19:51:51 +0000 (UTC) (envelope-from hunter@comsys.com.ua) Received: from mail.ice-tech.com.ua (mail.ice-tech.com.ua [77.120.117.100]) by mx1.freebsd.org (Postfix) with ESMTP id 38B0591A for ; Wed, 16 Jan 2013 19:51:51 +0000 (UTC) Received: from 94.244.147.77.nash.net.ua ([94.244.147.77] helo=hunters-MacBook-Pro.local) by mail.ice-tech.com.ua with esmtpa (Exim 4.77 (FreeBSD)) (envelope-from ) id 1TvYQd-000NSx-JY for freebsd-net@FreeBSD.org; Wed, 16 Jan 2013 21:13:43 +0200 Message-ID: <50F6FBC5.8060300@comsys.com.ua> Date: Wed, 16 Jan 2013 21:13:09 +0200 From: Sergey Smitienko User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:17.0) Gecko/20130107 Thunderbird/17.0.2 MIME-Version: 1.0 To: freebsd-net@FreeBSD.org Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-SA-Exim-Connect-IP: 94.244.147.77 X-SA-Exim-Mail-From: hunter@comsys.com.ua X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on mail.ice-tech.com.ua X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,TVD_RCVD_IP autolearn=unavailable version=3.3.2 Subject: pf with divert is not working properly. FreeBSD 9.1 X-SA-Exim-Version: 4.2 X-SA-Exim-Scanned: Yes (on mail.ice-tech.com.ua) X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 16 Jan 2013 19:51:51 -0000 Hello. I think I found a bug in divert sockets processing in pf, or maybe I'm missing something. Here is my setup, machine 192.168.250.103 is a DNS server and udp traffic coming to port 53 gets diverted to a test application. Test application is very simple, it just prints some info on the packet and reinjects it back to the kernel. Then divertion is done by IPFW, all works as expected. IPFW rule is "divert 1025 udp from any to 192.168.250.103 dst-port 53". Then I divert packets using pf rule "pass in log quick on em0 inet proto udp from any to 192.168.250.103 port 53 divert-to 127.0.0.1 port 1025", I'm starting to get a loop of the same packet comming back from divert socket again and again. If I change my sento() call to n = sendto(fd, packet, n, 0, (struct sockaddr*) &org, sizeof(org));, packet riches DNS server, but then I'm getting DNS reply in my divert socket and reply is getting looped all over again. I've also tried sample code from OpenBSD divert man page and I'm getting same loop once again. Here is my test code: #include #include #include #include #include #include #include #include #include #include #include void run (int port) { int fd; struct sockaddr_in sin; struct sockaddr_in org; int len, n, on=1; struct ip* ip; struct udphdr* udp; char *packet; packet = malloc(65536); if (packet == NULL) { warn ("malloc()"); exit(1); } ip = (struct ip*) packet; fd = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT); if (fd < 0) { warn ("socket(divert)"); exit(1); } sin.sin_len = sizeof(struct sockaddr_in); sin.sin_family = AF_INET; sin.sin_port=htons(port); sin.sin_addr.s_addr=inet_addr("127.0.0.1"); len = sizeof(struct sockaddr_in); if (bind(fd, (struct sockaddr *)&sin, len)<0) { warn("binding"); exit(1); } while (1) { len = sizeof(struct sockaddr_in); if (getsockname(fd, (struct sockaddr*) &org, &len) < 0) { warn("getsockname"); continue; } memset(packet, 0, 65536); memset(&sin, 0, sizeof(sin)); len = sizeof(sin); n = recvfrom(fd, packet, 65536, 0, (struct sockaddr*) &sin, &len); if (n < 0) { warn("recvfrom"); continue; } if (n < sizeof (struct ip)) continue; printf ("Got %d bytes from %s:%d | ", n, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); printf ("%s:%d\n", inet_ntoa(org.sin_addr), ntohs(org.sin_port)); printf ("%s -> ", inet_ntoa(ip->ip_src)); printf ("%s ", inet_ntoa(ip->ip_dst)); printf ("TTL %d, PROTO %d, hlen %d, CSUM %x\n", ip->ip_ttl, ip->ip_p, ip->ip_hl, ip->ip_sum); udp = (struct udphdr*) (packet + ip->ip_hl*4); printf ("UDP src_port %d, dst_port %d\n", ntohs(udp->uh_sport), ntohs(udp->uh_dport)); n = sendto(fd, packet, n, 0, (struct sockaddr*) &sin, sizeof(sin)); if (n < 0 ) { warn("sendto"); } } } int main(void) { run (1025); } -- Sergey Smitienko