Update changelog
[l2tpns.git] / l2tpns.c
index 4545d6c..5445013 100644 (file)
--- a/l2tpns.c
+++ b/l2tpns.c
@@ -10,6 +10,7 @@
 #include <fcntl.h>
 #include <linux/if_tun.h>
 #define SYSLOG_NAMES
 #include <fcntl.h>
 #include <linux/if_tun.h>
 #define SYSLOG_NAMES
+#include <stdio.h>
 #include <syslog.h>
 #include <malloc.h>
 #include <net/route.h>
 #include <syslog.h>
 #include <malloc.h>
 #include <net/route.h>
@@ -19,7 +20,6 @@
 #include <netinet/ip6.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <netinet/ip6.h>
 #include <stdarg.h>
 #include <stdlib.h>
-#include <stdio.h>
 #include <string.h>
 #include <ctype.h>
 #include <sys/ioctl.h>
 #include <string.h>
 #include <ctype.h>
 #include <sys/ioctl.h>
@@ -40,6 +40,7 @@
 #include <linux/rtnetlink.h>
 
 #include "md5.h"
 #include <linux/rtnetlink.h>
 
 #include "md5.h"
+#include "dhcp6.h"
 #include "l2tpns.h"
 #include "cluster.h"
 #include "plugin.h"
 #include "l2tpns.h"
 #include "cluster.h"
 #include "plugin.h"
@@ -55,6 +56,7 @@
 
 #include "l2tplac.h"
 #include "pppoe.h"
 
 #include "l2tplac.h"
 #include "pppoe.h"
+#include "dhcp6.h"
 
 char * Vendor_name = "Linux L2TPNS";
 uint32_t call_serial_number = 0;
 
 char * Vendor_name = "Linux L2TPNS";
 uint32_t call_serial_number = 0;
@@ -75,7 +77,7 @@ int cluster_sockfd = -1;      // Intra-cluster communications socket.
 int epollfd = -1;              // event polling
 time_t basetime = 0;           // base clock
 char hostname[MAXHOSTNAME] = "";       // us.
 int epollfd = -1;              // event polling
 time_t basetime = 0;           // base clock
 char hostname[MAXHOSTNAME] = "";       // us.
-static int tunidx;             // ifr_ifindex of tun device
+int tunidx;                            // ifr_ifindex of tun device
 int nlseqnum = 0;              // netlink sequence number
 int min_initok_nlseqnum = 0;   // minimun seq number for messages after init is ok
 static int syslog_log = 0;     // are we logging to syslog
 int nlseqnum = 0;              // netlink sequence number
 int min_initok_nlseqnum = 0;   // minimun seq number for messages after init is ok
 static int syslog_log = 0;     // are we logging to syslog
@@ -92,15 +94,16 @@ uint16_t MSS = 0;           // TCP MSS
 struct cli_session_actions *cli_session_actions = NULL;        // Pending session changes requested by CLI
 struct cli_tunnel_actions *cli_tunnel_actions = NULL;  // Pending tunnel changes required by CLI
 
 struct cli_session_actions *cli_session_actions = NULL;        // Pending session changes requested by CLI
 struct cli_tunnel_actions *cli_tunnel_actions = NULL;  // Pending tunnel changes required by CLI
 
-union iphash {
+union iphash
+{
        sessionidt sess;
        union iphash *idx;
        sessionidt sess;
        union iphash *idx;
-} ip_hash[256];                        // Mapping from IP address to session structures.
+}ip_hash[256]; // Mapping from IP address to session structures.
 
 struct ipv6radix {
        sessionidt sess;
        struct ipv6radix *branch;
 
 struct ipv6radix {
        sessionidt sess;
        struct ipv6radix *branch;
-} ipv6_hash[256];              // Mapping from IPv6 address to session structures.
+} ipv6_hash[16];               // Mapping from IPv6 address to session structures.
 
 // Traffic counters.
 static uint32_t udp_rx = 0, udp_rx_pkt = 0, udp_tx = 0;
 
 // Traffic counters.
 static uint32_t udp_rx = 0, udp_rx_pkt = 0, udp_tx = 0;
@@ -152,6 +155,7 @@ config_descriptt config_values[] = {
        CONFIG("throttle_speed", rl_rate, UNSIGNED_LONG),
        CONFIG("throttle_buckets", num_tbfs, INT),
        CONFIG("accounting_dir", accounting_dir, STRING),
        CONFIG("throttle_speed", rl_rate, UNSIGNED_LONG),
        CONFIG("throttle_buckets", num_tbfs, INT),
        CONFIG("accounting_dir", accounting_dir, STRING),
+       CONFIG("account_all_origin", account_all_origin, BOOL),
        CONFIG("dump_speed", dump_speed, BOOL),
        CONFIG("multi_read_count", multi_read_count, INT),
        CONFIG("scheduler_fifo", scheduler_fifo, BOOL),
        CONFIG("dump_speed", dump_speed, BOOL),
        CONFIG("multi_read_count", multi_read_count, INT),
        CONFIG("scheduler_fifo", scheduler_fifo, BOOL),
@@ -185,6 +189,16 @@ config_descriptt config_values[] = {
        CONFIG("disable_sending_hello", disable_sending_hello, BOOL),
        CONFIG("disable_no_spoof", disable_no_spoof, BOOL),
        CONFIG("bind_multi_address", bind_multi_address, STRING),
        CONFIG("disable_sending_hello", disable_sending_hello, BOOL),
        CONFIG("disable_no_spoof", disable_no_spoof, BOOL),
        CONFIG("bind_multi_address", bind_multi_address, STRING),
+       CONFIG("grp_txrate_average_time", grp_txrate_average_time, INT),
+       CONFIG("pppoe_only_equal_svc_name", pppoe_only_equal_svc_name, BOOL),
+       CONFIG("multi_hostname", multi_hostname, STRING),
+       CONFIG("no_throttle_local_IP", no_throttle_local_IP, BOOL),
+       CONFIG("dhcp6_preferred_lifetime", dhcp6_preferred_lifetime, INT),
+       CONFIG("dhcp6_valid_lifetime", dhcp6_valid_lifetime, INT),
+       CONFIG("dhcp6_server_duid", dhcp6_server_duid, INT),
+       CONFIG("primary_ipv6_dns", default_ipv6_dns1, IPv6),
+       CONFIG("secondary_ipv6_dns", default_ipv6_dns2, IPv6),
+       CONFIG("default_ipv6_domain_list", default_ipv6_domain_list, STRING),
        { NULL, 0, 0, 0 }
 };
 
        { NULL, 0, 0, 0 }
 };
 
@@ -213,6 +227,7 @@ tunnelt *tunnel = NULL;                     // Array of tunnel structures.
 bundlet *bundle = NULL;                        // Array of bundle structures.
 fragmentationt *frag = NULL;           // Array of fragmentation structures.
 sessiont *session = NULL;              // Array of session structures.
 bundlet *bundle = NULL;                        // Array of bundle structures.
 fragmentationt *frag = NULL;           // Array of fragmentation structures.
 sessiont *session = NULL;              // Array of session structures.
+groupsesst *grpsession = NULL;         // Array of groupsesst 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.
 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.
@@ -223,9 +238,6 @@ struct Tstats *_statistics = NULL;
 struct Tringbuffer *ringbuffer = NULL;
 #endif
 
 struct Tringbuffer *ringbuffer = NULL;
 #endif
 
-static ssize_t netlink_send(struct nlmsghdr *nh);
-static void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen);
-static void cache_ipmap(in_addr_t ip, sessionidt s);
 static void uncache_ipmap(in_addr_t ip);
 static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s);
 static void free_ip_address(sessionidt s);
 static void uncache_ipmap(in_addr_t ip);
 static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s);
 static void free_ip_address(sessionidt s);
@@ -254,8 +266,9 @@ static clockt now(double *f)
        if (f) *f = t.tv_sec + t.tv_usec / 1000000.0;
        if (t.tv_sec != time_now)
        {
        if (f) *f = t.tv_sec + t.tv_usec / 1000000.0;
        if (t.tv_sec != time_now)
        {
-           time_now = t.tv_sec;
-           time_changed++;
+               time_now = t.tv_sec;
+               time_changed++;
+               grp_time_changed();
        }
 
        // Time in milliseconds
        }
 
        // Time in milliseconds
@@ -614,7 +627,7 @@ static void initnetlink(void)
        }
 }
 
        }
 }
 
-static ssize_t netlink_send(struct nlmsghdr *nh)
+ssize_t netlink_send(struct nlmsghdr *nh)
 {
        struct sockaddr_nl nladdr;
        struct iovec iov;
 {
        struct sockaddr_nl nladdr;
        struct iovec iov;
@@ -650,7 +663,7 @@ static ssize_t netlink_recv(void *buf, ssize_t len)
 }
 
 /* adapted from iproute2 */
 }
 
 /* adapted from iproute2 */
-static void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen)
+void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen)
 {
        int len = RTA_LENGTH(alen);
        struct rtattr *rta;
 {
        int len = RTA_LENGTH(alen);
        struct rtattr *rta;
@@ -970,20 +983,24 @@ static sessionidt lookup_ipv6map(struct in6_addr ip)
        int s;
        char ipv6addr[INET6_ADDRSTRLEN];
 
        int s;
        char ipv6addr[INET6_ADDRSTRLEN];
 
-       curnode = &ipv6_hash[ip.s6_addr[0]];
+       curnode = &ipv6_hash[((ip.s6_addr[0]) & 0xF0)>>4];
        i = 1;
        s = curnode->sess;
 
        i = 1;
        s = curnode->sess;
 
-       while (s == 0 && i < 15 && curnode->branch != NULL)
+       while (s == 0 && i < 32 && curnode->branch != NULL)
        {
        {
-               curnode = &curnode->branch[ip.s6_addr[i]];
+               if (i & 1)
+                       curnode = &curnode->branch[ip.s6_addr[i>>1] & 0x0F];
+               else
+                       curnode = &curnode->branch[(ip.s6_addr[i>>1] & 0xF0)>>4];
+
                s = curnode->sess;
                i++;
        }
 
        LOG(4, s, session[s].tunnel, "Looking up address %s and got %d\n",
                s = curnode->sess;
                i++;
        }
 
        LOG(4, s, session[s].tunnel, "Looking up address %s and got %d\n",
-                       inet_ntop(AF_INET6, &ip, ipv6addr,
-                               INET6_ADDRSTRLEN),
+                       inet_ntop(AF_INET6, &ip, ipv6addr,
+                       INET6_ADDRSTRLEN),
                        s);
 
        return s;
                        s);
 
        return s;
@@ -1010,8 +1027,10 @@ sessionidt sessionbyipv6(struct in6_addr ip)
                 ip.s6_addr[1] == 0x80 &&
                 ip.s6_addr16[1] == 0 &&
                 ip.s6_addr16[2] == 0 &&
                 ip.s6_addr[1] == 0x80 &&
                 ip.s6_addr16[1] == 0 &&
                 ip.s6_addr16[2] == 0 &&
-                ip.s6_addr16[3] == 0)) {
-               s = lookup_ipmap(*(in_addr_t *) &ip.s6_addr[8]);
+                ip.s6_addr16[3] == 0))
+       {
+               in_addr_t *pipv4 = (in_addr_t *) &ip.s6_addr[8];
+               s = lookup_ipmap(*pipv4);
        } else {
                s = lookup_ipv6map(ip);
        }
        } else {
                s = lookup_ipv6map(ip);
        }
@@ -1022,13 +1041,26 @@ sessionidt sessionbyipv6(struct in6_addr ip)
        return 0;
 }
 
        return 0;
 }
 
+sessionidt sessionbyipv6new(struct in6_addr ip)
+{
+       sessionidt s;
+       CSTAT(sessionbyipv6new);
+
+       s = lookup_ipv6map(ip);
+
+       if (s > 0 && s < MAXSESSION && session[s].opened)
+               return s;
+
+       return 0;
+}
+
 //
 // Take an IP address in HOST byte order and
 // add it to the sessionid by IP cache.
 //
 // (It's actually cached in network order)
 //
 //
 // Take an IP address in HOST byte order and
 // add it to the sessionid by IP cache.
 //
 // (It's actually cached in network order)
 //
-static void cache_ipmap(in_addr_t ip, sessionidt s)
+void cache_ipmap(in_addr_t ip, sessionidt s)
 {
        in_addr_t nip = htonl(ip);      // MUST be in network order. I.e. MSB must in be ((char *) (&ip))[0]
        uint8_t *a = (uint8_t *) &nip;
 {
        in_addr_t nip = htonl(ip);      // MUST be in network order. I.e. MSB must in be ((char *) (&ip))[0]
        uint8_t *a = (uint8_t *) &nip;
@@ -1047,7 +1079,6 @@ static void cache_ipmap(in_addr_t ip, sessionidt s)
 
        if (s > 0)
                LOG(4, s, session[s].tunnel, "Caching ip address %s\n", fmtaddr(nip, 0));
 
        if (s > 0)
                LOG(4, s, session[s].tunnel, "Caching ip address %s\n", fmtaddr(nip, 0));
-
        else if (s == 0)
                LOG(4, 0, 0, "Un-caching ip address %s\n", fmtaddr(nip, 0));
        // else a map to an ip pool index.
        else if (s == 0)
                LOG(4, 0, 0, "Un-caching ip address %s\n", fmtaddr(nip, 0));
        // else a map to an ip pool index.
@@ -1061,22 +1092,28 @@ static void uncache_ipmap(in_addr_t ip)
 static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s)
 {
        int i;
 static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s)
 {
        int i;
-       int bytes;
+       int niblles;
        struct ipv6radix *curnode;
        char ipv6addr[INET6_ADDRSTRLEN];
 
        struct ipv6radix *curnode;
        char ipv6addr[INET6_ADDRSTRLEN];
 
-       curnode = &ipv6_hash[ip.s6_addr[0]];
+       curnode = &ipv6_hash[((ip.s6_addr[0]) & 0xF0)>>4];
 
 
-       bytes = prefixlen >> 3;
+       niblles = prefixlen >> 2;
        i = 1;
        i = 1;
-       while (i < bytes) {
+
+       while (i < niblles)
+       {
                if (curnode->branch == NULL)
                {
                if (curnode->branch == NULL)
                {
-                       if (!(curnode->branch = calloc(256,
-                                       sizeof (struct ipv6radix))))
+                       if (!(curnode->branch = calloc(16, sizeof (struct ipv6radix))))
                                return;
                }
                                return;
                }
-               curnode = &curnode->branch[ip.s6_addr[i]];
+
+               if (i & 1)
+                       curnode = &curnode->branch[ip.s6_addr[i>>1] & 0x0F];
+               else
+                       curnode = &curnode->branch[(ip.s6_addr[i>>1] & 0xF0)>>4];
+
                i++;
        }
 
                i++;
        }
 
@@ -1084,20 +1121,20 @@ static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s)
 
        if (s > 0)
                LOG(4, s, session[s].tunnel, "Caching ip address %s/%d\n",
 
        if (s > 0)
                LOG(4, s, session[s].tunnel, "Caching ip address %s/%d\n",
-                               inet_ntop(AF_INET6, &ip, ipv6addr, 
-                                       INET6_ADDRSTRLEN),
+                               inet_ntop(AF_INET6, &ip, ipv6addr,
+                               INET6_ADDRSTRLEN),
                                prefixlen);
        else if (s == 0)
                LOG(4, 0, 0, "Un-caching ip address %s/%d\n",
                                prefixlen);
        else if (s == 0)
                LOG(4, 0, 0, "Un-caching ip address %s/%d\n",
-                               inet_ntop(AF_INET6, &ip, ipv6addr, 
-                                       INET6_ADDRSTRLEN),
+                               inet_ntop(AF_INET6, &ip, ipv6addr,
+                               INET6_ADDRSTRLEN),
                                prefixlen);
 }
 
 //
 // CLI list to dump current ipcache.
 //
                                prefixlen);
 }
 
 //
 // CLI list to dump current ipcache.
 //
-int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc)
+int cmd_show_ipcache(struct cli_def *cli, const char *command, char **argv, int argc)
 {
        union iphash *d = ip_hash, *e, *f, *g;
        int i, j, k, l;
 {
        union iphash *d = ip_hash, *e, *f, *g;
        int i, j, k, l;
@@ -1141,7 +1178,6 @@ int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc)
        return CLI_OK;
 }
 
        return CLI_OK;
 }
 
-
 // Find session by username, 0 for not found
 // walled garden users aren't authenticated, so the username is
 // reasonably useless. Ignore them to avoid incorrect actions
 // Find session by username, 0 for not found
 // walled garden users aren't authenticated, so the username is
 // reasonably useless. Ignore them to avoid incorrect actions
@@ -1410,9 +1446,10 @@ static void update_session_out_stat(sessionidt s, sessiont *sp, int len)
 void processipout(uint8_t *buf, int len)
 {
        sessionidt s;
 void processipout(uint8_t *buf, int len)
 {
        sessionidt s;
+       groupidt g;
        sessiont *sp;
        tunnelidt t;
        sessiont *sp;
        tunnelidt t;
-       in_addr_t ip;
+       in_addr_t ip, ip_src;
 
        uint8_t *data = buf;    // Keep a copy of the originals.
        int size = len;
 
        uint8_t *data = buf;    // Keep a copy of the originals.
        int size = len;
@@ -1445,8 +1482,33 @@ void processipout(uint8_t *buf, int len)
                return;
        }
 
                return;
        }
 
+       ip_src = *(uint32_t *)(buf + 12);
        ip = *(uint32_t *)(buf + 16);
        ip = *(uint32_t *)(buf + 16);
-       if (!(s = sessionbyip(ip)))
+       if ((g = grp_groupbyip(ip)))
+       {
+               s = grp_getnextsession(g, &ip, &ip_src, 0);
+               if (!s)
+               {
+                       // Is this a packet for a session that doesn't exist?
+                       static int rate = 0;    // Number of ICMP packets we've sent this second.
+                       static int last = 0;    // Last time we reset the ICMP packet counter 'rate'.
+
+                       if (last != time_now)
+                       {
+                               last = time_now;
+                               rate = 0;
+                       }
+
+                       if (rate++ < config->icmp_rate) // Only send a max of icmp_rate per second.
+                       {
+                               LOG(4, 0, 0, "IP: Sending ICMP host unreachable to %s\n", fmtaddr(*(in_addr_t *)(buf + 12), 0));
+                               host_unreachable(*(in_addr_t *)(buf + 12), *(uint16_t *)(buf + 4),
+                                       config->bind_address ? config->bind_address : my_address, buf, len);
+                       }
+                       return;
+               }
+       }
+       else if (!(s = sessionbyip(ip)))
        {
                // Is this a packet for a session that doesn't exist?
                static int rate = 0;    // Number of ICMP packets we've sent this second.
        {
                // Is this a packet for a session that doesn't exist?
                static int rate = 0;    // Number of ICMP packets we've sent this second.
@@ -1529,12 +1591,15 @@ void processipout(uint8_t *buf, int len)
 
        if (sp->tbf_out)
        {
 
        if (sp->tbf_out)
        {
-               // Are we throttling this session?
-               if (config->cluster_iam_master)
-                       tbf_queue_packet(sp->tbf_out, data, size);
-               else
-                       master_throttle_packet(sp->tbf_out, data, size);
-               return;
+               if (!config->no_throttle_local_IP || !sessionbyip(ip_src))
+               {
+                       // Are we throttling this session?
+                       if (config->cluster_iam_master)
+                               tbf_queue_packet(sp->tbf_out, data, size);
+                       else
+                               master_throttle_packet(sp->tbf_out, data, size);
+                       return;
+               }
        }
 
        if (sp->walled_garden && !config->cluster_iam_master)
        }
 
        if (sp->walled_garden && !config->cluster_iam_master)
@@ -1672,10 +1737,11 @@ void processipout(uint8_t *buf, int len)
 static void processipv6out(uint8_t * buf, int len)
 {
        sessionidt s;
 static void processipv6out(uint8_t * buf, int len)
 {
        sessionidt s;
+       groupidt g;
        sessiont *sp;
        tunnelidt t;
        sessiont *sp;
        tunnelidt t;
-       in_addr_t ip;
-       struct in6_addr ip6;
+       struct in6_addr *p_ip6;
+       struct in6_addr *p_ip6_src;
 
        uint8_t *data = buf;    // Keep a copy of the originals.
        int size = len;
 
        uint8_t *data = buf;    // Keep a copy of the originals.
        int size = len;
@@ -1708,15 +1774,18 @@ static void processipv6out(uint8_t * buf, int len)
                return;
        }
 
                return;
        }
 
-       ip6 = *(struct in6_addr *)(buf+24);
-       s = sessionbyipv6(ip6);
+       p_ip6_src = (struct in6_addr *)(buf+8);
+       p_ip6 = (struct in6_addr *)(buf+24);
 
 
-       if (s == 0)
+       if ((g = grp_groupbyipv6(*p_ip6)))
        {
        {
-               ip = *(uint32_t *)(buf + 32);
-               s = sessionbyip(ip);
+               s = grp_getnextsession(g, p_ip6, p_ip6_src, 1);
        }
        }
-       
+       else if (!(s = sessionbyipv6(*p_ip6)))
+       {
+               s = sessionbyipv6new(*p_ip6);
+       }
+
        if (s == 0)
        {
                // Is this a packet for a session that doesn't exist?
        if (s == 0)
        {
                // Is this a packet for a session that doesn't exist?
@@ -1796,6 +1865,8 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len)
 {
        sessiont *sp;
        tunnelidt t;
 {
        sessiont *sp;
        tunnelidt t;
+       uint8_t *p;
+       uint8_t *data = buf;    // Keep a copy of the originals.
 
        uint8_t b[MAXETHER + 20];
 
 
        uint8_t b[MAXETHER + 20];
 
@@ -1818,11 +1889,14 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len)
        LOG(5, s, t, "Ethernet -> Tunnel (%d bytes)\n", len);
 
        // Add on L2TP header
        LOG(5, s, t, "Ethernet -> Tunnel (%d bytes)\n", len);
 
        // Add on L2TP header
-       {
-               uint8_t *p = makeppp(b, sizeof(b), buf, len, s, t, PPPIP, 0, 0, 0);
-               if (!p) return;
-               tunnelsend(b, len + (p-b), t); // send it...
-       }
+       if (*(uint16_t *) (data + 2) == htons(PKTIPV6))
+               p = makeppp(b, sizeof(b), buf, len, s, t, PPPIPV6, 0, 0, 0); // IPV6
+       else
+               p = makeppp(b, sizeof(b), buf, len, s, t, PPPIP, 0, 0, 0); // IPV4
+
+       if (!p) return;
+
+       tunnelsend(b, len + (p-b), t); // send it...
 
        // Snooping this session.
        if (sp->snoop_ip && sp->snoop_port)
 
        // Snooping this session.
        if (sp->snoop_ip && sp->snoop_port)
@@ -1841,10 +1915,11 @@ static void send_ipout(sessionidt s, uint8_t *buf, int len)
 static void control16(controlt * c, uint16_t avp, uint16_t val, uint8_t m)
 {
        uint16_t l = (m ? 0x8008 : 0x0008);
 static void control16(controlt * c, uint16_t avp, uint16_t val, uint8_t m)
 {
        uint16_t l = (m ? 0x8008 : 0x0008);
-       *(uint16_t *) (c->buf + c->length + 0) = htons(l);
-       *(uint16_t *) (c->buf + c->length + 2) = htons(0);
-       *(uint16_t *) (c->buf + c->length + 4) = htons(avp);
-       *(uint16_t *) (c->buf + c->length + 6) = htons(val);
+       uint16_t *pint16 = (uint16_t *) (c->buf + c->length + 0);
+       pint16[0] = htons(l);
+       pint16[1] = htons(0);
+       pint16[2] = htons(avp);
+       pint16[3] = htons(val);
        c->length += 8;
 }
 
        c->length += 8;
 }
 
@@ -1852,10 +1927,12 @@ static void control16(controlt * c, uint16_t avp, uint16_t val, uint8_t m)
 static void control32(controlt * c, uint16_t avp, uint32_t val, uint8_t m)
 {
        uint16_t l = (m ? 0x800A : 0x000A);
 static void control32(controlt * c, uint16_t avp, uint32_t val, uint8_t m)
 {
        uint16_t l = (m ? 0x800A : 0x000A);
-       *(uint16_t *) (c->buf + c->length + 0) = htons(l);
-       *(uint16_t *) (c->buf + c->length + 2) = htons(0);
-       *(uint16_t *) (c->buf + c->length + 4) = htons(avp);
-       *(uint32_t *) (c->buf + c->length + 6) = htonl(val);
+       uint16_t *pint16 = (uint16_t *) (c->buf + c->length + 0);
+       uint32_t *pint32 = (uint32_t *) (c->buf + c->length + 6);
+       pint16[0] = htons(l);
+       pint16[1] = htons(0);
+       pint16[2] = htons(avp);
+       pint32[0] = htonl(val);
        c->length += 10;
 }
 
        c->length += 10;
 }
 
@@ -1863,9 +1940,10 @@ static void control32(controlt * c, uint16_t avp, uint32_t val, uint8_t m)
 static void controls(controlt * c, uint16_t avp, char *val, uint8_t m)
 {
        uint16_t l = ((m ? 0x8000 : 0) + strlen(val) + 6);
 static void controls(controlt * c, uint16_t avp, char *val, uint8_t m)
 {
        uint16_t l = ((m ? 0x8000 : 0) + strlen(val) + 6);
-       *(uint16_t *) (c->buf + c->length + 0) = htons(l);
-       *(uint16_t *) (c->buf + c->length + 2) = htons(0);
-       *(uint16_t *) (c->buf + c->length + 4) = htons(avp);
+       uint16_t *pint16 = (uint16_t *) (c->buf + c->length + 0);
+       pint16[0] = htons(l);
+       pint16[1] = htons(0);
+       pint16[2] = htons(avp);
        memcpy(c->buf + c->length + 6, val, strlen(val));
        c->length += 6 + strlen(val);
 }
        memcpy(c->buf + c->length + 6, val, strlen(val));
        c->length += 6 + strlen(val);
 }
@@ -1874,9 +1952,10 @@ static void controls(controlt * c, uint16_t avp, char *val, uint8_t m)
 static void controlb(controlt * c, uint16_t avp, uint8_t *val, unsigned int len, uint8_t m)
 {
        uint16_t l = ((m ? 0x8000 : 0) + len + 6);
 static void controlb(controlt * c, uint16_t avp, uint8_t *val, unsigned int len, uint8_t m)
 {
        uint16_t l = ((m ? 0x8000 : 0) + len + 6);
-       *(uint16_t *) (c->buf + c->length + 0) = htons(l);
-       *(uint16_t *) (c->buf + c->length + 2) = htons(0);
-       *(uint16_t *) (c->buf + c->length + 4) = htons(avp);
+       uint16_t *pint16 = (uint16_t *) (c->buf + c->length + 0);
+       pint16[0] = htons(l);
+       pint16[1] = htons(0);
+       pint16[2] = htons(avp);
        memcpy(c->buf + c->length + 6, val, len);
        c->length += 6 + len;
 }
        memcpy(c->buf + c->length + 6, val, len);
        c->length += 6 + len;
 }
@@ -1921,10 +2000,11 @@ static void controlnull(tunnelidt t)
 // add a control message to a tunnel, and send if within window
 static void controladd(controlt *c, sessionidt far, tunnelidt t)
 {
 // add a control message to a tunnel, and send if within window
 static void controladd(controlt *c, sessionidt far, tunnelidt t)
 {
-       *(uint16_t *) (c->buf + 2) = htons(c->length); // length
-       *(uint16_t *) (c->buf + 4) = htons(tunnel[t].far); // tunnel
-       *(uint16_t *) (c->buf + 6) = htons(far); // session
-       *(uint16_t *) (c->buf + 8) = htons(tunnel[t].ns); // sequence
+       uint16_t *pint16 = (uint16_t *) (c->buf + 2);
+       pint16[0] = htons(c->length); // length
+       pint16[1] = htons(tunnel[t].far); // tunnel
+       pint16[2] = htons(far); // session
+       pint16[3] = htons(tunnel[t].ns); // sequence
        tunnel[t].ns++;              // advance sequence
        // link in message in to queue
        if (tunnel[t].controlc)
        tunnel[t].ns++;              // advance sequence
        // link in message in to queue
        if (tunnel[t].controlc)
@@ -2077,7 +2157,7 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e
                session[s].die = TIME + 150; // Clean up in 15 seconds
 
        if (session[s].ip)
                session[s].die = TIME + 150; // Clean up in 15 seconds
 
        if (session[s].ip)
-       {                          // IP allocated, clear and unroute
+       {       // IP allocated, clear and unroute
                int r;
                int routed = 0;
                for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
                int r;
                int routed = 0;
                for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
@@ -2099,9 +2179,17 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e
                        free_ip_address(s);
 
                // unroute IPv6, if setup
                        free_ip_address(s);
 
                // unroute IPv6, if setup
-               if (session[s].ppp.ipv6cp == Opened && session[s].ipv6prefixlen && del_routes)
-                       route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0);
-               
+               for (r = 0; r < MAXROUTE6 && session[s].route6[r].ipv6route.s6_addr[0] && session[s].route6[r].ipv6prefixlen; r++)
+               {
+                       if (del_routes) route6set(s, session[s].route6[r].ipv6route, session[s].route6[r].ipv6prefixlen, 0);
+                       memset(&session[s].route6[r], 0, sizeof(session[s].route6[r]));
+               }
+
+               if (session[s].ipv6address.s6_addr[0] && del_routes)
+               {
+                       route6set(s, session[s].ipv6address, 128, 0);
+               }
+
                if (b)
                {
                        // This session was part of a bundle
                if (b)
                {
                        // This session was part of a bundle
@@ -2155,8 +2243,15 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e
                                                cache_ipmap(session[new_s].ip, new_s);
 
                                                // IPV6 route
                                                cache_ipmap(session[new_s].ip, new_s);
 
                                                // IPV6 route
-                                               if (session[new_s].ipv6prefixlen)
-                                                       cache_ipv6map(session[new_s].ipv6route, session[new_s].ipv6prefixlen, new_s);
+                                               for (r = 0; r < MAXROUTE6 && session[new_s].route6[r].ipv6prefixlen; r++)
+                                               {
+                                                       cache_ipv6map(session[new_s].route6[r].ipv6route, session[new_s].route6[r].ipv6prefixlen, new_s);
+                                               }
+
+                                               if (session[new_s].ipv6address.s6_addr[0])
+                                               {
+                                                       cache_ipv6map(session[new_s].ipv6address, 128, new_s);
+                                               }
                                        }
                                }
                        }
                                        }
                                }
                        }
@@ -2277,6 +2372,8 @@ static void sessionclear(sessionidt s)
 // kill a session now
 void sessionkill(sessionidt s, char *reason)
 {
 // kill a session now
 void sessionkill(sessionidt s, char *reason)
 {
+       groupidt g;
+
        CSTAT(sessionkill);
 
        if (!session[s].opened) // not alive
        CSTAT(sessionkill);
 
        if (!session[s].opened) // not alive
@@ -2305,6 +2402,12 @@ void sessionkill(sessionidt s, char *reason)
        }
 
        LOG(2, s, session[s].tunnel, "Kill session %d (%s): %s\n", s, session[s].user, reason);
        }
 
        LOG(2, s, session[s].tunnel, "Kill session %d (%s): %s\n", s, session[s].user, reason);
+
+       if ((g = grp_groupbysession(s)))
+       {
+               grp_removesession(g, s);
+       }
+
        sessionclear(s);
        cluster_send_session(s);
 }
        sessionclear(s);
        cluster_send_session(s);
 }
@@ -2410,7 +2513,8 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha
 // read and process packet on tunnel (UDP)
 void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexudpfd)
 {
 // read and process packet on tunnel (UDP)
 void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexudpfd)
 {
-       uint8_t *chapresponse = NULL;
+       uint8_t *sendchalresponse = NULL;
+       uint8_t *recvchalresponse = NULL;
        uint16_t l = len, t = 0, s = 0, ns = 0, nr = 0;
        uint8_t *p = buf + 2;
 
        uint16_t l = len, t = 0, s = 0, ns = 0, nr = 0;
        uint8_t *p = buf + 2;
 
@@ -2814,17 +2918,20 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                                tunnel[t].window = 1; // window of 0 is silly
                                        LOG(4, s, t, "   rx window = %u\n", tunnel[t].window);
                                        break;
                                                tunnel[t].window = 1; // window of 0 is silly
                                        LOG(4, s, t, "   rx window = %u\n", tunnel[t].window);
                                        break;
-                               case 11:        // Challenge
+                               case 11:        // Request Challenge
                                        {
                                                LOG(4, s, t, "   LAC requested CHAP authentication for tunnel\n");
                                        {
                                                LOG(4, s, t, "   LAC requested CHAP authentication for tunnel\n");
-                                               build_chap_response(b, 2, n, &chapresponse);
+                                               if (message == 1)
+                                                       build_chap_response(b, 2, n, &sendchalresponse);
+                                               else if (message == 2)
+                                                       build_chap_response(b, 3, n, &sendchalresponse);
                                        }
                                        break;
                                        }
                                        break;
-                               case 13:    // Response
+                               case 13:    // receive challenge Response
                                        if (tunnel[t].isremotelns)
                                        {
                                        if (tunnel[t].isremotelns)
                                        {
-                                               chapresponse = calloc(17, 1);
-                                               memcpy(chapresponse, b, (n < 17) ? n : 16);
+                                               recvchalresponse = calloc(17, 1);
+                                               memcpy(recvchalresponse, b, (n < 17) ? n : 16);
                                                LOG(3, s, t, "received challenge response from REMOTE LNS\n");
                                        }
                                        else
                                                LOG(3, s, t, "received challenge response from REMOTE LNS\n");
                                        }
                                        else
@@ -3060,8 +3167,8 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                                controlt *c = controlnew(2); // sending SCCRP
                                                control16(c, 2, version, 1); // protocol version
                                                control32(c, 3, 3, 1); // framing
                                                controlt *c = controlnew(2); // sending SCCRP
                                                control16(c, 2, version, 1); // protocol version
                                                control32(c, 3, 3, 1); // framing
-                                               controls(c, 7, hostname, 1); // host name
-                                               if (chapresponse) controlb(c, 13, chapresponse, 16, 1); // Challenge response
+                                               controls(c, 7, config->multi_n_hostname[tunnel[t].indexudp][0]?config->multi_n_hostname[tunnel[t].indexudp]:hostname, 1); // host name
+                                               if (sendchalresponse) controlb(c, 13, sendchalresponse, 16, 1); // Send Challenge response
                                                control16(c, 9, t, 1); // assigned tunnel
                                                controladd(c, 0, t); // send the resply
                                        }
                                                control16(c, 9, t, 1); // assigned tunnel
                                                controladd(c, 0, t); // send the resply
                                        }
@@ -3076,20 +3183,21 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                        LOG(3, s, t, "Received SCCRP\n");
                                        if (main_quit != QUIT_SHUTDOWN)
                                        {
                                        LOG(3, s, t, "Received SCCRP\n");
                                        if (main_quit != QUIT_SHUTDOWN)
                                        {
-                                               if (tunnel[t].isremotelns && chapresponse)
+                                               if (tunnel[t].isremotelns && recvchalresponse)
                                                {
                                                        hasht hash;
 
                                                        lac_calc_rlns_auth(t, 2, hash); // id = 2 (SCCRP)
                                                        // check authenticator
                                                {
                                                        hasht hash;
 
                                                        lac_calc_rlns_auth(t, 2, hash); // id = 2 (SCCRP)
                                                        // check authenticator
-                                                       if (memcmp(hash, chapresponse, 16) == 0)
+                                                       if (memcmp(hash, recvchalresponse, 16) == 0)
                                                        {
                                                                LOG(3, s, t, "sending SCCCN to REMOTE LNS\n");
                                                                controlt *c = controlnew(3); // sending SCCCN
                                                        {
                                                                LOG(3, s, t, "sending SCCCN to REMOTE LNS\n");
                                                                controlt *c = controlnew(3); // sending SCCCN
-                                                               controls(c, 7, hostname, 1); // host name
+                                                               controls(c, 7, config->multi_n_hostname[tunnel[t].indexudp][0]?config->multi_n_hostname[tunnel[t].indexudp]:hostname, 1); // host name
                                                                controls(c, 8, Vendor_name, 1); // Vendor name
                                                                control16(c, 2, version, 1); // protocol version
                                                                control32(c, 3, 3, 1); // framing Capabilities
                                                                controls(c, 8, Vendor_name, 1); // Vendor name
                                                                control16(c, 2, version, 1); // protocol version
                                                                control32(c, 3, 3, 1); // framing Capabilities
+                                                               if (sendchalresponse) controlb(c, 13, sendchalresponse, 16, 1); // Challenge response
                                                                control16(c, 9, t, 1); // assigned tunnel
                                                                controladd(c, 0, t); // send
                                                        }
                                                                control16(c, 9, t, 1); // assigned tunnel
                                                                controladd(c, 0, t); // send
                                                        }
@@ -3210,7 +3318,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
 
                                        // Set multilink options before sending initial LCP packet
                                        sess_local[s].mp_mrru = 1614;
 
                                        // Set multilink options before sending initial LCP packet
                                        sess_local[s].mp_mrru = 1614;
-                                       sess_local[s].mp_epdis = ntohl(config->iftun_n_address[tunnel[t].indexudp] ? config->iftun_n_address[tunnel[t].indexudp] : my_address);
+                                       sess_local[s].mp_epdis = ntohl(config->iftun_address ? config->iftun_address : my_address);
 
                                        sendlcp(s, t);
                                        change_state(s, lcp, RequestSent);
 
                                        sendlcp(s, t);
                                        change_state(s, lcp, RequestSent);
@@ -3232,7 +3340,8 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                                LOG(1, s, t, "Unknown message type %u\n", message);
                                        break;
                                }
                                                LOG(1, s, t, "Unknown message type %u\n", message);
                                        break;
                                }
-                       if (chapresponse) free(chapresponse);
+                       if (sendchalresponse) free(sendchalresponse);
+                       if (recvchalresponse) free(recvchalresponse);
                        cluster_send_tunnel(t);
                }
                else
                        cluster_send_tunnel(t);
                }
                else
@@ -3388,6 +3497,20 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                return;
                        }
 
                                return;
                        }
 
+                       if (!config->cluster_iam_master)
+                       {
+                               // Check if DhcpV6, IP dst: FF02::1:2, Src Port 0x0222 (546), Dst Port 0x0223 (547)
+                               if (*(p + 6) == 17 && *(p + 24) == 0xFF && *(p + 25) == 2 &&
+                                               *(uint32_t *)(p + 26) == 0 && *(uint32_t *)(p + 30) == 0 &&
+                                               *(uint16_t *)(p + 34) == 0 && *(p + 36) == 0 && *(p + 37) == 1 && *(p + 38) == 0 && *(p + 39) == 2 &&
+                                               *(p + 40) == 2 && *(p + 41) == 0x22 && *(p + 42) == 2 && *(p + 43) == 0x23)
+                               {
+                                       // DHCPV6 must be managed by the Master.
+                                       master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd);
+                                       return;
+                               }
+                       }
+
                        processipv6in(s, t, p, l);
                }
                else if (session[s].ppp.lcp == Opened)
                        processipv6in(s, t, p, l);
                }
                else if (session[s].ppp.lcp == Opened)
@@ -3696,7 +3819,7 @@ static void regular_cleanups(double period)
 
                // No data in ECHO_TIMEOUT seconds, send LCP ECHO
                if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= config->echo_timeout) &&
 
                // No data in ECHO_TIMEOUT seconds, send LCP ECHO
                if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= config->echo_timeout) &&
-                       (time_now - sess_local[s].last_echo >= ECHO_TIMEOUT))
+                       (time_now - sess_local[s].last_echo >= config->echo_timeout))
                {
                        uint8_t b[MAXETHER];
 
                {
                        uint8_t b[MAXETHER];
 
@@ -4633,6 +4756,8 @@ static void initdata(int optdebug, char *optconfig)
 #endif /* BGP */
 
        lac_initremotelnsdata();
 #endif /* BGP */
 
        lac_initremotelnsdata();
+
+       grp_initdata();
 }
 
 static int assign_ip_address(sessionidt s)
 }
 
 static int assign_ip_address(sessionidt s)
@@ -4938,6 +5063,21 @@ static int dump_session(FILE **f, sessiont *s)
                }
 
                LOG(3, 0, 0, "Dumping accounting information to %s\n", filename);
                }
 
                LOG(3, 0, 0, "Dumping accounting information to %s\n", filename);
+               if(config->account_all_origin)
+               {
+               fprintf(*f, "# dslwatch.pl dump file V1.01\n"
+                       "# host: %s\n"
+                       "# endpoint: %s\n"
+                       "# time: %ld\n"
+                       "# uptime: %ld\n"
+                       "# format: username ip qos uptxoctets downrxoctets origin(L=LAC, R=Remote LNS, P=PPPOE)\n",
+                       hostname,
+                       fmtaddr(config->iftun_n_address[tunnel[s->tunnel].indexudp] ? config->iftun_n_address[tunnel[s->tunnel].indexudp] : my_address, 0),
+                       now,
+                       now - basetime);
+               }
+               else
+               {
                fprintf(*f, "# dslwatch.pl dump file V1.01\n"
                        "# host: %s\n"
                        "# endpoint: %s\n"
                fprintf(*f, "# dslwatch.pl dump file V1.01\n"
                        "# host: %s\n"
                        "# endpoint: %s\n"
@@ -4948,15 +5088,29 @@ static int dump_session(FILE **f, sessiont *s)
                        fmtaddr(config->iftun_n_address[tunnel[s->tunnel].indexudp] ? config->iftun_n_address[tunnel[s->tunnel].indexudp] : my_address, 0),
                        now,
                        now - basetime);
                        fmtaddr(config->iftun_n_address[tunnel[s->tunnel].indexudp] ? config->iftun_n_address[tunnel[s->tunnel].indexudp] : my_address, 0),
                        now,
                        now - basetime);
+               }
        }
 
        LOG(4, 0, 0, "Dumping accounting information for %s\n", s->user);
        }
 
        LOG(4, 0, 0, "Dumping accounting information for %s\n", s->user);
+       if(config->account_all_origin)
+       {
+       fprintf(*f, "%s %s %d %u %u %s\n",
+               s->user,                                                // username
+               fmtaddr(htonl(s->ip), 0),                               // ip
+               (s->throttle_in || s->throttle_out) ? 2 : 1,            // qos
+               (uint32_t) s->cin_delta,                                // uptxoctets
+               (uint32_t) s->cout_delta,                               // downrxoctets
+               (s->tunnel == TUNNEL_ID_PPPOE)?"P":(tunnel[s->tunnel].isremotelns?"R":"L"));    // Origin
+       }
+       else if (!tunnel[s->tunnel].isremotelns && (s->tunnel != TUNNEL_ID_PPPOE))
+       {
        fprintf(*f, "%s %s %d %u %u\n",
                s->user,                                                // username
                fmtaddr(htonl(s->ip), 0),                               // ip
                (s->throttle_in || s->throttle_out) ? 2 : 1,            // qos
                (uint32_t) s->cin_delta,                                // uptxoctets
                (uint32_t) s->cout_delta);                              // downrxoctets
        fprintf(*f, "%s %s %d %u %u\n",
                s->user,                                                // username
                fmtaddr(htonl(s->ip), 0),                               // ip
                (s->throttle_in || s->throttle_out) ? 2 : 1,            // qos
                (uint32_t) s->cin_delta,                                // uptxoctets
                (uint32_t) s->cout_delta);                              // downrxoctets
+       }
 
        s->cin_delta = s->cout_delta = 0;
 
 
        s->cin_delta = s->cout_delta = 0;
 
@@ -5004,9 +5158,9 @@ int main(int argc, char *argv[])
                case 'd':
                        if (fork()) exit(0);
                        setsid();
                case 'd':
                        if (fork()) exit(0);
                        setsid();
-                       freopen("/dev/null", "r", stdin);
-                       freopen("/dev/null", "w", stdout);
-                       freopen("/dev/null", "w", stderr);
+                       if(!freopen("/dev/null", "r", stdin)) LOG(0, 0, 0, "Error freopen stdin: %s\n", strerror(errno));
+                       if(!freopen("/dev/null", "w", stdout)) LOG(0, 0, 0, "Error freopen stdout: %s\n", strerror(errno));
+                       if(!freopen("/dev/null", "w", stderr)) LOG(0, 0, 0, "Error freopen stderr: %s\n", strerror(errno));
                        break;
                case 'v':
                        optdebug++;
                        break;
                case 'v':
                        optdebug++;
@@ -5046,6 +5200,7 @@ int main(int argc, char *argv[])
        init_tbf(config->num_tbfs);
 
        LOG(0, 0, 0, "L2TPNS version " VERSION "\n");
        init_tbf(config->num_tbfs);
 
        LOG(0, 0, 0, "L2TPNS version " VERSION "\n");
+       LOG(0, 0, 0, "Copyright (c) 2012, 2013, 2014 ISP FDN & SAMESWIRELESS\n");
        LOG(0, 0, 0, "Copyright (c) 2003, 2004, 2005, 2006 Optus Internet Engineering\n");
        LOG(0, 0, 0, "Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced\n");
        {
        LOG(0, 0, 0, "Copyright (c) 2003, 2004, 2005, 2006 Optus Internet Engineering\n");
        LOG(0, 0, 0, "Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced\n");
        {
@@ -5057,7 +5212,7 @@ int main(int argc, char *argv[])
                        LOG(0, 0, 0, "Can't set ulimit: %s\n", strerror(errno));
 
                // Make core dumps go to /tmp
                        LOG(0, 0, 0, "Can't set ulimit: %s\n", strerror(errno));
 
                // Make core dumps go to /tmp
-               chdir("/tmp");
+               if(chdir("/tmp")) LOG(0, 0, 0, "Error chdir /tmp: %s\n", strerror(errno));
        }
 
        if (config->scheduler_fifo)
        }
 
        if (config->scheduler_fifo)
@@ -5121,6 +5276,7 @@ int main(int argc, char *argv[])
 
        initrad();
        initippool();
 
        initrad();
        initippool();
+       dhcpv6_init();
 
        // seed prng
        {
 
        // seed prng
        {
@@ -5144,6 +5300,9 @@ int main(int argc, char *argv[])
                        LOG(0, 0, 0, "Can't lock pages: %s\n", strerror(errno));
        }
 
                        LOG(0, 0, 0, "Can't lock pages: %s\n", strerror(errno));
        }
 
+       //LOG(3, 0, 0, "Debug sizeof struct: sessiont %lu, tunnelt %lu, bundlet %lu, groupsesst %lu\n",
+       //      sizeof(sessiont), sizeof(tunnelt), sizeof(bundlet), sizeof(groupsesst));
+
        mainloop();
 
        /* remove plugins (so cleanup code gets run) */
        mainloop();
 
        /* remove plugins (so cleanup code gets run) */
@@ -5389,6 +5548,8 @@ static void update_config()
                                config->iftun_n_address[config->nbmultiaddress] = htonl(ip);
                                config->nbmultiaddress++;
                                LOG(1, 0, 0, "Bind address %s\n", fmtaddr(htonl(ip), 0));
                                config->iftun_n_address[config->nbmultiaddress] = htonl(ip);
                                config->nbmultiaddress++;
                                LOG(1, 0, 0, "Bind address %s\n", fmtaddr(htonl(ip), 0));
+
+                               if (config->nbmultiaddress >= MAX_BINDADDR) break;
                        }
 
                        sip = n;
                        }
 
                        sip = n;
@@ -5407,6 +5568,42 @@ static void update_config()
                config->iftun_n_address[0] = config->iftun_address;
        }
 
                config->iftun_n_address[0] = config->iftun_address;
        }
 
+       if (*config->multi_hostname)
+       {
+               char *shost = config->multi_hostname;
+               char *n = shost;
+               char *e = config->multi_hostname + strlen(config->multi_hostname);
+               config->nbmultihostname = 0;
+
+               while (*shost && (shost < e))
+               {
+                       while ((n < e) && (*n == ' ' || *n == ',' || *n == '\t')) n++;
+
+                       i = 0;
+                       while (n < e && (*n != ',') && (*n != '\t'))
+                       {
+                               config->multi_n_hostname[config->nbmultihostname][i] = *n;
+                               n++;i++;
+                       }
+
+                       if (i > 0)
+                       {
+                               config->multi_n_hostname[config->nbmultihostname][i] = 0;
+                               LOG(1, 0, 0, "Bind Hostname %s\n", config->multi_n_hostname[config->nbmultihostname]);
+                               config->nbmultihostname++;
+                               if (config->nbmultihostname >= MAX_NBHOSTNAME) break;
+                       }
+
+                       shost = n;
+               }
+
+               if (config->nbmultihostname >= 1)
+               {
+                       strcpy(hostname, config->multi_n_hostname[0]);
+                       strcpy(config->hostname, hostname);
+               }
+       }
+
        if (!*config->pppoe_ac_name)
                strncpy(config->pppoe_ac_name, DEFAULT_PPPOE_AC_NAME, sizeof(config->pppoe_ac_name) - 1);
 
        if (!*config->pppoe_ac_name)
                strncpy(config->pppoe_ac_name, DEFAULT_PPPOE_AC_NAME, sizeof(config->pppoe_ac_name) - 1);
 
@@ -5617,6 +5814,7 @@ int sessionsetup(sessionidt s, tunnelidt t)
        if (!session[s].bundle || (bundle[session[s].bundle].num_of_links == 1))
        {
                int routed = 0;
        if (!session[s].bundle || (bundle[session[s].bundle].num_of_links == 1))
        {
                int routed = 0;
+               groupidt g;
 
                // Add the route for this session.
                for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
 
                // Add the route for this session.
                for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
@@ -5639,6 +5837,12 @@ int sessionsetup(sessionidt s, tunnelidt t)
                }
                else
                        cache_ipmap(session[s].ip, s);
                }
                else
                        cache_ipmap(session[s].ip, s);
+
+               if ((g = grp_groupbysession(s)))
+               {
+                       grp_setgrouproute(g, 1);
+                       cluster_send_groupe(g);
+               }
        }
 
        sess_local[s].lcp_authtype = 0; // RADIUS authentication complete
        }
 
        sess_local[s].lcp_authtype = 0; // RADIUS authentication complete
@@ -5702,7 +5906,7 @@ int load_session(sessionidt s, sessiont *new)
        // needs update
        if (newip)
        {
        // needs update
        if (newip)
        {
-               int routed = 0;
+               int routed = 0;
 
                // remove old routes...
                for (i = 0; i < MAXROUTE && session[s].route[i].ip; i++)
 
                // remove old routes...
                for (i = 0; i < MAXROUTE && session[s].route[i].ip; i++)
@@ -5725,6 +5929,17 @@ int load_session(sessionidt s, sessiont *new)
                                uncache_ipmap(session[s].ip);
                }
 
                                uncache_ipmap(session[s].ip);
                }
 
+               // remove old IPV6 routes...
+               for (i = 0; i < MAXROUTE6 && session[s].route6[i].ipv6route.s6_addr[0] && session[s].route6[i].ipv6prefixlen; i++)
+               {
+                       route6set(s, session[s].route6[i].ipv6route, session[s].route6[i].ipv6prefixlen, 0);
+               }
+
+               if (session[s].ipv6address.s6_addr[0])
+               {
+                       route6set(s, session[s].ipv6address, 128, 0);
+               }
+
                routed = 0;
 
                // add new routes...
                routed = 0;
 
                // add new routes...
@@ -5751,8 +5966,20 @@ int load_session(sessionidt s, sessiont *new)
        }
 
        // check v6 routing
        }
 
        // check v6 routing
-       if (new->ipv6prefixlen && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
-                   route6set(s, new->ipv6route, new->ipv6prefixlen, 1);
+       if (new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
+       {
+               for (i = 0; i < MAXROUTE6 && new->route6[i].ipv6prefixlen; i++)
+               {
+                       route6set(s, new->route6[i].ipv6route, new->route6[i].ipv6prefixlen, 1);
+               }
+       }
+
+       if (new->ipv6address.s6_addr[0] && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
+       {
+               // Check if included in prefix
+               if (sessionbyipv6(new->ipv6address) != s)
+                       route6set(s, new->ipv6address, 128, 1);
+       }
 
        // check filters
        if (new->filter_in && (new->filter_in > MAXFILTER || !ip_filters[new->filter_in - 1].name[0]))
 
        // check filters
        if (new->filter_in && (new->filter_in > MAXFILTER || !ip_filters[new->filter_in - 1].name[0]))
@@ -6199,7 +6426,7 @@ void become_master(void)
        }
 }
 
        }
 }
 
-int cmd_show_hist_idle(struct cli_def *cli, char *command, char **argv, int argc)
+int cmd_show_hist_idle(struct cli_def *cli, const char *command, char **argv, int argc)
 {
        int s, i;
        int count = 0;
 {
        int s, i;
        int count = 0;
@@ -6237,7 +6464,7 @@ int cmd_show_hist_idle(struct cli_def *cli, char *command, char **argv, int argc
        return CLI_OK;
 }
 
        return CLI_OK;
 }
 
-int cmd_show_hist_open(struct cli_def *cli, char *command, char **argv, int argc)
+int cmd_show_hist_open(struct cli_def *cli, const char *command, char **argv, int argc)
 {
        int s, i;
        int count = 0;
 {
        int s, i;
        int count = 0;
@@ -6481,7 +6708,7 @@ void lac_send_SCCRQ(tunnelidt t, uint8_t * auth, unsigned int auth_len)
 
        // Sent SCCRQ - Start Control Connection Request
        controlt *c = controlnew(1); // sending SCCRQ
 
        // Sent SCCRQ - Start Control Connection Request
        controlt *c = controlnew(1); // sending SCCRQ
-       controls(c, 7, hostname, 1); // host name
+       controls(c, 7, config->multi_n_hostname[tunnel[t].indexudp][0]?config->multi_n_hostname[tunnel[t].indexudp]:hostname, 1); // host name
        controls(c, 8, Vendor_name, 1); // Vendor name
        control16(c, 2, version, 1); // protocol version
        control32(c, 3, 3, 1); // framing Capabilities
        controls(c, 8, Vendor_name, 1); // Vendor name
        control16(c, 2, version, 1); // protocol version
        control32(c, 3, 3, 1); // framing Capabilities