Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 9 Nov 1996 15:13:58 -0700 (MST)
From:      Marc Slemko <marcs@znep.com>
To:        hackers@freebsd.org
Subject:   TCP SYN attack prevention
Message-ID:  <Pine.BSF.3.95.961109141806.23409C-100000@alive.ampr.ab.ca>

next in thread | raw e-mail | index | archive | help
I'm having a little bit of trouble understanding exactly how the
change in -current to help protect against TCP SYN attacks works.

The relevant function from uipc_socket2.c:

	struct socket *
	sodropablereq(head)
		register struct socket *head;
	{
		register struct socket *so;
		unsigned int i, j, qlen;

		static int rnd;
		static long old_mono_secs;
		static unsigned int cur_cnt, old_cnt;

		if ((i = (mono_time.tv_sec - old_mono_secs)) != 0) {
			old_mono_secs = mono_time.tv_sec;
			old_cnt = cur_cnt / i;
			cur_cnt = 0;
		}

		so = TAILQ_FIRST(&head->so_incomp);
		if (!so)
			return (so);

		qlen = head->so_incqlen;
		if (++cur_cnt > qlen || old_cnt > qlen) {
			rnd = (314159 * rnd + 66329) & 0xffff;
			j = ((qlen + 1) * rnd) >> 16;

			while (j-- && so)
			    so = TAILQ_NEXT(so, so_list);
		}

		return (so);
	}

How I read the code is that cur_cnt will be the count of the number
of times this routine has been called during second; at high rates of
attack, this will be approximately equal to the total number of SYN
packets received.  old_cnt looks like it is the average number of
times per second that sodropablereq has been called in the previous
one or more (i) seconds; under high rates of attack, i will be 1.  

TAILQ_FIRST(&head->so_incomp) will be the oldest incomplete
connection.  qlen will be the current number of incomplete pending
connections.  

Where I get a bit confused is at the 
(++cur_cnt > qlen || old_cnt > qlen) conditional.  I am reading this
as saying that the body of the if is only execured if the number of
packets so far this second is greater than the length of the queue, or
the number of packets per second in the last i second(s) is greater
than the length of the queue.  That makes no sense at all to me.  If
somaxconn is set to something moderate like 512 (and the application
calls listen() in the right manner to be able to use all of that)
then it would take an extremely high rate of attack to enable the
random drop.  

If this conditional isn't enabled, then it just does oldest early drop.
Is this code intented to only switch to random early drop from oldest
early drop when the rate of attack is extremely high?  If so, I'm not
sure I quite see the logic behind the current condition.

BTW, I notice this code is still disabled in tcp_input.c behind a
TCPSYNRED ifdef.  From my reading of it, that essentially removes most
of the protection from -current and just does the standard BSD thing
of dropping the new reqeust.  This should probably be fixed up
before 2.2; actually, it probably would be a very good thing to
have (even if it was just oldest early drop) in 2.1.6.  Oh, now I
remember, -stable doesn't use the 4.4 queue macros so you can't
find the oldest pending connection cleanly.  Random drop would
still work though.





Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.3.95.961109141806.23409C-100000>