- Show session open time in "show session"/"show user" detailed output.
[l2tpns.git] / l2tpns.c
index a02be1d..db73793 100644 (file)
--- a/l2tpns.c
+++ b/l2tpns.c
@@ -1,10 +1,10 @@
 // L2TP Network Server
 // Adrian Kennard 2002
-// Copyright (c) 2003, 2004 Optus Internet Engineering
+// Copyright (c) 2003, 2004, 2005 Optus Internet Engineering
 // 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.73 2004/12/17 00:28:00 bodea Exp $";
+char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.73.2.11 2005/05/30 02:55:41 bodea Exp $";
 
 #include <arpa/inet.h>
 #include <assert.h>
@@ -83,7 +83,7 @@ uint32_t eth_tx = 0;
 static uint32_t ip_pool_size = 1;      // Size of the pool of addresses used for dynamic address allocation.
 time_t time_now = 0;                   // Current time in seconds since epoch.
 static char time_now_string[64] = {0}; // Current time as a string.
-static char main_quit = 0;             // True if we're in the process of exiting.
+char main_quit = 0;                    // True if we're in the process of exiting.
 linked_list *loaded_plugins;
 linked_list *plugins[MAX_PLUGIN_TYPES];
 
@@ -113,14 +113,17 @@ config_descriptt config_values[] = {
        CONFIG("setuid", target_uid, INT),
        CONFIG("dump_speed", dump_speed, BOOL),
        CONFIG("cleanup_interval", cleanup_interval, INT),
+       CONFIG("cleanup_limit", cleanup_limit, INT),
        CONFIG("multi_read_count", multi_read_count, INT),
        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, IP),
        CONFIG("cluster_interface", cluster_interface, STRING),
        CONFIG("cluster_hb_interval", cluster_hb_interval, INT),
        CONFIG("cluster_hb_timeout", cluster_hb_timeout, INT),
+       CONFIG("cluster_master_min_adv", cluster_master_min_adv, INT),
        { NULL, 0, 0, 0 },
 };
 
@@ -147,7 +150,7 @@ static sessionidt shut_acct_n = 0;
 
 tunnelt *tunnel = NULL;                        // Array of tunnel structures.
 sessiont *session = NULL;              // Array of session structures.
-sessioncountt *sess_count = NULL;      // Array of partial per-session traffic counters.
+sessionlocalt *sess_local = NULL;      // Array of local per-session counters.
 radiust *radius = NULL;                        // Array of radius structures.
 ippoolt *ip_address_pool = NULL;       // Array of dynamic IP addresses.
 ip_filtert *ip_filters = NULL; // Array of named filters.
@@ -179,6 +182,9 @@ static void processcontrol(uint8_t *buf, int len, struct sockaddr_in *addr, int
 static tunnelidt new_tunnel(void);
 static int unhide_avp(uint8_t *avp, tunnelidt t, sessionidt s, uint16_t length);
 
+// on slaves, alow BGP to withdraw cleanly before exiting
+#define QUIT_DELAY     5
+
 // return internal time (10ths since process startup)
 static clockt now(void)
 {
@@ -478,7 +484,7 @@ sessionidt sessionbyip(in_addr_t ip)
        int s = lookup_ipmap(ip);
        CSTAT(call_sessionbyip);
 
-       if (s > 0 && s < MAXSESSION && session[s].tunnel)
+       if (s > 0 && s < MAXSESSION && session[s].opened)
                return (sessionidt) s;
 
        return 0;
@@ -578,8 +584,11 @@ sessionidt sessionbyuser(char *username)
        int s;
        CSTAT(call_sessionbyuser);
 
-       for (s = 1; s < MAXSESSION ; ++s)
+       for (s = 1; s <= config->cluster_highest_sessionid ; ++s)
        {
+               if (!session[s].opened)
+                       continue;
+
                if (session[s].walled_garden)
                        continue;               // Skip walled garden users.
 
@@ -621,17 +630,16 @@ void send_garp(in_addr_t ip)
        sendarp(ifr.ifr_ifindex, mac, ip);
 }
 
-// Find session by username, 0 for not found
 static sessiont *sessiontbysessionidt(sessionidt s)
 {
-       if (!s || s > MAXSESSION) return NULL;
+       if (!s || s >= MAXSESSION) return NULL;
        return &session[s];
 }
 
 static sessionidt sessionidtbysessiont(sessiont *s)
 {
        sessionidt val = s-session;
-       if (s < session || val > MAXSESSION) return 0;
+       if (s < session || val >= MAXSESSION) return 0;
        return val;
 }
 
@@ -711,7 +719,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];
@@ -721,13 +729,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;
        }
 
@@ -765,6 +773,45 @@ 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_local[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_local[s].packets_out > max)
+                       {
+                               sess_local[s].packets_dropped++;
+                               return;
+                       }
+               }
+               else
+               {
+                       if (sess_local[s].packets_dropped)
+                       {
+                               INC_STAT(tun_rx_dropped, sess_local[s].packets_dropped);
+                               LOG(3, s, t, "Dropped %u/%u packets to %s for %suser %s\n",
+                                       sess_local[s].packets_dropped, sess_local[s].packets_out,
+                                       fmtaddr(ip, 0), sp->throttle_out ? "throttled " : "",
+                                       sp->user);
+                       }
+
+                       sess_local[s].last_packet_out = TIME;
+                       sess_local[s].packets_out = 1;
+                       sess_local[s].packets_dropped = 0;
+               }
+       }
+
        // run access-list if any
        if (session[s].filter_out && !ip_filter(buf, len, session[s].filter_out - 1))
                return;
@@ -802,7 +849,7 @@ static void processipout(uint8_t * buf, int len)
        sp->total_cout += len; // byte count
        sp->pout++;
        udp_tx += len;
-       sess_count[s].cout += len;      // To send to master..
+       sess_local[s].cout += len;      // To send to master..
 }
 
 //
@@ -852,7 +899,7 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len)
        sp->total_cout += len; // byte count
        sp->pout++;
        udp_tx += len;
-       sess_count[s].cout += len;      // To send to master..
+       sess_local[s].cout += len;      // To send to master..
 }
 
 // add an AVP (16 bit)
@@ -972,7 +1019,7 @@ static void controladd(controlt * c, tunnelidt t, sessionidt s)
 //
 void throttle_session(sessionidt s, int rate_in, int rate_out)
 {
-       if (!session[s].tunnel)
+       if (!session[s].opened)
                return; // No-one home.
 
        if (!*session[s].user)
@@ -1010,7 +1057,7 @@ void throttle_session(sessionidt s, int rate_in, int rate_out)
 // add/remove filters from session (-1 = no change)
 void filter_session(sessionidt s, int filter_in, int filter_out)
 {
-       if (!session[s].tunnel)
+       if (!session[s].opened)
                return; // No-one home.
 
        if (!*session[s].user)
@@ -1053,9 +1100,9 @@ void sessionshutdown(sessionidt s, char *reason)
 
        CSTAT(call_sessionshutdown);
 
-       if (!session[s].tunnel)
+       if (!session[s].opened)
        {
-               LOG(3, s, session[s].tunnel, "Called sessionshutdown on a session with no tunnel.\n");
+               LOG(3, s, session[s].tunnel, "Called sessionshutdown on an unopened session.\n");
                return;                   // not a live session
        }
 
@@ -1066,7 +1113,7 @@ void sessionshutdown(sessionidt s, char *reason)
                run_plugins(PLUGIN_KILL_SESSION, &data);
        }
 
-       if (session[s].opened && !walled_garden && !session[s].die)
+       if (session[s].ip && !walled_garden && !session[s].die)
        {
                // RADIUS Stop message
                uint16_t r = session[s].radius;
@@ -1075,7 +1122,6 @@ void sessionshutdown(sessionidt s, char *reason)
                        if (!(r = radiusnew(s)))
                        {
                                LOG(1, s, session[s].tunnel, "No free RADIUS sessions for Stop message\n");
-                               STAT(radius_overflow);
                        }
                        else
                        {
@@ -1127,7 +1173,7 @@ void sessionshutdown(sessionidt s, char *reason)
        }
 
        if (!session[s].die)
-               session[s].die = now() + 150; // Clean up in 15 seconds
+               session[s].die = TIME + 150; // Clean up in 15 seconds
 
        // update filter refcounts
        if (session[s].filter_in) ip_filters[session[s].filter_in - 1].used--;
@@ -1147,6 +1193,12 @@ void sendipcp(tunnelidt t, sessionidt s)
        if (!r)
                r = radiusnew(s);
 
+       if (!r)
+       {
+               sessionshutdown(s, "No free RADIUS sessions for IPCP");
+               return;
+       }
+
        if (radius[r].state != RADIUSIPCP)
        {
                radius[r].state = RADIUSIPCP;
@@ -1165,7 +1217,7 @@ void sendipcp(tunnelidt t, sessionidt s)
        if (!q) return;
 
        *q = ConfigReq;
-       q[1] = r << RADIUS_SHIFT;                    // ID, dont care, we only send one type of request
+       q[1] = r >> RADIUS_SHIFT;                    // ID, dont care, we only send one type of request
        *(uint16_t *) (q + 2) = htons(10);
        q[4] = 3;
        q[5] = 6;
@@ -1177,24 +1229,39 @@ void sendipcp(tunnelidt t, sessionidt s)
        session[s].flags &= ~SF_IPCP_ACKED;     // Clear flag.
 }
 
+static void sessionclear(sessionidt s)
+{
+       memset(&session[s], 0, sizeof(session[s]));
+       memset(&sess_local[s], 0, sizeof(sess_local[s]));
+       memset(&cli_session_actions[s], 0, sizeof(cli_session_actions[s]));
+
+       session[s].tunnel = T_FREE;     // Mark it as free.
+       session[s].next = sessionfree;
+       sessionfree = s;
+}
+
 // kill a session now
-static void sessionkill(sessionidt s, char *reason)
+void sessionkill(sessionidt s, char *reason)
 {
 
        CSTAT(call_sessionkill);
 
-       session[s].die = now();
+       if (!session[s].opened) // not alive
+               return;
+
+       if (session[s].next)
+       {
+               LOG(0, s, session[s].tunnel, "Tried to kill a session with next pointer set (%d)\n", session[s].next);
+               return;
+       }
+
+       session[s].die = TIME;
        sessionshutdown(s, reason);  // close radius/routes, etc.
        if (session[s].radius)
                radiusclear(session[s].radius, s); // cant send clean accounting data, session is killed
 
        LOG(2, s, session[s].tunnel, "Kill session %d (%s): %s\n", s, session[s].user, reason);
-
-       memset(&session[s], 0, sizeof(session[s]));
-       session[s].tunnel = T_FREE;     // Mark it as free.
-       session[s].next = sessionfree;
-       sessionfree = s;
-       cli_session_actions[s].action = 0;
+       sessionclear(s);
        cluster_send_session(s);
 }
 
@@ -1225,7 +1292,7 @@ static void tunnelkill(tunnelidt t, char *reason)
                controlfree = c;
        }
        // kill sessions
-       for (s = 1; s < MAXSESSION; s++)
+       for (s = 1; s <= config->cluster_highest_sessionid ; ++s)
                if (session[s].tunnel == t)
                        sessionkill(s, reason);
 
@@ -1252,12 +1319,12 @@ static void tunnelshutdown(tunnelidt t, char *reason)
        LOG(1, 0, t, "Shutting down tunnel %d (%s)\n", t, reason);
 
        // close session
-       for (s = 1; s < MAXSESSION; s++)
+       for (s = 1; s <= config->cluster_highest_sessionid ; ++s)
                if (session[s].tunnel == t)
                        sessionshutdown(s, reason);
 
        tunnel[t].state = TUNNELDIE;
-       tunnel[t].die = now() + 700; // Clean up in 70 seconds
+       tunnel[t].die = TIME + 700; // Clean up in 70 seconds
        cluster_send_tunnel(t);
        // TBA - should we wait for sessions to stop?
        {                            // Send StopCCN
@@ -1796,7 +1863,8 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
                                        if (!sessionfree)
                                        {
                                                STAT(session_overflow);
-                                               tunnelshutdown(t, "No free sessions");
+                                               LOG(1, 0, t, "No free sessions\n");
+                                               return;
                                        }
                                        else
                                        {
@@ -1814,13 +1882,13 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
                                                if (!(r = radiusnew(s)))
                                                {
                                                        LOG(1, s, t, "No free RADIUS sessions for ICRQ\n");
-                                                       sessionkill(s, "no free RADIUS sesions");
+                                                       sessionclear(s);
                                                        return;
                                                }
 
                                                c = controlnew(11); // sending ICRP
                                                session[s].id = sessionid++;
-                                               session[s].opened = time(NULL);
+                                               session[s].opened = time_now;
                                                session[s].tunnel = t;
                                                session[s].far = asession;
                                                session[s].last_packet = time_now;
@@ -1903,7 +1971,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
                        l -= 2;
                }
 
-               if (s && !session[s].tunnel)    // Is something wrong??
+               if (s && !session[s].opened)    // Is something wrong??
                {
                        if (!config->cluster_iam_master)
                        {
@@ -1912,10 +1980,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
                                return;
                        }
 
-
-                       LOG(1, s, t, "UDP packet contains session %d but no session[%d].tunnel "
-                                    "exists (LAC said tunnel = %d).  Dropping packet.\n", s, s, t);
-
+                       LOG(1, s, t, "UDP packet contains session which is not opened.  Dropping packet.\n");
                        STAT(tunnel_rx_errors);
                        return;
                }
@@ -1998,12 +2063,7 @@ static void processtun(uint8_t * buf, int len)
        // Else discard.
 }
 
-//
-// Maximum number of actions to complete.
-// This is to avoid sending out too many packets
-// at once.
-#define MAX_ACTIONS 500
-
+// Handle retries, timeouts
 static int regular_cleanups(void)
 {
        static sessionidt s = 0;        // Next session to check for actions on.
@@ -2083,7 +2143,7 @@ static int regular_cleanups(void)
                if (s > config->cluster_highest_sessionid)
                        s = 1;
 
-               if (!session[s].tunnel) // Session isn't in use
+               if (!session[s].opened) // Session isn't in use
                        continue;
 
                if (!session[s].die && session[s].ip && !(session[s].flags & SF_IPCP_ACKED))
@@ -2097,7 +2157,7 @@ static int regular_cleanups(void)
                if (session[s].die && session[s].die <= TIME)
                {
                        sessionkill(s, "Expired");
-                       if (++count >= MAX_ACTIONS) break;
+                       if (++count >= config->cleanup_limit) break;
                        continue;
                }
 
@@ -2106,7 +2166,7 @@ static int regular_cleanups(void)
                {
                        sessionshutdown(s, "No response to LCP ECHO requests");
                        STAT(session_timeout);
-                       if (++count >= MAX_ACTIONS) break;
+                       if (++count >= config->cleanup_limit) break;
                        continue;
                }
 
@@ -2126,7 +2186,7 @@ static int regular_cleanups(void)
                        LOG(4, s, session[s].tunnel, "No data in %d seconds, sending LCP ECHO\n",
                                        (int)(time_now - session[s].last_packet));
                        tunnelsend(b, 24, session[s].tunnel); // send it
-                       if (++count >= MAX_ACTIONS) break;
+                       if (++count >= config->cleanup_limit) break;
                }
 
                // Check for actions requested from the CLI
@@ -2195,7 +2255,7 @@ static int regular_cleanups(void)
                        if (send)
                                cluster_send_session(s);
 
-                       if (++count >= MAX_ACTIONS) break;
+                       if (++count >= config->cleanup_limit) break;
                }
        }
 
@@ -2217,7 +2277,7 @@ static int regular_cleanups(void)
                }
        }
 
-       if (count >= MAX_ACTIONS)
+       if (count >= config->cleanup_limit)
                return 1;       // Didn't finish!
 
        LOG(3, 0, 0, "End regular cleanup (%d actions), next in %d seconds\n", count, config->cleanup_interval);
@@ -2232,8 +2292,39 @@ static int regular_cleanups(void)
 static int still_busy(void)
 {
        int i;
+       static time_t stopped_bgp = 0;
        static clockt last_talked = 0;
        static clockt start_busy_wait = 0;
+
+       if (!config->cluster_iam_master)
+       {
+#ifdef BGP
+               if (bgp_configured)
+               {
+                       if (!stopped_bgp)
+                       {
+                               LOG(1, 0, 0, "Shutting down in %d seconds, stopping BGP...\n", QUIT_DELAY);
+
+                               for (i = 0; i < BGP_NUM_PEERS; i++)
+                                       if (bgp_peers[i].state == Established)
+                                               bgp_stop(&bgp_peers[i]);
+
+                               stopped_bgp = time_now;
+
+                               // we don't want to become master
+                               cluster_send_ping(0);
+
+                               return 1;
+                       }
+
+                       if (time_now < (stopped_bgp + QUIT_DELAY))
+                               return 1;
+               }
+#endif /* BGP */
+
+               return 0;
+       }
+
        if (start_busy_wait == 0)
                start_busy_wait = TIME;
 
@@ -2511,7 +2602,6 @@ static void mainloop(void)
 
                /* Handle timeouts. Make sure that this gets run anyway, even if there was
                 * something to read, else under load this will never actually run....
-                *
                 */
                if (config->cluster_iam_master && next_clean <= time_now)
                {
@@ -2537,6 +2627,7 @@ static void mainloop(void)
 
        //
        // Important!!! We MUST not process any packets past this point!
+       LOG(1, 0, 0, "Clean shutdown complete\n");
 }
 
 static void stripdomain(char *host)
@@ -2625,6 +2716,7 @@ static void initdata(int optdebug, char *optconfig)
        config->debug = optdebug;
        config->num_tbfs = MAXTBFS;
        config->rl_rate = 28; // 28kbps
+       config->cluster_master_min_adv = 1;
 
        if (!(tunnel = shared_malloc(sizeof(tunnelt) * MAXTUNNEL)))
        {
@@ -2637,9 +2729,9 @@ static void initdata(int optdebug, char *optconfig)
                exit(1);
        }
 
-       if (!(sess_count = shared_malloc(sizeof(sessioncountt) * MAXSESSION)))
+       if (!(sess_local = shared_malloc(sizeof(sessionlocalt) * MAXSESSION)))
        {
-               LOG(0, 0, 0, "Error doing malloc for sessions_count: %s\n", strerror(errno));
+               LOG(0, 0, 0, "Error doing malloc for sess_local: %s\n", strerror(errno));
                exit(1);
        }
 
@@ -2691,7 +2783,7 @@ memset(ip_filters, 0, sizeof(ip_filtert) * MAXFILTER);
        memset(ip_address_pool, 0, sizeof(ippoolt) * MAXIPPOOL);
 
                // Put all the sessions on the free list marked as undefined.
-       for (i = 1; i < MAXSESSION - 1; i++)
+       for (i = 1; i < MAXSESSION; i++)
        {
                session[i].next = i + 1;
                session[i].tunnel = T_UNDEF;    // mark it as not filled in.
@@ -2700,7 +2792,7 @@ memset(ip_filters, 0, sizeof(ip_filtert) * MAXFILTER);
        sessionfree = 1;
 
                // Mark all the tunnels as undefined (waiting to be filled in by a download).
-       for (i = 1; i < MAXTUNNEL- 1; i++)
+       for (i = 1; i < MAXTUNNEL; i++)
                tunnel[i].state = TUNNELUNDEF;  // mark it as not filled in.
 
        if (!*hostname)
@@ -2826,7 +2918,7 @@ void rebuild_address_pool(void)
        for (i = 0; i < MAXSESSION; ++i)
        {
                int ipid;
-               if (!session[i].ip || !session[i].tunnel)
+               if (!(session[i].opened && session[i].ip))
                        continue;
                ipid = - lookup_ipmap(htonl(session[i].ip));
 
@@ -3128,7 +3220,7 @@ int main(int argc, char *argv[])
        init_tbf(config->num_tbfs);
 
        LOG(0, 0, 0, "L2TPNS version " VERSION "\n");
-       LOG(0, 0, 0, "Copyright (c) 2003, 2004 Optus Internet Engineering\n");
+       LOG(0, 0, 0, "Copyright (c) 2003, 2004, 2005 Optus Internet Engineering\n");
        LOG(0, 0, 0, "Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced\n");
        {
                struct rlimit rlim;
@@ -3216,14 +3308,6 @@ int main(int argc, char *argv[])
 
        mainloop();
 
-#ifdef BGP
-       /* try to shut BGP down cleanly; with luck the sockets will be
-          writable since we're out of the select */
-       for (i = 0; i < BGP_NUM_PEERS; i++)
-               if (bgp_peers[i].state == Established)
-                       bgp_stop(&bgp_peers[i]);
-#endif /* BGP */
-
        /* remove plugins (so cleanup code gets run) */
        plugins_done();
 
@@ -3598,7 +3682,7 @@ static void update_config()
        if (!config->numradiusservers)
                LOG(0, 0, 0, "No RADIUS servers defined!\n");
 
-       config->num_radfds = 2 << RADIUS_SHIFT;
+       config->num_radfds = 1 << RADIUS_SHIFT;
 
        // Update plugins
        for (i = 0; i < MAXPLUGINS; i++)
@@ -3618,7 +3702,8 @@ static void update_config()
                }
        }
        memcpy(config->old_plugins, config->plugins, sizeof(config->plugins));
-       if (!config->cleanup_interval) config->cleanup_interval = 10;
+       if (!config->cleanup_interval) config->cleanup_interval = 2;
+       if (!config->cleanup_limit) config->cleanup_limit = 50;
        if (!config->multi_read_count) config->multi_read_count = 10;
        if (!config->cluster_address) config->cluster_address = inet_addr(DEFAULT_MCAST_ADDR);
        if (!*config->cluster_interface)
@@ -3699,7 +3784,7 @@ int sessionsetup(tunnelidt t, sessionidt s)
 
        LOG(3, s, t, "Doing session setup for session\n");
 
-       if (!session[s].ip || session[s].ip == 0xFFFFFFFE)
+       if (!session[s].ip)
        {
                assign_ip_address(s);
                if (!session[s].ip)
@@ -4297,7 +4382,7 @@ void become_master(void)
        {
                for (s = 1; s <= config->cluster_highest_sessionid ; ++s)
                {
-                       if (!session[s].tunnel) // Not an in-use session.
+                       if (!session[s].opened) // Not an in-use session.
                                continue;
 
                        run_plugins(PLUGIN_NEW_SESSION_MASTER, &session[s]);
@@ -4329,7 +4414,7 @@ int cmd_show_hist_idle(struct cli_def *cli, char *command, char **argv, int argc
        for (s = 1; s <= config->cluster_highest_sessionid ; ++s)
        {
                int idle;
-               if (!session[s].tunnel)
+               if (!session[s].opened)
                        continue;
 
                idle = time_now - session[s].last_packet;
@@ -4367,7 +4452,7 @@ int cmd_show_hist_open(struct cli_def *cli, char *command, char **argv, int argc
        for (s = 1; s <= config->cluster_highest_sessionid ; ++s)
        {
                int open = 0, d;
-               if (!session[s].tunnel)
+               if (!session[s].opened)
                        continue;
 
                d = time_now - session[s].opened;