Update changelog
[l2tpns.git] / l2tpns.c
index 07a45f7..0838607 100644 (file)
--- a/l2tpns.c
+++ b/l2tpns.c
@@ -102,7 +102,7 @@ union iphash {
 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;
@@ -132,6 +132,7 @@ config_descriptt config_values[] = {
        CONFIG("ppp_restart_time", ppp_restart_time, INT),
        CONFIG("ppp_max_configure", ppp_max_configure, INT),
        CONFIG("ppp_max_failure", ppp_max_failure, INT),
        CONFIG("ppp_restart_time", ppp_restart_time, INT),
        CONFIG("ppp_max_configure", ppp_max_configure, INT),
        CONFIG("ppp_max_failure", ppp_max_failure, INT),
+       CONFIG("ppp_keepalive", ppp_keepalive, BOOL),
        CONFIG("primary_dns", default_dns1, IPv4),
        CONFIG("secondary_dns", default_dns2, IPv4),
        CONFIG("primary_radius", radiusserver[0], IPv4),
        CONFIG("primary_dns", default_dns1, IPv4),
        CONFIG("secondary_dns", default_dns2, IPv4),
        CONFIG("primary_radius", radiusserver[0], IPv4),
@@ -162,6 +163,7 @@ config_descriptt config_values[] = {
        CONFIG("icmp_rate", icmp_rate, INT),
        CONFIG("packet_limit", max_packets, INT),
        CONFIG("cluster_address", cluster_address, IPv4),
        CONFIG("icmp_rate", icmp_rate, INT),
        CONFIG("packet_limit", max_packets, INT),
        CONFIG("cluster_address", cluster_address, IPv4),
+       CONFIG("cluster_port", cluster_port, INT),
        CONFIG("cluster_interface", cluster_interface, STRING),
        CONFIG("cluster_mcast_ttl", cluster_mcast_ttl, INT),
        CONFIG("cluster_hb_interval", cluster_hb_interval, INT),
        CONFIG("cluster_interface", cluster_interface, STRING),
        CONFIG("cluster_mcast_ttl", cluster_mcast_ttl, INT),
        CONFIG("cluster_hb_interval", cluster_hb_interval, INT),
@@ -194,6 +196,7 @@ config_descriptt config_values[] = {
        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("dhcp6_preferred_lifetime", dhcp6_preferred_lifetime, INT),
        CONFIG("dhcp6_valid_lifetime", dhcp6_valid_lifetime, INT),
        CONFIG("dhcp6_server_duid", dhcp6_server_duid, INT),
+       CONFIG("dns6_lifetime", dns6_lifetime, 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),
        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),
@@ -982,20 +985,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;
@@ -1036,6 +1043,19 @@ 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.
 //
 // Take an IP address in HOST byte order and
 // add it to the sessionid by IP cache.
@@ -1075,22 +1095,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++;
        }
 
@@ -1098,13 +1124,13 @@ 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);
 }
 
                                prefixlen);
 }
 
@@ -1155,7 +1181,6 @@ int cmd_show_ipcache(struct cli_def *cli, const char *command, char **argv, int
        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
@@ -1692,7 +1717,6 @@ static void processipv6out(uint8_t * buf, int len)
        sessionidt s;
        sessiont *sp;
        tunnelidt t;
        sessionidt s;
        sessiont *sp;
        tunnelidt t;
-       in_addr_t ip;
        struct in6_addr ip6;
 
        uint8_t *data = buf;    // Keep a copy of the originals.
        struct in6_addr ip6;
 
        uint8_t *data = buf;    // Keep a copy of the originals.
@@ -1731,10 +1755,9 @@ static void processipv6out(uint8_t * buf, int len)
 
        if (s == 0)
        {
 
        if (s == 0)
        {
-               ip = *(uint32_t *)(buf + 32);
-               s = sessionbyip(ip);
+               s = sessionbyipv6new(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?
@@ -2128,8 +2151,11 @@ 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].ipv6route.s6_addr[0] && 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)
                {
 
                if (session[s].ipv6address.s6_addr[0] && del_routes)
                {
@@ -2189,8 +2215,10 @@ 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])
                                                {
 
                                                if (session[new_s].ipv6address.s6_addr[0])
                                                {
@@ -2688,7 +2716,14 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                        result = 2; // general error
                                        error = 3; // reserved field non-zero
                                        msg = 0;
                                        result = 2; // general error
                                        error = 3; // reserved field non-zero
                                        msg = 0;
-                                       continue; // next
+                                       if (n == 0)
+                                       {
+                                               // if continue a infinity loop is created.
+                                               LOG(1, s, t, "It's infinite loop protection %02X\n", *b);
+                                               return;
+                                       }
+                                       else
+                                               continue; // next
                                }
                                b += 2;
                                if (*(uint16_t *) (b))
                                }
                                b += 2;
                                if (*(uint16_t *) (b))
@@ -2698,7 +2733,14 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                        result = 2; // general error
                                        error = 6; // generic vendor-specific error
                                        msg = "unsupported vendor-specific";
                                        result = 2; // general error
                                        error = 6; // generic vendor-specific error
                                        msg = "unsupported vendor-specific";
-                                       continue; // next
+                                       if (n == 0)
+                                       {
+                                               // if continue a infinity loop is created.
+                                               LOG(1, s, t, "It's infinite loop protection %02X\n", *b);
+                                               return;
+                                       }
+                                       else
+                                               continue; // next
                                }
                                b += 2;
                                mtype = ntohs(*(uint16_t *) (b));
                                }
                                b += 2;
                                mtype = ntohs(*(uint16_t *) (b));
@@ -2758,7 +2800,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                        n = orig_len;
                                }
 
                                        n = orig_len;
                                }
 
-                               LOG(4, s, t, "   AVP %u (%s) len %d%s%s\n", mtype, l2tp_avp_name(mtype), n,
+                               LOG(3, s, t, "   AVP %u (%s) len %d%s%s\n", mtype, l2tp_avp_name(mtype), n,
                                        flags & 0x40 ? ", hidden" : "", flags & 0x80 ? ", mandatory" : "");
 
                                switch (mtype)
                                        flags & 0x40 ? ", hidden" : "", flags & 0x80 ? ", mandatory" : "");
 
                                switch (mtype)
@@ -2766,7 +2808,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                case 0:     // message type
                                        message = ntohs(*(uint16_t *) b);
                                        mandatory = flags & 0x80;
                                case 0:     // message type
                                        message = ntohs(*(uint16_t *) b);
                                        mandatory = flags & 0x80;
-                                       LOG(4, s, t, "   Message type = %u (%s)\n", message, l2tp_code(message));
+                                       LOG(3, s, t, "   Message type = %u (%s)\n", message, l2tp_code(message));
                                        break;
                                case 1:     // result code
                                        {
                                        break;
                                case 1:     // result code
                                        {
@@ -2789,15 +2831,15 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                                                cause = TERM_ADMIN_RESET;
                                                }
 
                                                                cause = TERM_ADMIN_RESET;
                                                }
 
-                                               LOG(4, s, t, "   Result Code %u: %s\n", rescode, resdesc);
+                                               LOG(3, s, t, "   Result Code %u: %s\n", rescode, resdesc);
                                                if (n >= 4)
                                                {
                                                        uint16_t errcode = ntohs(*(uint16_t *)(b + 2));
                                                        errdesc = l2tp_error_code(errcode);
                                                if (n >= 4)
                                                {
                                                        uint16_t errcode = ntohs(*(uint16_t *)(b + 2));
                                                        errdesc = l2tp_error_code(errcode);
-                                                       LOG(4, s, t, "   Error Code %u: %s\n", errcode, errdesc);
+                                                       LOG(3, s, t, "   Error Code %u: %s\n", errcode, errdesc);
                                                }
                                                if (n > 4)
                                                }
                                                if (n > 4)
-                                                       LOG(4, s, t, "   Error String: %.*s\n", n-4, b+4);
+                                                       LOG(3, s, t, "   Error String: %.*s\n", n-4, b+4);
 
                                                if (cause && disc_cause_set < mtype) // take cause from attrib 46 in preference
                                                {
 
                                                if (cause && disc_cause_set < mtype) // take cause from attrib 46 in preference
                                                {
@@ -2812,7 +2854,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                case 2:     // protocol version
                                        {
                                                version = ntohs(*(uint16_t *) (b));
                                case 2:     // protocol version
                                        {
                                                version = ntohs(*(uint16_t *) (b));
-                                               LOG(4, s, t, "   Protocol version = %u\n", version);
+                                               LOG(3, s, t, "   Protocol version = %u\n", version);
                                                if (version && version != 0x0100)
                                                {   // allow 0.0 and 1.0
                                                        LOG(1, s, t, "   Bad protocol version %04X\n", version);
                                                if (version && version != 0x0100)
                                                {   // allow 0.0 and 1.0
                                                        LOG(1, s, t, "   Bad protocol version %04X\n", version);
@@ -2836,27 +2878,27 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                case 7:     // host name
                                        memset(tunnel[t].hostname, 0, sizeof(tunnel[t].hostname));
                                        memcpy(tunnel[t].hostname, b, (n < sizeof(tunnel[t].hostname)) ? n : sizeof(tunnel[t].hostname) - 1);
                                case 7:     // host name
                                        memset(tunnel[t].hostname, 0, sizeof(tunnel[t].hostname));
                                        memcpy(tunnel[t].hostname, b, (n < sizeof(tunnel[t].hostname)) ? n : sizeof(tunnel[t].hostname) - 1);
-                                       LOG(4, s, t, "   Tunnel hostname = \"%s\"\n", tunnel[t].hostname);
+                                       LOG(3, s, t, "   Tunnel hostname = \"%s\"\n", tunnel[t].hostname);
                                        // TBA - to send to RADIUS
                                        break;
                                case 8:     // vendor name
                                        memset(tunnel[t].vendor, 0, sizeof(tunnel[t].vendor));
                                        memcpy(tunnel[t].vendor, b, (n < sizeof(tunnel[t].vendor)) ? n : sizeof(tunnel[t].vendor) - 1);
                                        // TBA - to send to RADIUS
                                        break;
                                case 8:     // vendor name
                                        memset(tunnel[t].vendor, 0, sizeof(tunnel[t].vendor));
                                        memcpy(tunnel[t].vendor, b, (n < sizeof(tunnel[t].vendor)) ? n : sizeof(tunnel[t].vendor) - 1);
-                                       LOG(4, s, t, "   Vendor name = \"%s\"\n", tunnel[t].vendor);
+                                       LOG(3, s, t, "   Vendor name = \"%s\"\n", tunnel[t].vendor);
                                        break;
                                case 9:     // assigned tunnel
                                        tunnel[t].far = ntohs(*(uint16_t *) (b));
                                        break;
                                case 9:     // assigned tunnel
                                        tunnel[t].far = ntohs(*(uint16_t *) (b));
-                                       LOG(4, s, t, "   Remote tunnel id = %u\n", tunnel[t].far);
+                                       LOG(3, s, t, "   Remote tunnel id = %u\n", tunnel[t].far);
                                        break;
                                case 10:    // rx window
                                        tunnel[t].window = ntohs(*(uint16_t *) (b));
                                        if (!tunnel[t].window)
                                                tunnel[t].window = 1; // window of 0 is silly
                                        break;
                                case 10:    // rx window
                                        tunnel[t].window = ntohs(*(uint16_t *) (b));
                                        if (!tunnel[t].window)
                                                tunnel[t].window = 1; // window of 0 is silly
-                                       LOG(4, s, t, "   rx window = %u\n", tunnel[t].window);
+                                       LOG(3, s, t, "   rx window = %u\n", tunnel[t].window);
                                        break;
                                case 11:        // Request Challenge
                                        {
                                        break;
                                case 11:        // Request Challenge
                                        {
-                                               LOG(4, s, t, "   LAC requested CHAP authentication for tunnel\n");
+                                               LOG(3, s, t, "   LAC requested CHAP authentication for tunnel\n");
                                                if (message == 1)
                                                        build_chap_response(b, 2, n, &sendchalresponse);
                                                else if (message == 2)
                                                if (message == 1)
                                                        build_chap_response(b, 2, n, &sendchalresponse);
                                                else if (message == 2)
@@ -2877,28 +2919,28 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
 
                                case 14:    // assigned session
                                        asession = session[s].far = ntohs(*(uint16_t *) (b));
 
                                case 14:    // assigned session
                                        asession = session[s].far = ntohs(*(uint16_t *) (b));
-                                       LOG(4, s, t, "   assigned session = %u\n", asession);
+                                       LOG(3, s, t, "   assigned session = %u\n", asession);
                                        break;
                                case 15:    // call serial number
                                        break;
                                case 15:    // call serial number
-                                       LOG(4, s, t, "   call serial number = %u\n", ntohl(*(uint32_t *)b));
+                                       LOG(3, s, t, "   call serial number = %u\n", ntohl(*(uint32_t *)b));
                                        break;
                                case 18:    // bearer type
                                        break;
                                case 18:    // bearer type
-                                       LOG(4, s, t, "   bearer type = %u\n", ntohl(*(uint32_t *)b));
+                                       LOG(3, s, t, "   bearer type = %u\n", ntohl(*(uint32_t *)b));
                                        // TBA - for RADIUS
                                        break;
                                case 19:    // framing type
                                        // TBA - for RADIUS
                                        break;
                                case 19:    // framing type
-                                       LOG(4, s, t, "   framing type = %u\n", ntohl(*(uint32_t *)b));
+                                       LOG(3, s, t, "   framing type = %u\n", ntohl(*(uint32_t *)b));
                                        // TBA
                                        break;
                                case 21:    // called number
                                        memset(called, 0, sizeof(called));
                                        memcpy(called, b, (n < sizeof(called)) ? n : sizeof(called) - 1);
                                        // TBA
                                        break;
                                case 21:    // called number
                                        memset(called, 0, sizeof(called));
                                        memcpy(called, b, (n < sizeof(called)) ? n : sizeof(called) - 1);
-                                       LOG(4, s, t, "   Called <%s>\n", called);
+                                       LOG(3, s, t, "   Called <%s>\n", called);
                                        break;
                                case 22:    // calling number
                                        memset(calling, 0, sizeof(calling));
                                        memcpy(calling, b, (n < sizeof(calling)) ? n : sizeof(calling) - 1);
                                        break;
                                case 22:    // calling number
                                        memset(calling, 0, sizeof(calling));
                                        memcpy(calling, b, (n < sizeof(calling)) ? n : sizeof(calling) - 1);
-                                       LOG(4, s, t, "   Calling <%s>\n", calling);
+                                       LOG(3, s, t, "   Calling <%s>\n", calling);
                                        break;
                                case 23:    // subtype
                                        break;
                                        break;
                                case 23:    // subtype
                                        break;
@@ -2915,7 +2957,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                                memcpy(tmp, b, (n < sizeof(tmp)) ? n : sizeof(tmp) - 1);
                                                session[s].tx_connect_speed = atol(tmp);
                                        }
                                                memcpy(tmp, b, (n < sizeof(tmp)) ? n : sizeof(tmp) - 1);
                                                session[s].tx_connect_speed = atol(tmp);
                                        }
-                                       LOG(4, s, t, "   TX connect speed <%u>\n", session[s].tx_connect_speed);
+                                       LOG(3, s, t, "   TX connect speed <%u>\n", session[s].tx_connect_speed);
                                        break;
                                case 38:    // rx connect speed
                                        if (n == 4)
                                        break;
                                case 38:    // rx connect speed
                                        if (n == 4)
@@ -2930,18 +2972,18 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                                memcpy(tmp, b, (n < sizeof(tmp)) ? n : sizeof(tmp) - 1);
                                                session[s].rx_connect_speed = atol(tmp);
                                        }
                                                memcpy(tmp, b, (n < sizeof(tmp)) ? n : sizeof(tmp) - 1);
                                                session[s].rx_connect_speed = atol(tmp);
                                        }
-                                       LOG(4, s, t, "   RX connect speed <%u>\n", session[s].rx_connect_speed);
+                                       LOG(3, s, t, "   RX connect speed <%u>\n", session[s].rx_connect_speed);
                                        break;
                                case 25:    // Physical Channel ID
                                        {
                                                uint32_t tmp = ntohl(*(uint32_t *) b);
                                        break;
                                case 25:    // Physical Channel ID
                                        {
                                                uint32_t tmp = ntohl(*(uint32_t *) b);
-                                               LOG(4, s, t, "   Physical Channel ID <%X>\n", tmp);
+                                               LOG(3, s, t, "   Physical Channel ID <%X>\n", tmp);
                                                break;
                                        }
                                case 29:    // Proxy Authentication Type
                                        {
                                                uint16_t atype = ntohs(*(uint16_t *)b);
                                                break;
                                        }
                                case 29:    // Proxy Authentication Type
                                        {
                                                uint16_t atype = ntohs(*(uint16_t *)b);
-                                               LOG(4, s, t, "   Proxy Auth Type %u (%s)\n", atype, ppp_auth_type(atype));
+                                               LOG(3, s, t, "   Proxy Auth Type %u (%s)\n", atype, ppp_auth_type(atype));
                                                break;
                                        }
                                case 30:    // Proxy Authentication Name
                                                break;
                                        }
                                case 30:    // Proxy Authentication Name
@@ -2949,23 +2991,23 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                                char authname[64];
                                                memset(authname, 0, sizeof(authname));
                                                memcpy(authname, b, (n < sizeof(authname)) ? n : sizeof(authname) - 1);
                                                char authname[64];
                                                memset(authname, 0, sizeof(authname));
                                                memcpy(authname, b, (n < sizeof(authname)) ? n : sizeof(authname) - 1);
-                                               LOG(4, s, t, "   Proxy Auth Name (%s)\n",
+                                               LOG(3, s, t, "   Proxy Auth Name (%s)\n",
                                                        authname);
                                                break;
                                        }
                                case 31:    // Proxy Authentication Challenge
                                        {
                                                        authname);
                                                break;
                                        }
                                case 31:    // Proxy Authentication Challenge
                                        {
-                                               LOG(4, s, t, "   Proxy Auth Challenge\n");
+                                               LOG(3, s, t, "   Proxy Auth Challenge\n");
                                                break;
                                        }
                                case 32:    // Proxy Authentication ID
                                        {
                                                uint16_t authid = ntohs(*(uint16_t *)(b));
                                                break;
                                        }
                                case 32:    // Proxy Authentication ID
                                        {
                                                uint16_t authid = ntohs(*(uint16_t *)(b));
-                                               LOG(4, s, t, "   Proxy Auth ID (%u)\n", authid);
+                                               LOG(3, s, t, "   Proxy Auth ID (%u)\n", authid);
                                                break;
                                        }
                                case 33:    // Proxy Authentication Response
                                                break;
                                        }
                                case 33:    // Proxy Authentication Response
-                                       LOG(4, s, t, "   Proxy Auth Response\n");
+                                       LOG(3, s, t, "   Proxy Auth Response\n");
                                        break;
                                case 27:    // last sent lcp
                                        {        // find magic number
                                        break;
                                case 27:    // last sent lcp
                                        {        // find magic number
@@ -2989,7 +3031,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                case 39:    // seq required - we control it as an LNS anyway...
                                        break;
                                case 36:    // Random Vector
                                case 39:    // seq required - we control it as an LNS anyway...
                                        break;
                                case 36:    // Random Vector
-                                       LOG(4, s, t, "   Random Vector received.  Enabled AVP Hiding.\n");
+                                       LOG(3, s, t, "   Random Vector received.  Enabled AVP Hiding.\n");
                                        memset(session[s].random_vector, 0, sizeof(session[s].random_vector));
                                        if (n > sizeof(session[s].random_vector))
                                                n = sizeof(session[s].random_vector);
                                        memset(session[s].random_vector, 0, sizeof(session[s].random_vector));
                                        if (n > sizeof(session[s].random_vector))
                                                n = sizeof(session[s].random_vector);
@@ -3003,7 +3045,7 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu
                                                uint16_t proto = ntohs(*(uint16_t *) (b + 2));
                                                uint8_t dir = *(b + 4);
 
                                                uint16_t proto = ntohs(*(uint16_t *) (b + 2));
                                                uint8_t dir = *(b + 4);
 
-                                               LOG(4, s, t, "   PPP disconnect cause "
+                                               LOG(3, s, t, "   PPP disconnect cause "
                                                        "(code=%u, proto=%04X, dir=%u, msg=\"%.*s\")\n",
                                                        code, proto, dir, n - 5, b + 5);
 
                                                        "(code=%u, proto=%04X, dir=%u, msg=\"%.*s\")\n",
                                                        code, proto, dir, n - 5, b + 5);
 
@@ -3754,8 +3796,10 @@ static void regular_cleanups(double period)
                }
 
                // No data in ECHO_TIMEOUT seconds, send LCP ECHO
                }
 
                // 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))
+               if (session[s].ppp.phase >= Establish &&
+                    ((!config->ppp_keepalive) ||
+                     (time_now - session[s].last_packet >= config->echo_timeout)) &&
+                   (time_now - sess_local[s].last_echo >= ECHO_TIMEOUT))
                {
                        uint8_t b[MAXETHER];
 
                {
                        uint8_t b[MAXETHER];
 
@@ -4574,6 +4618,9 @@ static void initdata(int optdebug, char *optconfig)
        // Set default value echo_timeout and idle_echo_timeout
        config->echo_timeout = ECHO_TIMEOUT;
        config->idle_echo_timeout = IDLE_ECHO_TIMEOUT;
        // Set default value echo_timeout and idle_echo_timeout
        config->echo_timeout = ECHO_TIMEOUT;
        config->idle_echo_timeout = IDLE_ECHO_TIMEOUT;
+       config->ppp_keepalive = 1;
+       // Set default RDNSS lifetime
+       config->dns6_lifetime = 1200;
 
        log_stream = stderr;
 
 
        log_stream = stderr;
 
@@ -5596,6 +5643,7 @@ static void update_config()
        memcpy(config->old_plugins, config->plugins, sizeof(config->plugins));
        if (!config->multi_read_count) config->multi_read_count = 10;
        if (!config->cluster_address) config->cluster_address = inet_addr(DEFAULT_MCAST_ADDR);
        memcpy(config->old_plugins, config->plugins, sizeof(config->plugins));
        if (!config->multi_read_count) config->multi_read_count = 10;
        if (!config->cluster_address) config->cluster_address = inet_addr(DEFAULT_MCAST_ADDR);
+       if (!config->cluster_port) config->cluster_port = CLUSTERPORT;
        if (!*config->cluster_interface)
                strncpy(config->cluster_interface, DEFAULT_MCAST_INTERFACE, sizeof(config->cluster_interface) - 1);
 
        if (!*config->cluster_interface)
                strncpy(config->cluster_interface, DEFAULT_MCAST_INTERFACE, sizeof(config->cluster_interface) - 1);
 
@@ -5830,7 +5878,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++)
@@ -5854,8 +5902,10 @@ int load_session(sessionidt s, sessiont *new)
                }
 
                // remove old IPV6 routes...
                }
 
                // remove old IPV6 routes...
-               if (session[s].ipv6route.s6_addr[0] && session[s].ipv6prefixlen)
-                       route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0);
+               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])
                {
 
                if (session[s].ipv6address.s6_addr[0])
                {
@@ -5888,12 +5938,19 @@ 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)
        {
 
        if (new->ipv6address.s6_addr[0] && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
        {
-               route6set(s, new->ipv6address, 128, 1);
+               // Check if included in prefix
+               if (sessionbyipv6(new->ipv6address) != s)
+                       route6set(s, new->ipv6address, 128, 1);
        }
 
        // check filters
        }
 
        // check filters