]> git.meshlink.io Git - meshlink/blobdiff - src/protocol_auth.c
Check blacklist status before committing an invitation.
[meshlink] / src / protocol_auth.c
index 6517d9ceef8765bcb5493d03b75daecd98c9865a..e1a9a31341f8b73846628e49509335b1f4c0e511 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "conf.h"
 #include "connection.h"
+#include "devtools.h"
 #include "ecdsa.h"
 #include "edge.h"
 #include "graph.h"
 
 extern bool node_write_devclass(meshlink_handle_t *mesh, node_t *n);
 
-static bool send_proxyrequest(meshlink_handle_t *mesh, connection_t *c) {
-       switch(mesh->proxytype) {
-       case PROXY_HTTP: {
-               char *host;
-               char *port;
-
-               sockaddr2str(&c->address, &host, &port);
-               send_request(mesh, c, NULL, "CONNECT %s:%s HTTP/1.1\r\n\r", host, port);
-               free(host);
-               free(port);
-               return true;
-       }
-
-       case PROXY_SOCKS4: {
-               if(c->address.sa.sa_family != AF_INET) {
-                       logger(mesh, MESHLINK_ERROR, "Cannot connect to an IPv6 host through a SOCKS 4 proxy!");
-                       return false;
-               }
-
-               char s4req[9 + (mesh->proxyuser ? strlen(mesh->proxyuser) : 0)];
-               s4req[0] = 4;
-               s4req[1] = 1;
-               memcpy(s4req + 2, &c->address.in.sin_port, 2);
-               memcpy(s4req + 4, &c->address.in.sin_addr, 4);
-
-               if(mesh->proxyuser) {
-                       memcpy(s4req + 8, mesh->proxyuser, strlen(mesh->proxyuser));
-               }
-
-               s4req[sizeof(s4req) - 1] = 0;
-               c->tcplen = 8;
-               return send_meta(mesh, c, s4req, sizeof(s4req));
-       }
-
-       case PROXY_SOCKS5: {
-               int len = 3 + 6 + (c->address.sa.sa_family == AF_INET ? 4 : 16);
-               c->tcplen = 2;
-
-               if(mesh->proxypass) {
-                       len += 3 + strlen(mesh->proxyuser) + strlen(mesh->proxypass);
-               }
+bool send_id(meshlink_handle_t *mesh, connection_t *c) {
+       return send_request(mesh, c, NULL, "%d %s %d.%d %s", ID, mesh->self->name, PROT_MAJOR, PROT_MINOR, mesh->appname);
+}
 
-               char s5req[len];
-               int i = 0;
-               s5req[i++] = 5;
-               s5req[i++] = 1;
-
-               if(mesh->proxypass) {
-                       s5req[i++] = 2;
-                       s5req[i++] = 1;
-                       s5req[i++] = strlen(mesh->proxyuser);
-                       memcpy(s5req + i, mesh->proxyuser, strlen(mesh->proxyuser));
-                       i += strlen(mesh->proxyuser);
-                       s5req[i++] = strlen(mesh->proxypass);
-                       memcpy(s5req + i, mesh->proxypass, strlen(mesh->proxypass));
-                       i += strlen(mesh->proxypass);
-                       c->tcplen += 2;
-               } else {
-                       s5req[i++] = 0;
-               }
+static bool commit_invitation(meshlink_handle_t *mesh, connection_t *c, const void *data) {
+       // Check if the node is known
+       node_t *n = lookup_node(mesh, c->name);
 
-               s5req[i++] = 5;
-               s5req[i++] = 1;
-               s5req[i++] = 0;
-
-               if(c->address.sa.sa_family == AF_INET) {
-                       s5req[i++] = 1;
-                       memcpy(s5req + i, &c->address.in.sin_addr, 4);
-                       i += 4;
-                       memcpy(s5req + i, &c->address.in.sin_port, 2);
-                       i += 2;
-                       c->tcplen += 10;
-               } else if(c->address.sa.sa_family == AF_INET6) {
-                       s5req[i++] = 3;
-                       memcpy(s5req + i, &c->address.in6.sin6_addr, 16);
-                       i += 16;
-                       memcpy(s5req + i, &c->address.in6.sin6_port, 2);
-                       i += 2;
-                       c->tcplen += 22;
+       if(n) {
+               if(n->status.blacklisted) {
+                       logger(mesh, MESHLINK_ERROR, "Invitee %s is blacklisted", c->name);
                } else {
-                       logger(mesh, MESHLINK_ERROR, "Address family %hx not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
-                       return false;
-               }
-
-               if(i > len) {
-                       abort();
-               }
-
-               return send_meta(mesh, c, s5req, sizeof(s5req));
-       }
-
-       case PROXY_SOCKS4A:
-               logger(mesh, MESHLINK_ERROR, "Proxy type not implemented yet");
-               return false;
-
-       default:
-               logger(mesh, MESHLINK_ERROR, "Unknown proxy type");
-               return false;
-       }
-}
-
-bool send_id(meshlink_handle_t *mesh, connection_t *c) {
-       if(mesh->proxytype && c->outgoing)
-               if(!send_proxyrequest(mesh, c)) {
-                       return false;
+                       logger(mesh, MESHLINK_ERROR, "Invitee %s already known", c->name);
                }
 
-       return send_request(mesh, c, NULL, "%d %s %d.%d %s", ID, mesh->self->name, PROT_MAJOR, PROT_MINOR, mesh->appname);
-}
-
-static bool finalize_invitation(meshlink_handle_t *mesh, connection_t *c, const void *data, uint16_t len) {
-       if(len != 32) {
-               logger(mesh, MESHLINK_ERROR, "Received invalid key from invited node %s!\n", c->name);
                return false;
        }
 
        // Create a new node
-       node_t *n = new_node();
+       n = new_node();
        n->name = xstrdup(c->name);
        n->devclass = DEV_CLASS_UNKNOWN;
        n->ecdsa = ecdsa_set_public_key(data);
@@ -186,22 +89,7 @@ static bool finalize_invitation(meshlink_handle_t *mesh, connection_t *c, const
        return true;
 }
 
-static bool receive_invitation_sptps(void *handle, uint8_t type, const void *data, uint16_t len) {
-       connection_t *c = handle;
-       meshlink_handle_t *mesh = c->mesh;
-
-       if(type == 128) {
-               return true;
-       }
-
-       if(type == 1 && c->status.invitation_used) {
-               return finalize_invitation(mesh, c, data, len);
-       }
-
-       if(type != 0 || len != 18 || c->status.invitation_used) {
-               return false;
-       }
-
+static bool process_invitation(meshlink_handle_t *mesh, connection_t *c, const void *data) {
        // Recover the filename from the cookie and the key
        char *fingerprint = ecdsa_get_base64_public_key(mesh->invitation_key);
        char hash[64];
@@ -248,6 +136,14 @@ static bool receive_invitation_sptps(void *handle, uint8_t type, const void *dat
                }
        }
 
+       if(mesh->inviter_commits_first && !commit_invitation(mesh, c, (const char *)data + 18)) {
+               return false;
+       }
+
+       if(mesh->inviter_commits_first) {
+               devtool_set_inviter_commits_first(true);
+       }
+
        // Send the node the contents of the invitation file
        sptps_send_record(&c->sptps, 0, config.buf, config.len);
 
@@ -259,6 +155,33 @@ static bool receive_invitation_sptps(void *handle, uint8_t type, const void *dat
        return true;
 }
 
+static bool receive_invitation_sptps(void *handle, uint8_t type, const void *data, uint16_t len) {
+       connection_t *c = handle;
+       meshlink_handle_t *mesh = c->mesh;
+
+       // Extend the time for the invitation exchange upon receiving a valid message
+       c->last_ping_time = mesh->loop.now.tv_sec;
+
+       if(type == SPTPS_HANDSHAKE) {
+               // The peer should send its cookie first.
+               return true;
+       }
+
+       if(mesh->inviter_commits_first) {
+               if(type == 2 && len == 18 + 32 && !c->status.invitation_used) {
+                       return process_invitation(mesh, c, data);
+               }
+       } else {
+               if(type == 0 && len == 18 && !c->status.invitation_used) {
+                       return process_invitation(mesh, c, data);
+               } else if(type == 1 && len == 32 && c->status.invitation_used) {
+                       return commit_invitation(mesh, c, data);
+               }
+       }
+
+       return false;
+}
+
 bool id_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
        assert(request);
        assert(*request);
@@ -300,6 +223,7 @@ bool id_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
 
                c->protocol_minor = 2;
                c->allow_request = 1;
+               c->last_ping_time = mesh->loop.now.tv_sec;
 
                return sptps_start(&c->sptps, c, false, false, mesh->invitation_key, c->ecdsa, meshlink_invitation_label, sizeof(meshlink_invitation_label), send_meta_sptps, receive_invitation_sptps);
        }
@@ -368,6 +292,7 @@ bool id_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
        }
 
        c->allow_request = ACK;
+       c->last_ping_time = mesh->loop.now.tv_sec;
        char label[sizeof(meshlink_tcp_label) + strlen(mesh->self->name) + strlen(c->name) + 2];
 
        if(c->outgoing) {
@@ -384,6 +309,7 @@ bool id_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
 }
 
 bool send_ack(meshlink_handle_t *mesh, connection_t *c) {
+       c->last_ping_time = mesh->loop.now.tv_sec;
        return send_request(mesh, c, NULL, "%d %s %d %x", ACK, mesh->myport, mesh->devclass, OPTION_PMTU_DISCOVERY | (PROT_MINOR << 24));
 }
 
@@ -391,7 +317,7 @@ static void send_everything(meshlink_handle_t *mesh, connection_t *c) {
        /* Send all known subnets and edges */
 
        for splay_each(node_t, n, mesh->nodes) {
-               for splay_each(edge_t, e, n->edge_tree) {
+               for inner_splay_each(edge_t, e, n->edge_tree) {
                        send_add_edge(mesh, c, e, 0);
                }
        }
@@ -453,15 +379,40 @@ bool ack_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
        n->last_successfull_connection = mesh->loop.now.tv_sec;
 
        n->connection = c;
+       n->nexthop = n;
        c->node = n;
 
        /* Activate this connection */
 
        c->allow_request = ALL;
+       c->last_key_renewal = mesh->loop.now.tv_sec;
        c->status.active = true;
 
        logger(mesh, MESHLINK_INFO, "Connection with %s activated", c->name);
 
+       if(mesh->meta_status_cb) {
+               mesh->meta_status_cb(mesh, (meshlink_node_t *)n, true);
+       }
+
+       /*  Terminate any connections to this node that are not activated yet */
+
+       for list_each(connection_t, other, mesh->connections) {
+               if(!other->status.active && !strcmp(other->name, c->name)) {
+                       if(other->outgoing) {
+                               if(c->outgoing) {
+                                       logger(mesh, MESHLINK_WARNING, "Two outgoing connections to the same node!");
+                               } else {
+                                       c->outgoing = other->outgoing;
+                               }
+
+                               other->outgoing = NULL;
+                       }
+
+                       logger(mesh, MESHLINK_DEBUG, "Terminating pending second connection with %s", n->name);
+                       terminate_connection(mesh, other, false);
+               }
+       }
+
        /* Send him everything we know */
 
        send_everything(mesh, c);
@@ -477,6 +428,7 @@ bool ack_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
        c->edge->weight = mesh->dev_class_traits[devclass].edge_weight;
        c->edge->connection = c;
 
+       node_add_recent_address(mesh, n, &c->address);
        edge_add(mesh, c->edge);
 
        /* Notify everyone of the new edge */
@@ -487,5 +439,11 @@ bool ack_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
 
        graph(mesh);
 
+       /* Request a session key to jump start UDP traffic */
+
+       if(c->status.initiator) {
+               send_req_key(mesh, n);
+       }
+
        return true;
 }