add DAE support (PoD/CoA) from Vladislav Bjelic
authorBrendan O'Dea <bod@optus.net>
Tue, 28 Jun 2005 14:48:17 +0000 (14:48 +0000)
committerBrendan O'Dea <bod@optus.net>
Tue, 28 Jun 2005 14:48:17 +0000 (14:48 +0000)
16 files changed:
Changes
Docs/manual.html
Docs/startup-config.5
cli.c
cluster.c
cluster.h
constants.c
l2tpns.c
l2tpns.h
l2tpns.spec
plugin.h
radius.c
sessionctl.c
snoopctl.c
throttlectl.c
util.c

diff --git a/Changes b/Changes
index 70c1f61..452407b 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,9 +1,10 @@
-* Mon Jun 27 2005 Brendan O'Dea <bod@optus.net> 2.1.2
+* Wed Jun 29 2005 Brendan O'Dea <bod@c47.org> 2.1.2
 - Don't resend IPCP while still in progress.
 - Ignore duplicate ACKs for IPCP.
 - Clear RADIUSIPCP for walled garden sessions on ACK.
 - Clear cluster_master on election so that slaves will accept a new master.
 - Provide more comments/defaults in etc/startup-config.default.
+- Add DAE support (PoD/CoA) from Vladislav Bjelic.
 
 * Tue Jun 14 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.1
 - Add missing newline to backtrace macro.
index 1395e3a..4166235 100644 (file)
@@ -229,6 +229,11 @@ A comma separated list of supported RADIUS authentication methods
 (<B>pap</B> or <B>chap</B>), in order of preference (default <B>pap</B>).
 </LI>
 
+<LI><B>radius_dae_port</B> (short)<BR>
+Port for DAE RADIUS (Packet of Death/Disconnect, Change of Authorization)
+requests (default: <B>3799</B>).
+</LI>
+
 <LI><B>allow_duplicate_users</B> (boolean)</BR>
 Allow multiple logins with the same username.  If false (the default),
 any prior session with the same username will be dropped when a new
index 61c2dc2..7170dbe 100644 (file)
@@ -2,7 +2,7 @@
 .de Id
 .ds Dt \\$4 \\$5
 ..
-.Id $Id: startup-config.5,v 1.10 2005-06-02 11:32:33 bodea Exp $
+.Id $Id: startup-config.5,v 1.11 2005-06-28 14:48:31 bodea Exp $
 .TH STARTUP-CONFIG 5 "\*(Dt" L2TPNS "File Formats and Conventions"
 .SH NAME
 startup\-config \- configuration file for l2tpns
@@ -100,6 +100,10 @@ Secret to be used in RADIUS packets.
 A comma separated list of supported RADIUS authentication methods
 ("pap" or "chap"), in order of preference (default "pap").
 .TP
+.B radius_dae_port
+Port for DAE RADIUS (Packet of Death/Disconnect, Change of Authorization)
+requests (default: 3799).
+.TP
 .B allow_duplicate_users
 Allow multiple logins with the same username.  If false (the default),
 any prior session with the same username will be dropped when a new
diff --git a/cli.c b/cli.c
index 37682d6..d0f9a8a 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.62 2005-06-07 05:31:43 bodea Exp $";
+char const *cvs_id_cli = "$Id: cli.c,v 1.63 2005-06-28 14:48:17 bodea Exp $";
 
 #include <stdio.h>
 #include <stdarg.h>
@@ -2316,17 +2316,6 @@ static int cmd_restart_bgp(struct cli_def *cli, char *command, char **argv, int
 #endif /* BGP*/
 
 static int filt;
-static int find_access_list(char const *name)
-{
-       int i;
-
-       for (i = 0; i < MAXFILTER; i++)
-               if (!(*ip_filters[i].name && strcmp(ip_filters[i].name, name)))
-                       return i;
-
-       return -1;
-}
-
 static int access_list(struct cli_def *cli, char **argv, int argc, int add)
 {
        int extended;
@@ -2377,7 +2366,7 @@ static int access_list(struct cli_def *cli, char **argv, int argc, int add)
                return CLI_OK;
        }
 
-       filt = find_access_list(argv[1]);
+       filt = find_filter(argv[1], strlen(argv[1]));
        if (add)
        {
                if (filt < 0)
@@ -2970,7 +2959,7 @@ static int cmd_filter(struct cli_def *cli, char *command, char **argv, int argc)
                        return CLI_OK;
                }
 
-               v = find_access_list(argv[i+1]);
+               v = find_filter(argv[i+1], strlen(argv[i+1]));
                if (v < 0 || !*ip_filters[v].name)
                {
                        cli_error(cli, "Access-list %s not defined", argv[i+1]);
@@ -3046,7 +3035,7 @@ static int cmd_show_access_list(struct cli_def *cli, char *command, char **argv,
 
        for (i = 0; i < argc; i++)
        {
-               int f = find_access_list(argv[i]);
+               int f = find_filter(argv[i], strlen(argv[i]));
                ip_filter_rulet *rules;
 
                if (f < 0 || !*ip_filters[f].name)
index a8f34d0..ad41e46 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.43 2005-06-27 04:52:54 bodea Exp $";
+char const *cvs_id_cluster = "$Id: cluster.c,v 1.44 2005-06-28 14:48:19 bodea Exp $";
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -270,13 +270,8 @@ static int peer_send_message(in_addr_t peer, int type, int more, char *data, int
        return peer_send_data(peer, buf, (p-buf) );
 }
 
-//
-// Forward a state changing packet to the master.
-//
-// The master just processes the payload as if it had
-// received it off the tun device.
-//
-int master_forward_packet(char *data, int size, in_addr_t addr, int port)
+// send a packet to the master
+static int _forward_packet(char *data, int size, in_addr_t addr, int port, int type)
 {
        char buf[65536];        // Vast overkill.
        char *p = buf;
@@ -287,13 +282,30 @@ int master_forward_packet(char *data, int size, in_addr_t addr, int port)
        LOG(4, 0, 0, "Forwarding packet from %s to master (size %d)\n", fmtaddr(addr, 0), size);
 
        STAT(c_forwarded);
-       add_type(&p, C_FORWARD, addr, (char *) &port, sizeof(port)); // ick. should be uint16_t
+       add_type(&p, type, addr, (char *) &port, sizeof(port)); // ick. should be uint16_t
        memcpy(p, data, size);
        p += size;
 
        return peer_send_data(config->cluster_master_address, buf, (p - buf));
 }
 
+// 
+// Forward a state changing packet to the master.
+//
+// The master just processes the payload as if it had
+// received it off the tun device.
+//
+int master_forward_packet(char *data, int size, in_addr_t addr, int port)
+{
+       return _forward_packet(data, size, addr, port, C_FORWARD);
+}
+
+// Forward a DAE RADIUS packet to the master.
+int master_forward_dae_packet(char *data, int size, in_addr_t addr, int port)
+{
+       return _forward_packet(data, size, addr, port, C_FORWARD_DAE);
+}
+
 //
 // Forward a throttled packet to the master for handling.
 //
@@ -1585,7 +1597,8 @@ int processcluster(char *data, int size, in_addr_t addr)
        p += sizeof(uint32_t);
        s -= sizeof(uint32_t);
 
-       switch (type) {
+       switch (type)
+       {
        case C_PING: // Update the peers table.
                return cluster_add_peer(addr, more, (pingt *) p, s);
 
@@ -1595,24 +1608,36 @@ int processcluster(char *data, int size, in_addr_t addr)
        case C_LASTSEEN: // Catch up a slave (slave missed a packet).
                return cluster_catchup_slave(more, addr);
 
-       case C_FORWARD: { // Forwarded control packet. pass off to processudp.
-               struct sockaddr_in a;
-               a.sin_addr.s_addr = more;
-
-               a.sin_port = *(int *) p;
-               s -= sizeof(int);
-               p += sizeof(int);
+       case C_FORWARD: // Forwarded control packet. pass off to processudp.
+       case C_FORWARD_DAE: // Forwarded DAE packet. pass off to processdae.
+               if (!config->cluster_iam_master)
+               {
+                       LOG(0, 0, 0, "I'm not the master, but I got a C_FORWARD_%s from %s?\n",
+                               type == C_FORWARD_DAE ? "_DAE" : "", fmtaddr(addr, 0));
 
-               if (!config->cluster_iam_master) { // huh?
-                       LOG(0, 0, 0, "I'm not the master, but I got a C_FORWARD from %s?\n", fmtaddr(addr, 0));
                        return -1;
                }
+               else
+               {
+                       struct sockaddr_in a;
+                       a.sin_addr.s_addr = more;
+
+                       a.sin_port = *(int *) p;
+                       s -= sizeof(int);
+                       p += sizeof(int);
+
+                       LOG(4, 0, 0, "Got a forwarded %spacket... (%s:%d)\n",
+                               type == C_FORWARD_DAE ? "DAE " : "", fmtaddr(more, 0), a.sin_port);
+
+                       STAT(recv_forward);
+                       if (type == C_FORWARD_DAE)
+                               processdae(p, s, &a, sizeof(a));
+                       else
+                               processudp(p, s, &a);
+
+                       return 0;
+               }
 
-               LOG(4, 0, 0, "Got a forwarded packet... (%s:%d)\n", fmtaddr(more, 0), a.sin_port);
-               STAT(recv_forward);
-               processudp(p, s, &a);
-               return 0;
-       }
        case C_THROTTLE: {      // Receive a forwarded packet from a slave.
                if (!config->cluster_iam_master) {
                        LOG(0, 0, 0, "I'm not the master, but I got a C_THROTTLE from %s?\n", fmtaddr(addr, 0));
index 00e8e9b..931c007 100644 (file)
--- a/cluster.h
+++ b/cluster.h
@@ -1,5 +1,5 @@
 // L2TPNS Clustering Stuff
-// $Id: cluster.h,v 1.12 2005-06-02 11:32:30 bodea Exp $
+// $Id: cluster.h,v 1.13 2005-06-28 14:48:19 bodea Exp $
 
 #ifndef __CLUSTER_H__
 #define __CLUSTER_H__
@@ -20,6 +20,7 @@
 #define C_CTUNNEL              13      // Compressed tunnel structure.
 #define C_GARDEN               14      // Gardened packet
 #define C_MASTER               15      // Tell a slave the address of the master.
+#define C_FORWARD_DAE          16      // A DAE packet for the master to handle
 
 #define HB_VERSION             5       // Protocol version number..
 #define HB_MAX_SEQ             (1<<30) // Maximum sequence number. (MUST BE A POWER OF 2!)
@@ -75,6 +76,7 @@ int processcluster(char *buf, int size, in_addr_t addr);
 int cluster_send_session(int sid);
 int cluster_send_tunnel(int tid);
 int master_forward_packet(char *data, int size, in_addr_t addr, int port);
+int master_forward_dae_packet(char *data, int size, in_addr_t addr, int port);
 int master_throttle_packet(int tid, char *data, int size);
 int master_garden_packet(sessionidt s, char *data, int size);
 void master_update_counts(void);
index 0b9ef42..f9e3fa1 100644 (file)
@@ -1,6 +1,6 @@
 // L2TPNS: constants
 
-char const *cvs_id_constants = "$Id: constants.c,v 1.5 2005-05-05 10:02:07 bodea Exp $";
+char const *cvs_id_constants = "$Id: constants.c,v 1.6 2005-06-28 14:48:20 bodea Exp $";
 
 #include <stdio.h>
 #include "constants.h"
@@ -173,8 +173,17 @@ CONSTANT(radius_code,
     0,                                                 // 9
     0,                                                 // 10
     "Access-Challenge",                                        // 11
-    "Status-Server (experimental)",                    // 12
-    "Status-Client (experimental)"                     // 13
+    "Status-Server",                                   // 12
+    "Status-Client",                                   // 13
+    0, 0, 0, 0, 0, 0,                                  // 14-19
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                      // 20-29
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                      // 30-39
+    "Disconnect-Request",                              // 40
+    "Disconnect-ACK",                                  // 41
+    "Disconnect-NAK",                                  // 42
+    "CoA-Request",                                     // 43
+    "CoA-ACK",                                         // 44
+    "CoA-NAK"                                          // 45
 )
 
 CONSTANT(l2tp_message_type,
index 58246b3..50fde1d 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.112 2005-06-24 07:05:04 bodea Exp $";
+char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.113 2005-06-28 14:48:20 bodea Exp $";
 
 #include <arpa/inet.h>
 #include <assert.h>
@@ -60,6 +60,7 @@ int tunfd = -1;                       // tun interface file handle. (network device)
 int udpfd = -1;                        // UDP file handle
 int controlfd = -1;            // Control signal handle
 int clifd = -1;                        // Socket listening for CLI connections.
+int daefd = -1;                        // Socket listening for DAE connections.
 int snoopfd = -1;              // UDP file handle for sending out intercept data
 int *radfds = NULL;            // RADIUS requests file handles
 int ifrfd = -1;                        // File descriptor for routing, etc
@@ -114,6 +115,7 @@ config_descriptt config_values[] = {
        CONFIG("radius_interim", radius_interim, INT),
        CONFIG("radius_secret", radiussecret, STRING),
        CONFIG("radius_authtypes", radius_authtypes_s, STRING),
+       CONFIG("radius_dae_port", radius_dae_port, SHORT),
        CONFIG("allow_duplicate_users", allow_duplicate_users, BOOL),
        CONFIG("bind_address", bind_address, IPv4),
        CONFIG("peer_address", peer_address, IPv4),
@@ -148,6 +150,7 @@ static char *plugin_functions[] = {
        "plugin_kill_session",
        "plugin_control",
        "plugin_radius_response",
+       "plugin_radius_reset",
        "plugin_become_master",
        "plugin_new_session_master",
 };
@@ -163,7 +166,7 @@ sessiont *session = NULL;           // Array of session structures.
 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.
+ip_filtert *ip_filters = NULL;         // Array of named filters.
 static controlt *controlfree = 0;
 struct Tstats *_statistics = NULL;
 #ifdef RINGBUFFER
@@ -578,7 +581,7 @@ static void inittun(void)
        }
 }
 
-// set up UDP port
+// set up UDP ports
 static void initudp(void)
 {
        int on = 1;
@@ -600,7 +603,6 @@ static void initudp(void)
                LOG(0, 0, 0, "Error in UDP bind: %s\n", strerror(errno));
                exit(1);
        }
-       snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 
        // Control
        memset(&addr, 0, sizeof(addr));
@@ -613,6 +615,21 @@ static void initudp(void)
                LOG(0, 0, 0, "Error in control bind: %s\n", strerror(errno));
                exit(1);
        }
+
+       // Dynamic Authorization Extensions to RADIUS
+       memset(&addr, 0, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(config->radius_dae_port);
+       daefd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+       setsockopt(daefd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+       if (bind(daefd, (void *) &addr, sizeof(addr)) < 0)
+       {
+               LOG(0, 0, 0, "Error in DAE bind: %s\n", strerror(errno));
+               exit(1);
+       }
+
+       // Intercept
+       snoopfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 }
 
 //
@@ -1415,7 +1432,7 @@ void throttle_session(sessionidt s, int rate_in, int rate_out)
 }
 
 // add/remove filters from session (-1 = no change)
-static void filter_session(sessionidt s, int filter_in, int filter_out)
+void filter_session(sessionidt s, int filter_in, int filter_out)
 {
        if (!session[s].opened)
                return; // No-one home.
@@ -2959,8 +2976,8 @@ static int still_busy(void)
 # include "fake_epoll.h"
 #endif
 
-// the base set of fds polled: control, cli, udp, tun, cluster
-#define BASE_FDS       5
+// the base set of fds polled: cli, cluster, tun, udp, control, dae
+#define BASE_FDS       6
 
 // additional polled fds
 #ifdef BGP
@@ -2984,8 +3001,8 @@ static void mainloop(void)
                exit(1);
        }
 
-       LOG(4, 0, 0, "Beginning of main loop.  udpfd=%d, tunfd=%d, cluster_sockfd=%d, controlfd=%d\n",
-               udpfd, tunfd, cluster_sockfd, controlfd);
+       LOG(4, 0, 0, "Beginning of main loop.  clifd=%d, cluster_sockfd=%d, tunfd=%d, udpfd=%d, controlfd=%d, daefd=%d\n",
+               clifd, cluster_sockfd, tunfd, udpfd, controlfd, daefd);
 
        /* setup our fds to poll for input */
        {
@@ -2995,25 +3012,29 @@ static void mainloop(void)
                e.events = EPOLLIN;
                i = 0;
 
-               d[i].type = FD_TYPE_CONTROL;
-               e.data.ptr = &d[i++];
-               epoll_ctl(epollfd, EPOLL_CTL_ADD, controlfd, &e);
-
                d[i].type = FD_TYPE_CLI;
                e.data.ptr = &d[i++];
                epoll_ctl(epollfd, EPOLL_CTL_ADD, clifd, &e);
 
-               d[i].type = FD_TYPE_UDP;
+               d[i].type = FD_TYPE_CLUSTER;
                e.data.ptr = &d[i++];
-               epoll_ctl(epollfd, EPOLL_CTL_ADD, udpfd, &e);
+               epoll_ctl(epollfd, EPOLL_CTL_ADD, cluster_sockfd, &e);
 
                d[i].type = FD_TYPE_TUN;
                e.data.ptr = &d[i++];
                epoll_ctl(epollfd, EPOLL_CTL_ADD, tunfd, &e);
 
-               d[i].type = FD_TYPE_CLUSTER;
+               d[i].type = FD_TYPE_UDP;
                e.data.ptr = &d[i++];
-               epoll_ctl(epollfd, EPOLL_CTL_ADD, cluster_sockfd, &e);
+               epoll_ctl(epollfd, EPOLL_CTL_ADD, udpfd, &e);
+
+               d[i].type = FD_TYPE_CONTROL;
+               e.data.ptr = &d[i++];
+               epoll_ctl(epollfd, EPOLL_CTL_ADD, controlfd, &e);
+
+               d[i].type = FD_TYPE_DAE;
+               e.data.ptr = &d[i++];
+               epoll_ctl(epollfd, EPOLL_CTL_ADD, daefd, &e);
        }
 
 #ifdef BGP
@@ -3080,12 +3101,6 @@ static void mainloop(void)
                                struct event_data *d = events[i].data.ptr;
                                switch (d->type)
                                {
-                               case FD_TYPE_CONTROL: // nsctl commands
-                                       alen = sizeof(addr);
-                                       processcontrol(buf, recvfrom(controlfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen);
-                                       n--;
-                                       break;
-
                                case FD_TYPE_CLI: // CLI connections
                                {
                                        int cli;
@@ -3104,9 +3119,21 @@ static void mainloop(void)
                                }
 
                                // these are handled below, with multiple interleaved reads
-                               case FD_TYPE_UDP:       udp_ready++; break;
-                               case FD_TYPE_TUN:       tun_ready++; break;
                                case FD_TYPE_CLUSTER:   cluster_ready++; break;
+                               case FD_TYPE_TUN:       tun_ready++; break;
+                               case FD_TYPE_UDP:       udp_ready++; break;
+
+                               case FD_TYPE_CONTROL: // nsctl commands
+                                       alen = sizeof(addr);
+                                       processcontrol(buf, recvfrom(controlfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen);
+                                       n--;
+                                       break;
+
+                               case FD_TYPE_DAE: // DAE requests
+                                       alen = sizeof(addr);
+                                       processdae(buf, recvfrom(daefd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen);
+                                       n--;
+                                       break;
 
                                case FD_TYPE_RADIUS: // RADIUS response
                                        s = recv(radfds[d->index], buf, sizeof(buf), 0);
@@ -4186,6 +4213,9 @@ static void update_config()
                        strcat(config->radius_authtypes_s, ", pap");
        }
 
+       if (!config->radius_dae_port)
+               config->radius_dae_port = DAEPORT;
+
        // re-initialise the random number source
        initrandom(config->random_device);
 
@@ -5044,6 +5074,31 @@ static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vec
        }
 }
 
+int find_filter(char const *name, size_t len)
+{
+       int free = -1;
+       int i;
+
+       for (i = 0; i < MAXFILTER; i++)
+       {
+               if (!*ip_filters[i].name)
+               {
+                       if (free < 0)
+                               free = i;
+
+                       continue;
+               }
+
+               if (strlen(ip_filters[i].name) != len)
+                       continue;
+
+               if (!strncmp(ip_filters[i].name, name, len))
+                       return i;
+       }
+                       
+       return free;
+}
+
 static int ip_filter_port(ip_filter_portt *p, uint16_t port)
 {
        switch (p->op)
index 6a359fd..a8e2d9a 100644 (file)
--- a/l2tpns.h
+++ b/l2tpns.h
@@ -1,5 +1,5 @@
 // L2TPNS Global Stuff
-// $Id: l2tpns.h,v 1.79 2005-06-24 07:05:04 bodea Exp $
+// $Id: l2tpns.h,v 1.80 2005-06-28 14:48:27 bodea Exp $
 
 #ifndef __L2TPNS_H__
 #define __L2TPNS_H__
@@ -76,6 +76,7 @@
 #define ACCT_SHUT_TIME 600             // 1 minute for counters of shutdown sessions
 #define        L2TPPORT        1701            // L2TP port
 #define RADPORT                1645            // old radius port...
+#define DAEPORT                3799            // DAE port
 #define        PKTARP          0x0806          // ARP packet type
 #define        PKTIP           0x0800          // IPv4 packet type
 #define        PKTIPV6         0x86DD          // IPv6 packet type
@@ -111,7 +112,13 @@ enum {
        AccessReject,
        AccountingRequest,
        AccountingResponse,
-       AccessChallenge = 11
+       AccessChallenge = 11,
+       DisconnectRequest = 40,
+       DisconnectACK,
+       DisconnectNAK,
+       CoARequest,
+       CoAACK,
+       CoANAK
 };
 
 // Types
@@ -457,6 +464,8 @@ typedef struct
        uint16_t        radiusport[MAXRADSERVER];       // radius base ports
        uint8_t         numradiusservers;               // radius server count
 
+       uint16_t        radius_dae_port;                // local port for radius dae
+
        char            radius_authtypes_s[32];         // list of valid authentication types (chap, pap) in order of preference
        int             radius_authtypes;
        int             radius_authprefer;
@@ -611,6 +620,7 @@ void processrad(uint8_t *buf, int len, char socket_index);
 void radiusretry(uint16_t r);
 uint16_t radiusnew(sessionidt s);
 void radiusclear(uint16_t r, sessionidt s);
+void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen);
 
 
 // l2tpns.c
@@ -624,11 +634,13 @@ void increment_counter(uint32_t *counter, uint32_t *wrap, uint32_t delta);
 void random_data(uint8_t *buf, int len);
 void sessionkill(sessionidt s, char *reason);
 void sessionshutdown(sessionidt s, char *reason, int result, int error);
+void filter_session(sessionidt s, int filter_in, int filter_out);
 void send_garp(in_addr_t ip);
 void tunnelsend(uint8_t *buf, uint16_t l, tunnelidt t);
 void sendipcp(tunnelidt t, sessionidt s);
 void processudp(uint8_t *buf, int len, struct sockaddr_in *addr);
 void snoop_send_packet(char *packet, uint16_t size, in_addr_t destination, uint16_t port);
+int find_filter(char const *name, size_t len);
 int ip_filter(uint8_t *buf, int len, uint8_t filter);
 int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc);
 int cmd_show_hist_idle(struct cli_def *cli, char *command, char **argv, int argc);
@@ -696,11 +708,12 @@ extern int epollfd;
 
 struct event_data {
        enum {
-               FD_TYPE_CONTROL,
                FD_TYPE_CLI,
-               FD_TYPE_UDP,
-               FD_TYPE_TUN,
                FD_TYPE_CLUSTER,
+               FD_TYPE_TUN,
+               FD_TYPE_UDP,
+               FD_TYPE_CONTROL,
+               FD_TYPE_DAE,
                FD_TYPE_RADIUS,
                FD_TYPE_BGP,
        } type;
index 0557ab7..6b760a1 100644 (file)
@@ -43,5 +43,5 @@ rm -rf %{buildroot}
 %attr(644,root,root) /usr/share/man/man[58]/*
 
 %changelog
-* Mon Jun 27 2005 Brendan O'Dea <bod@optus.net> 2.1.2-1
+* Wed Jun 29 2005 Brendan O'Dea <bod@c47.org> 2.1.2-1
 - 2.1.2 release, see /usr/share/doc/l2tpns-2.1.2/Changes
index dcae48d..6619ad3 100644 (file)
--- a/plugin.h
+++ b/plugin.h
@@ -1,7 +1,7 @@
 #ifndef __PLUGIN_H__
 #define __PLUGIN_H__
 
-#define PLUGIN_API_VERSION     5
+#define PLUGIN_API_VERSION     6
 #define MAX_PLUGIN_TYPES       30
 
 enum
@@ -15,6 +15,7 @@ enum
        PLUGIN_KILL_SESSION,
        PLUGIN_CONTROL,
        PLUGIN_RADIUS_RESPONSE,
+       PLUGIN_RADIUS_RESET,
        PLUGIN_BECOME_MASTER,
        PLUGIN_NEW_SESSION_MASTER,
 };
@@ -111,4 +112,10 @@ struct param_radius_response
        char *value;
 };
 
+struct param_radius_reset
+{
+       tunnelt *t;
+       sessiont *s;
+};
+
 #endif /* __PLUGIN_H__ */
index f0500b8..c2474e3 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.33 2005-06-04 15:42:36 bodea Exp $";
+char const *cvs_id_radius = "$Id: radius.c,v 1.34 2005-06-28 14:48:28 bodea Exp $";
 
 #include <time.h>
 #include <stdio.h>
@@ -12,11 +12,13 @@ char const *cvs_id_radius = "$Id: radius.c,v 1.33 2005-06-04 15:42:36 bodea Exp
 #include <arpa/inet.h>
 #include <ctype.h>
 #include <netinet/in.h>
+#include <errno.h>
 #include "md5.h"
 #include "constants.h"
 #include "l2tpns.h"
 #include "plugin.h"
 #include "util.h"
+#include "cluster.h"
 
 extern radiust *radius;
 extern sessiont *session;
@@ -51,7 +53,7 @@ static uint16_t get_free_radius()
        int count;
        static uint32_t next_radius_id = 0;
 
-       for (count = MAXRADIUS; count > 0 ; --count)
+       for (count = MAXRADIUS; count > 0; --count)
        {
                ++next_radius_id;               // Find the next ID to check.
                if (next_radius_id >= MAXRADIUS)
@@ -296,7 +298,7 @@ void radiussend(uint16_t r, uint8_t state)
                        {
                                *p = 26;                                // vendor-specific
                                *(uint32_t *) (p + 2) = htonl(9);       // Cisco
-                               p[6] = 1;                               // Cisco-Avpair
+                               p[6] = 1;                               // Cisco-AVPair
                                p[7] = 2 + sprintf(p + 8, "intercept=%s:%d",
                                        fmtaddr(session[s].snoop_ip, 0), session[s].snoop_port);
 
@@ -377,6 +379,47 @@ void radiussend(uint16_t r, uint8_t state)
        sendto(radfds[r & RADIUS_MASK], b, p - b, 0, (void *) &addr, sizeof(addr));
 }
 
+static void handle_avpair(sessionidt s, uint8_t *avp, int len)
+{
+       char *key = avp;
+       char *value = memchr(avp, '=', len);
+       char tmp[2048] = "";
+
+       if (value)
+       {
+               *value++ = 0;
+               len -= value - key;
+       }
+       else
+       {
+               value = tmp;
+               len = 0;
+       }
+
+       // strip quotes
+       if (len > 2 && (*value == '"' || *value == '\'') && value[len - 1] == *value)
+       {
+               value++;
+               len--;
+               value[len - 1] = 0;
+       }
+       // copy and null terminate
+       else if (len < sizeof(tmp) - 1)
+       {
+               memcpy(tmp, value, len);
+               tmp[len] = 0;
+               value = tmp;
+       }
+       else
+               return;
+       
+       // Run hooks
+       {
+               struct param_radius_response p = { &tunnel[session[s].tunnel], &session[s], key, value };
+               run_plugins(PLUGIN_RADIUS_RESPONSE, &p);
+       }
+}
+
 // process RADIUS response
 void processrad(uint8_t *buf, int len, char socket_index)
 {
@@ -577,37 +620,36 @@ void processrad(uint8_t *buf, int len, char socket_index)
                                                char *filter = p + 2;
                                                int l = p[1] - 2;
                                                char *suffix;
-                                               uint8_t *f = 0;
-                                               int i;
+                                               int f;
+                                               uint8_t *fp = 0;
 
                                                LOG(3, s, session[s].tunnel, "   Radius reply contains Filter-Id \"%.*s\"\n", l, filter);
                                                if ((suffix = memchr(filter, '.', l)))
                                                {
                                                        int b = suffix - filter;
                                                        if (l - b == 3 && !memcmp("in", suffix+1, 2))
-                                                               f = &session[s].filter_in;
+                                                               fp = &session[s].filter_in;
                                                        else if (l - b == 4 && !memcmp("out", suffix+1, 3))
-                                                               f = &session[s].filter_out;
+                                                               fp = &session[s].filter_out;
 
                                                        l = b;
                                                }
 
-                                               if (!f)
+                                               if (!fp)
                                                {
                                                        LOG(3, s, session[s].tunnel, "    Invalid filter\n");
                                                        continue;
                                                }
 
-                                               for (*f = 0, i = 0; !*f && i < MAXFILTER; i++)
-                                                       if (strlen(ip_filters[i].name) == l &&
-                                                           !strncmp(ip_filters[i].name, filter, l))
-                                                               *f = i + 1;
-
-                                               if (*f)
-                                                       ip_filters[*f - 1].used++;
-                                               else
+                                               if ((f = find_filter(filter, l)) < 0 || !*ip_filters[f].name)
+                                               {
                                                        LOG(3, s, session[s].tunnel, "    Unknown filter\n");
-
+                                               }
+                                               else
+                                               {
+                                                       *fp = f + 1;
+                                                       ip_filters[f].used++;
+                                               }
                                        }
                                        else if (*p == 26 && p[1] >= 7)
                                        {
@@ -615,7 +657,6 @@ void processrad(uint8_t *buf, int len, char socket_index)
                                                int vendor = ntohl(*(int *)(p + 2));
                                                char attrib = *(p + 6);
                                                int attrib_length = *(p + 7) - 2;
-                                               char *avpair, *value, *key, *newp;
 
                                                LOG(3, s, session[s].tunnel, "   Radius reply contains Vendor-Specific.  Vendor=%d Attrib=%d Length=%d\n", vendor, attrib, attrib_length);
                                                if (vendor != 9 || attrib != 1)
@@ -624,36 +665,13 @@ void processrad(uint8_t *buf, int len, char socket_index)
                                                        continue;
                                                }
 
-                                               if (attrib_length < 0) continue;
-
-                                               avpair = key = calloc(attrib_length + 1, 1);
-                                               memcpy(avpair, p + 8, attrib_length);
-                                               LOG(3, s, session[s].tunnel, "      Cisco-Avpair value: %s\n", avpair);
-                                               do {
-                                                       value = strchr(key, '=');
-                                                       if (!value) break;
-                                                       *value++ = 0;
-
-                                                       // Trim quotes off reply string
-                                                       if (*value == '\'' || *value == '\"')
-                                                       {
-                                                               char *x;
-                                                               value++;
-                                                               x = value + strlen(value) - 1;
-                                                               if (*x == '\'' || *x == '\"')
-                                                                       *x = 0;
-                                                       }
+                                               if (attrib_length > 0)
+                                               {
+                                                       LOG(3, s, session[s].tunnel, "      Cisco-AVPair value: %.*s\n",
+                                                               attrib_length, p + 8);
 
-                                                       // Run hooks
-                                                       newp = strchr(value, ',');
-                                                       if (newp) *newp++ = 0;
-                                                       {
-                                                               struct param_radius_response p = { &tunnel[session[s].tunnel], &session[s], key, value };
-                                                               run_plugins(PLUGIN_RADIUS_RESPONSE, &p);
-                                                       }
-                                                       key = newp;
-                                               } while (newp);
-                                               free(avpair);
+                                                       handle_avpair(s, p + 8, attrib_length);
+                                               }
                                        }
                                        else if (*p == 99)
                                        {
@@ -756,3 +774,319 @@ void radiusretry(uint16_t r)
                        break;
        }
 }
+
+extern int daefd;
+
+void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen)
+{
+       int i, r_code, r_id, length, attribute_length;
+       uint8_t vector[16], hash[16], *packet, attribute;
+       MD5_CTX ctx;
+       char username[MAXUSER] = "";
+       in_addr_t nas = 0;
+       in_addr_t ip = 0;
+       uint32_t port = 0;
+       uint32_t error = 0;
+       sessionidt s = 0;
+       tunnelidt t;
+       int fin = -1;
+       int fout = -1;
+       uint8_t *avpair[64];
+       int avpair_len[sizeof(avpair)/sizeof(*avpair)];
+       int avp = 0;
+       int auth_only = 0;
+       uint8_t *p;
+
+       LOG(3, 0, 0, "DAE request from %s\n", fmtaddr(addr->sin_addr.s_addr, 0));
+
+       // check if DAE is from RADIUS server
+       for (i = 0; i < config->numradiusservers; i++)
+               if (config->radiusserver[i] == addr -> sin_addr.s_addr)
+                       break;
+
+       if (i >= config->numradiusservers)
+       {
+               LOG(1, 0, 0, "Unknown DAE client %s\n", fmtaddr(addr->sin_addr.s_addr, 0));
+               return;
+       }
+
+       LOG_HEX(5, "DAE Request", buf, len);
+
+       if (len < 20 || len < ntohs(*(uint16_t *) (buf + 2)))
+       {
+               LOG(1, 0, 0, "Duff DAE request length %d\n", len);
+               return;
+       }
+
+       r_code = buf[0]; // request type
+       r_id = buf[1]; // radius indentifier.
+
+       if (r_code != DisconnectRequest && r_code != CoARequest)
+       {
+               LOG(1, 0, 0, "Unrecognised DAE request %s\n", radius_code(r_code));
+               return;
+       }
+
+       if (!config->cluster_iam_master)
+       {
+               master_forward_dae_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port);
+               return;
+       }
+
+       len = ntohs(*(uint16_t *) (buf + 2));
+
+       LOG(3, 0, 0, "Received DAE %s, id %d\n", radius_code(r_code), r_id);
+
+       // check authenticator
+       memcpy(vector, buf + 4, 16);
+       memset(buf + 4, 0, 16);
+
+       i = strlen(config->radiussecret);
+       if (i > 16) i = 16;
+
+       MD5Init(&ctx);
+       MD5Update(&ctx, buf, len);
+       MD5Update(&ctx, buf, config->radiussecret, i);
+       MD5Final(hash, &ctx);
+       if (memcmp(hash, vector, 16) != 0)
+       {
+               LOG(1, 0, 0, "Incorrect vector in DAE request (wrong secret in radius config?)\n");
+               return;
+       }
+
+       // unpack attributes
+       packet = buf + 20;
+       length = len - 20;
+
+       while (length > 0)
+       {
+               attribute = *packet++;
+               attribute_length = *packet++;
+               if (attribute_length < 2)
+                       break;
+
+               length -= attribute_length;
+               attribute_length -= 2;
+               switch (attribute)
+               {
+               case 1: /* username */
+                       len = attribute_length < MAXUSER ? attribute_length : MAXUSER - 1;
+                       memcpy(username, packet, len);
+                       username[len] = 0;
+                       LOG(4, 0, 0, "    Received DAE User-Name: %s\n", username);
+                       break;
+
+               case 4: /* nas ip address */
+                       nas = *(uint32_t *) packet; // net order
+                       if (nas != config->bind_address)
+                               error = 403; // NAS identification mismatch
+
+                       LOG(4, 0, 0, "    Received DAE NAS-IP-Address: %s\n", fmtaddr(nas, 0));
+                       break;
+
+               case 5: /* nas port */
+                       port = ntohl(*(uint32_t *) packet);
+                       if (port < 1 || port > MAXSESSION)
+                               error = 404;
+
+                       LOG(4, 0, 0, "    Received DAE NAS-Port: %u\n", port);
+                       break;
+
+               case 6: /* service type */
+                       {
+                               uint32_t service_type = ntohl(*(uint32_t *) packet);
+                               auth_only = service_type == 8; // Authenticate only
+
+                               LOG(4, 0, 0, "    Received DAE Service-Type: %u\n", service_type);
+                       }
+                       break;
+
+               case 8: /* ip address */
+                       ip = *(uint32_t *) packet; // net order
+                       LOG(4, 0, 0, "    Received DAE Framed-IP-Address: %s\n", fmtaddr(ip, 0));
+                       break;
+
+               case 11: /* filter id */
+                       LOG(4, 0, 0, "    Received DAE Filter-Id: %.*s\n", attribute_length, packet);
+                       if (!(p = memchr(packet, '.', attribute_length)))
+                       {
+                               error = 404; // invalid request
+                               break;
+                       }
+
+                       len = p - packet;
+                       i = find_filter(packet, len);
+                       if (i < 0 || !*ip_filters[i].name)
+                       {
+                               error = 404;
+                               break;
+                       }
+
+                       if (!memcmp(p, ".in", attribute_length - len))
+                               fin = i + 1;
+                       else if (!memcmp(p, ".out", attribute_length - len))
+                               fout = i + 1;
+                       else
+                               error = 404;
+
+                       break;
+
+               case 26: /* vendor specific */
+                       if (attribute_length >= 6
+                           && ntohl(*(uint32_t *) packet) == 9 // Cisco
+                           && *(packet + 4) == 1               // Cisco-AVPair
+                           && *(packet + 5) >= 2)              // length
+                       {
+                               int len = *(packet + 5) - 2;
+                               uint8_t *a = packet + 6;
+
+                               LOG(4, 0, 0, "    Received DAE Cisco-AVPair: %.*s\n", len, a);
+                               if (avp < sizeof(avpair)/sizeof(*avpair) - 1)
+                               {
+                                       avpair[avp] = a;
+                                       avpair_len[avp++] = len;
+                               }
+                       }
+                       break;
+               }
+
+               packet += attribute_length;
+       }
+
+       if (!error && auth_only)
+       {
+               if (fin != -1 || fout != -1 || avp)
+                       error = 401; // unsupported attribute
+               else
+                       error = 405; // unsupported service
+       }
+
+       if (!error && !(port || ip || *username))
+               error = 402; // missing attribute
+
+       // exact match for SID if given
+       if (!error && port)
+       {
+               s = port;
+               if (!session[s].opened)
+                       error = 503; // not found
+       }
+
+       if (!error && ip)
+       {
+               // find/check session by IP
+               i = sessionbyip(ip);
+               if (!i || (s && s != i)) // not found or mismatching port
+                       error = 503;
+               else
+                       s = i;
+       }
+
+       if (!error && *username)
+       {
+               if (s)
+               {
+                       if (strcmp(session[s].user, username))
+                               error = 503;
+               }
+               else if (!(s = sessionbyuser(username)))
+                       error = 503;
+       }
+
+       t = session[s].tunnel;
+
+       switch (r_code)
+       {
+       case DisconnectRequest: // Packet of Disconnect/Death
+               if (error)
+               {
+                       r_code = DisconnectNAK;
+                       break;
+               }
+
+               LOG(3, s, t, "    DAE Disconnect %d (%s)\n", s, session[s].user);
+               r_code = DisconnectACK;
+
+               sessionshutdown(s, "Requested by PoD", 3, 0); // disconnect session
+               break;
+
+       case CoARequest: // Change of Authorization
+               if (error)
+               {
+                       r_code = CoANAK;
+                       break;
+               }
+
+               LOG(3, s, t, "    DAE Change %d (%s)\n", s, session[s].user);
+               r_code = CoAACK;
+       
+               // reset
+               {
+                       struct param_radius_reset p = { &tunnel[session[s].tunnel], &session[s] };
+                       run_plugins(PLUGIN_RADIUS_RESET, &p);
+               }
+
+               // apply filters
+               if (fin != -1 || fout != -1)
+               {
+                       if (fin == -1)
+                               fin = 0;
+                       else
+                               LOG(3, s, t, "        Filter in %d (%s)\n", fin, ip_filters[fin - 1].name);
+
+                       if (fout == -1)
+                               fout = 0;
+                       else
+                               LOG(3, s, t, "        Filter out %d (%s)\n", fout, ip_filters[fout - 1].name);
+
+                       filter_session(s, fin, fout);
+               }
+
+               // process cisco av-pair(s)
+               for (i = 0; i < avp; i++)
+               {
+                       LOG(3, s, t, "        Cisco-AVPair: %.*s\n", avpair_len[i], avpair[i]);
+                       handle_avpair(s, avpair[i], avpair_len[i]);
+               }
+
+               cluster_send_session(s);
+               break;
+       }
+
+       // send response
+       packet = buf;
+       *packet++ = r_code;
+       *packet++ = r_id;
+       packet += 2;
+       memset(packet, 0, 16);
+       packet += 16;
+       len = 20;
+
+       // add attributes
+       if (error)
+       {
+               // add error cause
+               *packet++ = 101;
+               *packet++ = 6;
+               *(uint32_t *) packet = htonl(error);
+               len += 6;
+       }
+
+       *((uint16_t *)(buf + 2)) = htons(len);
+
+       // make vector
+       i = strlen(config->radiussecret);
+       if (i > 16) i = 16;
+
+       MD5Init(&ctx);
+       MD5Update(&ctx, buf, len);
+       MD5Update(&ctx, config->radiussecret, i);
+       MD5Final(hash, &ctx);
+       memcpy(buf + 4, hash, 16);
+
+       LOG(3, 0, 0, "Sending DAE %s, id=%d\n", radius_code(r_code), r_id);
+
+       // send DAE response
+       if (sendto(daefd, buf, len, MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *) addr, alen) < 0)
+               LOG(0, 0, 0, "Error sending DAE response packet: %s\n", strerror(errno));
+}
index 7cb0316..0aae1c9 100644 (file)
@@ -5,7 +5,7 @@
 
 /* session control */
 
-char const *cvs_id = "$Id: sessionctl.c,v 1.2 2005-05-10 06:48:16 bodea Exp $";
+char const *cvs_id = "$Id: sessionctl.c,v 1.3 2005-06-28 14:48:28 bodea Exp $";
 
 int plugin_api_version = PLUGIN_API_VERSION;
 static struct pluginfuncs *p = 0;
@@ -16,15 +16,6 @@ char *plugin_control_help[] = {
     0
 };
 
-int plugin_init(struct pluginfuncs *funcs)
-{
-    if (!funcs)
-       return 0;
-
-    p = funcs;
-    return 1;
-}
-
 int plugin_control(struct param_control *data)
 {
     sessionidt session;
@@ -76,3 +67,8 @@ int plugin_control(struct param_control *data)
 
     return PLUGIN_RET_STOP;
 }
+
+int plugin_init(struct pluginfuncs *funcs)
+{
+       return ((p = funcs)) ? 1 : 0;
+}
index bc5fa28..f6e8535 100644 (file)
@@ -5,7 +5,7 @@
 
 /* snoop control */
 
-char const *cvs_id = "$Id: snoopctl.c,v 1.4 2004-12-16 08:49:53 bodea Exp $";
+char const *cvs_id = "$Id: snoopctl.c,v 1.5 2005-06-28 14:48:28 bodea Exp $";
 
 int plugin_api_version = PLUGIN_API_VERSION;
 static struct pluginfuncs *p = 0;
@@ -16,15 +16,6 @@ char *plugin_control_help[] = {
        0
 };
 
-int plugin_init(struct pluginfuncs *funcs)
-{
-       if (!funcs)
-               return 0;
-
-       p = funcs;
-       return 1;
-}
-
 int plugin_control(struct param_control *data)
 {
        sessionidt session;
@@ -124,3 +115,15 @@ int plugin_control(struct param_control *data)
 
        return PLUGIN_RET_STOP;
 }
+
+int plugin_radius_reset(struct param_radius_reset *data)
+{
+       data->s->snoop_ip = 0;
+       data->s->snoop_port = 0;
+       return PLUGIN_RET_OK;
+}
+
+int plugin_init(struct pluginfuncs *funcs)
+{
+       return ((p = funcs)) ? 1 : 0;
+}
index 3aeb963..7aca35e 100644 (file)
@@ -5,7 +5,7 @@
 
 /* throttle control */
 
-char const *cvs_id = "$Id: throttlectl.c,v 1.6 2004-12-01 04:44:29 bodea Exp $";
+char const *cvs_id = "$Id: throttlectl.c,v 1.7 2005-06-28 14:48:28 bodea Exp $";
 
 int plugin_api_version = PLUGIN_API_VERSION;
 static struct pluginfuncs *p = 0;
@@ -16,15 +16,6 @@ char *plugin_control_help[] = {
        0
 };
 
-int plugin_init(struct pluginfuncs *funcs)
-{
-       if (!funcs)
-               return 0;
-
-       p = funcs;
-       return 1;
-}
-
 int plugin_control(struct param_control *data)
 {
        sessionidt session;
@@ -137,3 +128,14 @@ int plugin_control(struct param_control *data)
 
        return PLUGIN_RET_STOP;
 }
+
+int plugin_radius_reset(struct param_radius_reset *data)
+{
+       p->throttle(p->get_id_by_session(data->s), 0, 0);
+       return PLUGIN_RET_OK;
+}
+
+int plugin_init(struct pluginfuncs *funcs)
+{
+       return ((p = funcs)) ? 1 : 0;
+}
diff --git a/util.c b/util.c
index 0ba92ec..e2941c8 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1,6 +1,6 @@
 /* Misc util functions */
 
-char const *cvs_id_util = "$Id: util.c,v 1.11 2005-06-04 15:42:36 bodea Exp $";
+char const *cvs_id_util = "$Id: util.c,v 1.12 2005-06-28 14:48:28 bodea Exp $";
 
 #include <unistd.h>
 #include <errno.h>
@@ -40,7 +40,7 @@ void *shared_malloc(unsigned int size)
 }
 
 extern int forked;
-extern int udpfd, controlfd, tunfd, snoopfd, ifrfd, ifr6fd, rand_fd, cluster_sockfd;
+extern int cluster_sockfd, tunfd, udpfd, controlfd, daefd, snoopfd, ifrfd, ifr6fd, rand_fd;
 extern int *radfds;
 
 pid_t fork_and_close()
@@ -73,15 +73,16 @@ pid_t fork_and_close()
        signal(SIGTERM, SIG_DFL);
 
        // Close sockets
+       if (clifd != -1)          close(clifd);
+       if (cluster_sockfd != -1) close(cluster_sockfd);
        if (tunfd != -1)          close(tunfd);
        if (udpfd != -1)          close(udpfd);
        if (controlfd != -1)      close(controlfd);
+       if (daefd != -1)          close(daefd);
        if (snoopfd != -1)        close(snoopfd);
        if (ifrfd != -1)          close(ifrfd);
        if (ifr6fd != -1)         close(ifr6fd);
        if (rand_fd != -1)        close(rand_fd);
-       if (cluster_sockfd != -1) close(cluster_sockfd);
-       if (clifd != -1)          close(clifd);
        if (epollfd != -1)        close(epollfd);
 
        for (i = 0; radfds && i < RADIUS_FDS; i++)