#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) {
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;
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) {
fd_del(&tnl->fd);
close(tnl->fd.fd);
- tnl_del(tnl);
-
return true;
}
sa_unmap(&ss);
- new(tnl);
+ clear(new(tnl));
tnl->local = listener->local;
tnl->remote.address = ss;
len = sizeof tnl->local.address;
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);
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;
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"));
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;
static bool tnl_listen_close(tnl_listen_t *listener) {
fd_del(&listener->fd);
close(listener->fd.fd);
- tnl_listen_del(listener);
return true;
}
}
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;