Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 10 Jan 2005 00:50:06 -0800 (PST)
From:      Don Lewis <truckman@FreeBSD.org>
To:        silby@silby.com
Cc:        net@FreeBSD.org
Subject:   Re: Slipping in the window update
Message-ID:  <200501100850.j0A8o6FY019623@gw.catspoiler.org>
In-Reply-To: <20050109031431.H2669@odysseus.silby.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On  9 Jan, Mike Silbersack wrote:
> 
> Ok, here's an updated patch for the SYN case.  I've included the patch 
> relative to 6.x, and some text from a tcpdump showing it in action.
> 
> It responds to each SYN with an ACK like the latest tcpsecure document 
> states, but it uses a global counter to rate limit the number of ACKs of 
> this type that it will send to 200 per second.
> 
> I was unable to incorporate the connect idle heuristic I wanted to because 
> right now the incoming spoofed syns would reset the idle counter, which 
> sounds like it could cause a problem somehow... best not to use it for 
> now.  Maybe a future change can clean up that along with the dropafterack 
> case in tcp_input, but that would make this patch far too complex.
> 
> Please take a look at the patch and the abbreviated tcpdump from my test 
> and see if it looks correct.

> +	if (thflags & TH_SYN) {
> +		if (tp->t_state == TCPS_ESTABLISHED &&
> +		    tcp_insecure_syn == 0) {


Any good reason for the extra level of nesting?

Testing the SYN flag first is probably optimum, since in normal
operation the vast majority of segments won't have this flag set.

> +			if (tp)
> +				INP_UNLOCK(inp);

If we've successfully dereferenced tp->t_state, it should not be
necessary to protect INP_UNLOCK() with
	if (tp)

> +			if (headlocked)
> +				INP_INFO_WUNLOCK(&tcbinfo);

I suspect that the headlocked flag is also known at this point in the
code.

Ordinary data segments will have the TH_SYN checked twice.  The first
time in this new code, and the second time after the segment has been
trimmed to fit the window.

        /*
         * If a SYN is in the window, then this is an
         * error and we send an RST and drop the connection.
         */
        if (thflags & TH_SYN) {
                tp = tcp_drop(tp, ECONNRESET);
                rstreason = BANDLIM_UNLIMITED;
                goto drop;
        }

This could make a bit of a performance difference at high speeds, for
instance gigabit Ethernet in a compute cluster.

An alternate fix would be to modify the latter block of code as follows:

        if (thflags & TH_SYN) {
+        	if (tp->t_state == TCPS_ESTABLISHED &&
+		    tcp_insecure_syn == 0)
+ 			goto dropafterack;
                tp = tcp_drop(tp, ECONNRESET);
                rstreason = BANDLIM_UNLIMITED;
                goto drop;
        }

and then after the dropafterack label add the code:

+	if (thflags & TH_SYN) {
+		if (tp->t_state == TCPS_ESTABLISHED &&
+		    tcp_insecure_syn == 0) {
+			if (badport_bandlim(BANDLIM_SYN_ESTABLISHED) < 0)
+				goto drop;
+			tcp_respond(tp, mtod(m, void *), th, m, tp->rcv_nxt,
+				tp->snd_una, TH_ACK);
		[snip]

I don't think this fix would be complete from the response rate limiting
point of view because this chunk of code in the block that trims to the
left window edge tosses the TH_SYN flag.

        todrop = tp->rcv_nxt - th->th_seq;
        if (todrop > 0) {
                if (thflags & TH_SYN) {
                        thflags &= ~TH_SYN;
                        th->th_seq++;
                        if (th->th_urp > 1)
                                th->th_urp--;
                        else
                                thflags &= ~TH_URG;
                        todrop--;
                }

and this block of code doesn't jump to dropafterack, even in the case
where the entire segment is to the left of the window.  Something else
would have to be done to implement rate limiting for this half of the
sequence space.

Now that I've looked at the above case, it looks to me like your
suggested patch might affect the response to a legitimate duplicate SYN.
It will definitely follow a different code path.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200501100850.j0A8o6FY019623>