add session/idle timeouts
authorbodea <bodea>
Sun, 11 Jun 2006 12:46:18 +0000 (12:46 +0000)
committerbodea <bodea>
Sun, 11 Jun 2006 12:46:18 +0000 (12:46 +0000)
Changes
THANKS
cli.c
cluster.c
l2tpns.c
l2tpns.h
l2tpns.spec
radius.c

diff --git a/Changes b/Changes
index 7927769..046dfc6 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,10 +1,11 @@
-* Wed May 24 2006 Brendan O'Dea <bod@optus.net> 2.2.0
+* Fri Jun 9 2006 Brendan O'Dea <bod@optus.net> 2.2.0
 - Only poll clifd if successfully bound.
 - Add "Practical VPNs" document from Liran Tal as Docs/vpn .
 - Add Multilink support from Khaled Al Hamwi.
 - Remove non-working setuid option.
 - Convert manual.html to Docbook.
 - Kludge around problem with Netgear DM602 authentication.
+- Add session/idle timeouts (Graham Maltby).
 
 * Tue Apr 18 2006 Brendan O'Dea <bod@optus.net> 2.1.18
 - Don't shutdown on TerminateReq, wait for CDN.
diff --git a/THANKS b/THANKS
index 046a513..5fbe93a 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -27,3 +27,4 @@ Paul Martin                <pm@zetnet.net>
 Jonathan Yarden            <jyarden@bluegrass.net>
 Patrick Cole               <z@amused.net>
 Khaled Al Hamwi            <kh.alhamwi@gmail.com>
+Graham Maltby              <gmaltby+l2tpns@iig.com.au>
diff --git a/cli.c b/cli.c
index fd8034a..9b2edca 100644 (file)
--- 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.73 2006/05/05 08:10:18 bodea Exp $";
+char const *cvs_id_cli = "$Id: cli.c,v 1.74 2006/06/11 12:46:18 bodea Exp $";
 
 #include <stdio.h>
 #include <stddef.h>
@@ -426,6 +426,11 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
                        cli_print(cli, "\tUnique SID:\t%u", session[s].unique_id);
                        cli_print(cli, "\tOpened:\t\t%u seconds", session[s].opened ? abs(time_now - session[s].opened) : 0);
                        cli_print(cli, "\tIdle time:\t%u seconds", session[s].last_packet ? abs(time_now - session[s].last_packet) : 0);
+                       if (session[s].session_timeout)
+                               cli_print(cli, "\tSess Timeout:\t%u seconds", session[s].session_timeout - (session[s].opened ? abs(time_now - session[s].opened) : 0));
+                       if (session[s].idle_timeout)
+                               cli_print(cli, "\tIdle Timeout:\t%u seconds", session[s].idle_timeout - (session[s].last_data ? abs(time_now - session[s].last_data) : 0));
+
                        cli_print(cli, "\tBytes In/Out:\t%u/%u", session[s].cout, session[s].cin);
                        if (session[s].timeout)
                        {
index abe2a63..d8a2e68 100644 (file)
--- a/cluster.c
+++ b/cluster.c
@@ -1,6 +1,6 @@
 // L2TPNS Clustering Stuff
 
-char const *cvs_id_cluster = "$Id: cluster.c,v 1.51 2006/04/27 09:53:49 bodea Exp $";
+char const *cvs_id_cluster = "$Id: cluster.c,v 1.52 2006/06/11 12:46:18 bodea Exp $";
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -654,7 +654,7 @@ void cluster_check_master(void)
                }
 
                        // Reset idle timeouts..
-               session[i].last_packet = time_now;
+               session[i].last_packet = session[i].last_data = time_now;
 
                        // Reset die relative to our uptime rather than the old master's
                if (session[i].die) session[i].die = TIME;
@@ -1214,7 +1214,9 @@ static int cluster_handle_bytes(uint8_t *data, int size)
                session[b->sid].cout_delta += b->cout;
 
                if (b->cin)
-                       session[b->sid].last_packet = time_now; // Reset idle timer!
+                       session[b->sid].last_packet = session[b->sid].last_data = time_now;
+               else if (b->cout)
+                       session[b->sid].last_data = time_now;
 
                size -= sizeof(*b);
                ++b;
index fb83200..60fc7c8 100644 (file)
--- 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.166 2006/05/16 06:46:37 bodea Exp $";
+char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.167 2006/06/11 12:46:18 bodea Exp $";
 
 #include <arpa/inet.h>
 #include <assert.h>
@@ -1075,6 +1075,7 @@ void processmpframe(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint8_t e
                p += 2;
                l -= 2;
        }
+
        if (proto == PPPIP)
        {
                if (session[s].die)
@@ -1082,7 +1083,8 @@ void processmpframe(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint8_t e
                        LOG(4, s, t, "MPPP: Session %u is closing.  Don't process PPP packets\n", s);
                        return;              // closing session, PPP not processed
                }
-               session[s].last_packet = time_now;
+
+               session[s].last_packet = session[s].last_data = time_now;
                processipin(s, t, p, l);
        }
        else if (proto == PPPIPV6 && config->ipv6_prefix.s6_addr[0])
@@ -1093,7 +1095,7 @@ void processmpframe(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l, uint8_t e
                        return;              // closing session, PPP not processed
                }
 
-               session[s].last_packet = time_now;
+               session[s].last_packet = session[s].last_data = time_now;
                processipv6in(s, t, p, l);
        }
        else
@@ -1166,6 +1168,7 @@ static void processipout(uint8_t *buf, int len)
        }
        t = session[s].tunnel;
        sp = &session[s];
+       sp->last_data = time_now;
 
        // DoS prevention: enforce a maximum number of packets per 0.1s for a session
        if (config->max_packets > 0)
@@ -1363,6 +1366,7 @@ static void processipv6out(uint8_t * buf, int len)
        }
        t = session[s].tunnel;
        sp = &session[s];
+       sp->last_data = time_now;
 
        // FIXME: add DoS prevention/filters?
 
@@ -2642,7 +2646,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr)
                                                session[s].opened = time_now;
                                                session[s].tunnel = t;
                                                session[s].far = asession;
-                                               session[s].last_packet = time_now;
+                                               session[s].last_packet = session[s].last_data = time_now;
                                                LOG(3, s, t, "New session (%u/%u)\n", tunnel[t].far, session[s].far);
                                                control16(c, 14, s, 1); // assigned session
                                                controladd(c, asession, t); // send the reply
@@ -2803,7 +2807,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr)
                                return;              // closing session, PPP not processed
                        }
 
-                       session[s].last_packet = time_now;
+                       session[s].last_packet = session[s].last_data = time_now;
                        if (session[s].walled_garden && !config->cluster_iam_master)
                        {
                                master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
@@ -2820,7 +2824,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr)
                                return;              // closing session, PPP not processed
                        }
 
-                       session[s].last_packet = time_now;
+                       session[s].last_packet = session[s].last_data = time_now;
                        if (session[s].walled_garden && !config->cluster_iam_master)
                        {
                                master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
@@ -2837,7 +2841,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr)
                                return;              // closing session, PPP not processed
                        }
 
-                       session[s].last_packet = time_now;
+                       session[s].last_packet = session[s].last_data = time_now;
                        if (session[s].walled_garden && !config->cluster_iam_master)
                        {
                                master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
@@ -3195,6 +3199,24 @@ static void regular_cleanups(double period)
                        s_actions++;
                }
 
+               // Drop sessions who have reached session_timeout seconds
+               if (session[s].session_timeout && (time_now - session[s].opened >= session[s].session_timeout))
+               {
+                       sessionshutdown(s, "Session Timeout Reached", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT);
+                       STAT(session_timeout);
+                       s_actions++;
+                       continue;
+               }
+
+               // Drop sessions who have reached idle_timeout seconds
+               if (session[s].last_data && session[s].idle_timeout && (time_now - session[s].last_data >= session[s].idle_timeout))
+               {
+                       sessionshutdown(s, "Idle Timeout Reached", CDN_ADMIN_DISC, TERM_IDLE_TIMEOUT);
+                       STAT(session_timeout);
+                       s_actions++;
+                       continue;
+               }
+
                // Check for actions requested from the CLI
                if ((a = cli_session_actions[s].action))
                {
@@ -4876,7 +4898,7 @@ int sessionsetup(sessionidt s, tunnelidt t)
        if (session[s].throttle_in || session[s].throttle_out)
                throttle_session(s, session[s].throttle_in, session[s].throttle_out);
 
-       session[s].last_packet = time_now;
+       session[s].last_packet = session[s].last_data = time_now;
 
        LOG(2, s, t, "Login by %s at %s from %s (%s)\n", session[s].user,
                fmtaddr(htonl(session[s].ip), 0),
@@ -5439,7 +5461,7 @@ int cmd_show_hist_idle(struct cli_def *cli, char *command, char **argv, int argc
                if (!session[s].opened)
                        continue;
 
-               idle = time_now - session[s].last_packet;
+               idle = time_now - session[s].last_data;
                idle /= 5 ; // In multiples of 5 seconds.
                if (idle < 0)
                        idle = 0;
index 3ad2cf5..2c760f2 100644 (file)
--- a/l2tpns.h
+++ b/l2tpns.h
@@ -1,5 +1,5 @@
 // L2TPNS Global Stuff
-// $Id: l2tpns.h,v 1.116 2006/04/27 14:37:28 bodea Exp $
+// $Id: l2tpns.h,v 1.117 2006/06/11 12:46:18 bodea Exp $
 
 #ifndef __L2TPNS_H__
 #define __L2TPNS_H__
@@ -284,7 +284,10 @@ typedef struct
        uint16_t mru;                   // maximum receive unit
        clockt opened;                  // when started
        clockt die;                     // being closed, when to finally free
+       uint32_t session_timeout;       // Maximum session time in seconds
+       uint32_t idle_timeout;          // Maximum idle time in seconds
        time_t last_packet;             // Last packet from the user (used for idle timeouts)
+       time_t last_data;               // Last data packet to/from the user (used for idle timeouts)
        in_addr_t dns1, dns2;           // DNS servers
        routet route[MAXROUTE];         // static routes
        uint16_t tbf_in;                // filter bucket for throttling in from the user.
index 15fffac..9507981 100644 (file)
@@ -43,5 +43,5 @@ rm -rf %{buildroot}
 %attr(644,root,root) /usr/share/man/man[58]/*
 
 %changelog
-* Wed May 24 2006 Brendan O'Dea <bod@optus.net> 2.2.0-1
+* Fri Jun 9 2006 Brendan O'Dea <bod@optus.net> 2.2.0-1
 - 2.2.0 release, see /usr/share/doc/l2tpns-2.2.0/Changes
index dd8a3e6..fdb54a1 100644 (file)
--- a/radius.c
+++ b/radius.c
@@ -1,6 +1,6 @@
 // L2TPNS Radius Stuff
 
-char const *cvs_id_radius = "$Id: radius.c,v 1.50 2006/04/27 09:53:50 bodea Exp $";
+char const *cvs_id_radius = "$Id: radius.c,v 1.51 2006/06/11 12:46:18 bodea Exp $";
 
 #include <time.h>
 #include <stdio.h>
@@ -330,6 +330,7 @@ void radiussend(uint16_t r, uint8_t state)
                        }
                }
        }
+
        if (s)
        {
                *p = 5;         // NAS-Port
@@ -346,52 +347,73 @@ void radiussend(uint16_t r, uint8_t state)
                p[1] = 6;
                *(uint32_t *) (p + 2) = htonl(1); // PPP
                p += p[1];
-       }
-       if (s && session[s].ip)
-       {
-               *p = 8;                 // Framed-IP-Address
-               p[1] = 6;
-               *(uint32_t *) (p + 2) = htonl(session[s].ip);
-               p += p[1];
-       }
-       if (s && session[s].route[0].ip)
-       {
-               int r;
-               for (r = 0; s && r < MAXROUTE && session[s].route[r].ip; r++)
+
+               if (session[s].ip)
                {
-                       int width = 32;
-                       if (session[s].route[r].mask)
+                       *p = 8;                 // Framed-IP-Address
+                       p[1] = 6;
+                       *(uint32_t *) (p + 2) = htonl(session[s].ip);
+                       p += p[1];
+               }
+
+               if (session[s].route[0].ip)
+               {
+                       int r;
+                       for (r = 0; s && r < MAXROUTE && session[s].route[r].ip; r++)
                        {
-                           int mask = session[s].route[r].mask;
-                           while (!(mask & 1))
-                           {
-                               width--;
-                               mask >>= 1;
-                           }
+                               int width = 32;
+                               if (session[s].route[r].mask)
+                               {
+                                   int mask = session[s].route[r].mask;
+                                   while (!(mask & 1))
+                                   {
+                                       width--;
+                                       mask >>= 1;
+                                   }
+                               }
+
+                               *p = 22;        // Framed-Route
+                               p[1] = sprintf((char *) p + 2, "%s/%d %s 1",
+                                       fmtaddr(htonl(session[s].route[r].ip), 0),
+                                       width, fmtaddr(htonl(session[s].ip), 1)) + 2;
+
+                               p += p[1];
                        }
+               }
+
+               if (session[s].session_timeout)
+               {
+                       *p = 27;                // Session-Timeout
+                       p[1] = 6;
+                       *(uint32_t *) (p + 2) = htonl(session[s].session_timeout);
+                       p += p[1];
+               }
 
-                       *p = 22;        // Framed-Route
-                       p[1] = sprintf((char *) p + 2, "%s/%d %s 1",
-                               fmtaddr(htonl(session[s].route[r].ip), 0),
-                               width, fmtaddr(htonl(session[s].ip), 1)) + 2;
+               if (session[s].idle_timeout)
+               {
+                       *p = 28;                // Idle-Timeout
+                       p[1] = 6;
+                       *(uint32_t *) (p + 2) = htonl(session[s].idle_timeout);
+                       p += p[1];
+               }
 
+               if (*session[s].called)
+               {
+                       *p = 30;                // called
+                       p[1] = strlen(session[s].called) + 2;
+                       strcpy((char *) p + 2, session[s].called);
+                       p += p[1];
+               }
+
+               if (*session[s].calling)
+               {
+                       *p = 31;                // calling
+                       p[1] = strlen(session[s].calling) + 2;
+                       strcpy((char *) p + 2, session[s].calling);
                        p += p[1];
                }
        }
-       if (*session[s].called)
-       {
-               *p = 30;                // called
-               p[1] = strlen(session[s].called) + 2;
-               strcpy((char *) p + 2, session[s].called);
-               p += p[1];
-       }
-       if (*session[s].calling)
-       {
-               *p = 31;                // calling
-               p[1] = strlen(session[s].calling) + 2;
-               strcpy((char *) p + 2, session[s].calling);
-               p += p[1];
-       }
+
        // NAS-IP-Address
        *p = 4;
        p[1] = 6;
@@ -699,6 +721,28 @@ void processrad(uint8_t *buf, int len, char socket_index)
                                                        ip_filters[f].used++;
                                                }
                                        }
+                                       else if (*p == 27)
+                                       {
+                                               // Session-Timeout
+                                               uint32_t to = ntohl(*(uint32_t *)(p + 2));
+
+                                               LOG(3, s, session[s].tunnel, "   Radius reply contains Session-Timeout = %u\n", to);
+                                               if (to > 0)
+                                               {
+                                                       session[s].session_timeout = to;
+                                               }
+                                       }
+                                       else if (*p == 28)
+                                       {
+                                               // Idle-Timeout
+                                               uint32_t to = ntohl(*(uint32_t *)(p + 2));
+
+                                               LOG(3, s, session[s].tunnel, "   Radius reply contains Idle-Timeout = %u\n", to);
+                                               if (to > 0)
+                                               {
+                                                       session[s].idle_timeout = to;
+                                               }
+                                       }
                                        else if (*p == 26 && p[1] >= 7)
                                        {
                                                // Vendor-Specific Attribute