From owner-freebsd-net@FreeBSD.ORG Mon Aug 21 09:23:53 2006 Return-Path: X-Original-To: freebsd-net@freebsd.org Delivered-To: freebsd-net@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id B677116A4DF; Mon, 21 Aug 2006 09:23:53 +0000 (UTC) (envelope-from dhartmei@insomnia.benzedrine.cx) Received: from insomnia.benzedrine.cx (insomnia.benzedrine.cx [62.65.145.30]) by mx1.FreeBSD.org (Postfix) with ESMTP id CC42043D45; Mon, 21 Aug 2006 09:23:52 +0000 (GMT) (envelope-from dhartmei@insomnia.benzedrine.cx) Received: from insomnia.benzedrine.cx (dhartmei@localhost [127.0.0.1]) by insomnia.benzedrine.cx (8.13.4/8.13.4) with ESMTP id k7L9NopT028574 (version=TLSv1/SSLv3 cipher=DHE-DSS-AES256-SHA bits=256 verify=NO); Mon, 21 Aug 2006 11:23:50 +0200 (MEST) Received: (from dhartmei@localhost) by insomnia.benzedrine.cx (8.13.4/8.12.10/Submit) id k7L9Nofe001713; Mon, 21 Aug 2006 11:23:50 +0200 (MEST) Date: Mon, 21 Aug 2006 11:23:50 +0200 From: Daniel Hartmeier To: Rostislav Krasny Message-ID: <20060821092350.GL20788@insomnia.benzedrine.cx> References: <20060818235756.25f72db4.rosti.bsd@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20060818235756.25f72db4.rosti.bsd@gmail.com> User-Agent: Mutt/1.5.10i Cc: freebsd-net@freebsd.org Subject: Re: PF or "traceroute -e -P TCP" bug? X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 21 Aug 2006 09:23:53 -0000 [ I'm CC'ing Crist, maybe he can explain why -e behaves like it does ] On Fri, Aug 18, 2006 at 11:57:56PM +0300, Rostislav Krasny wrote: > I've tried the new "-e" traceroute option on today's RELENG_6 and > found following problem: > > > traceroute -nq 1 -e -P TCP -p 80 216.136.204.117 As I understand the -e option, that should send a sequence of TCP SYNs with - constant source port (randomly picked per invokation) - constant destination port 80 - increasing TTL per probe Assuming you pass the packets with pf, it matters whether you create state or not. Filtering statelessly (without 'keep state'), there should be no problem at all. I assume you're filtering statefully. With constant source and destination ports, the first probe should create a state entry and all further probes (of the same traceroute invokation) should match that state entry. What you changed in your patch is switching to a sequential (instead of constant) source port. This forces creation of one state per probe, treating each probe as a separate connection. I don't think that's in the spirit of the -e option. There's really no need for that, once the underlying problem is fixed. So, why doesn't -e without your patch produce probes that all match a single state entry? Look at how the TCP sequence numbers are generated across the probes: tcp->th_seq = (tcp->th_sport << 16) | (tcp->th_dport + (fixedPort ? outdata->seq : 0)); This is the problem. traceroute increments the sequence number with each probe. I don't know why that is done. Why not use the same th_seq for all probes, like an ISN (initial sequence number) would be re-used in retransmissions in a real TCP handshake? If you create state on the first TCP SYN pf sees, pf will note the ISN from the traceroute side. When pf sees further SYNs from that side, it will deal with them like with any client retransmitting the SYN of the handshake (before the peer replies with a SYN+ACK, giving its side's ISN). Subsequent TCP SYNs with different ISN matching the address/port pairs will be blocked by pf. If this happens on the IP forwarding path (i.e. pf blocks the packet outgoing), the stack produces the ICMP host unreachable error that shows up as "!H" in traceroute. I assume you have a "pass out on $ext_if keep state" rule, and don't filter on the internal interface. If you add stateful filtering on the internal interface, I think you'll find that subsequent TCP SYNs are blocked without eliciting the ICMP error. I suggest traceroute with -e uses fixed th_seq, as in - tcp->th_seq = (tcp->th_sport << 16) | (tcp->th_dport + - (fixedPort ? outdata->seq : 0)); + tcp->th_seq = (tcp->th_sport << 16) tcp->th_dport; Maybe the (fixedPort?:) operands were mistakenly switched, and you want to increment th_seq when -e is NOT used, but I can't think off-hand why you would. Daniel