summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjayanth <jayanth@FreeBSD.org>2000-07-21 23:26:37 +0000
committerjayanth <jayanth@FreeBSD.org>2000-07-21 23:26:37 +0000
commit8c2fae53742ffaf1871be8c56947b9ac306af564 (patch)
tree2f611787ca557e2258deb0760e8546f691acd9c6 /sys
parent9ed7fa2a25f71339ba2c167377581dec855bbbe4 (diff)
downloadFreeBSD-src-8c2fae53742ffaf1871be8c56947b9ac306af564.zip
FreeBSD-src-8c2fae53742ffaf1871be8c56947b9ac306af564.tar.gz
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
Diffstat (limited to 'sys')
-rw-r--r--sys/net/route.h2
-rw-r--r--sys/netinet/in_pcb.c25
-rw-r--r--sys/netinet/tcp_input.c8
-rw-r--r--sys/netinet/tcp_reass.c8
-rw-r--r--sys/netinet/tcp_subr.c12
-rw-r--r--sys/netinet/tcp_timewait.c12
-rw-r--r--sys/netinet/tcp_var.h1
7 files changed, 65 insertions, 3 deletions
diff --git a/sys/net/route.h b/sys/net/route.h
index c9c5c3f..c5642a4 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -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) */
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index b8b8278..3204aa8 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -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);
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 427e6c7..f49a7f4 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -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 @@ findpcb:
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);
}
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index 427e6c7..f49a7f4 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -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 @@ findpcb:
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);
}
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 68f87aa..da613d5 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -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) {
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index 68f87aa..da613d5 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -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) {
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index eb2c9b1..af18c09 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -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 */
OpenPOWER on IntegriCloud