more DoS prevention: add packet_limit option to apply a hard limit to downstream packets per session

This commit is contained in:
bodea 2005-01-10 07:17:37 +00:00
parent ee333473db
commit bb63cb9994
7 changed files with 79 additions and 17 deletions

View file

@ -1,10 +1,12 @@
* Fri Jan 7 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.0 * Mon Jan 10 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.0
- Add IPv6 support from Jonathan McDowell (work in progress). - Add IPv6 support from Jonathan McDowell (work in progress).
- Add CHAP support from Jordan Hrycaj (work in progress). - Add CHAP support from Jordan Hrycaj (work in progress).
- Sanity check that cluster_send_session is not called from a child - Sanity check that cluster_send_session is not called from a child
process. process.
- Throttle outgoing LASTSEEN packets to at most one per second for a - Throttle outgoing LASTSEEN packets to at most one per second for a
given seq#. 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. - Use bounds-checking lookup functions for string constants.
- Add enum for RADIUS codes. - Add enum for RADIUS codes.
- Make "call_" prefix implict in CSTAT() macro. - Make "call_" prefix implict in CSTAT() macro.

View file

@ -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. Maximum number of host unreachable ICMP packets to send per second.
</LI> </LI>
<LI><B>packet_limit</B> (int><BR>
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).
</LI>
<LI><B>cluster_address</B> (ip address)<BR> <LI><B>cluster_address</B> (ip address)<BR>
Multicast cluster address (default: 239.192.13.13). See the section Multicast cluster address (default: 239.192.13.13). See the section
on <A HREF="#Clustering">Clustering</A> for more information. on <A HREF="#Clustering">Clustering</A> for more information.

View file

@ -2,7 +2,7 @@
.de Id .de Id
.ds Dt \\$4 \\$5 .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" .TH STARTUP-CONFIG 5 "\*(Dt" L2TPNS "File Formats and Conventions"
.SH NAME .SH NAME
startup\-config \- configuration file for l2tpns startup\-config \- configuration file for l2tpns
@ -160,6 +160,12 @@ process in memory.
.B icmp_rate .B icmp_rate
Maximum number of host unreachable ICMP packets to send per second. Maximum number of host unreachable ICMP packets to send per second.
.TP .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 .B cluster_address
Multicast cluster address (default: 239.192.13.13). Multicast cluster address (default: 239.192.13.13).
.TP .TP

17
cli.c
View file

@ -2,7 +2,7 @@
// vim: sw=8 ts=8 // vim: sw=8 ts=8
char const *cvs_name = "$Name: $"; 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 <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
@ -646,23 +646,24 @@ static int cmd_show_counters(struct cli_def *cli, char *command, char **argv, in
if (CLI_HELP_REQUESTED) if (CLI_HELP_REQUESTED)
return CLI_HELP_NO_ARGS; return CLI_HELP_NO_ARGS;
cli_print(cli, "%-10s %-8s %-10s %-8s", "Ethernet", "Bytes", "Packets", "Errors"); cli_print(cli, "%-10s %10s %8s %8s %8s", "Ethernet", "Bytes", "Packets", "Errors", "Dropped");
cli_print(cli, "%-10s %8u %8u %8u", "RX", cli_print(cli, "%-10s %10u %8u %8u %8u", "RX",
GET_STAT(tun_rx_bytes), GET_STAT(tun_rx_bytes),
GET_STAT(tun_rx_packets), GET_STAT(tun_rx_packets),
GET_STAT(tun_rx_errors)); GET_STAT(tun_rx_errors),
cli_print(cli, "%-10s %8u %8u %8u", "TX", GET_STAT(tun_rx_dropped));
cli_print(cli, "%-10s %10u %8u %8u", "TX",
GET_STAT(tun_tx_bytes), GET_STAT(tun_tx_bytes),
GET_STAT(tun_tx_packets), GET_STAT(tun_tx_packets),
GET_STAT(tun_tx_errors)); GET_STAT(tun_tx_errors));
cli_print(cli, ""); cli_print(cli, "");
cli_print(cli, "%-10s %-8s %-10s %-8s %-8s", "Tunnel", "Bytes", "Packets", "Errors", "Retries"); cli_print(cli, "%-10s %10s %8s %8s %8s", "Tunnel", "Bytes", "Packets", "Errors", "Retries");
cli_print(cli, "%-10s %8u %8u %8u", "RX", cli_print(cli, "%-10s %10u %8u %8u", "RX",
GET_STAT(tunnel_rx_bytes), GET_STAT(tunnel_rx_bytes),
GET_STAT(tunnel_rx_packets), GET_STAT(tunnel_rx_packets),
GET_STAT(tunnel_rx_errors)); 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_bytes),
GET_STAT(tunnel_tx_packets), GET_STAT(tunnel_tx_packets),
GET_STAT(tunnel_tx_errors), GET_STAT(tunnel_tx_errors),

View file

@ -4,7 +4,7 @@
// Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced // Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced
// vim: sw=8 ts=8 // 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 <arpa/inet.h> #include <arpa/inet.h>
#include <assert.h> #include <assert.h>
@ -120,6 +120,7 @@ config_descriptt config_values[] = {
CONFIG("scheduler_fifo", scheduler_fifo, BOOL), CONFIG("scheduler_fifo", scheduler_fifo, BOOL),
CONFIG("lock_pages", lock_pages, BOOL), CONFIG("lock_pages", lock_pages, BOOL),
CONFIG("icmp_rate", icmp_rate, INT), CONFIG("icmp_rate", icmp_rate, INT),
CONFIG("packet_limit", max_packets, INT),
CONFIG("cluster_address", cluster_address, IPv4), CONFIG("cluster_address", cluster_address, IPv4),
CONFIG("cluster_interface", cluster_interface, STRING), CONFIG("cluster_interface", cluster_interface, STRING),
CONFIG("cluster_hb_interval", cluster_hb_interval, INT), CONFIG("cluster_hb_interval", cluster_hb_interval, INT),
@ -784,13 +785,13 @@ static void processipout(uint8_t * buf, int len)
if (len < MIN_IP_SIZE) if (len < MIN_IP_SIZE)
{ {
LOG(1, 0, 0, "Short IP, %d bytes\n", len); LOG(1, 0, 0, "Short IP, %d bytes\n", len);
STAT(tunnel_tx_errors); STAT(tun_rx_errors);
return; return;
} }
if (len >= MAXETHER) if (len >= MAXETHER)
{ {
LOG(1, 0, 0, "Oversize IP packet %d bytes\n", len); LOG(1, 0, 0, "Oversize IP packet %d bytes\n", len);
STAT(tunnel_tx_errors); STAT(tun_rx_errors);
return; return;
} }
@ -828,6 +829,43 @@ static void processipout(uint8_t * buf, int len)
t = session[s].tunnel; t = session[s].tunnel;
sp = &session[s]; 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 // run access-list if any
if (session[s].filter_out && !ip_filter(buf, len, session[s].filter_out - 1)) if (session[s].filter_out && !ip_filter(buf, len, session[s].filter_out - 1))
return; return;

View file

@ -1,5 +1,5 @@
// L2TPNS Global Stuff // 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__ #ifndef __L2TPNS_H__
#define __L2TPNS_H__ #define __L2TPNS_H__
@ -228,8 +228,14 @@ sessiont;
typedef struct typedef struct
{ {
// byte counters
uint32_t cin; uint32_t cin;
uint32_t cout; uint32_t cout;
// DoS prevention
clockt last_packet_out;
uint32_t packets_out;
uint32_t packets_dropped;
} sessioncountt; } sessioncountt;
#define SESSIONPFC 1 // PFC negotiated flags #define SESSIONPFC 1 // PFC negotiated flags
@ -333,6 +339,7 @@ struct Tstats
uint32_t tun_tx_bytes; uint32_t tun_tx_bytes;
uint32_t tun_rx_errors; uint32_t tun_rx_errors;
uint32_t tun_tx_errors; uint32_t tun_tx_errors;
uint32_t tun_rx_dropped;
uint32_t tunnel_rx_packets; uint32_t tunnel_rx_packets;
uint32_t tunnel_tx_packets; uint32_t tunnel_tx_packets;
@ -470,7 +477,8 @@ typedef struct
int next_tbf; // Next HTB id available to use 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 scheduler_fifo; // If the system has multiple CPUs, use FIFO scheduling policy for this process.
int lock_pages; // Lock pages into memory. 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. in_addr_t cluster_address; // Multicast address of cluster.
// Send to this address to have everyone hear. // Send to this address to have everyone hear.

View file

@ -43,5 +43,5 @@ rm -rf %{buildroot}
%attr(644,root,root) /usr/share/man/man[58]/* %attr(644,root,root) /usr/share/man/man[58]/*
%changelog %changelog
* Fri Jan 7 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.0-1 * Mon Jan 10 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.0-1
- 2.1.0 release, see /usr/share/doc/l2tpns-2.1.0/Changes - 2.1.0 release, see /usr/share/doc/l2tpns-2.1.0/Changes