summaryrefslogtreecommitdiff
path: root/sys/netinet/tcp_reass.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/tcp_reass.c')
-rw-r--r--sys/netinet/tcp_reass.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index 36f044484028..263dfd83f163 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -919,6 +919,61 @@ after_listen:
panic("tcp_input: TCPS_LISTEN");
/*
+ * This is the second part of the MSS DoS prevention code (after
+ * minmss on the sending side) and it deals with too many too small
+ * tcp packets in a too short timeframe (1 second).
+ *
+ * For every full second we count the number of received packets
+ * and bytes. If we get a lot of packets per second for this connection
+ * (tcp_minmssoverload) we take a closer look at it and compute the
+ * average packet size for the past second. If that is less than
+ * tcp_minmss we get too many packets with very small payload which
+ * is not good and burdens our system (and every packet generates
+ * a wakeup to the process connected to our socket). We can reasonable
+ * expect this to be small packet DoS attack to exhaust our CPU
+ * cycles.
+ *
+ * Care has to be taken for the minimum packet overload value. This
+ * value defines the minimum number of packets per second before we
+ * start to worry. This must not be too low to avoid killing for
+ * example interactive connections with many small packets like
+ * telnet or SSH.
+ *
+ * Setting either tcp_minmssoverload or tcp_minmss to "0" disables
+ * this check.
+ *
+ * Account for packet if payload packet, skip over ACK, etc.
+ */
+ if (tcp_minmss && tcp_minmssoverload &&
+ tp->t_state == TCPS_ESTABLISHED && tlen > 0) {
+ if (tp->rcv_second > ticks) {
+ tp->rcv_pps++;
+ tp->rcv_byps += tlen + off;
+ if (tp->rcv_pps > tcp_minmssoverload) {
+ if ((tp->rcv_byps / tp->rcv_pps) < tcp_minmss) {
+ printf("too many small tcp packets from "
+ "%s:%u, av. %lubyte/packet, "
+ "dropping connection\n",
+#ifdef INET6
+ isipv6 ?
+ ip6_sprintf(&inp->inp_inc.inc6_faddr) :
+#endif
+ inet_ntoa(inp->inp_inc.inc_faddr),
+ inp->inp_inc.inc_fport,
+ tp->rcv_byps / tp->rcv_pps);
+ tp = tcp_drop(tp, ECONNRESET);
+ tcpstat.tcps_minmssdrops++;
+ goto drop;
+ }
+ }
+ } else {
+ tp->rcv_second = ticks + hz;
+ tp->rcv_pps = 1;
+ tp->rcv_byps = tlen + off;
+ }
+ }
+
+ /*
* Segment received on connection.
* Reset idle time and keep-alive timer.
*/
@@ -2691,6 +2746,11 @@ tcp_mss(tp, offer)
default:
/*
+ * 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 if the
* all the option space is used (40bytes). Otherwise