summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Smirnov <denis.smirnov.91@gmail.com>2019-04-14 21:25:40 +0300
committerYorhel <git@yorhel.nl>2019-04-15 12:38:42 +0200
commit089574cbfd85530ea9ebe7d11bc293598142e41c (patch)
treec346504b80c87d308e67e915d012075a4808beea
parenteac34241a43d1169c124998ca1a9a9f3f14d795b (diff)
Negotiate the protocol using ALPN (C-H only).
-rw-r--r--src/cc.c6
-rw-r--r--src/hub.c12
-rw-r--r--src/net.c39
3 files changed, 48 insertions, 9 deletions
diff --git a/src/cc.c b/src/cc.c
index a5f7cae..0312e2c 100644
--- a/src/cc.c
+++ b/src/cc.c
@@ -1351,7 +1351,7 @@ cc_t *cc_create(hub_t *hub) {
// Simply stores the keyprint of the certificate in cc->kp_real, it will be
// checked when receiving CINF.
-static void handle_handshake(net_t *n, const char *kpr) {
+static void handle_handshake(net_t *n, const char *kpr, int proto) {
cc_t *c = net_handle(n);
if(kpr) {
if(!c->kp_real)
@@ -1375,7 +1375,7 @@ static void handle_connect(net_t *n, const char *addr) {
}
if(cc->tls)
- net_settls(cc->net, FALSE, handle_handshake);
+ net_settls(cc->net, FALSE, FALSE, handle_handshake);
if(!net_is_connected(cc->net))
return;
@@ -1445,7 +1445,7 @@ static void handle_detectprotocol(net_t *net, char *dat, int len) {
// Enable TLS
if(!cc->tls && *dat >= 0x14 && *dat <= 0x17) {
cc->tls = TRUE;
- net_settls(cc->net, TRUE, handle_handshake);
+ net_settls(cc->net, TRUE, FALSE, handle_handshake);
if(net_is_connected(cc->net))
net_peekbytes(cc->net, 1, handle_detectprotocol); // Queue another detectprotocol to detect NMDC/ADC
return;
diff --git a/src/hub.c b/src/hub.c
index 044ea00..508a134 100644
--- a/src/hub.c
+++ b/src/hub.c
@@ -1854,11 +1854,19 @@ hub_t *hub_create(ui_tab_t *tab) {
}
-static void handle_handshake(net_t *n, const char *kpr) {
+static void handle_handshake(net_t *n, const char *kpr, int proto) {
g_return_if_fail(kpr != NULL);
hub_t *hub = net_handle(n);
g_return_if_fail(!hub->kp);
+ if(proto == ALPN_NMDC) {
+ hub->adc = FALSE;
+ ui_mf(hub->tab, 0, "ALPN: negotiated NMDC.");
+ } else if(proto == ALPN_ADC) {
+ hub->adc = TRUE;
+ ui_mf(hub->tab, 0, "ALPN: negotiated ADC.");
+ }
+
char kpf[53] = {};
base32_encode_dat(kpr, kpf, 32);
@@ -1903,7 +1911,7 @@ static void handle_connect(net_t *n, const char *addr) {
ui_mf(hub->tab, 0, "Connected to %s.", net_remoteaddr(n));
if(hub->tls)
- net_settls(hub->net, FALSE, handle_handshake);
+ net_settls(hub->net, FALSE, TRUE, handle_handshake);
if(!net_is_connected(hub->net))
return;
diff --git a/src/net.c b/src/net.c
index 60e2cfa..f47dd49 100644
--- a/src/net.c
+++ b/src/net.c
@@ -46,6 +46,11 @@ ratecalc_t net_in, net_out;
typedef struct net_t net_t;
+// ALPN protocols
+#define ALPN_DEFAULT 0 // default, no ALPN
+#define ALPN_NMDC 1
+#define ALPN_ADC 2
+
#endif
@@ -73,7 +78,7 @@ struct net_t {
char laddr[40]; // state ASY,SYN,DIS, ip only
gnutls_session_t tls; // state ASY,SYN,DIS (only if tls is enabled)
- void (*cb_handshake)(net_t *, const char *); // state ASY, called after complete handshake.
+ void (*cb_handshake)(net_t *, const char *, int); // state ASY, called after complete handshake.
void (*cb_shutdown)(net_t *); // state DIS, called after complete disconnect.
gboolean v6 : 4; // state ASY,SYN, whether we're on IPv6
@@ -753,7 +758,6 @@ static gboolean asy_write(net_t *n) {
return TRUE;
}
-
static gboolean asy_handshake(net_t *n) {
if(!n->tls_handshake)
return TRUE;
@@ -772,9 +776,24 @@ static gboolean asy_handshake(net_t *n) {
g_debug("%s: TLS Handshake successful, KP=SHA256/%s", net_remoteaddr(n), kpf);
n->tls_handshake = FALSE;
gboolean ret = TRUE;
+
+ int alpn_selected = ALPN_DEFAULT;
+
+#if GNUTLS_VERSION_NUMBER >= 0x030200
+ gnutls_datum_t neg;
+ if(gnutls_alpn_get_selected_protocol(n->tls, &neg) == GNUTLS_E_SUCCESS) {
+ g_debug("%s: ALPN negotiated: %.*s", net_remoteaddr(n), (int)neg.size, neg.data);
+ if (neg.size == 3 && !memcmp(neg.data, "adc", neg.size)) {
+ alpn_selected = ALPN_ADC;
+ } else if (neg.size == 4 && !memcmp(neg.data, "nmdc", neg.size)) {
+ alpn_selected = ALPN_NMDC;
+ }
+ }
+#endif
+
if(n->cb_handshake) {
net_ref(n);
- n->cb_handshake(n, *kpf ? kpr : NULL);
+ n->cb_handshake(n, *kpf ? kpr : NULL, alpn_selected);
n->cb_handshake = NULL;
ret = n->state == NETST_ASY;
net_unref(n);
@@ -969,6 +988,12 @@ void net_shutdown(net_t *n, void(*cb)(net_t *)) {
dis_shutdown(n);
}
+#if GNUTLS_VERSION_NUMBER >= 0x030200
+static const gnutls_datum_t alpn_protos[2] = {
+ { (unsigned char *)"adc", 3 },
+ { (unsigned char *)"nmdc", 4 }
+};
+#endif
// Enables TLS-mode and initates the handshake. May not be called when there's
// something in the write buffer. If the read buffer is not empty, its contents
@@ -978,7 +1003,7 @@ void net_shutdown(net_t *n, void(*cb)(net_t *)) {
// be sent as first argument. NULL otherwise.
// Once TLS is enabled, it's not possible to switch back to a raw connection
// again.
-void net_settls(net_t *n, gboolean serv, void (*cb)(net_t *, const char *)) {
+void net_settls(net_t *n, gboolean serv, gboolean negotiate, void (*cb)(net_t *, const char *, int)) {
g_return_if_fail(n->state == NETST_ASY);
g_return_if_fail(!n->wbuf->len);
g_return_if_fail(!n->tls);
@@ -995,6 +1020,12 @@ void net_settls(net_t *n, gboolean serv, void (*cb)(net_t *, const char *)) {
gnutls_transport_set_push_function(n->tls, tls_push);
gnutls_transport_set_pull_function(n->tls, tls_pull);
+#if GNUTLS_VERSION_NUMBER >= 0x030200
+ if(negotiate) {
+ gnutls_alpn_set_protocols(n->tls, alpn_protos, 2, 0);
+ }
+#endif
+
n->cb_handshake = cb;
n->tls_handshake = TRUE;
asy_handshake(n);