diff options
author | fenner <fenner@FreeBSD.org> | 1998-01-21 02:05:59 +0000 |
---|---|---|
committer | fenner <fenner@FreeBSD.org> | 1998-01-21 02:05:59 +0000 |
commit | 606a03ebe5beda6ea740330bf2295c7adc7f4101 (patch) | |
tree | 9f85d573b646bcdb41ae4e051267b7dae6496ed1 /sys/netinet | |
parent | 1ee427586a6b33df8a82d8e3adcce1fe5c75caa5 (diff) | |
download | FreeBSD-src-606a03ebe5beda6ea740330bf2295c7adc7f4101.zip FreeBSD-src-606a03ebe5beda6ea740330bf2295c7adc7f4101.tar.gz |
A more complete fix for the "land" attack, removing the "quick fix" from
rev 1.66. This fix contains both belt and suspenders.
Belt: ignore packets where src == dst and srcport == dstport in TCPS_LISTEN.
These packets can only legitimately occur when connecting a socket to itself,
which doesn't go through TCPS_LISTEN (it goes CLOSED->SYN_SENT->SYN_RCVD->
ESTABLISHED). This prevents the "standard" "land" attack, although doesn't
prevent the multi-homed variation.
Suspenders: send a RST in response to a SYN/ACK in SYN_RECEIVED state.
The only packets we should get in SYN_RECEIVED are
1. A retransmitted SYN, or
2. An ack of our SYN/ACK.
The "land" attack depends on us accepting our own SYN/ACK as an ACK;
in SYN_RECEIVED state; this should prevent all "land" attacks.
We also move up the sequence number check for the ACK in SYN_RECEIVED.
This neither helps nor hurts with respect to the "land" attack, but
puts more of the validation checking in one spot.
PR: kern/5103
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/tcp_input.c | 45 | ||||
-rw-r--r-- | sys/netinet/tcp_reass.c | 45 |
2 files changed, 50 insertions, 40 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index ca4430d..0fe6d37 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)tcp_input.c 8.12 (Berkeley) 5/24/95 - * $Id: tcp_input.c,v 1.66 1997/11/20 20:04:49 wollman Exp $ + * $Id: tcp_input.c,v 1.67 1997/12/19 23:46:15 bde Exp $ */ #include "opt_tcpdebug.h" @@ -317,19 +317,6 @@ tcp_input(m, iphlen) #endif /* TUBA_INCLUDE */ /* - * Reject attempted self-connects. XXX This actually masks - * a bug elsewhere, since self-connect should work. - * However, a urrently-active DoS attack in the Internet - * sends a phony self-connect request which causes an infinite - * loop. - */ - if (ti->ti_src.s_addr == ti->ti_dst.s_addr - && ti->ti_sport == ti->ti_dport) { - tcpstat.tcps_badsyn++; - goto drop; - } - - /* * Check that TCP offset makes sense, * pull out TCP options and adjust length. XXX */ @@ -626,6 +613,7 @@ findpcb: * If the state is LISTEN then ignore segment if it contains an RST. * If the segment contains an ACK then it is bad and send a RST. * If it does not contain a SYN then it is not interesting; drop it. + * If it is from this socket, drop it, it must be forged. * Don't bother responding if the destination was a broadcast. * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial * tp->iss, and send a segment: @@ -644,6 +632,9 @@ findpcb: goto dropwithreset; if ((tiflags & TH_SYN) == 0) goto drop; + if ((ti->ti_dport == ti->ti_sport) && + (ti->ti_dst.s_addr == ti->ti_src.s_addr)) + goto drop; /* * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN * in_broadcast() should never return true on a received @@ -762,6 +753,23 @@ findpcb: } /* + * If the state is SYN_RECEIVED: + * if seg contains SYN/ACK, send a RST. + * if seg contains an ACK, but not for our SYN/ACK, send a RST. + */ + case TCPS_SYN_RECEIVED: + if (tiflags & TH_ACK) { + if (tiflags & TH_SYN) { + tcpstat.tcps_badsyn++; + goto dropwithreset; + } + if (SEQ_LEQ(ti->ti_ack, tp->snd_una) || + SEQ_GT(ti->ti_ack, tp->snd_max)) + goto dropwithreset; + } + break; + + /* * If the state is SYN_SENT: * if seg contains an ACK, but not for our SYN, drop the input. * if seg contains a RST, then drop the connection. @@ -1176,14 +1184,11 @@ trimthenstep6: switch (tp->t_state) { /* - * In SYN_RECEIVED state if the ack ACKs our SYN then enter - * ESTABLISHED state and continue processing, otherwise - * send an RST. + * In SYN_RECEIVED state, the ack ACKs our SYN, so enter + * ESTABLISHED state and continue processing. + * The ACK was checked above. */ case TCPS_SYN_RECEIVED: - if (SEQ_GT(tp->snd_una, ti->ti_ack) || - SEQ_GT(ti->ti_ack, tp->snd_max)) - goto dropwithreset; tcpstat.tcps_connects++; soisconnected(so); diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index ca4430d..0fe6d37 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)tcp_input.c 8.12 (Berkeley) 5/24/95 - * $Id: tcp_input.c,v 1.66 1997/11/20 20:04:49 wollman Exp $ + * $Id: tcp_input.c,v 1.67 1997/12/19 23:46:15 bde Exp $ */ #include "opt_tcpdebug.h" @@ -317,19 +317,6 @@ tcp_input(m, iphlen) #endif /* TUBA_INCLUDE */ /* - * Reject attempted self-connects. XXX This actually masks - * a bug elsewhere, since self-connect should work. - * However, a urrently-active DoS attack in the Internet - * sends a phony self-connect request which causes an infinite - * loop. - */ - if (ti->ti_src.s_addr == ti->ti_dst.s_addr - && ti->ti_sport == ti->ti_dport) { - tcpstat.tcps_badsyn++; - goto drop; - } - - /* * Check that TCP offset makes sense, * pull out TCP options and adjust length. XXX */ @@ -626,6 +613,7 @@ findpcb: * If the state is LISTEN then ignore segment if it contains an RST. * If the segment contains an ACK then it is bad and send a RST. * If it does not contain a SYN then it is not interesting; drop it. + * If it is from this socket, drop it, it must be forged. * Don't bother responding if the destination was a broadcast. * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial * tp->iss, and send a segment: @@ -644,6 +632,9 @@ findpcb: goto dropwithreset; if ((tiflags & TH_SYN) == 0) goto drop; + if ((ti->ti_dport == ti->ti_sport) && + (ti->ti_dst.s_addr == ti->ti_src.s_addr)) + goto drop; /* * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN * in_broadcast() should never return true on a received @@ -762,6 +753,23 @@ findpcb: } /* + * If the state is SYN_RECEIVED: + * if seg contains SYN/ACK, send a RST. + * if seg contains an ACK, but not for our SYN/ACK, send a RST. + */ + case TCPS_SYN_RECEIVED: + if (tiflags & TH_ACK) { + if (tiflags & TH_SYN) { + tcpstat.tcps_badsyn++; + goto dropwithreset; + } + if (SEQ_LEQ(ti->ti_ack, tp->snd_una) || + SEQ_GT(ti->ti_ack, tp->snd_max)) + goto dropwithreset; + } + break; + + /* * If the state is SYN_SENT: * if seg contains an ACK, but not for our SYN, drop the input. * if seg contains a RST, then drop the connection. @@ -1176,14 +1184,11 @@ trimthenstep6: switch (tp->t_state) { /* - * In SYN_RECEIVED state if the ack ACKs our SYN then enter - * ESTABLISHED state and continue processing, otherwise - * send an RST. + * In SYN_RECEIVED state, the ack ACKs our SYN, so enter + * ESTABLISHED state and continue processing. + * The ACK was checked above. */ case TCPS_SYN_RECEIVED: - if (SEQ_GT(tp->snd_una, ti->ti_ack) || - SEQ_GT(ti->ti_ack, tp->snd_max)) - goto dropwithreset; tcpstat.tcps_connects++; soisconnected(so); |