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
This commit is contained in:
parent
5ec0ebbb0d
commit
764d8cef56
@ -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"
|
||||
@ -316,19 +316,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 @@ tcp_input(m, iphlen)
|
||||
* 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 @@ tcp_input(m, iphlen)
|
||||
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
|
||||
@ -761,6 +752,23 @@ tcp_input(m, iphlen)
|
||||
goto trimthenstep6;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@ -1176,14 +1184,11 @@ tcp_input(m, iphlen)
|
||||
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);
|
||||
|
@ -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"
|
||||
@ -316,19 +316,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 @@ tcp_input(m, iphlen)
|
||||
* 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 @@ tcp_input(m, iphlen)
|
||||
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
|
||||
@ -761,6 +752,23 @@ tcp_input(m, iphlen)
|
||||
goto trimthenstep6;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@ -1176,14 +1184,11 @@ tcp_input(m, iphlen)
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user