mirror of https://github.com/getdnsapi/getdns.git
alpn determines DoH upstream
This commit is contained in:
parent
ca416a8f9b
commit
7deed7e1d4
168
src/context.c
168
src/context.c
|
@ -91,9 +91,11 @@ typedef unsigned short in_port_t;
|
|||
#define GETDNS_PORT_ZERO 0
|
||||
#define GETDNS_PORT_DNS 53
|
||||
#define GETDNS_PORT_DNS_OVER_TLS 853
|
||||
#define GETDNS_PORT_DNS_OVER_HTTPS 443
|
||||
#define GETDNS_STR_PORT_ZERO "0"
|
||||
#define GETDNS_STR_PORT_DNS "53"
|
||||
#define GETDNS_STR_PORT_DNS_OVER_TLS "853"
|
||||
#define GETDNS_STR_PORT_DNS_OVER_HTTPS "443"
|
||||
|
||||
#ifdef HAVE_PTHREAD
|
||||
static pthread_mutex_t ssl_init_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
@ -135,7 +137,7 @@ getdns_port_array[GETDNS_UPSTREAM_TRANSPORTS] = {
|
|||
};
|
||||
|
||||
static char*
|
||||
getdns_port_str_array[] = {
|
||||
getdns_port_str_array[GETDNS_UPSTREAM_TRANSPORTS] = {
|
||||
GETDNS_STR_PORT_DNS,
|
||||
GETDNS_STR_PORT_DNS_OVER_TLS
|
||||
};
|
||||
|
@ -978,6 +980,8 @@ upstream_init(getdns_upstream *upstream,
|
|||
upstream->best_tls_auth_state = GETDNS_AUTH_NONE;
|
||||
upstream->tls_pubkey_pinset = NULL;
|
||||
upstream->tls_dane_records = NULL;
|
||||
upstream->alpn = NULL;
|
||||
upstream->doh_path[0] = '\0';
|
||||
upstream->loop = NULL;
|
||||
(void) getdns_eventloop_event_init(
|
||||
&upstream->event, upstream, NULL, NULL, NULL);
|
||||
|
@ -2885,6 +2889,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
|||
getdns_bindata *address_type;
|
||||
getdns_bindata *address_data;
|
||||
getdns_bindata *tls_auth_name;
|
||||
getdns_bindata *doh_path;
|
||||
struct sockaddr_storage addr;
|
||||
|
||||
getdns_bindata *scope_id;
|
||||
|
@ -3022,17 +3027,30 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
|||
for (j = 0; j < GETDNS_UPSTREAM_TRANSPORTS; j++) {
|
||||
uint32_t port;
|
||||
struct addrinfo *ai;
|
||||
getdns_bindata *alpn = NULL;
|
||||
|
||||
static const char *alpn_dot = "dot";
|
||||
static const char *alpn_h2 = "h2";
|
||||
|
||||
port = getdns_port_array[j];
|
||||
if (port == GETDNS_PORT_ZERO)
|
||||
continue;
|
||||
|
||||
if (getdns_upstream_transports[j] != GETDNS_TRANSPORT_TLS) {
|
||||
if (dict)
|
||||
(void) getdns_dict_get_int(dict, "port", &port);
|
||||
} else {
|
||||
if (dict)
|
||||
(void) getdns_dict_get_int(dict, "tls_port", &port);
|
||||
}
|
||||
if (!dict)
|
||||
; /* pass */
|
||||
|
||||
else if (getdns_upstream_transports[j]
|
||||
!= GETDNS_TRANSPORT_TLS)
|
||||
getdns_dict_get_int(dict, "port", &port);
|
||||
|
||||
else if (!getdns_dict_get_bindata(dict, "alpn", &alpn)
|
||||
&& alpn->size == 2 && alpn->data[0] == 'h'
|
||||
&& alpn->data[1] == '2') {
|
||||
port = GETDNS_PORT_DNS_OVER_HTTPS;
|
||||
getdns_dict_get_int(dict, "tls_port", &port);
|
||||
} else
|
||||
getdns_dict_get_int(dict, "tls_port", &port);
|
||||
|
||||
(void) snprintf(portstr, 1024, "%d", (int)port);
|
||||
|
||||
if (getaddrinfo(addrstr, portstr, &hints, &ai))
|
||||
|
@ -3048,7 +3066,21 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
|||
upstream->addr.ss_family = addr.ss_family;
|
||||
upstream_init(upstream, upstreams, ai);
|
||||
upstream->transport = getdns_upstream_transports[j];
|
||||
if (dict && getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS) {
|
||||
if (!alpn)
|
||||
; /* pass */
|
||||
|
||||
else if (alpn->size == 3 && alpn->data[0] == 'd'
|
||||
&& alpn->data[1] == 'o' && alpn->data[2] == 't')
|
||||
upstream->alpn = alpn_dot;
|
||||
|
||||
else if (alpn->size == 2 && alpn->data[0] == 'h'
|
||||
&& alpn->data[1] == '2')
|
||||
upstream->alpn = alpn_h2;
|
||||
else
|
||||
goto invalid_parameter;
|
||||
|
||||
if (dict && getdns_upstream_transports[j] ==
|
||||
GETDNS_TRANSPORT_TLS) {
|
||||
getdns_list *pubkey_pinset = NULL;
|
||||
getdns_list *dane_records = NULL;
|
||||
getdns_bindata *tls_cipher_list = NULL;
|
||||
|
@ -3078,6 +3110,19 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
|||
upstream->tls_auth_name
|
||||
[tls_auth_name->size] = '\0';
|
||||
}
|
||||
if ((r = getdns_dict_get_bindata(
|
||||
dict, "doh_path", &doh_path)) == GETDNS_RETURN_GOOD) {
|
||||
|
||||
if (doh_path->size >= sizeof(upstream->doh_path)) {
|
||||
freeaddrinfo(ai);
|
||||
goto invalid_parameter;
|
||||
}
|
||||
memcpy(upstream->doh_path,
|
||||
(char *)doh_path->data,
|
||||
doh_path->size);
|
||||
upstream->doh_path
|
||||
[doh_path->size] = '\0';
|
||||
}
|
||||
if ((r = getdns_dict_get_list(dict, "tls_pubkey_pinset",
|
||||
&pubkey_pinset)) == GETDNS_RETURN_GOOD) {
|
||||
/* TODO: what if the user supplies tls_pubkey_pinset with
|
||||
|
@ -5396,52 +5441,71 @@ getdns_context_get_upstream_recursive_servers(
|
|||
(uint32_t)upstream_port(upstream))))
|
||||
break;
|
||||
|
||||
if (upstream->transport == GETDNS_TRANSPORT_TLS) {
|
||||
if (upstream_port(upstream) != getdns_port_array[j] &&
|
||||
(r = getdns_dict_set_int(d, "tls_port",
|
||||
(uint32_t) upstream_port(upstream))))
|
||||
if (upstream->transport != GETDNS_TRANSPORT_TLS)
|
||||
continue;
|
||||
|
||||
if (!is_doh_upstream(upstream)
|
||||
&& upstream_port(upstream) != GETDNS_PORT_DNS_OVER_TLS
|
||||
&& (r = getdns_dict_set_int(d, "tls_port",
|
||||
(uint32_t) upstream_port(upstream))))
|
||||
break;
|
||||
|
||||
if (is_doh_upstream(upstream)
|
||||
&& upstream_port(upstream) != GETDNS_PORT_DNS_OVER_HTTPS
|
||||
&& (r = getdns_dict_set_int(d, "tls_port",
|
||||
(uint32_t) upstream_port(upstream))))
|
||||
break;
|
||||
|
||||
if (upstream->alpn
|
||||
&& (r = getdns_dict_util_set_string(
|
||||
d, "alpn", upstream->alpn)))
|
||||
break;
|
||||
|
||||
if (upstream->tls_auth_name[0] != '\0' &&
|
||||
(r = getdns_dict_util_set_string(d,
|
||||
"tls_auth_name",
|
||||
upstream->tls_auth_name)))
|
||||
break;
|
||||
if (upstream->tls_pubkey_pinset) {
|
||||
getdns_list *pins = NULL;
|
||||
if ((_getdns_get_pubkey_pinset_list(context,
|
||||
upstream->tls_pubkey_pinset,
|
||||
&pins) == GETDNS_RETURN_GOOD) &&
|
||||
(r = _getdns_dict_set_this_list(d, "tls_pubkey_pinset", pins))) {
|
||||
getdns_list_destroy(pins);
|
||||
break;
|
||||
if (upstream->tls_auth_name[0] != '\0' &&
|
||||
(r = getdns_dict_util_set_string(d,
|
||||
"tls_auth_name",
|
||||
upstream->tls_auth_name)))
|
||||
break;
|
||||
if (upstream->tls_pubkey_pinset) {
|
||||
getdns_list *pins = NULL;
|
||||
if ((_getdns_get_pubkey_pinset_list(context,
|
||||
upstream->tls_pubkey_pinset,
|
||||
&pins) == GETDNS_RETURN_GOOD) &&
|
||||
(r = _getdns_dict_set_this_list(d, "tls_pubkey_pinset", pins))) {
|
||||
getdns_list_destroy(pins);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (upstream->tls_cipher_list) {
|
||||
(void) getdns_dict_util_set_string(
|
||||
d, "tls_cipher_list",
|
||||
upstream->tls_cipher_list);
|
||||
}
|
||||
if (upstream->tls_ciphersuites) {
|
||||
(void) getdns_dict_util_set_string(
|
||||
d, "tls_ciphersuites",
|
||||
upstream->tls_ciphersuites);
|
||||
}
|
||||
if (upstream->tls_curves_list) {
|
||||
(void) getdns_dict_util_set_string(
|
||||
d, "tls_curves_list",
|
||||
upstream->tls_curves_list);
|
||||
}
|
||||
if (upstream->tls_min_version) {
|
||||
(void) getdns_dict_set_int(
|
||||
d, "tls_min_version",
|
||||
upstream->tls_min_version);
|
||||
}
|
||||
if (upstream->tls_max_version) {
|
||||
(void) getdns_dict_set_int(
|
||||
d, "tls_max_version",
|
||||
upstream->tls_max_version);
|
||||
}
|
||||
}
|
||||
if (upstream->tls_cipher_list) {
|
||||
(void) getdns_dict_util_set_string(
|
||||
d, "tls_cipher_list",
|
||||
upstream->tls_cipher_list);
|
||||
}
|
||||
if (upstream->tls_ciphersuites) {
|
||||
(void) getdns_dict_util_set_string(
|
||||
d, "tls_ciphersuites",
|
||||
upstream->tls_ciphersuites);
|
||||
}
|
||||
if (upstream->tls_curves_list) {
|
||||
(void) getdns_dict_util_set_string(
|
||||
d, "tls_curves_list",
|
||||
upstream->tls_curves_list);
|
||||
}
|
||||
if (upstream->tls_min_version) {
|
||||
(void) getdns_dict_set_int(
|
||||
d, "tls_min_version",
|
||||
upstream->tls_min_version);
|
||||
}
|
||||
if (upstream->tls_max_version) {
|
||||
(void) getdns_dict_set_int(
|
||||
d, "tls_max_version",
|
||||
upstream->tls_max_version);
|
||||
}
|
||||
if (upstream->doh_path[0] != '\0'
|
||||
&& (r = getdns_dict_util_set_string(
|
||||
d, "doh_path",
|
||||
upstream->doh_path)))
|
||||
break;
|
||||
}
|
||||
if (!r)
|
||||
if (!(r = _getdns_list_append_this_dict(upstreams, d)))
|
||||
|
|
|
@ -230,6 +230,10 @@ typedef struct getdns_upstream {
|
|||
getdns_tls_version_t tls_min_version;
|
||||
getdns_tls_version_t tls_max_version;
|
||||
|
||||
/* DoH settings */
|
||||
const char *alpn;
|
||||
char doh_path[256];
|
||||
|
||||
/* Auth credentials */
|
||||
char tls_auth_name[256];
|
||||
sha256_pin_t *tls_pubkey_pinset;
|
||||
|
@ -271,6 +275,10 @@ typedef struct getdns_upstream {
|
|||
|
||||
} getdns_upstream;
|
||||
|
||||
INLINE int is_doh_upstream(getdns_upstream *u)
|
||||
{ return u && u->alpn && u->alpn[0] == 'h'
|
||||
&& (u->alpn[1] == '2' || u->alpn[1] == '3'); }
|
||||
|
||||
#define POLICY_N_ADDR 3
|
||||
#define POLICY_N_SVCPARAMS 8
|
||||
|
||||
|
|
|
@ -1126,6 +1126,8 @@ _getdns_ipaddr_dict_mf(struct mem_funcs *mf, const char *ipstr)
|
|||
char *p = strchr(ipstr, '@'), *portstr = "";
|
||||
char *t = strchr(ipstr, '#'), *tls_portstr = "";
|
||||
char *n = strchr(ipstr, '~'), *tls_namestr = "";
|
||||
char *P = strchr(ipstr, '/'), *doh_pathstr = "";
|
||||
char *A = strchr(ipstr, '_'), *alpnstr = "";
|
||||
/* ^[alg:]name:key */
|
||||
char *T = strchr(ipstr, '^'), *tsig_name_str = ""
|
||||
, *tsig_secret_str = ""
|
||||
|
@ -1173,6 +1175,14 @@ _getdns_ipaddr_dict_mf(struct mem_funcs *mf, const char *ipstr)
|
|||
*n = 0;
|
||||
tls_namestr = n + 1;
|
||||
}
|
||||
if (P) {
|
||||
*P = 0;
|
||||
doh_pathstr = P + 1;
|
||||
}
|
||||
if (A) {
|
||||
*A = 0;
|
||||
alpnstr = A + 1;
|
||||
}
|
||||
if (T) {
|
||||
*T = 0;
|
||||
tsig_name_str = T + 1;
|
||||
|
@ -1213,9 +1223,12 @@ _getdns_ipaddr_dict_mf(struct mem_funcs *mf, const char *ipstr)
|
|||
getdns_dict_set_int(r, "port", (int32_t)atoi(portstr));
|
||||
if (*tls_portstr)
|
||||
getdns_dict_set_int(r, "tls_port", (int32_t)atoi(tls_portstr));
|
||||
if (*tls_namestr) {
|
||||
if (*tls_namestr)
|
||||
getdns_dict_util_set_string(r, "tls_auth_name", tls_namestr);
|
||||
}
|
||||
if (*doh_pathstr)
|
||||
getdns_dict_util_set_string(r, "doh_path", doh_pathstr);
|
||||
if (*alpnstr)
|
||||
getdns_dict_util_set_string(r, "alpn", alpnstr);
|
||||
if (*scope_id_str)
|
||||
getdns_dict_util_set_string(r, "scope_id", scope_id_str);
|
||||
if (*tsig_name_str)
|
||||
|
|
|
@ -807,6 +807,25 @@ getdns_return_t _getdns_tls_connection_set_curves_list(_getdns_tls_connection* c
|
|||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
getdns_return_t _getdns_tls_connection_set_alpn(_getdns_tls_connection* conn, const char* alpn)
|
||||
{
|
||||
uint8_t protos[] = "\x03" "dot";
|
||||
if (!conn || !conn->ssl)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
if (!alpn)
|
||||
;
|
||||
else if (strlen(alpn) > sizeof(protos) - 2)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
else {
|
||||
strcpy((char *)(protos + 1), alpn);
|
||||
protos[0] = (uint8_t)strlen(alpn);
|
||||
}
|
||||
if (SSL_set_alpn_protos(conn->ssl, protos, protos[0] + 1))
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
else
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
getdns_return_t _getdns_tls_connection_set_session(_getdns_tls_connection* conn, _getdns_tls_session* s)
|
||||
{
|
||||
if (!conn || !conn->ssl || !s || !s->ssl)
|
||||
|
|
|
@ -1006,6 +1006,8 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
|
|||
r = _getdns_tls_connection_set_curves_list(tls, upstream->tls_curves_list);
|
||||
if (!r && upstream->tls_ciphersuites)
|
||||
r = _getdns_tls_connection_set_cipher_suites(tls, upstream->tls_ciphersuites);
|
||||
if (!r)
|
||||
r = _getdns_tls_connection_set_alpn(tls, upstream->alpn);
|
||||
if (!r)
|
||||
r = _getdns_tls_connection_set_min_max_tls_version(tls, upstream->tls_min_version, upstream->tls_max_version);
|
||||
|
||||
|
|
12
src/tls.h
12
src/tls.h
|
@ -227,6 +227,18 @@ getdns_return_t _getdns_tls_connection_set_cipher_list(_getdns_tls_connection* c
|
|||
*/
|
||||
getdns_return_t _getdns_tls_connection_set_cipher_suites(_getdns_tls_connection* conn, const char* list);
|
||||
|
||||
/**
|
||||
* Set alpn to send on this connection.
|
||||
*
|
||||
* @param conn the connection.
|
||||
* @param alpn the application layer protocol negotiation (alpn) value.
|
||||
NULL for default setting (dot).
|
||||
* @return GETDNS_RETURN_GOOD on success.
|
||||
* @return GETDNS_RETURN_INVALID_PARAMETER on bad context pointer.
|
||||
* @return GETDNS_RETURN_BAD_CONTEXT on failure.
|
||||
*/
|
||||
getdns_return_t _getdns_tls_connection_set_alpn(_getdns_tls_connection* conn, const char* alpn);
|
||||
|
||||
/**
|
||||
* Set list of allowed curves on this connection.
|
||||
*
|
||||
|
|
|
@ -178,10 +178,12 @@ print_usage(FILE *out, const char *progname)
|
|||
#endif
|
||||
fprintf(out, "\ndefault mode: " DEFAULT_RESOLUTION_TYPE
|
||||
", synchronous resolution of NS record\n\t\tusing UDP with TCP fallback\n");
|
||||
fprintf(out, "\nupstreams: @<ip>[%%<scope_id>][@<port>][#<tls port>][~<tls name>][^<tsig spec>]");
|
||||
fprintf(out, "\nupstreams: @<ip>[%%<scope_id>][@<port>][^<tsig spec>]");
|
||||
fprintf(out, "\n [#<tls port>][~<tls name>][_<alpn>][/<doh path>]");
|
||||
fprintf(out, "\n <ip>@<port> may be given as <IPv4>:<port>");
|
||||
fprintf(out, "\n or \'[\'<IPv6>[%%<scope_id>]\']\':<port> too\n");
|
||||
fprintf(out, "\ntsig spec: [<algorithm>:]<name>:<secret in Base64>\n");
|
||||
fprintf(out, "\nalpn: [dot | h2]\n");
|
||||
fprintf(out, "\nextensions:\n");
|
||||
fprintf(out, "\t+add_warning_for_bad_dns\n");
|
||||
fprintf(out, "\t+dnssec\n");
|
||||
|
|
Loading…
Reference in New Issue