"Listen Queue Overflow");
#if TCP_DROP_SYNFIN
-static int drop_synfin = 0;
+static int drop_synfin = 1;
SYSCTL_INT(_net_inet_tcp, OID_AUTO, drop_synfin, CTLFLAG_RW,
&drop_synfin, 0, "Drop TCP packets with SYN+FIN set");
#endif
+SYSCTL_NODE(_net_inet_tcp, OID_AUTO, reass, CTLFLAG_RW, 0,
+ "TCP Segment Reassembly Queue");
+
+__private_extern__ int tcp_reass_maxseg = 0;
+SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, maxsegments, CTLFLAG_RW,
+ &tcp_reass_maxseg, 0,
+ "Global maximum number of TCP Segments in Reassembly Queue");
+
+__private_extern__ int tcp_reass_qsize = 0;
+SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, cursegments, CTLFLAG_RD,
+ &tcp_reass_qsize, 0,
+ "Global number of TCP Segments currently in Reassembly Queue");
+
+static int tcp_reass_overflows = 0;
+SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, overflows, CTLFLAG_RD,
+ &tcp_reass_overflows, 0,
+ "Global number of TCP Segment Reassembly Queue Overflows");
+
+
__private_extern__ int slowlink_wsize = 8192;
SYSCTL_INT(_net_inet_tcp, OID_AUTO, slowlink_wsize, CTLFLAG_RW,
&slowlink_wsize, 0, "Maximum advertised window size for slowlink");
if (th == 0)
goto present;
+ /*
+ * Limit the number of segments in the reassembly queue to prevent
+ * holding on to too many segments (and thus running out of mbufs).
+ * Make sure to let the missing segment through which caused this
+ * queue. Always keep one global queue entry spare to be able to
+ * process the missing segment.
+ */
+ if (th->th_seq != tp->rcv_nxt &&
+ tcp_reass_qsize + 1 >= tcp_reass_maxseg) {
+ tcp_reass_overflows++;
+ tcpstat.tcps_rcvmemdrop++;
+ m_freem(m);
+ return (0);
+ }
+
/* Allocate a new queue entry. If we can't, just drop the pkt. XXX */
MALLOC(te, struct tseg_qent *, sizeof (struct tseg_qent), M_TSEGQ,
M_NOWAIT);
m_freem(m);
return (0);
}
+ tcp_reass_qsize++;
/*
* Find a segment which begins after this one does.
tcpstat.tcps_rcvdupbyte += *tlenp;
m_freem(m);
FREE(te, M_TSEGQ);
+ tcp_reass_qsize--;
/*
* Try to present any queued data
* at the left window edge to the user.
LIST_REMOVE(q, tqe_q);
m_freem(q->tqe_m);
FREE(q, M_TSEGQ);
+ tcp_reass_qsize--;
q = nq;
}
else
sbappend(&so->so_rcv, q->tqe_m);
FREE(q, M_TSEGQ);
+ tcp_reass_qsize--;
q = nq;
} while (q && q->tqe_th->th_seq == tp->rcv_nxt);
ND6_HINT(tp);
*/
#if INET6
int
-tcp6_input(mp, offp, proto)
+tcp6_input(mp, offp)
struct mbuf **mp;
- int *offp, proto;
+ int *offp;
{
register struct mbuf *m = *mp;
struct in6_ifaddr *ia6;
#if INET6
struct inpcb *oinp = sotoinpcb(so);
#endif /* INET6 */
+ int ogencnt = so->so_gencnt;
#if !IPSEC
/*
if (!so2)
goto drop;
}
+ /*
+ * Make sure listening socket did not get closed during socket allocation,
+ * not only this is incorrect but it is know to cause panic
+ */
+ if (so->so_gencnt != ogencnt)
+ goto drop;
#if IPSEC
oso = so;
#endif
*/
tp->t_rcvtime = 0;
if (TCPS_HAVEESTABLISHED(tp->t_state))
- tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+ tp->t_timer[TCPT_KEEP] = TCP_KEEPIDLE(tp);
/*
* Process options if not in LISTEN state,
thflags &= ~TH_SYN;
} else {
tp->t_state = TCPS_ESTABLISHED;
- tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+ tp->t_timer[TCPT_KEEP] = TCP_KEEPIDLE(tp);
}
} else {
/*
tp->t_flags &= ~TF_NEEDFIN;
} else {
tp->t_state = TCPS_ESTABLISHED;
- tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+ tp->t_timer[TCPT_KEEP] = TCP_KEEPIDLE(tp);
}
tp->t_flags |= TF_NEEDSYN;
} else
goto drop;
}
break; /* continue normal processing */
+
+ /* Received a SYN while connection is already established.
+ * This is a "half open connection and other anomalies" described
+ * in RFC793 page 34, send an ACK so the remote reset the connection
+ * or recovers by adjusting its sequence numberering
+ */
+ case TCPS_ESTABLISHED:
+ if (thflags & TH_SYN)
+ goto dropafterack;
+ break;
}
/*
tp->t_flags &= ~TF_NEEDFIN;
} else {
tp->t_state = TCPS_ESTABLISHED;
- tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+ tp->t_timer[TCPT_KEEP] = TCP_KEEPIDLE(tp);
}
/*
* If segment contains data or ACK, will call tcp_reass()
isipv6 ? tcp_v6mssdflt :
#endif /* INET6 */
tcp_mssdflt;
- else
+ else {
+ /*
+ * Prevent DoS attack with too small MSS. Round up
+ * to at least minmss.
+ */
+ offer = max(offer, tcp_minmss);
/*
* Sanity check: make sure that maxopd will be large
* enough to allow some data on segments even is the
* funny things may happen in tcp_output.
*/
offer = max(offer, 64);
+ }
taop->tao_mssopt = offer;
/*
(tp->t_flags & TF_RCVD_CC) == TF_RCVD_CC))
mss -= TCPOLEN_CC_APPA;
-#if (MCLBYTES & (MCLBYTES - 1)) == 0
- if (mss > MCLBYTES)
- mss &= ~(MCLBYTES-1);
-#else
- if (mss > MCLBYTES)
- mss = mss / MCLBYTES * MCLBYTES;
-#endif
/*
- * If there's a pipesize, change the socket buffer
- * to that size. Make the socket buffers an integral
+ * If there's a pipesize (ie loopback), change the socket
+ * buffer to that size only if it's bigger than the current
+ * sockbuf size. Make the socket buffers an integral
* number of mss units; if the mss is larger than
* the socket buffer, decrease the mss.
*/
#if RTV_SPIPE
- if ((bufsize = rt->rt_rmx.rmx_sendpipe) == 0)
+ bufsize = rt->rt_rmx.rmx_sendpipe;
+ if (bufsize < so->so_snd.sb_hiwat)
#endif
bufsize = so->so_snd.sb_hiwat;
if (bufsize < mss)
tp->t_maxseg = mss;
#if RTV_RPIPE
- if ((bufsize = rt->rt_rmx.rmx_recvpipe) == 0)
+ bufsize = rt->rt_rmx.rmx_recvpipe;
+ if (bufsize < so->so_rcv.sb_hiwat)
#endif
bufsize = so->so_rcv.sb_hiwat;
if (bufsize > mss) {