Send TSIG

This commit is contained in:
Willem Toorop 2015-12-21 22:11:16 +01:00
parent 98dc4018c3
commit 6c1e00fc3f
5 changed files with 160 additions and 6 deletions

View File

@ -206,7 +206,7 @@ else
fi fi
AC_CHECK_HEADERS([openssl/conf.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/conf.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([openssl/engine.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/engine.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode]) AC_CHECK_FUNCS([OPENSSL_config EVP_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode])
AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto], [], [], [ AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto], [], [], [
AC_INCLUDES_DEFAULT AC_INCLUDES_DEFAULT
#ifdef HAVE_OPENSSL_ERR_H #ifdef HAVE_OPENSSL_ERR_H

View File

@ -87,6 +87,19 @@ gldns_write_uint32(void *dst, uint32_t data)
} }
INLINE void
gldns_write_uint48(void *dst, uint64_t data)
{
uint8_t *p = (uint8_t *) dst;
p[0] = (uint8_t) ((data >> 40) & 0xff);
p[1] = (uint8_t) ((data >> 32) & 0xff);
p[2] = (uint8_t) ((data >> 24) & 0xff);
p[3] = (uint8_t) ((data >> 16) & 0xff);
p[4] = (uint8_t) ((data >> 8) & 0xff);
p[5] = (uint8_t) (data & 0xff);
}
/** /**
* \file gbuffer.h * \file gbuffer.h
* *
@ -534,6 +547,20 @@ gldns_buffer_write_u32_at(gldns_buffer *buffer, size_t at, uint32_t data)
gldns_write_uint32(buffer->_data + at, data); gldns_write_uint32(buffer->_data + at, data);
} }
/**
* writes the given 6 byte integer at the given position in the buffer
* \param[in] buffer the buffer
* \param[in] at the position in the buffer
* \param[in] data the (lower) 48 bits to write
*/
INLINE void
gldns_buffer_write_u48_at(gldns_buffer *buffer, size_t at, uint64_t data)
{
if (buffer->_fixed && at + 6 > buffer->_limit) return;
assert(gldns_buffer_available_at(buffer, at, 6));
gldns_write_uint48(buffer->_data + at, data);
}
/** /**
* writes the given 4 byte integer at the current position in the buffer * writes the given 4 byte integer at the current position in the buffer
* \param[in] buffer the buffer * \param[in] buffer the buffer
@ -546,6 +573,18 @@ gldns_buffer_write_u32(gldns_buffer *buffer, uint32_t data)
buffer->_position += sizeof(data); buffer->_position += sizeof(data);
} }
/**
* writes the given 6 byte integer at the current position in the buffer
* \param[in] buffer the buffer
* \param[in] data the 48 bits to write
*/
INLINE void
gldns_buffer_write_u48(gldns_buffer *buffer, uint64_t data)
{
gldns_buffer_write_u48_at(buffer, buffer->_position, data);
buffer->_position += 6;
}
/** /**
* copies count bytes of data at the given position to the given data-array * copies count bytes of data at the given position to the given data-array
* \param[in] buffer the buffer * \param[in] buffer the buffer

View File

@ -41,6 +41,26 @@
#include "gldns/gbuffer.h" #include "gldns/gbuffer.h"
#include "gldns/pkthdr.h" #include "gldns/pkthdr.h"
#include "dict.h" #include "dict.h"
#include "debug.h"
/* MAXIMUM_TSIG_SPACE = TSIG name (dname) : 256
* TSIG type (uint16_t) : 2
* TSIG class (uint16_t) : 2
* TSIG TTL (uint32_t) : 4
* RdLen (uint16_t) : 2
* Algorithm name (dname) : 256
* Time Signed (uint48_t) : 6
* Fudge (uint16_t) : 2
* Mac Size (uint16_t) : 2
* Mac (variable) : EVP_MAX_MD_SIZE
* Original Id (uint16_t) : 2
* Error (uint16_t) : 2
* Other Len (uint16_t) : 2
* Other Data (nothing) : 0
* ---- +
* 538 + EVP_MAX_MD_SIZE
*/
#define MAXIMUM_TSIG_SPACE (538 + EVP_MAX_MD_SIZE)
getdns_dict dnssec_ok_checking_disabled_spc = { getdns_dict dnssec_ok_checking_disabled_spc = {
{ RBTREE_NULL, 0, (int (*)(const void *, const void *)) strcmp }, { RBTREE_NULL, 0, (int (*)(const void *, const void *)) strcmp },
@ -249,7 +269,7 @@ _getdns_network_req_add_upstream_option(getdns_network_req * req, uint16_t code,
/* no overflow allowed for OPT size either (maybe this is overkill /* no overflow allowed for OPT size either (maybe this is overkill
given the above check?) */ given the above check?) */
oldlen = gldns_read_uint16(req->opt + 9); oldlen = gldns_read_uint16(req->opt + 9);
newlen = oldlen + 4 + sz; newlen = oldlen + 4 + sz;
if (newlen > UINT16_MAX) if (newlen > UINT16_MAX)
return GETDNS_RETURN_GENERIC_ERROR; return GETDNS_RETURN_GENERIC_ERROR;
@ -277,6 +297,98 @@ _getdns_network_req_add_upstream_option(getdns_network_req * req, uint16_t code,
return GETDNS_RETURN_GOOD; return GETDNS_RETURN_GOOD;
} }
size_t
_getdns_network_req_add_tsig(getdns_network_req *req)
{
getdns_upstream *upstream = req->upstream;
gldns_buffer gbuf;
uint16_t arcount;
const getdns_tsig_info *tsig_info;
uint8_t md_buf[EVP_MAX_MD_SIZE];
unsigned int md_len = EVP_MAX_MD_SIZE;
const EVP_MD *digester;
if (upstream->tsig_alg == GETDNS_NO_TSIG || !upstream->tsig_dname_len)
return req->response - req->query;
arcount = gldns_read_uint16(req->query + 10);
#if defined(STUB_DEBUG) && STUB_DEBUG
/* TSIG should not have been written yet. */
if (req->opt) {
assert(arcount == 1);
assert(req->opt + 11 + gldns_read_uint16(req->opt + 9)
== req->response);
} else
assert(arcount == 0);
#endif
tsig_info = _getdns_get_tsig_info(upstream->tsig_alg);
gldns_buffer_init_frm_data(&gbuf, req->response, MAXIMUM_TSIG_SPACE);
gldns_buffer_write(&gbuf,
upstream->tsig_dname, upstream->tsig_dname_len); /* Name */
gldns_buffer_write_u16(&gbuf, GETDNS_RRCLASS_ANY); /* Class */
gldns_buffer_write_u32(&gbuf, 0); /* TTL */
gldns_buffer_write(&gbuf,
tsig_info->dname, tsig_info->dname_len); /* Algorithm Name */
gldns_buffer_write_u48(&gbuf, time(NULL)); /* Time Signed */
gldns_buffer_write_u16(&gbuf, 300); /* Fudge */
gldns_buffer_write_u16(&gbuf, 0); /* Error */
gldns_buffer_write_u16(&gbuf, 0); /* Other len */
switch (upstream->tsig_alg) {
#ifdef HAVE_EVP_MD5
case GETDNS_HMAC_MD5 : digester = EVP_md5() ; break;
#endif
#ifdef HAVE_EVP_SHA1
case GETDNS_HMAC_SHA1 : digester = EVP_sha1() ; break;
#endif
#ifdef HAVE_EVP_SHA224
case GETDNS_HMAC_SHA224: digester = EVP_sha224(); break;
#endif
#ifdef HAVE_EVP_SHA256
case GETDNS_HMAC_SHA256: digester = EVP_sha256(); break;
#endif
#ifdef HAVE_EVP_SHA384
case GETDNS_HMAC_SHA384: digester = EVP_sha384(); break;
#endif
#ifdef HAVE_EVP_SHA512
case GETDNS_HMAC_SHA512: digester = EVP_sha512(); break;
#endif
default : return req->response - req->query;
}
(void) HMAC(digester, upstream->tsig_key, upstream->tsig_size,
(void *)req->query, gldns_buffer_current(&gbuf) - req->query,
md_buf, &md_len);
gldns_buffer_rewind(&gbuf);
gldns_buffer_write(&gbuf,
upstream->tsig_dname, upstream->tsig_dname_len); /* Name */
gldns_buffer_write_u16(&gbuf, GETDNS_RRTYPE_TSIG); /* Type*/
gldns_buffer_write_u16(&gbuf, GETDNS_RRCLASS_ANY); /* Class */
gldns_buffer_write_u32(&gbuf, 0); /* TTL */
gldns_buffer_write_u16(&gbuf,
tsig_info->dname_len + 10 + md_len + 6); /* RdLen */
gldns_buffer_write(&gbuf,
tsig_info->dname, tsig_info->dname_len); /* Algorithm Name */
gldns_buffer_write_u48(&gbuf, time(NULL)); /* Time Signed */
gldns_buffer_write_u16(&gbuf, 300); /* Fudge */
gldns_buffer_write_u16(&gbuf, md_len); /* MAC Size */
gldns_buffer_write(&gbuf, md_buf, md_len); /* MAC*/
gldns_buffer_write(&gbuf, req->query, 2); /* Original ID */
gldns_buffer_write_u16(&gbuf, 0); /* Error */
gldns_buffer_write_u16(&gbuf, 0); /* Other len */
if (gldns_buffer_position(&gbuf) > gldns_buffer_limit(&gbuf))
return req->response - req->query;
DEBUG_STUB("Sending with TSIG, mac length: %d\n", (int)md_len);
gldns_write_uint16(req->query + 10, arcount + 1);
req->response = gldns_buffer_current(&gbuf);
return req->response - req->query;
}
void void
_getdns_dns_req_free(getdns_dns_req * req) _getdns_dns_req_free(getdns_dns_req * req)
{ {
@ -439,7 +551,7 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop,
+ strlen(name) + 1 + 4 /* dname always smaller then strlen(name) + 1 */ + strlen(name) + 1 + 4 /* dname always smaller then strlen(name) + 1 */
+ 12 + opt_options_size /* space needed for OPT (if needed) */ + 12 + opt_options_size /* space needed for OPT (if needed) */
+ MAXIMUM_UPSTREAM_OPTION_SPACE + MAXIMUM_UPSTREAM_OPTION_SPACE
/* TODO: TSIG */ + MAXIMUM_TSIG_SPACE
+ 7) / 8 * 8; + 7) / 8 * 8;
} }
max_response_sz = (( edns_maximum_udp_payload_size != -1 max_response_sz = (( edns_maximum_udp_payload_size != -1

View File

@ -737,7 +737,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
if (attach_edns_client_subnet_private(netreq)) if (attach_edns_client_subnet_private(netreq))
return STUB_OUT_OF_OPTIONS; return STUB_OUT_OF_OPTIONS;
} }
pkt_len = netreq->response - netreq->query; pkt_len = _getdns_network_req_add_tsig(netreq);
/* We have an initialized packet buffer. /* We have an initialized packet buffer.
* Lets see how much of it we can write * Lets see how much of it we can write
*/ */
@ -1212,7 +1212,7 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp,
} }
} }
pkt_len = netreq->response - netreq->query; pkt_len = _getdns_network_req_add_tsig(netreq);
/* We have an initialized packet buffer. /* We have an initialized packet buffer.
* Lets see how much of it we can write */ * Lets see how much of it we can write */
@ -1337,7 +1337,7 @@ stub_udp_write_cb(void *userarg)
if (attach_edns_client_subnet_private(netreq)) if (attach_edns_client_subnet_private(netreq))
return; /* too many upstream options */ return; /* too many upstream options */
} }
pkt_len = netreq->response - netreq->query; pkt_len = _getdns_network_req_add_tsig(netreq);
if ((ssize_t)pkt_len != sendto(netreq->fd, netreq->query, pkt_len, 0, if ((ssize_t)pkt_len != sendto(netreq->fd, netreq->query, pkt_len, 0,
(struct sockaddr *)&netreq->upstream->addr, (struct sockaddr *)&netreq->upstream->addr,
netreq->upstream->addr_len)) { netreq->upstream->addr_len)) {

View File

@ -379,5 +379,8 @@ getdns_return_t _getdns_network_req_add_upstream_option(getdns_network_req * req
uint16_t code, uint16_t sz, const void* data); uint16_t code, uint16_t sz, const void* data);
void _getdns_network_req_clear_upstream_options(getdns_network_req * req); void _getdns_network_req_clear_upstream_options(getdns_network_req * req);
/* Adds TSIG signature (if needed) and returns query length */
size_t _getdns_network_req_add_tsig(getdns_network_req *req);
#endif #endif
/* types-internal.h */ /* types-internal.h */