mirror of https://github.com/getdnsapi/getdns.git
Fetch and equip context with trust-anchors
This commit is contained in:
parent
742588dd6f
commit
3e6c5775ff
563
src/anchor.c
563
src/anchor.c
|
@ -40,16 +40,20 @@
|
|||
#include <time.h>
|
||||
#include "types-internal.h"
|
||||
#include "context.h"
|
||||
#include "dnssec.h"
|
||||
#include "yxml/yxml.h"
|
||||
#include "gldns/parseutil.h"
|
||||
#include "gldns/gbuffer.h"
|
||||
#include "gldns/str2wire.h"
|
||||
#include "gldns/pkthdr.h"
|
||||
#include "general.h"
|
||||
#include "rr-iter.h"
|
||||
#include "util-internal.h"
|
||||
|
||||
#define P7SIGNER "dnssec@iana.org"
|
||||
|
||||
/* The ICANN CA fetched at 24 Sep 2010. Valid to 2028 */
|
||||
static char* _getdns_builtin_cert =
|
||||
static char _getdns_builtin_cert[] =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIDdzCCAl+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQ4wDAYDVQQKEwVJQ0FO\n"
|
||||
"TjEmMCQGA1UECxMdSUNBTk4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNV\n"
|
||||
|
@ -72,6 +76,9 @@ static char* _getdns_builtin_cert =
|
|||
"j/Br5BZw3X/zd325TvnswzMC1+ljLzHnQGGk\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
static getdns_bindata _getdns_builtin_cert_bd =
|
||||
{ sizeof(_getdns_builtin_cert) - 1, (void *)_getdns_builtin_cert};
|
||||
|
||||
/* get key usage out of its extension, returns 0 if no key_usage extension */
|
||||
static unsigned long
|
||||
_getdns_get_usage_of_ex(X509* cert)
|
||||
|
@ -665,6 +672,79 @@ uint16_t _getdns_parse_xml_trust_anchors_buf(
|
|||
return ta_count;
|
||||
}
|
||||
|
||||
static uint8_t *tas_validate(struct mem_funcs *mf,
|
||||
const getdns_bindata *xml_bd, const getdns_bindata *p7s_bd,
|
||||
const getdns_bindata *crt_bd, const char *p7signer,
|
||||
time_t now, uint8_t *tas, size_t *tas_len)
|
||||
{
|
||||
BIO *xml = NULL, *p7s = NULL, *crt = NULL;
|
||||
X509 *x = NULL;
|
||||
X509_STORE *store = NULL;
|
||||
uint8_t *success = NULL;
|
||||
|
||||
if (!(xml = BIO_new_mem_buf(xml_bd->data, xml_bd->size)))
|
||||
DEBUG_ANCHOR("ERROR %s(): Failed allocating xml BIO\n"
|
||||
, __FUNC__);
|
||||
|
||||
else if (!(p7s = BIO_new_mem_buf(p7s_bd->data, p7s_bd->size)))
|
||||
DEBUG_ANCHOR("ERROR %s(): Failed allocating p7s BIO\n"
|
||||
, __FUNC__);
|
||||
|
||||
else if (!(crt = BIO_new_mem_buf(crt_bd->data, crt_bd->size)))
|
||||
DEBUG_ANCHOR("ERROR %s(): Failed allocating crt BIO\n"
|
||||
, __FUNC__);
|
||||
|
||||
else if (!(x = PEM_read_bio_X509(crt, NULL, 0, NULL)))
|
||||
DEBUG_ANCHOR("ERROR %s(): Parsing builtin certificate\n"
|
||||
, __FUNC__);
|
||||
|
||||
else if (!(store = X509_STORE_new()))
|
||||
DEBUG_ANCHOR("ERROR %s(): Failed allocating store\n"
|
||||
, __FUNC__);
|
||||
|
||||
else if (!X509_STORE_add_cert(store, x))
|
||||
DEBUG_ANCHOR("ERROR %s(): Adding certificate to store\n"
|
||||
, __FUNC__);
|
||||
|
||||
else if (_getdns_verify_p7sig(xml, p7s, store, p7signer)) {
|
||||
gldns_buffer gbuf;
|
||||
|
||||
gldns_buffer_init_vfixed_frm_data(&gbuf, tas, *tas_len);
|
||||
|
||||
if (!_getdns_parse_xml_trust_anchors_buf(&gbuf, now,
|
||||
(char *)xml_bd->data, xml_bd->size))
|
||||
DEBUG_ANCHOR("Failed to parse trust anchor XML data");
|
||||
|
||||
else if (gldns_buffer_position(&gbuf) > *tas_len) {
|
||||
*tas_len = gldns_buffer_position(&gbuf);
|
||||
if ((success = GETDNS_XMALLOC(*mf, uint8_t, *tas_len))) {
|
||||
gldns_buffer_init_frm_data(&gbuf, success, *tas_len);
|
||||
if (!_getdns_parse_xml_trust_anchors_buf(&gbuf,
|
||||
now, (char *)xml_bd->data, xml_bd->size)) {
|
||||
|
||||
DEBUG_ANCHOR("Failed to re-parse trust"
|
||||
" anchor XML data\n");
|
||||
GETDNS_FREE(*mf, success);
|
||||
success = NULL;
|
||||
}
|
||||
} else
|
||||
DEBUG_ANCHOR("Could not allocate space for "
|
||||
"trust anchors\n");
|
||||
} else {
|
||||
success = tas;
|
||||
*tas_len = gldns_buffer_position(&gbuf);
|
||||
}
|
||||
} else {
|
||||
DEBUG_ANCHOR("Verifying trust-anchors failed!\n");
|
||||
}
|
||||
if (store) X509_STORE_free(store);
|
||||
if (x) X509_free(x);
|
||||
if (crt) BIO_free(crt);
|
||||
if (xml) BIO_free(xml);
|
||||
if (p7s) BIO_free(p7s);
|
||||
return success;
|
||||
}
|
||||
|
||||
void _getdns_context_equip_with_anchor(getdns_context *context, time_t now)
|
||||
{
|
||||
uint8_t xml_spc[4096], *xml_data;
|
||||
|
@ -757,4 +837,485 @@ void _getdns_context_equip_with_anchor(getdns_context *context, time_t now)
|
|||
GETDNS_FREE(context->mf, p7s_data);
|
||||
}
|
||||
|
||||
static const uint8_t tas_write_xml_buf[] =
|
||||
"GET /root-anchors/root-anchors.xml HTTP/1.1\r\n"
|
||||
"Host: data.iana.org\r\n"
|
||||
"\r\n";
|
||||
|
||||
static const uint8_t tas_write_p7s_buf[] =
|
||||
"GET /root-anchors/root-anchors.p7s HTTP/1.1\r\n"
|
||||
"Host: data.iana.org\r\n"
|
||||
"\r\n";
|
||||
|
||||
static const uint8_t tas_write_xml_p7s_buf[] =
|
||||
"GET /root-anchors/root-anchors.xml HTTP/1.1\r\n"
|
||||
"Host: data.iana.org\r\n"
|
||||
"\r\n"
|
||||
"GET /root-anchors/root-anchors.p7s HTTP/1.1\r\n"
|
||||
"Host: data.iana.org\r\n"
|
||||
"\r\n";
|
||||
|
||||
|
||||
static inline const char * rt_str(uint16_t rt)
|
||||
{ return rt == GETDNS_RRTYPE_A ? "A" : rt == GETDNS_RRTYPE_AAAA ? "AAAA" : "?"; }
|
||||
|
||||
static int tas_busy(tas_connection *a)
|
||||
{
|
||||
return a->req != NULL;
|
||||
}
|
||||
|
||||
static void tas_cleanup(getdns_context *context, tas_connection *a)
|
||||
{
|
||||
if (a->req)
|
||||
_getdns_context_cancel_request(a->req->owner);
|
||||
if (a->event.ev)
|
||||
GETDNS_CLEAR_EVENT(a->loop, &a->event);
|
||||
if (a->fd >= 0)
|
||||
close(a->fd);
|
||||
if (a->xml.data)
|
||||
GETDNS_FREE(context->mf, a->xml.data);
|
||||
if (a->tcp.read_buf && a->tcp.read_buf != context->tas_hdr_spc)
|
||||
GETDNS_FREE(context->mf, a->tcp.read_buf);
|
||||
(void) memset(a, 0, sizeof(*a));
|
||||
}
|
||||
|
||||
static void tas_success(getdns_context *context, tas_connection *a)
|
||||
{
|
||||
tas_connection *other = &context->a == a ? &context->aaaa : &context->a;
|
||||
|
||||
tas_cleanup(context, a);
|
||||
tas_cleanup(context, other);
|
||||
|
||||
DEBUG_ANCHOR("Successfully fetched new trust anchors\n");
|
||||
context->trust_anchors_source = GETDNS_TASRC_XML;
|
||||
_getdns_ta_notify_dnsreqs(context);
|
||||
}
|
||||
|
||||
static void tas_fail(getdns_context *context, tas_connection *a)
|
||||
{
|
||||
tas_connection *other = &context->a == a ? &context->aaaa : &context->a;
|
||||
uint16_t rt = &context->a == a ? GETDNS_RRTYPE_A : GETDNS_RRTYPE_AAAA;
|
||||
uint16_t ort = rt == GETDNS_RRTYPE_A ? GETDNS_RRTYPE_AAAA : GETDNS_RRTYPE_A;
|
||||
tas_cleanup(context, a);
|
||||
|
||||
if (!tas_busy(other)) {
|
||||
DEBUG_ANCHOR("Fatal error fetching trust anchor: "
|
||||
"%s connection failed too\n", rt_str(rt));
|
||||
context->trust_anchors_source = GETDNS_TASRC_FAILED;
|
||||
_getdns_ta_notify_dnsreqs(context);
|
||||
} else
|
||||
DEBUG_ANCHOR("%s connection failed, waiting for %s\n"
|
||||
, rt_str(rt), rt_str(ort));
|
||||
}
|
||||
|
||||
static void tas_connect(getdns_context *context, tas_connection *a);
|
||||
static void tas_next(getdns_context *context, tas_connection *a)
|
||||
{
|
||||
DEBUG_ANCHOR("Try next address\n");
|
||||
if (!(a->rr = _getdns_rrtype_iter_next(a->rr)))
|
||||
tas_fail(context, a);
|
||||
else tas_connect(context, a);
|
||||
}
|
||||
|
||||
static void tas_timeout_cb(void *userarg)
|
||||
{
|
||||
getdns_dns_req *dnsreq = (getdns_dns_req *)userarg;
|
||||
getdns_context *context = (getdns_context *)dnsreq->user_pointer;
|
||||
tas_connection *a;
|
||||
|
||||
if (dnsreq->netreqs[0]->request_type == GETDNS_RRTYPE_A)
|
||||
a = &context->a;
|
||||
else a = &context->aaaa;
|
||||
|
||||
DEBUG_ANCHOR("Trust anchor fetch timeout\n");
|
||||
GETDNS_CLEAR_EVENT(a->loop, &a->event);
|
||||
tas_next(context, a);
|
||||
}
|
||||
|
||||
static void tas_read_cb(void *userarg);
|
||||
static void tas_write_cb(void *userarg);
|
||||
static void tas_doc_read(getdns_context *context, tas_connection *a)
|
||||
{
|
||||
DEBUG_ANCHOR("doc (size: %d): \"%.*s\"\n",
|
||||
(int)a->tcp.read_buf_len,
|
||||
(int)a->tcp.read_buf_len, (char *)a->tcp.read_buf);
|
||||
if (a->state == TAS_READ_XML_DOC) {
|
||||
if (a->xml.data)
|
||||
GETDNS_FREE(context->mf, a->xml.data);
|
||||
a->xml.data = a->tcp.read_buf;
|
||||
a->xml.size = a->tcp.read_buf_len;
|
||||
}
|
||||
a->state += 1;
|
||||
GETDNS_CLEAR_EVENT(a->loop, &a->event);
|
||||
if (a->state == TAS_DONE) {
|
||||
getdns_bindata p7s_bd;
|
||||
uint8_t *tas = context->trust_anchors_spc;
|
||||
size_t tas_len = sizeof(context->trust_anchors_spc);
|
||||
|
||||
p7s_bd.data = a->tcp.read_buf;
|
||||
p7s_bd.size = a->tcp.read_buf_len;
|
||||
tas = tas_validate(&context->mf, &a->xml, &p7s_bd,
|
||||
&_getdns_builtin_cert_bd, "dnssec@iana.org",
|
||||
time(NULL), tas, &tas_len);
|
||||
|
||||
if (tas) {
|
||||
context->trust_anchors = tas;
|
||||
context->trust_anchors_len = tas_len;
|
||||
/* TODO: Try to write xml & p7s */
|
||||
tas_success(context, a);
|
||||
} else
|
||||
tas_fail(context, a);
|
||||
return;
|
||||
}
|
||||
assert(a->state == TAS_WRITE_GET_PS7);
|
||||
a->tcp.write_buf = tas_write_p7s_buf;
|
||||
a->tcp.write_buf_len = sizeof(tas_write_p7s_buf) - 1;
|
||||
a->tcp.written = 0;
|
||||
|
||||
/* First try to read signatures immediately */
|
||||
a->state += 1;
|
||||
assert(a->state == TAS_READ_PS7_HDR);
|
||||
a->tcp.read_buf = context->tas_hdr_spc;
|
||||
a->tcp.read_buf_len = sizeof(context->tas_hdr_spc);
|
||||
a->tcp.read_pos = a->tcp.read_buf;
|
||||
a->tcp.to_read = sizeof(context->tas_hdr_spc);
|
||||
|
||||
GETDNS_SCHEDULE_EVENT(a->loop, a->fd, 50,
|
||||
getdns_eventloop_event_init(&a->event, a->req->owner,
|
||||
tas_read_cb, NULL, tas_timeout_cb));
|
||||
#if 0
|
||||
GETDNS_SCHEDULE_EVENT(a->loop, a->fd, 2000,
|
||||
getdns_eventloop_event_init(&a->event, a->req->owner,
|
||||
NULL, tas_write_cb, tas_timeout_cb));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
static void tas_read_cb(void *userarg)
|
||||
{
|
||||
getdns_dns_req *dnsreq = (getdns_dns_req *)userarg;
|
||||
getdns_context *context = (getdns_context *)dnsreq->user_pointer;
|
||||
tas_connection *a;
|
||||
ssize_t n, i;
|
||||
|
||||
if (dnsreq->netreqs[0]->request_type == GETDNS_RRTYPE_A)
|
||||
a = &context->a;
|
||||
else a = &context->aaaa;
|
||||
|
||||
DEBUG_ANCHOR( "state: %d, to_read: %d\n"
|
||||
, (int)a->state, (int)a->tcp.to_read);
|
||||
|
||||
n = read(a->fd, a->tcp.read_pos, a->tcp.to_read);
|
||||
if (n >= 0 && ( a->state == TAS_READ_XML_DOC
|
||||
|| a->state == TAS_READ_PS7_DOC)) {
|
||||
|
||||
assert(n <= (ssize_t)a->tcp.to_read);
|
||||
|
||||
DEBUG_ANCHOR("read: %d bytes at %p, for doc %p of size %d\n",
|
||||
(int)n, a->tcp.read_pos, a->tcp.read_buf, (int)a->tcp.read_buf_len);
|
||||
a->tcp.read_pos += n;
|
||||
a->tcp.to_read -= n;
|
||||
if (a->tcp.to_read == 0)
|
||||
tas_doc_read(context, a);
|
||||
return;
|
||||
|
||||
} else if (n >= 0) {
|
||||
ssize_t p = 0;
|
||||
int doc_len = -1;
|
||||
int len;
|
||||
char *ln;
|
||||
char *endptr;
|
||||
|
||||
n += a->tcp.read_pos - a->tcp.read_buf;
|
||||
for (i = 0; i < (n - 1); i++) {
|
||||
if (a->tcp.read_buf[i] != '\r' ||
|
||||
a->tcp.read_buf[i+1] != '\n')
|
||||
continue;
|
||||
|
||||
len = (int)(i - p);
|
||||
ln = (char *)&a->tcp.read_buf[p];
|
||||
|
||||
DEBUG_ANCHOR("line: \"%.*s\"\n", len, ln);
|
||||
if (len >= 16 &&
|
||||
!strncasecmp(ln, "Content-Length: ", 16)) {
|
||||
ln[len] = 0;
|
||||
doc_len = (int)strtol(ln + 16, &endptr , 10);
|
||||
if (endptr == ln || *endptr != 0)
|
||||
doc_len = -1;
|
||||
}
|
||||
if (i - p == 0) {
|
||||
i += 2;
|
||||
break;
|
||||
}
|
||||
p = i + 2;
|
||||
i++;
|
||||
}
|
||||
if (doc_len > 0) {
|
||||
uint8_t *doc = GETDNS_XMALLOC(
|
||||
context->mf, uint8_t, doc_len);
|
||||
|
||||
DEBUG_ANCHOR("i: %d, n: %d, doc_len: %d\n"
|
||||
, (int)i, (int)n, doc_len);
|
||||
if (!doc)
|
||||
DEBUG_ANCHOR("Memory error");
|
||||
else {
|
||||
a->state += 1;
|
||||
/* TODO: With pipelined read, the buffer might
|
||||
* contain the full document, plus a piece
|
||||
* of the headers of the next document!
|
||||
* Currently context->tas_hdr_spc is kept
|
||||
* small enough to anticipate this.
|
||||
*/
|
||||
if (n - i > 0) {
|
||||
if ((n - i) > doc_len)
|
||||
n -= (doc_len - i);
|
||||
(void) memcpy(
|
||||
doc, a->tcp.read_buf + i, (n - i));
|
||||
a->tcp.read_pos = doc + (n - i);
|
||||
a->tcp.to_read = doc_len - (n - i);
|
||||
} else {
|
||||
a->tcp.read_pos = doc;
|
||||
a->tcp.to_read = doc_len;
|
||||
}
|
||||
a->tcp.read_buf = doc;
|
||||
a->tcp.read_buf_len = doc_len;
|
||||
|
||||
if (a->tcp.to_read == 0)
|
||||
tas_doc_read(context, a);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (_getdns_EWOULDBLOCK)
|
||||
return;
|
||||
|
||||
DEBUG_ANCHOR("Read error: %s\n", strerror(errno));
|
||||
GETDNS_CLEAR_EVENT(a->loop, &a->event);
|
||||
tas_next(context, a);
|
||||
}
|
||||
|
||||
static void tas_write_cb(void *userarg)
|
||||
{
|
||||
getdns_dns_req *dnsreq = (getdns_dns_req *)userarg;
|
||||
getdns_context *context = (getdns_context *)dnsreq->user_pointer;
|
||||
tas_connection *a;
|
||||
ssize_t written;
|
||||
|
||||
if (dnsreq->netreqs[0]->request_type == GETDNS_RRTYPE_A)
|
||||
a = &context->a;
|
||||
else a = &context->aaaa;
|
||||
|
||||
DEBUG_ANCHOR( "state: %d, to_write: %d\n"
|
||||
, (int)a->state, (int)a->tcp.write_buf_len);
|
||||
|
||||
written = write(a->fd, a->tcp.write_buf, a->tcp.write_buf_len);
|
||||
if (written >= 0) {
|
||||
assert(written <= (ssize_t)a->tcp.write_buf_len);
|
||||
|
||||
a->tcp.write_buf += written;
|
||||
a->tcp.write_buf_len -= written;
|
||||
if (a->tcp.write_buf_len > 0)
|
||||
/* Write remainder */
|
||||
return;
|
||||
|
||||
a->state += 1;
|
||||
a->tcp.read_buf = context->tas_hdr_spc;
|
||||
a->tcp.read_buf_len = sizeof(context->tas_hdr_spc);
|
||||
a->tcp.read_pos = a->tcp.read_buf;
|
||||
a->tcp.to_read = sizeof(context->tas_hdr_spc);
|
||||
GETDNS_CLEAR_EVENT(a->loop, &a->event);
|
||||
DEBUG_ANCHOR("All written, schedule read\n");
|
||||
GETDNS_SCHEDULE_EVENT(a->loop, a->fd, 2000,
|
||||
getdns_eventloop_event_init(&a->event, a->req->owner,
|
||||
tas_read_cb, NULL, tas_timeout_cb));
|
||||
return;
|
||||
|
||||
} else if (_getdns_EWOULDBLOCK)
|
||||
return;
|
||||
|
||||
DEBUG_ANCHOR("Write error: %s\n", strerror(errno));
|
||||
GETDNS_CLEAR_EVENT(a->loop, &a->event);
|
||||
tas_next(context, a);
|
||||
}
|
||||
|
||||
static void tas_connect(getdns_context *context, tas_connection *a)
|
||||
{
|
||||
char a_buf[40];
|
||||
int r;
|
||||
|
||||
#ifdef HAVE_FCNTL
|
||||
int flag;
|
||||
#elif defined(HAVE_IOCTLSOCKET)
|
||||
unsigned long on = 1;
|
||||
#endif
|
||||
|
||||
if (a->rr->rr_i.nxt - (a->rr->rr_i.rr_type + 10) !=
|
||||
( a->req->request_type == GETDNS_RRTYPE_A ? 4
|
||||
: a->req->request_type == GETDNS_RRTYPE_AAAA ? 16 : -1)) {
|
||||
|
||||
tas_next(context, a);
|
||||
return;
|
||||
}
|
||||
DEBUG_ANCHOR("Initiating connection to %s\n"
|
||||
, inet_ntop(( a->req->request_type == GETDNS_RRTYPE_A
|
||||
? AF_INET : AF_INET6)
|
||||
, a->rr->rr_i.rr_type + 10, a_buf, sizeof(a_buf)));
|
||||
|
||||
if ((a->fd = socket(( a->req->request_type == GETDNS_RRTYPE_A
|
||||
? AF_INET : AF_INET6), SOCK_STREAM, IPPROTO_TCP)) == -1) {
|
||||
DEBUG_ANCHOR("Error creating socket: %s\n", strerror(errno));
|
||||
tas_next(context, a);
|
||||
return;
|
||||
}
|
||||
#ifdef HAVE_FCNTL
|
||||
if((flag = fcntl(a->fd, F_GETFL)) != -1) {
|
||||
flag |= O_NONBLOCK;
|
||||
if(fcntl(a->fd, F_SETFL, flag) == -1) {
|
||||
/* ignore error, continue blockingly */
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_IOCTLSOCKET)
|
||||
if(ioctlsocket(a->fd, FIONBIO, &on) != 0) {
|
||||
/* ignore error, continue blockingly */
|
||||
}
|
||||
#endif
|
||||
if (a->req->request_type == GETDNS_RRTYPE_A) {
|
||||
struct sockaddr_in addr;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(80);
|
||||
(void) memcpy(&addr.sin_addr, a->rr->rr_i.rr_type + 10, 4);
|
||||
r = connect(a->fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
} else {
|
||||
struct sockaddr_in6 addr;
|
||||
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_port = htons(80);
|
||||
addr.sin6_flowinfo = 0;
|
||||
(void) memcpy(&addr.sin6_addr, a->rr->rr_i.rr_type + 10, 16);
|
||||
addr.sin6_scope_id = 0;
|
||||
r = connect(a->fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
}
|
||||
if (r == 0 || (r == -1 && (_getdns_EINPROGRESS ||
|
||||
_getdns_EWOULDBLOCK))) {
|
||||
|
||||
a->state += 1;
|
||||
a->tcp.write_buf = tas_write_xml_p7s_buf;
|
||||
a->tcp.write_buf_len = sizeof(tas_write_xml_p7s_buf) - 1;
|
||||
a->tcp.written = 0;
|
||||
|
||||
GETDNS_SCHEDULE_EVENT(a->loop, a->fd, 2000,
|
||||
getdns_eventloop_event_init(&a->event, a->req->owner,
|
||||
NULL, tas_write_cb, tas_timeout_cb));
|
||||
DEBUG_ANCHOR("Scheduled write\n");
|
||||
return;
|
||||
} else
|
||||
DEBUG_ANCHOR("Connect error: %s\n", strerror(errno));
|
||||
|
||||
tas_next(context, a);
|
||||
}
|
||||
|
||||
static void data_iana_org(getdns_dns_req *dnsreq)
|
||||
{
|
||||
getdns_context *context = (getdns_context *)dnsreq->user_pointer;
|
||||
tas_connection *a;
|
||||
|
||||
if (dnsreq->netreqs[0]->request_type == GETDNS_RRTYPE_A)
|
||||
a = &context->a;
|
||||
else a = &context->aaaa;
|
||||
|
||||
a->rrset = _getdns_rrset_answer(
|
||||
&a->rrset_spc, a->req->response, a->req->response_len);
|
||||
|
||||
if (!a->rrset)
|
||||
DEBUG_ANCHOR("%s lookup for data.iana.org. returned no "
|
||||
"response\n", rt_str(a->req->request_type));
|
||||
|
||||
else if (a->req->response_len < dnsreq->name_len + 12 ||
|
||||
!_getdns_dname_equal(a->req->response + 12, dnsreq->name) ||
|
||||
a->rrset->rr_type != a->req->request_type)
|
||||
DEBUG_ANCHOR("%s lookup for data.iana.org. returned wrong "
|
||||
"response\n", rt_str(a->req->request_type));
|
||||
else if (!(a->rr = _getdns_rrtype_iter_init(&a->rr_spc, a->rrset)))
|
||||
DEBUG_ANCHOR("%s lookup for data.iana.org. returned no "
|
||||
"addresses\n", rt_str(a->req->request_type));
|
||||
else {
|
||||
a->loop = dnsreq->loop;
|
||||
tas_connect(context, a);
|
||||
return;
|
||||
}
|
||||
tas_fail(context, a);
|
||||
}
|
||||
|
||||
void _getdns_start_fetching_ta(getdns_context *context, getdns_eventloop *loop)
|
||||
{
|
||||
getdns_return_t r;
|
||||
size_t scheduled;
|
||||
|
||||
DEBUG_ANCHOR("%s on the %ssynchronous loop\n", __FUNC__,
|
||||
loop == &context->sync_eventloop.loop ? "" : "a");
|
||||
|
||||
while (!context->sys_ctxt) {
|
||||
if ((r = getdns_context_create_with_extended_memory_functions(
|
||||
&context->sys_ctxt, 1, context->mf.mf_arg,
|
||||
context->mf.mf.ext.malloc, context->mf.mf.ext.realloc,
|
||||
context->mf.mf.ext.free)))
|
||||
DEBUG_ANCHOR("Could not create system context: %s\n"
|
||||
, getdns_get_errorstr_by_id(r));
|
||||
|
||||
else if ((r = getdns_context_set_eventloop(
|
||||
context->sys_ctxt, loop)))
|
||||
DEBUG_ANCHOR("Could not configure %ssynchronous loop "
|
||||
"with system context: %s\n"
|
||||
, ( loop == &context->sync_eventloop.loop
|
||||
? "" : "a" )
|
||||
, getdns_get_errorstr_by_id(r));
|
||||
|
||||
else if ((r = getdns_context_set_resolution_type(
|
||||
context->sys_ctxt, GETDNS_RESOLUTION_STUB)))
|
||||
DEBUG_ANCHOR("Could not configure system context for "
|
||||
"stub resolver: %s\n"
|
||||
, getdns_get_errorstr_by_id(r));
|
||||
else
|
||||
break;
|
||||
|
||||
getdns_context_destroy(context->sys_ctxt);
|
||||
context->sys_ctxt = NULL;
|
||||
DEBUG_ANCHOR("Fatal error fetching trust anchor: "
|
||||
"missing system context\n");
|
||||
context->trust_anchors_source = GETDNS_TASRC_FAILED;
|
||||
_getdns_ta_notify_dnsreqs(context);
|
||||
return;
|
||||
}
|
||||
scheduled = 0;
|
||||
#if 1
|
||||
context->a.state = TAS_LOOKUP_ADDRESSES;
|
||||
if ((r = _getdns_general_loop(context->sys_ctxt, loop,
|
||||
"data.iana.org.", GETDNS_RRTYPE_A, NULL, context,
|
||||
&context->a.req, NULL, data_iana_org))) {
|
||||
DEBUG_ANCHOR("Error scheduling A lookup for data.iana.org: "
|
||||
"%s\n", getdns_get_errorstr_by_id(r));
|
||||
} else
|
||||
scheduled += 1;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
context->aaaa.state = TAS_LOOKUP_ADDRESSES;
|
||||
if ((r = _getdns_general_loop(context->sys_ctxt, loop,
|
||||
"data.iana.org.", GETDNS_RRTYPE_AAAA, NULL, context,
|
||||
&context->aaaa.req, NULL, data_iana_org))) {
|
||||
DEBUG_ANCHOR("Error scheduling AAAA lookup for data.iana.org: "
|
||||
"%s\n", getdns_get_errorstr_by_id(r));
|
||||
} else
|
||||
scheduled += 1;
|
||||
#endif
|
||||
|
||||
if (!scheduled) {
|
||||
DEBUG_ANCHOR("Fatal error fetching trust anchor: Unable to "
|
||||
"schedule address requests for data.iana.org\n");
|
||||
context->trust_anchors_source = GETDNS_TASRC_FAILED;
|
||||
_getdns_ta_notify_dnsreqs(context);
|
||||
} else
|
||||
context->trust_anchors_source = GETDNS_TASRC_FETCHING;
|
||||
}
|
||||
|
||||
/* anchor.c */
|
||||
|
|
|
@ -35,9 +35,12 @@
|
|||
#define ANCHOR_H_
|
||||
|
||||
#include "getdns/getdns.h"
|
||||
#include "getdns/getdns_extra.h"
|
||||
#include <time.h>
|
||||
|
||||
void _getdns_context_equip_with_anchor(getdns_context *context, time_t now);
|
||||
|
||||
void _getdns_start_fetching_ta(getdns_context *context, getdns_eventloop *loop);
|
||||
|
||||
#endif
|
||||
/* anchor.h */
|
||||
|
|
|
@ -1426,6 +1426,10 @@ getdns_context_create_with_extended_memory_functions(
|
|||
result->suffixes_len = sizeof(no_suffixes);
|
||||
|
||||
result->trust_anchors_source = GETDNS_TASRC_NONE;
|
||||
|
||||
(void) memset(&result->a, 0, sizeof(result->a));
|
||||
(void) memset(&result->aaaa, 0, sizeof(result->aaaa));
|
||||
|
||||
gldns_buffer_init_vfixed_frm_data(&gbuf, result->trust_anchors_spc
|
||||
, sizeof(result->trust_anchors_spc));
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#ifdef HAVE_MDNS_SUPPORT
|
||||
#include "util/lruhash.h"
|
||||
#endif
|
||||
#include "rr-iter.h"
|
||||
|
||||
struct getdns_dns_req;
|
||||
struct ub_ctx;
|
||||
|
@ -95,6 +96,7 @@ typedef enum getdns_conn_state {
|
|||
typedef enum getdns_tasrc {
|
||||
GETDNS_TASRC_NONE,
|
||||
GETDNS_TASRC_ZONE,
|
||||
GETDNS_TASRC_FETCHING,
|
||||
GETDNS_TASRC_XML,
|
||||
GETDNS_TASRC_FAILED
|
||||
} getdns_tasrc;
|
||||
|
@ -262,6 +264,31 @@ typedef struct getdns_upstreams {
|
|||
getdns_upstream upstreams[];
|
||||
} getdns_upstreams;
|
||||
|
||||
typedef enum tas_state {
|
||||
TAS_LOOKUP_ADDRESSES = 0,
|
||||
TAS_WRITE_GET_XML,
|
||||
TAS_READ_XML_HDR,
|
||||
TAS_READ_XML_DOC,
|
||||
TAS_WRITE_GET_PS7,
|
||||
TAS_READ_PS7_HDR,
|
||||
TAS_READ_PS7_DOC,
|
||||
TAS_DONE
|
||||
} tas_state;
|
||||
|
||||
typedef struct tas_connection {
|
||||
getdns_eventloop *loop;
|
||||
getdns_network_req *req;
|
||||
_getdns_rrset_spc rrset_spc;
|
||||
_getdns_rrset *rrset;
|
||||
_getdns_rrtype_iter rr_spc;
|
||||
_getdns_rrtype_iter *rr;
|
||||
int fd;
|
||||
getdns_eventloop_event event;
|
||||
tas_state state;
|
||||
getdns_tcp_state tcp;
|
||||
getdns_bindata xml;
|
||||
} tas_connection;
|
||||
|
||||
struct getdns_context {
|
||||
/* Context values */
|
||||
getdns_resolution_t resolution_type;
|
||||
|
@ -283,9 +310,15 @@ struct getdns_context {
|
|||
const uint8_t *suffixes;
|
||||
/* Length of all suffixes in the suffix buffer */
|
||||
size_t suffixes_len;
|
||||
|
||||
uint8_t *trust_anchors;
|
||||
size_t trust_anchors_len;
|
||||
getdns_tasrc trust_anchors_source;
|
||||
|
||||
tas_connection a;
|
||||
tas_connection aaaa;
|
||||
uint8_t tas_hdr_spc[512];
|
||||
|
||||
getdns_upstreams *upstreams;
|
||||
uint16_t limit_outstanding_queries;
|
||||
uint32_t dnssec_allowed_skew;
|
||||
|
|
89
src/dnssec.c
89
src/dnssec.c
|
@ -209,6 +209,7 @@
|
|||
#include "dict.h"
|
||||
#include "list.h"
|
||||
#include "util/val_secalgo.h"
|
||||
#include "anchor.h"
|
||||
|
||||
#define SIGNATURE_VERIFIED 0x10000
|
||||
#define NSEC3_ITERATION_COUNT_HIGH 0x20000
|
||||
|
@ -2980,14 +2981,6 @@ static void append_empty_ds2val_chain_list(
|
|||
getdns_dict_destroy(rr_dict);
|
||||
}
|
||||
|
||||
static void data_iana_org_a(getdns_dns_req *dnsreq)
|
||||
{
|
||||
getdns_dns_req *orig_dnsreq = (getdns_dns_req *)dnsreq->user_pointer;
|
||||
DEBUG_SEC("Address for data.iana.org. found\n");
|
||||
_getdns_context_cancel_request(dnsreq);
|
||||
check_chain_complete(orig_dnsreq->chain);
|
||||
}
|
||||
|
||||
static void check_chain_complete(chain_head *chain)
|
||||
{
|
||||
getdns_dns_req *dnsreq;
|
||||
|
@ -3019,57 +3012,16 @@ static void check_chain_complete(chain_head *chain)
|
|||
}
|
||||
}
|
||||
|
||||
} else if (context->trust_anchors_source == GETDNS_TASRC_NONE) {
|
||||
DEBUG_SEC("Need to fetch a trust anchor\n");
|
||||
} else {
|
||||
if (context->trust_anchors_source == GETDNS_TASRC_NONE)
|
||||
_getdns_start_fetching_ta(context, dnsreq->loop);
|
||||
|
||||
dnsreq->waiting_for_ta = 1;
|
||||
dnsreq->ta_notify = context->ta_notify;
|
||||
context->ta_notify = dnsreq;
|
||||
|
||||
if (dnsreq->ta_notify)
|
||||
return; /* Wait for the notify callback */
|
||||
|
||||
else if (!context->sys_ctxt) {
|
||||
if (getdns_context_create_with_extended_memory_functions(
|
||||
&context->sys_ctxt, 1,
|
||||
context->mf.mf_arg,
|
||||
context->mf.mf.ext.malloc,
|
||||
context->mf.mf.ext.realloc,
|
||||
context->mf.mf.ext.free)) {
|
||||
DEBUG_SEC("TA fetch: Error creating system context\n");
|
||||
|
||||
} else if (getdns_context_set_eventloop(
|
||||
context->sys_ctxt, context->extension) ||
|
||||
getdns_context_set_resolution_type(
|
||||
context->sys_ctxt, GETDNS_RESOLUTION_STUB)
|
||||
) {
|
||||
DEBUG_SEC("TA fetch: Error configuring system context\n");
|
||||
|
||||
getdns_context_destroy(context->sys_ctxt);
|
||||
context->sys_ctxt = NULL;
|
||||
}
|
||||
if (context->trust_anchors_source == GETDNS_TASRC_FETCHING) {
|
||||
dnsreq->waiting_for_ta = 1;
|
||||
dnsreq->ta_notify = context->ta_notify;
|
||||
context->ta_notify = dnsreq;
|
||||
return;
|
||||
}
|
||||
if (context->sys_ctxt) {
|
||||
DEBUG_SEC("Start of fetching of root-anchors.xml\n");
|
||||
if (!_getdns_general_loop(context->sys_ctxt,
|
||||
dnsreq->loop, "data.iana.org.", GETDNS_RRTYPE_A,
|
||||
NULL, dnsreq, NULL, NULL, data_iana_org_a)
|
||||
#if 0
|
||||
|| !_getdns_general_loop(context->sys_ctxt,
|
||||
dnsreq->loop, "data.iana.org.", GETDNS_RRTYPE_AAAA,
|
||||
NULL, context, NULL, data_iana_org_aaaa)
|
||||
#endif
|
||||
)
|
||||
return;
|
||||
|
||||
DEBUG_SEC("Scheduling of lookup for \"data.iana.org.\" failed\n");
|
||||
|
||||
getdns_context_destroy(context->sys_ctxt);
|
||||
context->sys_ctxt = NULL;
|
||||
}
|
||||
dnsreq->waiting_for_ta = 0;
|
||||
context->ta_notify = dnsreq->ta_notify;
|
||||
dnsreq->ta_notify = NULL;
|
||||
}
|
||||
#ifdef STUB_NATIVE_DNSSEC
|
||||
/* Perform validation only on GETDNS_RESOLUTION_STUB (unbound_id == -1)
|
||||
|
@ -3184,6 +3136,29 @@ static void check_chain_complete(chain_head *chain)
|
|||
_getdns_call_user_callback(dnsreq, response_dict);
|
||||
}
|
||||
|
||||
void _getdns_ta_notify_dnsreqs(getdns_context *context)
|
||||
{
|
||||
getdns_dns_req **dnsreq_p, *dnsreq = NULL;
|
||||
|
||||
assert(context);
|
||||
|
||||
if (context->trust_anchors_source == GETDNS_TASRC_NONE ||
|
||||
context->trust_anchors_source == GETDNS_TASRC_FETCHING)
|
||||
return;
|
||||
|
||||
dnsreq_p = &context->ta_notify;
|
||||
while ((dnsreq = *dnsreq_p)) {
|
||||
|
||||
assert(dnsreq->waiting_for_ta && dnsreq->chain);
|
||||
|
||||
check_chain_complete(dnsreq->chain);
|
||||
|
||||
assert(*dnsreq_p != dnsreq);
|
||||
/* if (*dnsreq_p == dnsreq)
|
||||
dnsreq_p = &dnsreq->ta_notify; */
|
||||
}
|
||||
}
|
||||
|
||||
void _getdns_validation_chain_timeout(getdns_dns_req *dnsreq)
|
||||
{
|
||||
chain_head *head = dnsreq->chain, *next;
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
void _getdns_get_validation_chain(getdns_dns_req *dns_req);
|
||||
void _getdns_cancel_validation_chain(getdns_dns_req *dns_req);
|
||||
void _getdns_validation_chain_timeout(getdns_dns_req *dns_req);
|
||||
void _getdns_ta_notify_dnsreqs(getdns_context *context);
|
||||
|
||||
uint16_t _getdns_parse_ta_file(time_t *ta_mtime, gldns_buffer *gbuf);
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include "dict.h"
|
||||
#include "mdns.h"
|
||||
#include "debug.h"
|
||||
#include "anchor.h"
|
||||
|
||||
void _getdns_call_user_callback(getdns_dns_req *dnsreq, getdns_dict *response)
|
||||
{
|
||||
|
@ -578,6 +579,10 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
|
|||
req->internal_cb = internal_cb;
|
||||
req->is_sync_request = loop == &context->sync_eventloop.loop;
|
||||
|
||||
if (req->dnssec_return_status &&
|
||||
context->trust_anchors_source == GETDNS_TASRC_NONE)
|
||||
_getdns_start_fetching_ta(context, loop);
|
||||
|
||||
if (return_netreq_p)
|
||||
*return_netreq_p = req->netreqs[0];
|
||||
|
||||
|
|
12
src/stub.c
12
src/stub.c
|
@ -66,18 +66,6 @@
|
|||
#include "general.h"
|
||||
#include "pubkey-pinning.h"
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
typedef u_short sa_family_t;
|
||||
#define _getdns_EWOULDBLOCK (WSAGetLastError() == WSATRY_AGAIN ||\
|
||||
WSAGetLastError() == WSAEWOULDBLOCK)
|
||||
#define _getdns_EINPROGRESS (WSAGetLastError() == WSAEINPROGRESS)
|
||||
#define _getdns_EMFILE (WSAGetLastError() == WSAEMFILE)
|
||||
#else
|
||||
#define _getdns_EWOULDBLOCK (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
#define _getdns_EINPROGRESS (errno == EINPROGRESS)
|
||||
#define _getdns_EMFILE (errno == EMFILE)
|
||||
#endif
|
||||
|
||||
/* WSA TODO:
|
||||
* STUB_TCP_WOULDBLOCK added to deal with edge triggered event loops (versus
|
||||
* level triggered). See also lines containing WSA TODO below...
|
||||
|
|
|
@ -171,7 +171,7 @@ typedef enum network_req_state_enum
|
|||
/* State for async tcp stub resolving */
|
||||
typedef struct getdns_tcp_state {
|
||||
|
||||
uint8_t *write_buf;
|
||||
const uint8_t *write_buf;
|
||||
size_t write_buf_len;
|
||||
size_t written;
|
||||
|
||||
|
|
|
@ -218,5 +218,18 @@ INLINE uint64_t _getdns_ms_until_expiry2(uint64_t expires, uint64_t *now_ms)
|
|||
return *now_ms >= expires ? 0 : expires - *now_ms;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_WINSOCK
|
||||
typedef u_short sa_family_t;
|
||||
#define _getdns_EWOULDBLOCK (WSAGetLastError() == WSATRY_AGAIN ||\
|
||||
WSAGetLastError() == WSAEWOULDBLOCK)
|
||||
#define _getdns_EINPROGRESS (WSAGetLastError() == WSAEINPROGRESS)
|
||||
#define _getdns_EMFILE (WSAGetLastError() == WSAEMFILE)
|
||||
#else
|
||||
#define _getdns_EWOULDBLOCK (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
#define _getdns_EINPROGRESS (errno == EINPROGRESS)
|
||||
#define _getdns_EMFILE (errno == EMFILE)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* util-internal.h */
|
||||
|
|
Loading…
Reference in New Issue