When a connection is being dropped due to a listen queue overflow,
delete the cloned route that is associated with the connection. This does not exhaust the routing table memory when the system is under a SYN flood attack. The route entry is not deleted if there is any prior information cached in it. Reviewed by: Peter Wemm,asmodai
This commit is contained in:
parent
9ed7fa2a25
commit
8c2fae5374
@ -139,7 +139,7 @@ struct ortentry {
|
||||
#define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */
|
||||
#define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */
|
||||
#define RTF_DONE 0x40 /* message confirmed */
|
||||
/* 0x80 unused */
|
||||
#define RTF_DELCLONE 0x80 /* delete cloned route */
|
||||
#define RTF_CLONING 0x100 /* generate new routes on use */
|
||||
#define RTF_XRESOLVE 0x200 /* external daemon resolves name */
|
||||
#define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */
|
||||
|
@ -531,6 +531,7 @@ in_pcbdetach(inp)
|
||||
{
|
||||
struct socket *so = inp->inp_socket;
|
||||
struct inpcbinfo *ipi = inp->inp_pcbinfo;
|
||||
struct rtentry *rt = inp->inp_route.ro_rt;
|
||||
|
||||
#ifdef IPSEC
|
||||
ipsec4_delete_pcbpolicy(inp);
|
||||
@ -541,8 +542,28 @@ in_pcbdetach(inp)
|
||||
sofree(so);
|
||||
if (inp->inp_options)
|
||||
(void)m_free(inp->inp_options);
|
||||
if (inp->inp_route.ro_rt)
|
||||
rtfree(inp->inp_route.ro_rt);
|
||||
if (rt) {
|
||||
/*
|
||||
* route deletion requires reference count to be <= zero
|
||||
*/
|
||||
if ((rt->rt_flags & RTF_DELCLONE) &&
|
||||
(rt->rt_flags & RTF_WASCLONED)) {
|
||||
if (--rt->rt_refcnt <= 0) {
|
||||
rt->rt_flags &= ~RTF_UP;
|
||||
rtrequest(RTM_DELETE, rt_key(rt),
|
||||
rt->rt_gateway, rt_mask(rt),
|
||||
rt->rt_flags, (struct rtentry **)0);
|
||||
}
|
||||
else
|
||||
/*
|
||||
* more than one reference, bump it up
|
||||
* again.
|
||||
*/
|
||||
rt->rt_refcnt++;
|
||||
}
|
||||
else
|
||||
rtfree(rt);
|
||||
}
|
||||
ip_freemoptions(inp->inp_moptions);
|
||||
inp->inp_vflag = 0;
|
||||
zfreei(ipi->ipi_zone, inp);
|
||||
|
@ -121,6 +121,11 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, delayed_ack, CTLFLAG_RW,
|
||||
&tcp_delack_enabled, 0,
|
||||
"Delay ACK to try and piggyback it onto a data packet");
|
||||
|
||||
int tcp_lq_overflow = 1;
|
||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_lq_overflow, CTLFLAG_RW,
|
||||
&tcp_lq_overflow, 0,
|
||||
"Listen Queue Overflow");
|
||||
|
||||
#ifdef TCP_DROP_SYNFIN
|
||||
static int drop_synfin = 0;
|
||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, drop_synfin, CTLFLAG_RW,
|
||||
@ -710,6 +715,9 @@ tcp_input(m, off0, proto)
|
||||
tcpstat.tcps_listendrop++;
|
||||
so2 = sodropablereq(so);
|
||||
if (so2) {
|
||||
if (tcp_lq_overflow)
|
||||
sototcpcb(so2)->t_flags |=
|
||||
TF_LQ_OVERFLOW;
|
||||
tcp_drop(sototcpcb(so2), ETIMEDOUT);
|
||||
so2 = sonewconn(so, 0);
|
||||
}
|
||||
|
@ -121,6 +121,11 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, delayed_ack, CTLFLAG_RW,
|
||||
&tcp_delack_enabled, 0,
|
||||
"Delay ACK to try and piggyback it onto a data packet");
|
||||
|
||||
int tcp_lq_overflow = 1;
|
||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_lq_overflow, CTLFLAG_RW,
|
||||
&tcp_lq_overflow, 0,
|
||||
"Listen Queue Overflow");
|
||||
|
||||
#ifdef TCP_DROP_SYNFIN
|
||||
static int drop_synfin = 0;
|
||||
SYSCTL_INT(_net_inet_tcp, OID_AUTO, drop_synfin, CTLFLAG_RW,
|
||||
@ -710,6 +715,9 @@ tcp_input(m, off0, proto)
|
||||
tcpstat.tcps_listendrop++;
|
||||
so2 = sodropablereq(so);
|
||||
if (so2) {
|
||||
if (tcp_lq_overflow)
|
||||
sototcpcb(so2)->t_flags |=
|
||||
TF_LQ_OVERFLOW;
|
||||
tcp_drop(sototcpcb(so2), ETIMEDOUT);
|
||||
so2 = sonewconn(so, 0);
|
||||
}
|
||||
|
@ -680,6 +680,18 @@ tcp_close(tp)
|
||||
tcpstat.tcps_cachedssthresh++;
|
||||
}
|
||||
}
|
||||
rt = inp->inp_route.ro_rt;
|
||||
if (rt) {
|
||||
/*
|
||||
* mark route for deletion if no information is
|
||||
* cached.
|
||||
*/
|
||||
if ((tp->t_flags & TF_LQ_OVERFLOW) &&
|
||||
((rt->rt_rmx.rmx_locks & RTV_RTT) == 0)){
|
||||
if (rt->rt_rmx.rmx_rtt == 0)
|
||||
rt->rt_flags |= RTF_DELCLONE;
|
||||
}
|
||||
}
|
||||
no_valid_rt:
|
||||
/* free the reassembly queue, if any */
|
||||
while((q = LIST_FIRST(&tp->t_segq)) != NULL) {
|
||||
|
@ -680,6 +680,18 @@ tcp_close(tp)
|
||||
tcpstat.tcps_cachedssthresh++;
|
||||
}
|
||||
}
|
||||
rt = inp->inp_route.ro_rt;
|
||||
if (rt) {
|
||||
/*
|
||||
* mark route for deletion if no information is
|
||||
* cached.
|
||||
*/
|
||||
if ((tp->t_flags & TF_LQ_OVERFLOW) &&
|
||||
((rt->rt_rmx.rmx_locks & RTV_RTT) == 0)){
|
||||
if (rt->rt_rmx.rmx_rtt == 0)
|
||||
rt->rt_flags |= RTF_DELCLONE;
|
||||
}
|
||||
}
|
||||
no_valid_rt:
|
||||
/* free the reassembly queue, if any */
|
||||
while((q = LIST_FIRST(&tp->t_segq)) != NULL) {
|
||||
|
@ -94,6 +94,7 @@ struct tcpcb {
|
||||
#define TF_RCVD_CC 0x04000 /* a CC was received in SYN */
|
||||
#define TF_SENDCCNEW 0x08000 /* send CCnew instead of CC in SYN */
|
||||
#define TF_MORETOCOME 0x10000 /* More data to be appended to sock */
|
||||
#define TF_LQ_OVERFLOW 0x20000 /* listen queue overflow */
|
||||
int t_force; /* 1 if forcing out a byte */
|
||||
|
||||
tcp_seq snd_una; /* send unacknowledged */
|
||||
|
Loading…
Reference in New Issue
Block a user