Merge from Master
[l2tpns.git] / l2tpns.c
index 77c302c..5403364 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;
@@ -186,6 +188,13 @@ config_descriptt config_values[] = {
        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("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 }
 };
 
@@ -1010,8 +1019,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);
        }
@@ -1097,7 +1108,7 @@ static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s)
 //
 // CLI list to dump current ipcache.
 //
 //
 // 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;
@@ -1413,7 +1424,7 @@ void processipout(uint8_t *buf, int len)
        groupidt g;
        sessiont *sp;
        tunnelidt t;
        groupidt g;
        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;
@@ -1446,10 +1457,11 @@ void processipout(uint8_t *buf, int len)
                return;
        }
 
                return;
        }
 
+       ip_src = *(uint32_t *)(buf + 12);
        ip = *(uint32_t *)(buf + 16);
        if ((g = grp_groupbyip(ip)))
        {
        ip = *(uint32_t *)(buf + 16);
        if ((g = grp_groupbyip(ip)))
        {
-               s = grp_getnextsession(g, ip);
+               s = grp_getnextsession(g, ip, ip_src);
                if (!s)
                {
                        // Is this a packet for a session that doesn't exist?
                if (!s)
                {
                        // Is this a packet for a session that doesn't exist?
@@ -1554,12 +1566,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)
@@ -1821,6 +1836,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];
 
@@ -1843,11 +1860,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)
@@ -1866,10 +1886,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;
 }
 
@@ -1877,10 +1898,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;
 }
 
@@ -1888,9 +1911,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);
 }
@@ -1899,9 +1923,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;
 }
@@ -1946,10 +1971,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)
@@ -2124,9 +2150,14 @@ 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)
+               if (session[s].ipv6route.s6_addr[0] && session[s].ipv6prefixlen && del_routes)
                        route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0);
                        route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0);
-               
+
+               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
@@ -2182,6 +2213,11 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e
                                                // IPV6 route
                                                if (session[new_s].ipv6prefixlen)
                                                        cache_ipv6map(session[new_s].ipv6route, session[new_s].ipv6prefixlen, new_s);
                                                // IPV6 route
                                                if (session[new_s].ipv6prefixlen)
                                                        cache_ipv6map(session[new_s].ipv6route, session[new_s].ipv6prefixlen, new_s);
+
+                                               if (session[new_s].ipv6address.s6_addr[0])
+                                               {
+                                                       cache_ipv6map(session[new_s].ipv6address, 128, new_s);
+                                               }
                                        }
                                }
                        }
                                        }
                                }
                        }
@@ -3248,7 +3284,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);
@@ -3427,6 +3463,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)
@@ -5074,9 +5124,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++;
@@ -5116,6 +5166,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");
        {
@@ -5127,7 +5178,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)
@@ -5191,6 +5242,7 @@ int main(int argc, char *argv[])
 
        initrad();
        initippool();
 
        initrad();
        initippool();
+       dhcpv6_init();
 
        // seed prng
        {
 
        // seed prng
        {
@@ -5491,7 +5543,7 @@ static void update_config()
 
                while (*shost && (shost < e))
                {
 
                while (*shost && (shost < e))
                {
-                       while ((n < e) && (*n == ' ' || *n == '\t')) n++;
+                       while ((n < e) && (*n == ' ' || *n == ',' || *n == '\t')) n++;
 
                        i = 0;
                        while (n < e && (*n != ',') && (*n != '\t'))
 
                        i = 0;
                        while (n < e && (*n != ',') && (*n != '\t'))
@@ -5499,6 +5551,7 @@ static void update_config()
                                config->multi_n_hostname[config->nbmultihostname][i] = *n;
                                n++;i++;
                        }
                                config->multi_n_hostname[config->nbmultihostname][i] = *n;
                                n++;i++;
                        }
+
                        if (i > 0)
                        {
                                config->multi_n_hostname[config->nbmultihostname][i] = 0;
                        if (i > 0)
                        {
                                config->multi_n_hostname[config->nbmultihostname][i] = 0;
@@ -5842,6 +5895,15 @@ int load_session(sessionidt s, sessiont *new)
                                uncache_ipmap(session[s].ip);
                }
 
                                uncache_ipmap(session[s].ip);
                }
 
+               // remove old IPV6 routes...
+               if (session[s].ipv6route.s6_addr[0] && session[s].ipv6prefixlen)
+                       route6set(s, session[s].ipv6route, session[s].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...
@@ -5869,7 +5931,14 @@ int load_session(sessionidt s, sessiont *new)
 
        // check v6 routing
        if (new->ipv6prefixlen && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
 
        // check v6 routing
        if (new->ipv6prefixlen && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
-                   route6set(s, new->ipv6route, new->ipv6prefixlen, 1);
+               route6set(s, new->ipv6route, new->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]))
@@ -6316,7 +6385,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;
@@ -6354,7 +6423,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;