Ignore ICMP Source Quench messages for TCP sessions. Source Quench is

ineffective, depreciated and can be abused to degrade the performance
of active TCP sessions if spoofed.

Replace a bogus call to tcp_quench() in tcp_output() with the direct
equivalent tcpcb variable assignment.

Security:	draft-gont-tcpm-icmp-attacks-03.txt Section 7.1
MFC after:	3 days
This commit is contained in:
Andre Oppermann 2005-04-21 12:37:12 +00:00
parent 1d968d225f
commit 1600372b6b
4 changed files with 23 additions and 51 deletions

View File

@ -1066,7 +1066,7 @@ tcp_output(struct tcpcb *tp)
!callout_active(tp->tt_persist)) !callout_active(tp->tt_persist))
callout_reset(tp->tt_rexmt, tp->t_rxtcur, callout_reset(tp->tt_rexmt, tp->t_rxtcur,
tcp_timer_rexmt, tp); tcp_timer_rexmt, tp);
tcp_quench(tp->t_inpcb, 0); tp->snd_cwnd = tp->t_maxseg;
return (0); return (0);
} }
if (error == EMSGSIZE) { if (error == EMSGSIZE) {

View File

@ -1117,18 +1117,21 @@ tcp_ctlinput(cmd, sa, vip)
if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY) if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
return; return;
if (cmd == PRC_QUENCH) if (cmd == PRC_MSGSIZE)
notify = tcp_quench; notify = tcp_mtudisc;
else if (icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB || else if (icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB ||
cmd == PRC_UNREACH_PORT || cmd == PRC_TIMXCEED_INTRANS) && ip) cmd == PRC_UNREACH_PORT || cmd == PRC_TIMXCEED_INTRANS) && ip)
notify = tcp_drop_syn_sent; notify = tcp_drop_syn_sent;
else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc;
/* /*
* Redirects don't need to be handled up here. * Redirects don't need to be handled up here.
*/ */
else if (PRC_IS_REDIRECT(cmd)) else if (PRC_IS_REDIRECT(cmd))
return; return;
/*
* Source quench is depreciated.
*/
else if (cmd == PRC_QUENCH)
return;
/* /*
* Hostdead is ugly because it goes linearly through all PCBs. * Hostdead is ugly because it goes linearly through all PCBs.
* XXX: We never get this from ICMP, otherwise it makes an * XXX: We never get this from ICMP, otherwise it makes an
@ -1197,13 +1200,14 @@ tcp6_ctlinput(cmd, sa, d)
sa->sa_len != sizeof(struct sockaddr_in6)) sa->sa_len != sizeof(struct sockaddr_in6))
return; return;
if (cmd == PRC_QUENCH) if (cmd == PRC_MSGSIZE)
notify = tcp_quench;
else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc; notify = tcp_mtudisc;
else if (!PRC_IS_REDIRECT(cmd) && else if (!PRC_IS_REDIRECT(cmd) &&
((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0)) ((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0))
return; return;
/* Source quench is depreciated. */
else if (cmd == PRC_QUENCH)
return;
/* if the parameter is from icmp6, decode it. */ /* if the parameter is from icmp6, decode it. */
if (d != NULL) { if (d != NULL) {
@ -1372,23 +1376,6 @@ tcp_isn_tick(xtp)
INP_INFO_WUNLOCK(&tcbinfo); INP_INFO_WUNLOCK(&tcbinfo);
} }
/*
* When a source quench is received, close congestion window
* to one segment. We will gradually open it again as we proceed.
*/
struct inpcb *
tcp_quench(inp, errno)
struct inpcb *inp;
int errno;
{
struct tcpcb *tp = intotcpcb(inp);
INP_LOCK_ASSERT(inp);
if (tp != NULL)
tp->snd_cwnd = tp->t_maxseg;
return (inp);
}
/* /*
* When a specific ICMP unreachable message is received and the * When a specific ICMP unreachable message is received and the
* connection state is SYN-SENT, drop the connection. This behavior * connection state is SYN-SENT, drop the connection. This behavior

View File

@ -1117,18 +1117,21 @@ tcp_ctlinput(cmd, sa, vip)
if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY) if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
return; return;
if (cmd == PRC_QUENCH) if (cmd == PRC_MSGSIZE)
notify = tcp_quench; notify = tcp_mtudisc;
else if (icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB || else if (icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB ||
cmd == PRC_UNREACH_PORT || cmd == PRC_TIMXCEED_INTRANS) && ip) cmd == PRC_UNREACH_PORT || cmd == PRC_TIMXCEED_INTRANS) && ip)
notify = tcp_drop_syn_sent; notify = tcp_drop_syn_sent;
else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc;
/* /*
* Redirects don't need to be handled up here. * Redirects don't need to be handled up here.
*/ */
else if (PRC_IS_REDIRECT(cmd)) else if (PRC_IS_REDIRECT(cmd))
return; return;
/*
* Source quench is depreciated.
*/
else if (cmd == PRC_QUENCH)
return;
/* /*
* Hostdead is ugly because it goes linearly through all PCBs. * Hostdead is ugly because it goes linearly through all PCBs.
* XXX: We never get this from ICMP, otherwise it makes an * XXX: We never get this from ICMP, otherwise it makes an
@ -1197,13 +1200,14 @@ tcp6_ctlinput(cmd, sa, d)
sa->sa_len != sizeof(struct sockaddr_in6)) sa->sa_len != sizeof(struct sockaddr_in6))
return; return;
if (cmd == PRC_QUENCH) if (cmd == PRC_MSGSIZE)
notify = tcp_quench;
else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc; notify = tcp_mtudisc;
else if (!PRC_IS_REDIRECT(cmd) && else if (!PRC_IS_REDIRECT(cmd) &&
((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0)) ((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0))
return; return;
/* Source quench is depreciated. */
else if (cmd == PRC_QUENCH)
return;
/* if the parameter is from icmp6, decode it. */ /* if the parameter is from icmp6, decode it. */
if (d != NULL) { if (d != NULL) {
@ -1372,23 +1376,6 @@ tcp_isn_tick(xtp)
INP_INFO_WUNLOCK(&tcbinfo); INP_INFO_WUNLOCK(&tcbinfo);
} }
/*
* When a source quench is received, close congestion window
* to one segment. We will gradually open it again as we proceed.
*/
struct inpcb *
tcp_quench(inp, errno)
struct inpcb *inp;
int errno;
{
struct tcpcb *tp = intotcpcb(inp);
INP_LOCK_ASSERT(inp);
if (tp != NULL)
tp->snd_cwnd = tp->t_maxseg;
return (inp);
}
/* /*
* When a specific ICMP unreachable message is received and the * When a specific ICMP unreachable message is received and the
* connection state is SYN-SENT, drop the connection. This behavior * connection state is SYN-SENT, drop the connection. This behavior

View File

@ -534,8 +534,6 @@ struct inpcb *
struct tcpcb * struct tcpcb *
tcp_newtcpcb(struct inpcb *); tcp_newtcpcb(struct inpcb *);
int tcp_output(struct tcpcb *); int tcp_output(struct tcpcb *);
struct inpcb *
tcp_quench(struct inpcb *, int);
void tcp_respond(struct tcpcb *, void *, void tcp_respond(struct tcpcb *, void *,
struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, int); struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, int);
int tcp_twrespond(struct tcptw *, int); int tcp_twrespond(struct tcptw *, int);