diff options
author | Denys Smirnov <denis.smirnov.91@gmail.com> | 2019-04-14 21:25:40 +0300 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2019-04-15 12:38:42 +0200 |
commit | 089574cbfd85530ea9ebe7d11bc293598142e41c (patch) | |
tree | c346504b80c87d308e67e915d012075a4808beea | |
parent | eac34241a43d1169c124998ca1a9a9f3f14d795b (diff) |
Negotiate the protocol using ALPN (C-H only).
-rw-r--r-- | src/cc.c | 6 | ||||
-rw-r--r-- | src/hub.c | 12 | ||||
-rw-r--r-- | src/net.c | 39 |
3 files changed, 48 insertions, 9 deletions
@@ -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; @@ -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; @@ -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); |