X-Git-Url: https://www.tinc-vpn.org/git/browse?a=blobdiff_plain;f=tnl%2Ftnl.c;h=91706b2cd66c482f33d1f3eb1afa976a39b58ae0;hb=942ee816b88f9c35b456abab1864e5e2b811e5c8;hp=5a767f52f0f2fc1c9240180c022fff421f38f329;hpb=7d12cbb6e6acebbe8f9bcab75f5ec878a3360eb9;p=tinc diff --git a/tnl/tnl.c b/tnl/tnl.c index 5a767f52..91706b2c 100644 --- a/tnl/tnl.c +++ b/tnl/tnl.c @@ -29,28 +29,7 @@ #include "support/xalloc.h" #include "tnl/tnl.h" -static avl_tree_t *tnls, *listeners; - -bool tnl_init(void) { - tnls = avl_tree_new(NULL, (avl_action_t)free); - listeners = avl_tree_new(NULL, (avl_action_t)free); - - return true; -} - -bool tnl_exit(void) { - avl_tree_del(listeners); - avl_tree_del(tnls); - - return true; -} - -#define tnl_add(t) avl_add(tnls, t) -#define tnl_del(t) avl_del(tnls, t) -#define tnl_listen_add(l) avl_add(listeners, l) -#define tnl_listen_del(l) avl_del(listeners, l) - -static bool tnl_send(tnl_t *tnl, const char *buf, int len) { +static bool tnl_send(tnl_t *tnl, const void *buf, int len) { int result; while(len) { @@ -139,7 +118,65 @@ static bool tnl_recv_handler(fd_t *fd) { return tnl_recv(tnl); } +static bool tnl_authenticate(tnl_t *tnl) { + gnutls_x509_crt cert; + const gnutls_datum *certs; + int ncerts = 0, result; + char buf[1024], *name, *p; + int len; + + certs = gnutls_certificate_get_peers(tnl->session, &ncerts); + + if (!certs || !ncerts) { + logger(LOG_ERR, _("tnl: no certificates from %s"), tnl->remote.hostname); + return false; + } + + len = sizeof buf; + gnutls_x509_crt_init(&cert); + result = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_DER) ?: gnutls_x509_crt_get_dn(cert, buf, &len); + + if(result) { + logger(LOG_ERR, _("tnl: error importing certificate from %s: %s"), tnl->remote.hostname, gnutls_strerror(errno)); + gnutls_x509_crt_deinit(cert); + return false; + } + + name = strstr(buf, "CN="); + if(!name) { + logger(LOG_ERR, _("tnl: no name in certificate from %s"), tnl->remote.hostname); + gnutls_x509_crt_deinit(cert); + return false; + } + + name += 3; + for(p = name; *p && *p != ','; p++); + *p = '\0'; + + if(tnl->remote.id && strcmp(tnl->remote.id, name)) { + logger(LOG_ERR, _("tnl: peer %s is %s instead of %s"), tnl->remote.hostname, name, tnl->remote.id); + return false; + } + + replace(tnl->remote.id, name); + + result = gnutls_certificate_verify_peers(tnl->session); + + if(result < 0) { + logger(LOG_ERR, "tnl: error verifying certificate from %s (%s): %s\n", tnl->remote.id, tnl->remote.hostname, gnutls_strerror(result)); + return false; + } + + if(result) { + logger(LOG_ERR, "tnl: certificate from %s (%s) not good, verification result %x", tnl->remote.id, tnl->remote.hostname, result); + return false; + } +} + + + static bool tnl_handshake_handler(fd_t *fd) { + char id[1024]; tnl_t *tnl = fd->data; int result; @@ -157,41 +194,31 @@ static bool tnl_handshake_handler(fd_t *fd) { logger(LOG_DEBUG, _("tnl: handshake finished")); - result = gnutls_certificate_verify_peers(tnl->session); - if(result < 0) { - logger(LOG_ERR, "tnl: certificate error: %s\n", gnutls_strerror(result)); - tnl->close(tnl); - return false; - } - - if(result) { - logger(LOG_ERR, "tnl: certificate not good, verification result %x", result); - tnl->close(tnl); + if(!tnl_authenticate(tnl)) return false; - } tnl->status == TNL_STATUS_UP; - tnl->fd.handler = tnl_recv_handler; + tnl->fd.read = tnl_recv_handler; tnl->accept(tnl); return true; } -static bool tnl_send_meta(tnl_t *tnl, const char *buf, int len) { +static bool tnl_send_meta(tnl_t *tnl, const void *buf, int len) { tnl_record_t record = { .type = TNL_RECORD_META, .len = len, }; - return tnl_send(tnl, (char *)&record, sizeof(record)) && tnl_send(tnl, buf, len); + return tnl_send(tnl, &record, sizeof record) && tnl_send(tnl, buf, len); } -static bool tnl_send_packet(tnl_t *tnl, const char *buf, int len) { +static bool tnl_send_packet(tnl_t *tnl, const void *buf, int len) { tnl_record_t record = { .type = TNL_RECORD_PACKET, .len = len, }; - return tnl_send(tnl, (char *)&record, sizeof(record)) && tnl_send(tnl, buf, len); + return tnl_send(tnl, &record, sizeof record) && tnl_send(tnl, buf, len); } static bool tnl_close(tnl_t *tnl) { @@ -203,8 +230,6 @@ static bool tnl_close(tnl_t *tnl) { fd_del(&tnl->fd); close(tnl->fd.fd); - tnl_del(tnl); - return true; } @@ -231,7 +256,7 @@ static bool tnl_accept_handler(fd_t *fd) { sa_unmap(&ss); - new(tnl); + clear(new(tnl)); tnl->local = listener->local; tnl->remote.address = ss; len = sizeof tnl->local.address; @@ -244,14 +269,11 @@ static bool tnl_accept_handler(fd_t *fd) { tnl->close = tnl_close; tnl->fd.fd = sock; - tnl->fd.mode = FD_MODE_READ; - tnl->fd.handler = tnl_handshake_handler; + tnl->fd.read = tnl_handshake_handler; tnl->fd.data = tnl; fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK); - tnl_add(tnl); - gnutls_init(&tnl->session, GNUTLS_SERVER); //gnutls_handshake_set_private_extensions(tnl->session, 1); gnutls_set_default_priority(tnl->session); @@ -281,8 +303,6 @@ static bool tnl_connect_handler(fd_t *fd) { return false; } - fd_del(&tnl->fd); - fcntl(tnl->fd.fd, F_SETFL, fcntl(tnl->fd.fd, F_GETFL) | O_NONBLOCK); tnl->status = TNL_STATUS_HANDSHAKE; @@ -294,9 +314,9 @@ static bool tnl_connect_handler(fd_t *fd) { gnutls_transport_set_ptr(tnl->session, (gnutls_transport_ptr)fd->fd); gnutls_handshake(tnl->session); - tnl->fd.mode = FD_MODE_READ; - tnl->fd.handler = tnl_handshake_handler; - fd_add(&tnl->fd); + tnl->fd.write = NULL; + tnl->fd.read = tnl_handshake_handler; + fd_mod(&tnl->fd); logger(LOG_DEBUG, _("tnl: connected")); @@ -330,17 +350,13 @@ bool tnl_connect(tnl_t *tnl) { tnl->status = TNL_STATUS_CONNECTING; tnl->fd.fd = sock; - tnl->fd.mode = FD_MODE_WRITE; - tnl->fd.handler = tnl_connect_handler; + tnl->fd.write = tnl_connect_handler; tnl->fd.data = tnl; tnl->send_packet = tnl_send_packet; tnl->send_meta = tnl_send_meta; tnl->close = tnl_close; - tnl_add(tnl); - - fd_add(&tnl->fd); return true; @@ -349,7 +365,6 @@ bool tnl_connect(tnl_t *tnl) { static bool tnl_listen_close(tnl_listen_t *listener) { fd_del(&listener->fd); close(listener->fd.fd); - tnl_listen_del(listener); return true; } @@ -374,12 +389,10 @@ bool tnl_listen(tnl_listen_t *listener) { } listener->fd.fd = sock; - listener->fd.mode = FD_MODE_READ; - listener->fd.handler = tnl_accept_handler; + listener->fd.read = tnl_accept_handler; listener->fd.data = listener; listener->close = tnl_listen_close; - tnl_listen_add(listener); fd_add(&listener->fd); return true;