diff options
author | 1997-08-09 01:26:00 +0000 | |
---|---|---|
committer | 1997-08-09 01:26:00 +0000 | |
commit | bac2006fcf6add909c336ad82b0dec4012758f54 (patch) | |
tree | db94bd0dde9a5d018f44d5486b89850ab29e66d1 /sys/netinet/tcp_input.c | |
parent | Clarify a bit. (diff) | |
download | wireguard-openbsd-bac2006fcf6add909c336ad82b0dec4012758f54.tar.xz wireguard-openbsd-bac2006fcf6add909c336ad82b0dec4012758f54.zip |
SYN flood protection, by specifying
option TCPCOOKIE
in the kernel config file. For very busy servers, consider raising
the TCK_NFRIENDS value (it's currenly set to 16).
Code originally from Matt Blaze and John Ioannidis.
Diffstat (limited to 'sys/netinet/tcp_input.c')
-rw-r--r-- | sys/netinet/tcp_input.c | 153 |
1 files changed, 151 insertions, 2 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 2dde11271fb..e31c9f7f7e3 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_input.c,v 1.12 1997/07/06 08:04:10 deraadt Exp $ */ +/* $OpenBSD: tcp_input.c,v 1.13 1997/08/09 01:26:00 angelos Exp $ */ /* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */ /* @@ -62,8 +62,8 @@ #include <netinet/tcpip.h> #include <netinet/tcp_debug.h> #include <dev/rndvar.h> - #include <machine/stdarg.h> +#include <sys/md5k.h> int tcprexmtthresh = 3; struct tcpiphdr tcp_saveti; @@ -78,6 +78,123 @@ extern u_long sb_max; #define TSTMP_LT(a,b) ((int)((a)-(b)) < 0) #define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0) +#ifdef TCPCOOKIE +/* + * Code originally by Matt Blaze and John Ioannidis. This code implements + * a cookie-like extension for TCP. Adapted to OpenBSD by Angelos D. + * Keromytis. + */ + +#ifndef TCK_NFRIENDS +#define TCK_NFRIENDS 16 +#endif /* TCK_NFRIENDS */ + +static struct in_addr tck_friends[TCK_NFRIENDS]; +static int tck_nfriends = 0; +static int tck_initialized = 0; + +#define TCK_PORT 333 /* Unused port! */ + +static int +tck_isafriend(struct in_addr f) +{ + register int i; + + for (i = tck_nfriends - 1; i >= 0; i--) + if (tck_friends[i].s_addr == f.s_addr) + return 1; + + return 0; +} + +static void +tck_delat(int n) +{ + int i; + + if ((n >= tck_nfriends) || (tck_nfriends == 0)) + return; + + for (i = n+1; i < tck_nfriends ; i++) + tck_friends[i - 1] = tck_friends[i]; + + tck_nfriends--; +} + +static void +tck_addfriend(struct in_addr f) +{ +#ifdef DEBUG_TCPCOOKIE + printf("tck_addfriend: 0x%08x\n", ntohl(f.s_addr)); +#endif /* DEBUG_TCPCOOKIE */ + + if (tck_isafriend(f)) + return; + + if (tck_nfriends == TCK_NFRIENDS) + tck_delat(0); + + tck_friends[tck_nfriends++] = f; +} + +/* + * static void + * tck_delfriend(struct in_addr f) + * { + * int i; + * + * for (i = tck_nfriends - 1; i >= 0; i--) + * if (tck_friends[i].s_addr == f.s_addr) + * goto found1; + * + * return; + * + * found1: + * tck_delat(i); + * } +*/ + +static u_int32_t +tck_makecookie(struct in_addr f) +{ + static MD5_CTX ctx; + u_int8_t buf[16]; + MD5_CTX ctx2; + + if (tck_initialized == 0) /* This only happens once per reboot */ + { + tck_initialized = 1; + + get_random_bytes((void *) buf, 16); + + MD5Init(&ctx); + MD5Update(&ctx, buf, 16); + } + + ctx2 = ctx; + MD5Update(&ctx2, (void *) &f, sizeof(f)); + MD5Final(buf, &ctx2); /* This may not be necessary */ + + return ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); +} + +static int +tck_chkcookie(struct tcpiphdr *ti) +{ +#ifdef DEBUG_TCPCOOKIE + printf("tck_chkcookie: src = 0x%08x, cookie = 0x%08x, ack = 0x%08x\n", ntohl(ti->ti_src.s_addr), tck_makecookie(ti->ti_src), ti->ti_ack); +#endif /* DEBUG_TCPCOOKIE */ + + if (tck_makecookie(ti->ti_src) == ti->ti_seq) /* seq in host order */ + { + tck_addfriend(ti->ti_src); + return 1; + } + else + return 0; +} + +#endif /* TCPCOOKIE */ /* * Insert segment ti into reassembly queue of tcp with @@ -394,6 +511,18 @@ tcp_input(m, va_alist) NTOHS(ti->ti_win); NTOHS(ti->ti_urp); +#ifdef TCPCOOKIE + /* + * If this looks like a cookie response, check it. + * If it is, the check routine also adds the source + * of the packet to the friends list. + */ + + if ((tiflags & TH_RST) && (ntohs(ti->ti_dport) == TCK_PORT)) + if (tck_chkcookie(ti)) + goto drop; /* RST is no longer needed */ +#endif /* TCPCOOKIE */ + /* * Locate pcb for segment. */ @@ -636,6 +765,26 @@ findpcb: goto dropwithreset; if ((tiflags & TH_SYN) == 0) goto drop; + +#ifdef TCPCOOKIE + /* + * If source address is on friends list, proceed, otherwise + * try to obtain a cookie and drop the frame. + */ + + if (!tck_isafriend(ti->ti_src)) + { + u_long acookie; + acookie = tck_makecookie(ti->ti_src); + ti->ti_dport = htons(TCK_PORT); + tcp_respond(tp, ti, m, acookie, acookie, TH_ACK); + /* destroy temporarily created socket */ + if (dropsocket) + (void) soabort(so); + return; + } +#endif /* TCPCOOKIE */ + /* * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN * in_broadcast() should never return true on a received |