From bb63cb999417e2fea8e70e498b8f8eb97a0edd80 Mon Sep 17 00:00:00 2001 From: bodea Date: Mon, 10 Jan 2005 07:17:37 +0000 Subject: [PATCH] more DoS prevention: add packet_limit option to apply a hard limit to downstream packets per session --- Changes | 4 +++- Docs/manual.html | 7 +++++++ Docs/startup-config.5 | 8 +++++++- cli.c | 17 ++++++++-------- l2tpns.c | 46 +++++++++++++++++++++++++++++++++++++++---- l2tpns.h | 12 +++++++++-- l2tpns.spec | 2 +- 7 files changed, 79 insertions(+), 17 deletions(-) diff --git a/Changes b/Changes index 5bf2336..d7d3f91 100644 --- a/Changes +++ b/Changes @@ -1,10 +1,12 @@ -* Fri Jan 7 2005 Brendan O'Dea 2.1.0 +* Mon Jan 10 2005 Brendan O'Dea 2.1.0 - Add IPv6 support from Jonathan McDowell (work in progress). - Add CHAP support from Jordan Hrycaj (work in progress). - Sanity check that cluster_send_session is not called from a child process. - Throttle outgoing LASTSEEN packets to at most one per second for a given seq#. +- More DoS prevention: add packet_limit option to apply a hard limit + to downstream packets per session. - Use bounds-checking lookup functions for string constants. - Add enum for RADIUS codes. - Make "call_" prefix implict in CSTAT() macro. diff --git a/Docs/manual.html b/Docs/manual.html index b95858b..8dd2532 100644 --- a/Docs/manual.html +++ b/Docs/manual.html @@ -307,6 +307,13 @@ Keep all pages mapped by the l2tpns process in memory. Maximum number of host unreachable ICMP packets to send per second. +
  • packet_limit (int>
    +Maximum number of packets of downstream traffic to be handled each +tenth of a second per session. If zero, no limit is applied (default: +0). Intended as a DoS prevention mechanism and not a general +throttling control (packets are dropped, not queued). +
  • +
  • cluster_address (ip address)
    Multicast cluster address (default: 239.192.13.13). See the section on Clustering for more information. diff --git a/Docs/startup-config.5 b/Docs/startup-config.5 index 3ced03f..5b4c3ae 100644 --- a/Docs/startup-config.5 +++ b/Docs/startup-config.5 @@ -2,7 +2,7 @@ .de Id .ds Dt \\$4 \\$5 .. -.Id $Id: startup-config.5,v 1.3 2004/11/29 06:29:28 bodea Exp $ +.Id $Id: startup-config.5,v 1.4 2005/01/10 07:17:37 bodea Exp $ .TH STARTUP-CONFIG 5 "\*(Dt" L2TPNS "File Formats and Conventions" .SH NAME startup\-config \- configuration file for l2tpns @@ -160,6 +160,12 @@ process in memory. .B icmp_rate Maximum number of host unreachable ICMP packets to send per second. .TP +.B packet_limit +Maximum number of packets of downstream traffic to be handled each +tenth of a second per session. If zero, no limit is applied (default: +0). Intended as a DoS prevention mechanism and not a general +throttling control (packets are dropped, not queued). +.TP .B cluster_address Multicast cluster address (default: 239.192.13.13). .TP diff --git a/cli.c b/cli.c index 526985f..15d901e 100644 --- a/cli.c +++ b/cli.c @@ -2,7 +2,7 @@ // vim: sw=8 ts=8 char const *cvs_name = "$Name: $"; -char const *cvs_id_cli = "$Id: cli.c,v 1.45 2005/01/07 07:15:10 bodea Exp $"; +char const *cvs_id_cli = "$Id: cli.c,v 1.46 2005/01/10 07:17:37 bodea Exp $"; #include #include @@ -646,23 +646,24 @@ static int cmd_show_counters(struct cli_def *cli, char *command, char **argv, in if (CLI_HELP_REQUESTED) return CLI_HELP_NO_ARGS; - cli_print(cli, "%-10s %-8s %-10s %-8s", "Ethernet", "Bytes", "Packets", "Errors"); - cli_print(cli, "%-10s %8u %8u %8u", "RX", + cli_print(cli, "%-10s %10s %8s %8s %8s", "Ethernet", "Bytes", "Packets", "Errors", "Dropped"); + cli_print(cli, "%-10s %10u %8u %8u %8u", "RX", GET_STAT(tun_rx_bytes), GET_STAT(tun_rx_packets), - GET_STAT(tun_rx_errors)); - cli_print(cli, "%-10s %8u %8u %8u", "TX", + GET_STAT(tun_rx_errors), + GET_STAT(tun_rx_dropped)); + cli_print(cli, "%-10s %10u %8u %8u", "TX", GET_STAT(tun_tx_bytes), GET_STAT(tun_tx_packets), GET_STAT(tun_tx_errors)); cli_print(cli, ""); - cli_print(cli, "%-10s %-8s %-10s %-8s %-8s", "Tunnel", "Bytes", "Packets", "Errors", "Retries"); - cli_print(cli, "%-10s %8u %8u %8u", "RX", + cli_print(cli, "%-10s %10s %8s %8s %8s", "Tunnel", "Bytes", "Packets", "Errors", "Retries"); + cli_print(cli, "%-10s %10u %8u %8u", "RX", GET_STAT(tunnel_rx_bytes), GET_STAT(tunnel_rx_packets), GET_STAT(tunnel_rx_errors)); - cli_print(cli, "%-10s %8u %8u %8u %8u", "TX", + cli_print(cli, "%-10s %10u %8u %8u %8u", "TX", GET_STAT(tunnel_tx_bytes), GET_STAT(tunnel_tx_packets), GET_STAT(tunnel_tx_errors), diff --git a/l2tpns.c b/l2tpns.c index f2537a4..e6d2ba4 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -4,7 +4,7 @@ // Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced // vim: sw=8 ts=8 -char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.75 2005/01/07 07:18:33 bodea Exp $"; +char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.76 2005/01/10 07:17:37 bodea Exp $"; #include #include @@ -120,6 +120,7 @@ config_descriptt config_values[] = { CONFIG("scheduler_fifo", scheduler_fifo, BOOL), CONFIG("lock_pages", lock_pages, BOOL), CONFIG("icmp_rate", icmp_rate, INT), + CONFIG("packet_limit", max_packets, INT), CONFIG("cluster_address", cluster_address, IPv4), CONFIG("cluster_interface", cluster_interface, STRING), CONFIG("cluster_hb_interval", cluster_hb_interval, INT), @@ -774,7 +775,7 @@ static void processipout(uint8_t * buf, int len) tunnelidt t; in_addr_t ip; - char * data = buf; // Keep a copy of the originals. + char *data = buf; // Keep a copy of the originals. int size = len; uint8_t b[MAXETHER + 20]; @@ -784,13 +785,13 @@ static void processipout(uint8_t * buf, int len) if (len < MIN_IP_SIZE) { LOG(1, 0, 0, "Short IP, %d bytes\n", len); - STAT(tunnel_tx_errors); + STAT(tun_rx_errors); return; } if (len >= MAXETHER) { LOG(1, 0, 0, "Oversize IP packet %d bytes\n", len); - STAT(tunnel_tx_errors); + STAT(tun_rx_errors); return; } @@ -828,6 +829,43 @@ static void processipout(uint8_t * buf, int len) t = session[s].tunnel; sp = &session[s]; + // DoS prevention: enforce a maximum number of packets per 0.1s for a session + if (config->max_packets > 0) + { + if (sess_count[s].last_packet_out == TIME) + { + int max = config->max_packets; + + // All packets for throttled sessions are handled by the + // master, so further limit by using the throttle rate. + // A bit of a kludge, since throttle rate is in kbps, + // but should still be generous given our average DSL + // packet size is 200 bytes: a limit of 28kbps equates + // to around 180 packets per second. + if (!config->cluster_iam_master && sp->throttle_out && sp->throttle_out < max) + max = sp->throttle_out; + + if (++sess_count[s].packets_out > max) + { + sess_count[s].packets_dropped++; + return; + } + } + else + { + if (sess_count[s].packets_dropped) + { + INC_STAT(tun_rx_dropped, sess_count[s].packets_dropped); + LOG(2, s, t, "Possible DoS attack on %s (%s); dropped %u packets.", + fmtaddr(ip, 0), sp->user, sess_count[s].packets_dropped); + } + + sess_count[s].last_packet_out = TIME; + sess_count[s].packets_out = 1; + sess_count[s].packets_dropped = 0; + } + } + // run access-list if any if (session[s].filter_out && !ip_filter(buf, len, session[s].filter_out - 1)) return; diff --git a/l2tpns.h b/l2tpns.h index d29c547..959c9ed 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -1,5 +1,5 @@ // L2TPNS Global Stuff -// $Id: l2tpns.h,v 1.51 2005/01/07 07:17:13 bodea Exp $ +// $Id: l2tpns.h,v 1.52 2005/01/10 07:17:37 bodea Exp $ #ifndef __L2TPNS_H__ #define __L2TPNS_H__ @@ -228,8 +228,14 @@ sessiont; typedef struct { + // byte counters uint32_t cin; uint32_t cout; + + // DoS prevention + clockt last_packet_out; + uint32_t packets_out; + uint32_t packets_dropped; } sessioncountt; #define SESSIONPFC 1 // PFC negotiated flags @@ -333,6 +339,7 @@ struct Tstats uint32_t tun_tx_bytes; uint32_t tun_rx_errors; uint32_t tun_tx_errors; + uint32_t tun_rx_dropped; uint32_t tunnel_rx_packets; uint32_t tunnel_tx_packets; @@ -470,7 +477,8 @@ typedef struct int next_tbf; // Next HTB id available to use int scheduler_fifo; // If the system has multiple CPUs, use FIFO scheduling policy for this process. int lock_pages; // Lock pages into memory. - int icmp_rate; // Max number of ICMP unreachable per second to send> + int icmp_rate; // Max number of ICMP unreachable per second to send + int max_packets; // DoS prevention: per session limit of packets/0.1s in_addr_t cluster_address; // Multicast address of cluster. // Send to this address to have everyone hear. diff --git a/l2tpns.spec b/l2tpns.spec index 5c59415..9e3a27a 100644 --- a/l2tpns.spec +++ b/l2tpns.spec @@ -43,5 +43,5 @@ rm -rf %{buildroot} %attr(644,root,root) /usr/share/man/man[58]/* %changelog -* Fri Jan 7 2005 Brendan O'Dea 2.1.0-1 +* Mon Jan 10 2005 Brendan O'Dea 2.1.0-1 - 2.1.0 release, see /usr/share/doc/l2tpns-2.1.0/Changes -- 2.20.1