From: Wouter Wijngaards Date: Thu, 16 Feb 2017 09:48:03 +0000 (+0000) Subject: - sldns updated for vfixed and buffer resize indication from getdns. X-Git-Tag: release-1.6.2rc1~99 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=648c15fbac8dc8c4ef254da79907e9150c9ec911;p=thirdparty%2Funbound.git - sldns updated for vfixed and buffer resize indication from getdns. git-svn-id: file:///svn/unbound/trunk@4014 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index b7a90e557..a555be3c9 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,6 @@ +16 February 2017: Wouter + - sldns updated for vfixed and buffer resize indication from getdns. + 15 February 2017: Wouter - sldns has ED25519 and ED448 algorithm number and name for display. diff --git a/sldns/rrdef.h b/sldns/rrdef.h index 44e9b84ce..618e62c67 100644 --- a/sldns/rrdef.h +++ b/sldns/rrdef.h @@ -423,6 +423,7 @@ enum sldns_enum_edns_option LDNS_EDNS_DHU = 6, /* RFC6975 */ LDNS_EDNS_N3U = 7, /* RFC6975 */ LDNS_EDNS_CLIENT_SUBNET = 8, /* draft-vandergaast-edns-client-subnet */ + LDNS_EDNS_KEEPALIVE = 11, /* draft-ietf-dnsop-edns-tcp-keepalive*/ LDNS_EDNS_PADDING = 12 /* RFC7830 */ }; typedef enum sldns_enum_edns_option sldns_edns_option; diff --git a/sldns/sbuffer.c b/sldns/sbuffer.c index a7fe53aa0..a04b9b655 100644 --- a/sldns/sbuffer.c +++ b/sldns/sbuffer.c @@ -33,6 +33,7 @@ sldns_buffer_new(size_t capacity) buffer->_position = 0; buffer->_limit = buffer->_capacity = capacity; buffer->_fixed = 0; + buffer->_vfixed = 0; buffer->_status_err = 0; sldns_buffer_invariant(buffer); @@ -48,6 +49,7 @@ sldns_buffer_new_frm_data(sldns_buffer *buffer, void *data, size_t size) buffer->_position = 0; buffer->_limit = buffer->_capacity = size; buffer->_fixed = 0; + buffer->_vfixed = 0; buffer->_data = malloc(size); if(!buffer->_data) { buffer->_status_err = 1; @@ -66,6 +68,17 @@ sldns_buffer_init_frm_data(sldns_buffer *buffer, void *data, size_t size) buffer->_data = data; buffer->_capacity = buffer->_limit = size; buffer->_fixed = 1; + buffer->_vfixed = 0; +} + +void +sldns_buffer_init_vfixed_frm_data(sldns_buffer *buffer, void *data, size_t size) +{ + memset(buffer, 0, sizeof(*buffer)); + buffer->_data = data; + buffer->_capacity = buffer->_limit = size; + buffer->_fixed = 1; + buffer->_vfixed = 1; } int @@ -74,7 +87,7 @@ sldns_buffer_set_capacity(sldns_buffer *buffer, size_t capacity) void *data; sldns_buffer_invariant(buffer); - assert(buffer->_position <= capacity); + assert(buffer->_position <= capacity && !buffer->_fixed); data = (uint8_t *) realloc(buffer->_data, capacity); if (!data) { @@ -126,7 +139,7 @@ sldns_buffer_printf(sldns_buffer *buffer, const char *format, ...) if (written == -1) { buffer->_status_err = 1; return -1; - } else if ((size_t) written >= remaining) { + } else if (!buffer->_vfixed && (size_t) written >= remaining) { if (!sldns_buffer_reserve(buffer, (size_t) written + 1)) { buffer->_status_err = 1; return -1; diff --git a/sldns/sbuffer.h b/sldns/sbuffer.h index 3ce874fc7..c3b95e13d 100644 --- a/sldns/sbuffer.h +++ b/sldns/sbuffer.h @@ -87,6 +87,19 @@ sldns_write_uint32(void *dst, uint32_t data) } +INLINE void +sldns_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 sbuffer.h * @@ -117,6 +130,17 @@ struct sldns_buffer /** If the buffer is fixed it cannot be resized */ unsigned _fixed : 1; + /** If the buffer is vfixed, no more than capacity bytes willl be + * written to _data, however the _position counter will be updated + * with the amount that would have been written in consecutive + * writes. This allows for a modus operandi in which a sequence is + * written on a fixed capacity buffer (perhaps with _data on stack). + * When everything could be written, then the _data is immediately + * usable, if not, then a buffer could be allocated sized precisely + * to fit the data for a second attempt. + */ + unsigned _vfixed : 1; + /** The current state of the buffer. If writing to the buffer fails * for any reason, this value is changed. This way, you can perform * multiple writes in sequence and check for success afterwards. */ @@ -134,9 +158,9 @@ INLINE void sldns_buffer_invariant(sldns_buffer *buffer) { assert(buffer != NULL); - assert(buffer->_position <= buffer->_limit); + assert(buffer->_position <= buffer->_limit || buffer->_vfixed); assert(buffer->_limit <= buffer->_capacity); - assert(buffer->_data != NULL); + assert(buffer->_data != NULL || (buffer->_vfixed && buffer->_capacity == 0)); } #endif @@ -168,6 +192,19 @@ void sldns_buffer_new_frm_data(sldns_buffer *buffer, void *data, size_t size); */ void sldns_buffer_init_frm_data(sldns_buffer *buffer, void *data, size_t size); +/** + * Setup a buffer with the data pointed to. No data copied, no memory allocs. + * The buffer is "virtually" fixed. Writes beyond size (the capacity) will + * only update position, but no data will be written beyond capacity. This + * allows to determine how big the buffer should have been to contain all the + * written data, by looking at the position with sldns_buffer_position(), + * similarly to the return value of POSIX's snprintf. + * \param[in] buffer pointer to the buffer to put the data in + * \param[in] data the data to encapsulate in the buffer + * \param[in] size the size of the data + */ +void sldns_buffer_init_vfixed_frm_data(sldns_buffer *buffer, void *data, size_t size); + /** * clears the buffer and make it ready for writing. The buffer's limit * is set to the capacity and the position is set to 0. @@ -231,7 +268,7 @@ sldns_buffer_position(sldns_buffer *buffer) INLINE void sldns_buffer_set_position(sldns_buffer *buffer, size_t mark) { - assert(mark <= buffer->_limit); + assert(mark <= buffer->_limit || buffer->_vfixed); buffer->_position = mark; } @@ -245,7 +282,7 @@ sldns_buffer_set_position(sldns_buffer *buffer, size_t mark) INLINE void sldns_buffer_skip(sldns_buffer *buffer, ssize_t count) { - assert(buffer->_position + count <= buffer->_limit); + assert(buffer->_position + count <= buffer->_limit || buffer->_vfixed); buffer->_position += count; } @@ -317,7 +354,7 @@ int sldns_buffer_reserve(sldns_buffer *buffer, size_t amount); INLINE uint8_t * sldns_buffer_at(const sldns_buffer *buffer, size_t at) { - assert(at <= buffer->_limit); + assert(at <= buffer->_limit || buffer->_vfixed); return buffer->_data + at; } @@ -367,8 +404,8 @@ INLINE size_t sldns_buffer_remaining_at(sldns_buffer *buffer, size_t at) { sldns_buffer_invariant(buffer); - assert(at <= buffer->_limit); - return buffer->_limit - at; + assert(at <= buffer->_limit || buffer->_vfixed); + return at < buffer->_limit ? buffer->_limit - at : 0; } /** @@ -420,7 +457,15 @@ sldns_buffer_available(sldns_buffer *buffer, size_t count) INLINE void sldns_buffer_write_at(sldns_buffer *buffer, size_t at, const void *data, size_t count) { - assert(sldns_buffer_available_at(buffer, at, count)); + if (!buffer->_vfixed) + assert(sldns_buffer_available_at(buffer, at, count)); + else if (sldns_buffer_remaining_at(buffer, at) == 0) + return; + else if (count > sldns_buffer_remaining_at(buffer, at)) { + memcpy(buffer->_data + at, data, + sldns_buffer_remaining_at(buffer, at)); + return; + } memcpy(buffer->_data + at, data, count); } @@ -469,6 +514,7 @@ sldns_buffer_write_string(sldns_buffer *buffer, const char *str) INLINE void sldns_buffer_write_u8_at(sldns_buffer *buffer, size_t at, uint8_t data) { + if (buffer->_vfixed && at + sizeof(data) > buffer->_limit) return; assert(sldns_buffer_available_at(buffer, at, sizeof(data))); buffer->_data[at] = data; } @@ -494,6 +540,7 @@ sldns_buffer_write_u8(sldns_buffer *buffer, uint8_t data) INLINE void sldns_buffer_write_u16_at(sldns_buffer *buffer, size_t at, uint16_t data) { + if (buffer->_vfixed && at + sizeof(data) > buffer->_limit) return; assert(sldns_buffer_available_at(buffer, at, sizeof(data))); sldns_write_uint16(buffer->_data + at, data); } @@ -519,10 +566,25 @@ sldns_buffer_write_u16(sldns_buffer *buffer, uint16_t data) INLINE void sldns_buffer_write_u32_at(sldns_buffer *buffer, size_t at, uint32_t data) { + if (buffer->_vfixed && at + sizeof(data) > buffer->_limit) return; assert(sldns_buffer_available_at(buffer, at, sizeof(data))); sldns_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 +sldns_buffer_write_u48_at(sldns_buffer *buffer, size_t at, uint64_t data) +{ + if (buffer->_vfixed && at + 6 > buffer->_limit) return; + assert(sldns_buffer_available_at(buffer, at, 6)); + sldns_write_uint48(buffer->_data + at, data); +} + /** * writes the given 4 byte integer at the current position in the buffer * \param[in] buffer the buffer @@ -535,6 +597,18 @@ sldns_buffer_write_u32(sldns_buffer *buffer, uint32_t 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 +sldns_buffer_write_u48(sldns_buffer *buffer, uint64_t data) +{ + sldns_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 * \param[in] buffer the buffer diff --git a/sldns/wire2str.c b/sldns/wire2str.c index acb353251..0ccf3492d 100644 --- a/sldns/wire2str.c +++ b/sldns/wire2str.c @@ -167,6 +167,7 @@ static sldns_lookup_table sldns_edns_options_data[] = { { 6, "DHU" }, { 7, "N3U" }, { 8, "edns-client-subnet" }, + { 11, "edns-tcp-keepalive"}, { 12, "Padding" }, { 0, NULL} }; @@ -1840,6 +1841,25 @@ int sldns_wire2str_edns_subnet_print(char** s, size_t* sl, uint8_t* data, return w; } +int sldns_wire2str_edns_keepalive_print(char** s, size_t* sl, uint8_t* data, + size_t len) +{ + int w = 0; + uint16_t timeout; + if(!(len == 0 || len == 2)) { + w += sldns_str_print(s, sl, "malformed keepalive "); + w += print_hex_buf(s, sl, data, len); + return w; + } + if(len == 0 ) { + w += sldns_str_print(s, sl, "no timeout value (only valid for client option) "); + } else { + timeout = sldns_read_uint16(data); + w += sldns_str_print(s, sl, "timeout value in units of 100ms %u", (int)timeout); + } + return w; +} + int sldns_wire2str_edns_option_print(char** s, size_t* sl, uint16_t option_code, uint8_t* optdata, size_t optlen) { @@ -1868,6 +1888,9 @@ int sldns_wire2str_edns_option_print(char** s, size_t* sl, case LDNS_EDNS_CLIENT_SUBNET: w += sldns_wire2str_edns_subnet_print(s, sl, optdata, optlen); break; + case LDNS_EDNS_KEEPALIVE: + w += sldns_wire2str_edns_keepalive_print(s, sl, optdata, optlen); + break; case LDNS_EDNS_PADDING: w += print_hex_buf(s, sl, optdata, optlen); break;