Fix: Tunnel creation does not work when the length of the hostname is odd. (revert...
[l2tpns.git] / l2tpns.c
index 0da9a24..8fca167 100644 (file)
--- a/l2tpns.c
+++ b/l2tpns.c
@@ -190,7 +190,9 @@ config_descriptt config_values[] = {
        CONFIG("pppoe_if_to_bind", pppoe_if_to_bind, STRING),
        CONFIG("pppoe_service_name", pppoe_service_name, STRING),
        CONFIG("pppoe_ac_name", pppoe_ac_name, STRING),
-       { NULL, 0, 0, 0 },
+       CONFIG("disable_sending_hello", disable_sending_hello, BOOL),
+       CONFIG("disable_no_spoof", disable_no_spoof, BOOL),
+       { NULL, 0, 0, 0 }
 };
 
 static char *plugin_functions[] = {
@@ -1624,17 +1626,15 @@ void processipout(uint8_t *buf, int len)
                else
                {
                        // Send it as one frame (NO MPPP Frame)
-                       uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, 0, 0);
-                       if (!p) return;
-                       tunnelsend(fragbuf, len + (p-fragbuf), t); // send it...
+                       uint8_t *p = opt_makeppp(buf, len, s, t, PPPIP, 0, 0, 0);
+                       tunnelsend(p, len + (buf-p), t); // send it...
                        update_session_out_stat(s, sp, len);
                }
        }
        else
        {
-               uint8_t *p = makeppp(fragbuf, sizeof(fragbuf), buf, len, s, t, PPPIP, 0, 0, 0);
-               if (!p) return;
-               tunnelsend(fragbuf, len + (p-fragbuf), t); // send it...
+               uint8_t *p = opt_makeppp(buf, len, s, t, PPPIP, 0, 0, 0);
+               tunnelsend(p, len + (buf-p), t); // send it...
                update_session_out_stat(s, sp, len);
        }
 
@@ -1819,10 +1819,10 @@ 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);
-       c->buf16[c->length/2 + 0] = htons(l);
-       c->buf16[c->length/2 + 1] = htons(0);
-       c->buf16[c->length/2 + 2] = htons(avp);
-       c->buf16[c->length/2 + 3] = htons(val);
+       *(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);
        c->length += 8;
 }
 
@@ -1830,10 +1830,10 @@ 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);
-       c->buf16[c->length/2 + 0] = htons(l);
-       c->buf16[c->length/2 + 1] = htons(0);
-       c->buf16[c->length/2 + 2] = htons(avp);
-       *(uint32_t *) &c->buf[c->length + 6] = htonl(val);
+       *(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);
        c->length += 10;
 }
 
@@ -1841,10 +1841,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);
-       c->buf16[c->length/2 + 0] = htons(l);
-       c->buf16[c->length/2 + 1] = htons(0);
-       c->buf16[c->length/2 + 2] = htons(avp);
-       memcpy(&c->buf[c->length + 6], val, strlen(val));
+       *(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);
+       memcpy(c->buf + c->length + 6, val, strlen(val));
        c->length += 6 + strlen(val);
 }
 
@@ -1852,10 +1852,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);
-       c->buf16[c->length/2 + 0] = htons(l);
-       c->buf16[c->length/2 + 1] = htons(0);
-       c->buf16[c->length/2 + 2] = htons(avp);
-       memcpy(&c->buf[c->length + 6], val, len);
+       *(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);
+       memcpy(c->buf + c->length + 6, val, len);
        c->length += 6 + len;
 }
 
@@ -1872,7 +1872,7 @@ static controlt *controlnew(uint16_t mtype)
        }
        assert(c);
        c->next = 0;
-       c->buf16[0] = htons(0xC802); // flags/ver
+       *(uint16_t *) (c->buf + 0) = htons(0xC802); // flags/ver
        c->length = 12;
        control16(c, 0, mtype, 1);
        return c;
@@ -1882,26 +1882,26 @@ static controlt *controlnew(uint16_t mtype)
 // (ZLB send).
 static void controlnull(tunnelidt t)
 {
-       uint16_t buf[6];
+       uint8_t buf[12];
        if (tunnel[t].controlc) // Messages queued; They will carry the ack.
                return;
 
-       buf[0] = htons(0xC802); // flags/ver
-       buf[1] = htons(12); // length
-       buf[2] = htons(tunnel[t].far); // tunnel
-       buf[3] = htons(0); // session
-       buf[4] = htons(tunnel[t].ns); // sequence
-       buf[5] = htons(tunnel[t].nr); // sequence
-       tunnelsend((uint8_t *)buf, 12, t);
+       *(uint16_t *) (buf + 0) = htons(0xC802); // flags/ver
+       *(uint16_t *) (buf + 2) = htons(12); // length
+       *(uint16_t *) (buf + 4) = htons(tunnel[t].far); // tunnel
+       *(uint16_t *) (buf + 6) = htons(0); // session
+       *(uint16_t *) (buf + 8) = htons(tunnel[t].ns); // sequence
+       *(uint16_t *) (buf + 10) = htons(tunnel[t].nr); // sequence
+       tunnelsend(buf, 12, t);
 }
 
 // add a control message to a tunnel, and send if within window
 static void controladd(controlt *c, sessionidt far, tunnelidt t)
 {
-       c->buf16[1] = htons(c->length); // length
-       c->buf16[2] = htons(tunnel[t].far); // tunnel
-       c->buf16[3] = htons(far); // session
-       c->buf16[4] = htons(tunnel[t].ns); // sequence
+       *(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
        tunnel[t].ns++;              // advance sequence
        // link in message in to queue
        if (tunnel[t].controlc)
@@ -2026,7 +2026,6 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e
                struct param_kill_session data = { &tunnel[session[s].tunnel], &session[s] };
                LOG(2, s, session[s].tunnel, "Shutting down session %u: %s\n", s, reason);
                run_plugins(PLUGIN_KILL_SESSION, &data);
-               session[s].die = TIME + 150; // Clean up in 15 seconds
        }
 
        if (session[s].ip && !walled_garden && !session[s].die)
@@ -2051,6 +2050,9 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e
                        memcpy(&shut_acct[shut_acct_n++], &session[s], sizeof(session[s]));
        }
 
+       if (!session[s].die)
+               session[s].die = TIME + 150; // Clean up in 15 seconds
+
        if (session[s].ip)
        {                          // IP allocated, clear and unroute
                int r;
@@ -2150,15 +2152,14 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e
                        pppoe_shutdown_session(s);
                }
                else
-               {
-                       // Send CDN
+               {       // Send CDN
                        controlt *c = controlnew(14); // sending CDN
                        if (cdn_error)
                        {
-                               uint16_t buf[2];
-                               buf[0] = htons(cdn_result);
-                               buf[1] = htons(cdn_error);
-                               controlb(c, 1, (uint8_t *)buf, 4, 1);
+                               uint8_t buf[4];
+                               *(uint16_t *) buf     = htons(cdn_result);
+                               *(uint16_t *) (buf+2) = htons(cdn_error);
+                               controlb(c, 1, buf, 4, 1);
                        }
                        else
                                control16(c, 1, cdn_result, 1);
@@ -2360,21 +2361,21 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha
                controlt *c = controlnew(4);    // sending StopCCN
                if (error)
                {
-                       uint16_t buf[32];
+                       uint8_t buf[64];
                        int l = 4;
-                       buf[0] = htons(result);
-                       buf[1] = htons(error);
+                       *(uint16_t *) buf     = htons(result);
+                       *(uint16_t *) (buf+2) = htons(error);
                        if (msg)
                        {
                                int m = strlen(msg);
                                if (m + 4 > sizeof(buf))
                                    m = sizeof(buf) - 4;
 
-                               memcpy(buf+2, msg, m);
+                               memcpy(buf+4, msg, m);
                                l += m;
                        }
 
-                       controlb(c, 1, (uint8_t *)buf, l, 1);
+                       controlb(c, 1, buf, l, 1);
                }
                else
                        control16(c, 1, result, 1);
@@ -3500,10 +3501,13 @@ static void regular_cleanups(double period)
                // Send hello
                if (tunnel[t].state == TUNNELOPEN && !tunnel[t].controlc && (time_now - tunnel[t].lastrec) > 60)
                {
-                       controlt *c = controlnew(6); // sending HELLO
-                       controladd(c, 0, t); // send the message
-                       LOG(3, 0, t, "Sending HELLO message\n");
-                       t_actions++;
+                       if (!config->disable_sending_hello)
+                       {
+                               controlt *c = controlnew(6); // sending HELLO
+                               controladd(c, 0, t); // send the message
+                               LOG(3, 0, t, "Sending HELLO message\n");
+                               t_actions++;
+                       }
                }
 
                // Check for tunnel changes requested from the CLI
@@ -3963,9 +3967,9 @@ static void mainloop(void)
 {
        int i;
        uint8_t buf[65536];
-       uint8_t *p = buf + 24; // for the hearder of the forwarded MPPP packet (see C_MPPP_FORWARD)
+       uint8_t *p = buf + 32; // for the hearder of the forwarded MPPP packet (see C_MPPP_FORWARD)
                                                // and the forwarded pppoe session
-       int size_bufp = sizeof(buf) - 24;
+       int size_bufp = sizeof(buf) - 32;
        clockt next_cluster_ping = 0;   // send initial ping immediately
        struct epoll_event events[BASE_FDS + RADIUS_FDS + EXTRA_FDS];
        int maxevent = sizeof(events)/sizeof(*events);
@@ -4154,26 +4158,26 @@ static void mainloop(void)
 
                                case FD_TYPE_CONTROL: // nsctl commands
                                        alen = sizeof(addr);
-                                       s = recvfromto(controlfd, buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local);
-                                       if (s > 0) processcontrol(buf, s, &addr, alen, &local);
+                                       s = recvfromto(controlfd, p, size_bufp, MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local);
+                                       if (s > 0) processcontrol(p, s, &addr, alen, &local);
                                        n--;
                                        break;
 
                                case FD_TYPE_DAE: // DAE requests
                                        alen = sizeof(addr);
-                                       s = recvfromto(daefd, buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local);
-                                       if (s > 0) processdae(buf, s, &addr, alen, &local);
+                                       s = recvfromto(daefd, p, size_bufp, MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local);
+                                       if (s > 0) processdae(p, s, &addr, alen, &local);
                                        n--;
                                        break;
 
                                case FD_TYPE_RADIUS: // RADIUS response
                                        alen = sizeof(addr);
-                                       s = recvfrom(radfds[d->index], buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen);
+                                       s = recvfrom(radfds[d->index], p, size_bufp, MSG_WAITALL, (struct sockaddr *) &addr, &alen);
                                        if (s >= 0 && config->cluster_iam_master)
                                        {
                                                if (addr.sin_addr.s_addr == config->radiusserver[0] ||
                                                    addr.sin_addr.s_addr == config->radiusserver[1])
-                                                       processrad(buf, s, d->index);
+                                                       processrad(p, s, d->index);
                                                else
                                                        LOG(3, 0, 0, "Dropping RADIUS packet from unknown source %s\n",
                                                                fmtaddr(addr.sin_addr.s_addr, 0));
@@ -4191,8 +4195,8 @@ static void mainloop(void)
 
                                case FD_TYPE_NETLINK:
                                {
-                                       struct nlmsghdr *nh = (struct nlmsghdr *)buf;
-                                       s = netlink_recv(buf, sizeof(buf));
+                                       struct nlmsghdr *nh = (struct nlmsghdr *)p;
+                                       s = netlink_recv(p, size_bufp);
                                        if (nh->nlmsg_type == NLMSG_ERROR)
                                        {
                                                struct nlmsgerr *errmsg = NLMSG_DATA(nh);
@@ -4313,11 +4317,11 @@ static void mainloop(void)
                        if (c >= config->multi_read_count)
                        {
 #ifdef LAC
-                               LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun %d cluster and %d rmlns packets\n",
-                                       config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts, udplac_pkts);
+                               LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun %d cluster %d rmlns and %d pppoe packets\n",
+                                       config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts, udplac_pkts, pppoesess_pkts);
 #else
-                               LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun and %d cluster packets\n",
-                                       config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts);
+                               LOG(3, 0, 0, "Reached multi_read_count (%d); processed %d udp, %d tun %d cluster and %d pppoe packets\n",
+                                       config->multi_read_count, udp_pkts, tun_pkts, cluster_pkts, pppoesess_pkts);
 #endif
                                STAT(multi_read_exceeded);
                                more++;
@@ -5548,8 +5552,7 @@ int sessionsetup(sessionidt s, tunnelidt t)
 
                        if (ip == session[i].ip)
                        {
-                               sessionkill(i, "Duplicate IP address");
-                               cluster_listinvert_session(s, i);
+                               sessionshutdown(i, "Duplicate IP address", CDN_ADMIN_DISC, TERM_ADMIN_RESET);  // close radius/routes, etc.
                                continue;
                        }
 
@@ -5570,7 +5573,7 @@ int sessionsetup(sessionidt s, tunnelidt t)
 
                        // Drop the new session in case of duplicate sessionss, not the old one.
                        if (!strcasecmp(user, session[i].user))
-                               sessionkill(i, "Duplicate session for users");
+                               sessionshutdown(i, "Duplicate session for users", CDN_ADMIN_DISC, TERM_ADMIN_RESET);  // close radius/routes, etc.
                }
        }