Skip to content
Permalink
master
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
1978 lines (1602 sloc) 53.6 KB
/*------------------------------------------------------------------------------
*
* Copyright (c) 2011-2021, EURid vzw. All rights reserved.
* The YADIFA TM software product is provided under the BSD 3-clause license:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of EURid nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*------------------------------------------------------------------------------
*
*/
/** @defgroup dnspacket DNS Messages
* @ingroup dnscore
* @brief
*
* @{
*/
/*----------------------------------------------------------------------------*/
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
/* ------------------------------------------------------------ */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <netinet/in.h>
#include <dnscore/thread.h>
#include <dnscore/rfc.h>
#include <dnscore/sys_types.h>
#include <dnscore/fingerprint.h>
#include <dnscore/host_address.h>
#include <dnscore/input_stream.h>
#include <dnscore/output_stream.h>
#include <dnscore/tsig.h>
#include <dnscore/network.h>
#include <dnscore/fdtools.h>
#include <dnscore/ptr_vector.h>
#include <dnscore/format.h>
#include <dnscore/logger.h>
// Processing flags
#define PROCESS_FL_ADDITIONAL_AUTH 0x01
#define PROCESS_FL_AUTHORITY_AUTH 0x02
#define PROCESS_FL_ADDITIONAL_CACHE 0x04
#define PROCESS_FL_AUTHORITY_CACHE 0x08
#define PROCESS_FL_RECURSION 0x20
#define PROCESS_FL_TCP 0x80
#define NETWORK_BUFFER_SIZE 65536
#define MESSAGE_PAYLOAD_IS_POINTER 1
/**
* @note buffer MUST be aligned on 16 bits
*/
#define MESSAGE_HIFLAGS(buffer_) ((buffer_)[ 2])
#define MESSAGE_LOFLAGS(buffer_) ((buffer_)[ 3])
#define MESSAGE_FLAGS(buffer_) GET_U16_AT((buffer_)[ 2])
/* Only use constants with this */
#if AVOID_ANTIALIASING
static inline void MESSAGE_FLAGS_OR_P(void* address, u16 f)
{
u16 *p = (u16*)address;
*p |= f;
}
static inline void MESSAGE_FLAGS_AND_P(void* address, u16 f)
{
u16 *p = (u16*)address;
*p &= f;
}
struct packet_writer;
struct dns_resource_record;
#ifdef WORDS_BIGENDIAN
#define MESSAGE_FLAGS_OR(buffer_, hi_, lo_) MESSAGE_FLAGS_OR_P(&(buffer_)[2], (u16)((u16)((lo_) & 0xff) | ((u16)(hi_) << 8)))
#define MESSAGE_FLAGS_AND(buffer_, hi_, lo_) MESSAGE_FLAGS_AND_P(&(buffer_)[2], (u16)((u16)((lo_) & 0xff) | ((u16)(hi_) << 8)))
#define MESSAGE_FLAGS_SET(buffer_, hi_, lo_) SET_U16_AT_P(&(buffer_)[2], (u16)((u16)((lo_) & 0xff) | ((u16)hi_ << 8)))
#else
#define MESSAGE_FLAGS_OR(buffer_, hi_, lo_) MESSAGE_FLAGS_OR_P(&(buffer_)[2], (u16)(((u16)((hi_) & 0xff)) | (((u16)(lo_)) << 8)))
#define MESSAGE_FLAGS_AND(buffer_, hi_, lo_) MESSAGE_FLAGS_AND_P(&(buffer_)[2], (u16)(((u16)((hi_) & 0xff)) | (((u16)(lo_)) << 8)))
#define MESSAGE_FLAGS_SET(buffer_, hi_, lo_) SET_U16_AT_P(&(buffer_)[2], (u16)(((u16)((hi_) & 0xff)) | (((u16)(lo_)) << 8)))
#endif
#define MESSAGE_ID(buffer_) GET_U16_AT_P(&(buffer_)[0])
#define MESSAGE_SET_ID(buffer_,id_) SET_U16_AT_P(&(buffer_)[0],(id_))
#else
#ifdef WORDS_BIGENDIAN
#define MESSAGE_FLAGS_OR(buffer_, hi_, lo_) *((u16*)&(buffer_[2])) |= (lo_ | ((u16)hi_ << 8))
#define MESSAGE_FLAGS_AND(buffer_, hi_, lo_) *((u16*)&(buffer_[2])) &= (lo_ | ((u16)hi_ << 8))
#define MESSAGE_FLAGS_SET(buffer_, hi_, lo_) *((u16*)&(buffer_[2])) = (lo_ | ((u16)hi_ << 8))
#else
#define MESSAGE_FLAGS_OR(buffer_, hi_, lo_) *((u16*)&(buffer_[2])) |= (hi_ | ((u16)lo_ << 8))
#define MESSAGE_FLAGS_AND(buffer_, hi_, lo_) *((u16*)&(buffer_[2])) &= (hi_ | ((u16)lo_ << 8))
#define MESSAGE_FLAGS_SET(buffer_, hi_, lo_) *((u16*)&(buffer_[2])) = (hi_ | ((u16)lo_ << 8))
#endif
#define MESSAGE_ID(buffer) (*((u16*)&(buffer)[ 0]))
#define MESSAGE_SET_ID(buffer_,id_) (*((u16*)&(buffer)[ 0])) = (id_)
#endif
#define MESSAGE_QR(buffer_) (MESSAGE_HIFLAGS(buffer_) & QR_BITS)
#define MESSAGE_OP(buffer_) (MESSAGE_HIFLAGS(buffer_) & OPCODE_BITS)
#define MESSAGE_AA(buffer_) (MESSAGE_HIFLAGS(buffer_) & AA_BITS)
#define MESSAGE_TC(buffer_) (MESSAGE_HIFLAGS(buffer_) & TC_BITS)
#define MESSAGE_RD(buffer_) (MESSAGE_HIFLAGS(buffer_) & RD_BITS)
#define MESSAGE_RA(buffer_) (MESSAGE_LOFLAGS(buffer_) & RA_BITS)
#define MESSAGE_ZF(buffer_) (MESSAGE_LOFLAGS(buffer_) & Z_BITS)
#define MESSAGE_AD(buffer_) (MESSAGE_LOFLAGS(buffer_) & AD_BITS)
#define MESSAGE_CD(buffer_) (MESSAGE_LOFLAGS(buffer_) & CD_BITS)
#define MESSAGE_RCODE(buffer_) (MESSAGE_LOFLAGS(buffer_) & RCODE_BITS)
// the size of the section by index [0;3]
#define MESSAGE_SECTION_COUNT(buffer_,index_) GET_U16_AT(((buffer_)[4 + ((index_)<< 1)]))
#define MESSAGE_QD(buffer_) GET_U16_AT((buffer_)[4])
#define MESSAGE_AN(buffer_) GET_U16_AT((buffer_)[6])
#define MESSAGE_NS(buffer_) GET_U16_AT((buffer_)[8])
#define MESSAGE_AR(buffer_) GET_U16_AT((buffer_)[10])
#define MESSAGE_NSAR(buffer_) GET_U32_AT((buffer_)[8])
#define MESSAGE_SET_OP(buffer_, val_) (MESSAGE_HIFLAGS(buffer_) = (MESSAGE_HIFLAGS(buffer_) & ~OPCODE_BITS) | (val_))
#define MESSAGE_SET_QD(buffer_,val_) SET_U16_AT((buffer_)[4],(val_))
#define MESSAGE_SET_AN(buffer_,val_) SET_U16_AT((buffer_)[6],(val_))
#define MESSAGE_SET_NS(buffer_,val_) SET_U16_AT((buffer_)[8],(val_))
#define MESSAGE_SET_AR(buffer_,val_) SET_U16_AT((buffer_)[10],(val_))
#define MESSAGE_SET_NSAR(buffer_,val_) SET_U32_AT((buffer_)[8],(val_))
/* DYNUPDATE rfc 2136 */
#define MESSAGE_ZO(buffer_) GET_U16_AT((buffer_)[4])
#define MESSAGE_PR(buffer_) GET_U16_AT((buffer_)[6])
#define MESSAGE_UP(buffer_) GET_U16_AT((buffer_)[8])
#define MESSAGE_SET_ZO(buffer_, val_) SET_U16_AT((buffer_)[4],(val_))
#define MESSAGE_SET_PR(buffer_, val_) SET_U16_AT((buffer_)[6],(val_))
#define MESSAGE_SET_UP(buffer_, val_) SET_U16_AT((buffer_)[8],(val_))
//#define MESSAGE_AD(buffer) (*((u16*)&(buffer)[10]))
#define MESGDATA_TAG 0x415441444753454d
#if DNSCORE_HAS_TSIG_SUPPORT
typedef struct message_tsig message_tsig;
struct message_tsig
{
const tsig_item *tsig;
u16 reserved_0; /* ALIGN32 */
u16 timehi; /* NETWORK */
u32 timelo; /* NETWORK */
u16 fudge; /* NETWORK */
u16 mac_size; /* NATIVE */
u16 original_id;/* NETWORK */
u16 error; /* NETWORK */
u16 other_len; /* NETWORK */
u16 reserved_1; /* ALIGN32 */
u32 reserved_2; /* ALIGN64 */
u8 mac[64];
u8 *other;
tsig_hmac_t hmac; /* only used for tcp */
s8 tcp_tsig_countdown; /* maximum value is supposed to be 100 */
u8 mac_algorithm;
};
#endif
/* A memory pool for the lookup's benefit */
#define MESSAGE_POOL_SIZE 0x20000
// flags for MESSAGE_MAKE_QUERY_EX
#define MESSAGE_EDNS0_SIZE 0x4000 // any bit that is not set in EDNS0
#define MESSAGE_EDNS0_DNSSEC 0x8000
#define MESSAGE_BUFFER_SIZE 0x10500
#define MESSAGE_DATA_CONTROL_BUFFER_SIZE 64
struct message_data
{
struct msghdr _msghdr;
struct iovec _iovec;
socketaddress _sender; // who the sender is
u8 *_ar_start; // for the TSIG
// THIS CROUP IS COPIED USING A MEMCPY IN message_dup() ->
u32 _rcode_ext; // network endian
finger_print _status; // contains an RCODE, why is it separated from the buffer ?
#if MESSAGE_PAYLOAD_IS_POINTER
u32 _message_data_size; // the size of the allocated message structure
#endif
u16 _query_type;
u16 _query_class;
bool _edns;
bool _nsid;
char _protocol; // will probably be removed
u8 _referral;
u8 _control_buffer_size;
u8 _tcp_serial;
/* bool is_delegation; for quick referral : later */
u32 _buffer_size; // 32 bits aligned // the maximum number of bytes we are ready to fill (can be changed)
u32 _buffer_size_limit; // // the maximum number of bytes we can ever fill (as the buffer size is limited and )
void *_pool; // a pool to be used as a quick memory for the message
int _pool_size; // a zdb query will store some temporary records in it. Consider size to be from 64K to 128K.
#if DNSCORE_HAS_TSIG_SUPPORT
message_tsig _tsig;
#endif
volatile u64 recv_us;
volatile u64 pushed_us;
volatile u64 popped_us;
// <- THIS GROUP IS COPIED USING A MEMCPY IN message_dup()
u8 _msghdr_control_buffer[(MESSAGE_DATA_CONTROL_BUFFER_SIZE + 7) & ~7]; // receives the destination address, IF MOVED, YOU NEED TO LOOK AT message_new_instance() ZEROMEMORY call
u8 _canonised_fqdn[(MAX_DOMAIN_LENGTH + 7) & ~7];
/* Ensure (buffer - buffer_tcp_len) is equal to 2 ! */
#if MESSAGE_PAYLOAD_IS_POINTER
u8 *_buffer;
#else
u64 __reserved_force_align__1; // 64 bits aligned
u16 __reserved_force_align__2; // 32 bits aligned
u8 _buffer_tcp_len[2]; // DON'T SEPARATE THESE TWO (FIRST)
u8 _buffer[NETWORK_BUFFER_SIZE]; // DON'T SEPARATE THESE TWO (SECOND)
#endif
};
typedef struct message_data message_data;
struct message_data_with_buffer
{
message_data message;
#if MESSAGE_PAYLOAD_IS_POINTER
u64 __reserved_force_align__1; // 64 bits aligned
u8 _buffer[NETWORK_BUFFER_SIZE]; // DON'T SEPARATE THESE TWO (SECOND)
u8 _buffer_limit[1];
#endif
};
typedef struct message_data_with_buffer message_data_with_buffer;
struct message_dnsupdate_data
{
struct message_dnsupdate_data *next;
u32 zttl;
u16 ztype;
u16 zclass;
u8 zname[MAX_DOMAIN_LENGTH];
output_stream zrdata[RDATA_MAX_LENGTH +1];
u8 *zrdata2;
u16 zrdata_len;
};
typedef struct message_dnsupdate_data message_dnsupdate_data;
/**
* A message_map is a message_data wrapper that got the records indexed
* Each vector entry points to the FQDN of a record in the message.
*/
struct message_map
{
const message_data *mesg;
ptr_vector records;
u16 section_base[4];
};
typedef struct message_map message_map;
/* ------------------------------------------------------------ */
/**
* This sets a default, global, rate for functions supporting it.
* Rate is used in TCP streaming so that if the other end reads or writes
* too slowly then the connection is severed, harshly.
*
* @param rate
*/
void message_set_minimum_troughput_default(double rate);
/* ------------------------------------------------------------ */
static inline void message_set_protocol(message_data *mesg, u8 protocol)
{
// THIS SEEMS POINTLESS AS IT'S ONLY USED FOR LOGGING
(void)mesg;
(void)protocol;
}
static inline u8 message_get_protocol(const message_data *mesg)
{
// THIS SEEMS POINTLESS AS IT'S ONLY USED FOR LOGGING
(void)mesg;
return 0;
}
/**
*
* The hope here is that the compiler will be smart enough to translates this as
* one move. (mov)
*
* @param mesg
* @param qd
* @param an
* @param ns
* @param ar
*/
static inline void message_set_query_answer_authority_additional_counts_ne(message_data *mesg, u16 qd, u16 an, u16 ns, u16 ar)
{
#ifdef WORDS_BIGENDIAN
u64 value = (((u64)qd) << 48) | (((u64)an) << 32) | (((u64)ns) << 16) | (((u64)ar) );
#else
u64 value = (((u64)qd) ) | (((u64)an) << 16) | (((u64)ns) << 32) | (((u64)ar) << 48);
#endif
SET_U64_AT(mesg->_buffer[4], value);
}
static inline void message_set_query_answer_authority_additional_counts(message_data *mesg, u16 qd, u16 an, u16 ns, u16 ar)
{
#ifdef WORDS_BIGENDIAN
u64 value = (((u64)ntohs(qd)) << 48) | (((u64)ntohs(an)) << 32) | (((u64)ntohs(ns)) << 16) | (((u64)ntohs(ar)) );
#else
u64 value = (((u64)ntohs(qd)) ) | (((u64)ntohs(an)) << 16) | (((u64)ntohs(ns)) << 32) | (((u64)ntohs(ar)) << 48);
#endif
SET_U64_AT(mesg->_buffer[4], value);
}
static inline void message_set_authority_additional_counts(message_data *mesg, u16 ns, u16 ar)
{
#ifdef WORDS_BIGENDIAN
u32 value = (((u32)ns) << 16) | (((u32)ar) );
#else
u32 value = (((u32)ns) ) | (((u32)ar) << 16);
#endif
MESSAGE_SET_NSAR(mesg->_buffer, value);
}
static inline void message_set_pool_buffer(message_data *mesg, void *p, int size)
{
mesg->_pool = p;
mesg->_pool_size = size;
}
static inline void* message_get_pool_buffer(const message_data *mesg)
{
return mesg->_pool;
}
static inline int message_get_pool_size(const message_data *mesg)
{
return mesg->_pool_size;
}
static inline u8 message_get_opcode(const message_data *mesg)
{
return MESSAGE_OP(mesg->_buffer);
}
static inline void message_set_opcode(message_data *mesg, u8 op)
{
MESSAGE_SET_OP(mesg->_buffer, op);
}
static inline void message_set_referral(message_data *mesg, u8 referral)
{
mesg->_referral = referral;
}
static inline u8 message_get_referral(const message_data *mesg)
{
return mesg->_referral;
}
// Network Endian operations
static inline u16 message_get_query_count_ne(const message_data *mesg)
{
return MESSAGE_QD(mesg->_buffer);
}
static inline void message_set_answer_count_ne(message_data *mesg, u16 network_endian_value)
{
MESSAGE_SET_AN(mesg->_buffer, network_endian_value);
}
static inline u16 message_get_answer_count_ne(const message_data *mesg)
{
return MESSAGE_AN(mesg->_buffer);
}
static inline void message_set_authority_count_ne(message_data *mesg, u16 network_endian_value)
{
MESSAGE_SET_NS(mesg->_buffer, network_endian_value);
}
static inline u16 message_get_authority_count_ne(const message_data *mesg)
{
return MESSAGE_NS(mesg->_buffer);
}
static inline void message_set_additional_count_ne(message_data *mesg, u16 network_endian_value)
{
MESSAGE_SET_AR(mesg->_buffer, network_endian_value);
}
static inline u16 message_get_additional_count_ne(const message_data *mesg)
{
return MESSAGE_AR(mesg->_buffer);
}
static inline void message_set_update_count_ne(message_data *mesg, u16 network_endian_value)
{
MESSAGE_SET_UP(mesg->_buffer, network_endian_value);
}
static inline u16 message_get_update_count_ne(const message_data *mesg)
{
return MESSAGE_UP(mesg->_buffer);
}
static inline u16 message_get_prerequisite_count_ne(const message_data *mesg)
{
return MESSAGE_PR(mesg->_buffer);
}
static inline u16 message_get_section_count_ne(const message_data *mesg, int section)
{
return MESSAGE_SECTION_COUNT(mesg->_buffer, section);
}
// Host endian
static inline u16 message_get_query_count(const message_data *mesg)
{
return ntohs(message_get_query_count_ne(mesg));
}
static inline void message_set_answer_count(message_data *mesg, u16 host_endian_value)
{
message_set_answer_count_ne(mesg, htons(host_endian_value));
}
static inline u16 message_get_answer_count(const message_data *mesg)
{
return ntohs(message_get_answer_count_ne(mesg));
}
static inline void message_set_authority_count(message_data *mesg, u16 host_endian_value)
{
message_set_authority_count_ne(mesg, htons(host_endian_value));
}
static inline u16 message_get_authority_count(const message_data *mesg)
{
return ntohs(message_get_authority_count_ne(mesg));
}
static inline void message_set_additional_count(message_data *mesg, u16 host_endian_value)
{
message_set_additional_count_ne(mesg, htons(host_endian_value));
}
static inline u16 message_get_additional_count(const message_data *mesg)
{
return ntohs(message_get_additional_count_ne(mesg));
}
static inline void message_add_additional_count(message_data *mesg, u16 value)
{
message_set_additional_count(mesg, message_get_additional_count(mesg) + value);
}
static inline void message_sub_additional_count(message_data *mesg, u16 value)
{
message_set_additional_count(mesg, message_get_additional_count(mesg) - value);
}
static inline void message_set_update_count(message_data *mesg, u16 host_endian_value)
{
message_set_update_count_ne(mesg, htons(host_endian_value));
}
static inline u16 message_get_update_count(const message_data *mesg)
{
return ntohs(message_get_update_count_ne(mesg));
}
static inline void message_add_update_count(message_data *mesg, u16 host_endian_value)
{
message_set_update_count(mesg, message_get_update_count(mesg) + host_endian_value);
}
static inline u16 message_get_prerequisite_count(const message_data *mesg)
{
return ntohs(message_get_prerequisite_count_ne(mesg));
}
static inline u16 message_get_section_count(const message_data *mesg, int section)
{
return ntohs(message_get_section_count_ne(mesg, section));
}
//
static inline bool message_isquery(const message_data *mesg)
{
return MESSAGE_QR(mesg->_buffer) == 0;
}
static inline bool message_isanswer(const message_data *mesg)
{
return MESSAGE_QR(mesg->_buffer) != 0;
}
static inline bool message_istruncated(const message_data *mesg)
{
return MESSAGE_TC(mesg->_buffer) != 0;
}
static inline void message_set_truncated(message_data *mesg, bool truncated)
{
if(truncated)
{
MESSAGE_HIFLAGS(mesg->_buffer) |= TC_BITS;
}
else
{
MESSAGE_HIFLAGS(mesg->_buffer) &= ~TC_BITS;
}
}
static inline void message_set_answer(message_data *mesg)
{
MESSAGE_HIFLAGS(mesg->_buffer) |= QR_BITS;
}
static inline void message_clear_answer(message_data *mesg)
{
MESSAGE_HIFLAGS(mesg->_buffer) &= ~QR_BITS;
}
static inline bool message_has_recursion_desired(const message_data *mesg)
{
return MESSAGE_RD(mesg->_buffer) != 0;
}
static inline bool message_has_recursion_available(const message_data *mesg)
{
return MESSAGE_RA(mesg->_buffer) != 0;
}
static inline bool message_has_authenticated_data(const message_data *mesg)
{
return MESSAGE_AD(mesg->_buffer) != 0;
}
static inline bool message_has_checking_disabled(const message_data *mesg)
{
return MESSAGE_CD(mesg->_buffer) != 0;
}
static inline u8 message_get_rcode(const message_data *mesg)
{
return MESSAGE_RCODE(mesg->_buffer);
}
static inline void message_or_rcode(message_data *mesg, u8 rcode)
{
MESSAGE_LOFLAGS(mesg->_buffer) |= rcode;
}
static inline void message_set_rcode(message_data *mesg, u8 rcode)
{
MESSAGE_LOFLAGS(mesg->_buffer) = (MESSAGE_LOFLAGS(mesg->_buffer) & ~RCODE_BITS) | rcode;
}
static inline u32 message_get_rcode_ext(const message_data *mesg)
{
return mesg->_rcode_ext;
}
static inline bool message_has_rcode_ext_dnssec(const message_data *mesg)
{
return (mesg->_rcode_ext & RCODE_EXT_DNSSEC) != 0;
}
static inline void message_set_authoritative_answer(message_data *mesg)
{
MESSAGE_HIFLAGS(mesg->_buffer) |= AA_BITS|QR_BITS;
}
static inline void message_set_truncated_answer(message_data *mesg)
{
MESSAGE_HIFLAGS(mesg->_buffer) |= TC_BITS|QR_BITS;
}
static inline void message_set_authoritative(message_data *mesg)
{
MESSAGE_HIFLAGS(mesg->_buffer) |= AA_BITS;
}
static inline void message_disable_authoritative(message_data *mesg)
{
MESSAGE_HIFLAGS(mesg->_buffer) &= ~AA_BITS;
}
static inline void message_set_recursion_desired(message_data *mesg)
{
MESSAGE_HIFLAGS(mesg->_buffer) |= RD_BITS;
}
static inline void message_set_authenticated_data(message_data *mesg)
{
MESSAGE_LOFLAGS(mesg->_buffer) |= AD_BITS;
}
static inline bool message_isauthoritative(const message_data *mesg)
{
return (MESSAGE_HIFLAGS(mesg->_buffer) & AA_BITS) != 0;
}
static inline void message_apply_mask(message_data *mesg, int hi, int lo)
{
MESSAGE_FLAGS_AND(mesg->_buffer, (u8)hi, (u8)lo);
}
static inline void message_apply_lo_mask(message_data *mesg, u8 lo)
{
MESSAGE_LOFLAGS(mesg->_buffer) &= lo;
}
static inline u16 message_get_query_type(const message_data *mesg)
{
return mesg->_query_type;
}
static inline const u16* message_get_query_type_ptr(const message_data *mesg)
{
return &mesg->_query_type;
}
static inline void message_set_query_type(message_data *mesg, u16 qtype)
{
mesg->_query_type = qtype;
}
static inline u16 message_get_query_class(const message_data *mesg)
{
return mesg->_query_class;
}
// mostly for printing with format
static inline const u16* message_get_query_class_ptr(const message_data *mesg)
{
return &mesg->_query_class;
}
static inline void message_set_query_class(message_data *mesg, u16 qclass)
{
mesg->_query_class = qclass;
}
static inline u16 message_get_size_u16(const message_data *mesg)
{
return (u16)mesg->_msghdr.msg_iov[0].iov_len;
}
static inline size_t message_get_size(const message_data *mesg)
{
return mesg->_msghdr.msg_iov[0].iov_len;
}
static inline void message_set_size(message_data *mesg, size_t size)
{
mesg->_msghdr.msg_iov[0].iov_len = size;
}
static inline void message_increase_size(message_data *mesg, size_t size)
{
mesg->_msghdr.msg_iov[0].iov_len += size;
}
static inline const u8 *message_get_buffer_const(const message_data *mesg)
{
return mesg->_buffer;
}
static inline u8 *message_get_buffer(message_data *mesg)
{
return mesg->_buffer;
}
static inline u16 message_get_flags(const message_data *mesg)
{
return MESSAGE_FLAGS(mesg->_buffer);
}
static inline u8 message_get_flags_hi(const message_data *mesg)
{
return MESSAGE_HIFLAGS(mesg->_buffer);
}
static inline u8 message_get_flags_lo(const message_data *mesg)
{
return MESSAGE_LOFLAGS(mesg->_buffer);
}
static inline void message_set_flags_hi(message_data *mesg, u8 hi)
{
MESSAGE_HIFLAGS(mesg->_buffer) = hi;
}
static inline void message_set_flags_lo(message_data *mesg, u8 lo)
{
MESSAGE_LOFLAGS(mesg->_buffer) = lo;
}
static inline u8 message_get_op(message_data *mesg)
{
return MESSAGE_OP(mesg->_buffer);
}
/**
* Returns a pointer to the first byte not set in the buffer (&buffer[size])
* WILL BE RENAMED INTO message_get_buffer_end(mesg)
* @param mesg
* @return
*/
static inline u8 *message_get_buffer_limit(message_data *mesg)
{
return &mesg->_buffer[message_get_size(mesg)];
}
static inline const u8 *message_get_buffer_limit_const(const message_data *mesg)
{
return &mesg->_buffer[message_get_size(mesg)];
}
/**
* The maximum size of the buffer is, of course, a constant.
* This value is the one used to artificially limit the writing in the buffer.
* This is mostly used to reserve room for additional records (EDNS, TSIG)
*
* @param
* @return
*/
static inline void message_set_buffer_size(message_data *mesg, u32 size)
{
assert(size <= mesg->_buffer_size_limit);
mesg->_buffer_size = size;
}
static inline void message_reserve_buffer_size(message_data *mesg, u32 size)
{
assert(size <= mesg->_buffer_size);
mesg->_buffer_size -= size;
}
static inline void message_increase_buffer_size(message_data *mesg, u32 size)
{
assert(size + mesg->_buffer_size <= mesg->_buffer_size_limit);
mesg->_buffer_size += size;
}
static inline u32 message_get_buffer_size(const message_data *mesg)
{
return mesg->_buffer_size;
}
static inline void message_reset_buffer_size(message_data *mesg)
{
mesg->_buffer_size = mesg->_buffer_size_limit;
}
static inline u32 message_get_buffer_size_max(const message_data *mesg)
{
return mesg->_buffer_size_limit;
}
/**
* Copies the data content into the buffer
*/
static inline void message_copy_buffer(const message_data *mesg, void *out_data, size_t data_size)
{
yassert(data_size >= message_get_size(mesg));
(void)data_size;
memcpy(out_data, message_get_buffer_const(mesg), message_get_size(mesg));
}
static inline void message_copy_into_buffer(message_data *mesg, const void *in_data, size_t data_size)
{
if(data_size > message_get_buffer_size(mesg))
{
formatln("message_copy_into_buffer: %p data_size=%llu <= buffer_size=%u", mesg, data_size, message_get_buffer_size(mesg));
}
yassert(data_size <= message_get_buffer_size(mesg));
memcpy(message_get_buffer(mesg), in_data, data_size);
message_set_size(mesg, data_size);
}
/**
* Copies the control content into the buffer
*/
static inline u8 message_copy_control(const message_data *mesg, void *out_data, size_t data_size)
{
#ifndef WIN32
yassert(data_size >= mesg->_msghdr.msg_controllen);
(void)data_size;
memcpy(out_data, mesg->_msghdr.msg_control, mesg->_msghdr.msg_controllen);
return mesg->_msghdr.msg_controllen;
#else
return 0;
#endif
}
static inline u8 message_control_size(const message_data *mesg)
{
return mesg->_msghdr.msg_controllen;
}
static inline void message_set_control(message_data *mesg, const void *data, size_t data_size)
{
#ifndef WIN32
yassert(data_size <= sizeof(mesg->_msghdr_control_buffer));
memcpy(mesg->_msghdr_control_buffer, data, data_size);
mesg->_msghdr.msg_controllen = data_size;
#if __FreeBSD__
if(data_size != 0)
{
mesg->_msghdr.msg_control = mesg->_msghdr_control_buffer;
}
else
{
mesg->_msghdr.msg_control = NULL;
}
#endif
#else
#endif
}
static inline void message_reset_control_size(message_data *mesg)
{
#ifndef WIN32
#if __FreeBSD__
mesg->_msghdr.msg_control = mesg->_msghdr_control_buffer;
#endif
mesg->_msghdr.msg_controllen = sizeof(mesg->_msghdr_control_buffer);
#else
#endif
}
static inline void message_reset_control(message_data *mesg)
{
#ifndef WIN32
mesg->_msghdr.msg_control = mesg->_msghdr_control_buffer;
mesg->_msghdr.msg_controllen = sizeof(mesg->_msghdr_control_buffer);
#else
#endif
}
static inline void message_clear_control(message_data *mesg)
{
#ifndef WIN32
mesg->_msghdr.msg_control = NULL;
mesg->_msghdr.msg_controllen = 0;
#else
#endif
}
static inline void message_set_edns0(message_data *mesg, bool enabled)
{
mesg->_edns = enabled;
}
static inline bool message_is_edns0(const message_data *mesg)
{
return mesg->_edns;
}
static inline bool message_has_nsid(const message_data *mesg)
{
return mesg->_nsid;
}
static inline bool message_has_tsig(const message_data *mesg)
{
return mesg->_tsig.tsig != NULL;
}
static inline void message_clear_hmac(message_data *mesg)
{
if(mesg->_tsig.hmac != NULL)
{
hmac_free(mesg->_tsig.hmac);
mesg->_tsig.hmac = NULL;
}
}
static inline const u8 *message_tsig_get_name(const message_data *mesg)
{
return mesg->_tsig.tsig->name;
}
static inline s64 message_tsig_get_epoch(const message_data *mesg)
{
u64 then = (u64)ntohs(mesg->_tsig.timehi);
then <<= 32;
then |= (u64)ntohl(mesg->_tsig.timelo);
return (s64)then;
}
static inline s64 message_tsig_get_fudge(const message_data *mesg)
{
u64 then = (u64)ntohs(mesg->_tsig.fudge);
return (s64)then;
}
static inline int message_tsig_mac_get_size(const message_data *mesg)
{
return mesg->_tsig.mac_size;
}
static inline void message_tsig_set_error(message_data *mesg, u16 err)
{
mesg->_tsig.error = err;
}
static inline void message_tsig_mac_copy(const message_data *mesg, u8 *to)
{
memcpy(to, mesg->_tsig.mac, message_tsig_mac_get_size(mesg));
}
static inline const u8* message_tsig_mac_get_const(const message_data *mesg)
{
return mesg->_tsig.mac;
}
static inline void message_tsig_copy_from(message_data *mesg, const message_data *source)
{
message_tsig *d = &mesg->_tsig;
const message_tsig *s = &source->_tsig;
memcpy(d, s, offsetof(message_tsig, mac));
memcpy(d->mac, s->mac, s->mac_size);
d->other = s->other;
d->hmac = s->hmac;
d->tcp_tsig_countdown = s->tcp_tsig_countdown;
d->mac_algorithm = s->mac_algorithm;
}
static inline void message_tsig_set_key(message_data *mesg, const tsig_item *key)
{
mesg->_tsig.tsig = key;
mesg->_tsig.mac_algorithm = key->mac_algorithm;
}
static inline const tsig_item *message_tsig_get_key(const message_data *mesg)
{
return mesg->_tsig.tsig;
}
static inline void message_tsig_clear_key(message_data *mesg)
{
mesg->_tsig.tsig = NULL ;
}
static inline const u8 *message_tsig_get_key_bytes(const message_data *mesg)
{
return mesg->_tsig.tsig->mac;
}
static inline u16 message_tsig_get_key_size(const message_data *mesg)
{
return mesg->_tsig.tsig->mac_size;
}
static inline message_header *message_get_header(message_data *mesg)
{
return (message_header*)message_get_buffer(mesg);
}
#if DEBUG
static inline void message_debug_trash_buffer(message_data *mesg)
{
memset(message_get_buffer(mesg), 0xee, message_get_buffer_size_max(mesg));
}
#else
static inline void message_debug_trash_buffer(message_data *mesg)
{
(void)mesg;
}
#endif
static inline void message_copy_msghdr(const message_data *mesg, struct msghdr *copyto)
{
memcpy(copyto, &mesg->_msghdr, sizeof(mesg->_msghdr));
}
ya_result message_process_query(message_data *mesg);
int message_process(message_data *);
int message_process_lenient(message_data *mesg);
void message_transform_to_error(message_data *mesg);
/* global */
void message_edns0_setmaxsize(u16 maxsize);
static inline void message_edns0_clear_undefined_flags(message_data *mesg) // all but DO
{
mesg->_rcode_ext &= RCODE_EXT_DNSSEC;
}
/**
*
* @param mesg
* @param qname
* @param qtype
* @param qclass
* @param id
*/
void message_make_query(message_data *mesg, u16 id, const u8 *qname, u16 qtype, u16 qclass);
void message_make_query_ex(message_data *mesg, u16 id, const u8 *qname, u16 qtype, u16 qclass, u16 flags);
struct packet_writer;
void message_make_message(message_data *mesg, u16 id, const u8 *qname, u16 qtype, u16 qclass, struct packet_writer* uninitialised_packet_writer);
void message_make_dnsupdate_init(message_data *mesg, u16 id, const u8 *zzone, u16 zclass, u32 max_size, struct packet_writer *uninitialised_pw);
ya_result message_make_dnsupdate_delete_all_rrsets(message_data *mesg, struct packet_writer *pw, const u8 *fqdn);
ya_result message_make_dnsupdate_delete_rrset(message_data *mesg, struct packet_writer *pw, const u8 *fqdn, u16 rtype);
ya_result message_make_dnsupdate_delete_record(message_data *mesg, struct packet_writer *pw, const u8 *fqdn, u16 rtype, u16 rdata_size, const u8 *rdata);
ya_result message_make_dnsupdate_delete_dns_resource_record(message_data *mesg, struct packet_writer *pw, const struct dns_resource_record *rr);
ya_result message_make_dnsupdate_delete_dnskey(message_data *mesg, struct packet_writer *pw, dnssec_key *key);
ya_result message_make_dnsupdate_add_record(message_data *mesg, struct packet_writer *pw, const u8 *fqdn, u16 rtype, u16 rclass, s32 rttl, u16 rdata_size, const u8 *rdata);
ya_result message_make_dnsupdate_add_dns_resource_record(message_data *mesg, struct packet_writer *pw, const struct dns_resource_record *rr);
ya_result message_make_dnsupdate_add_dnskey(message_data *mesg, struct packet_writer *pw, dnssec_key *key, s32 ttl);
ya_result message_make_dnsupdate_finalize(message_data *mesg, struct packet_writer *pw);
/**
*
* @param mesg
* @param qname
* @param qtype
* @param qclass
* @param id
*/
void message_make_notify(message_data *mesg, u16 id, const u8 *qname, u16 qtype /* TYPE_SOA */, u16 qclass /* CLASS_IN */);
void message_make_ixfr_query(message_data *mesg, u16 id, const u8 *qname, u32 soa_ttl, u16 soa_rdata_size, const u8 *soa_rdata);
#if DNSCORE_HAS_TSIG_SUPPORT
ya_result message_sign_query_by_name(message_data *mesg, const u8 *tsig_name);
ya_result message_sign_answer_by_name(message_data *mesg, const u8 *tsig_name);
ya_result message_sign_query(message_data *mesg, const tsig_item *key);
ya_result message_sign_answer(message_data *mesg, const tsig_item *key);
#endif
/**
* Creates an empty answer with an error code
*
* @param mesg
* @param error_code
*/
void message_make_error(message_data *mesg, u16 error_code);
/**
* Creates an empty answer with an error code and TSIG signs it if needed
*
* @param mesg
* @param error_code
*/
void message_make_signed_error(message_data *mesg, u16 error_code);
ya_result message_make_error_and_reply_tcp(message_data *mesg, u16 error_code, int tcpfd);
ssize_t message_make_error_and_reply_tcp_with_default_minimum_throughput(message_data *mesg, u16 error_code, int tcpfd);
/**
* Creates an answer with an OPT error code
*/
void message_make_error_ext(message_data *mesg, u32 error_code);
static inline ya_result message_set_sender_from_host_address(message_data *mesg, const host_address *ha)
{
ya_result ret = host_address2sockaddr(ha, &mesg->_sender);
if(ISOK(ret))
{
mesg->_msghdr.msg_namelen = ret;
}
return ret;
}
static inline int message_get_sender_size(const message_data *mesg)
{
return mesg->_msghdr.msg_namelen;
}
static inline const socketaddress *message_get_sender(const message_data *mesg)
{
return &mesg->_sender;
}
static inline ya_result message_set_sender_port(message_data *mesg, u16 port)
{
switch(mesg->_sender.sa.sa_family)
{
case AF_INET:
{
mesg->_sender.sa4.sin_port = port;
return port;
}
case AF_INET6:
{
mesg->_sender.sa6.sin6_port = port;
return port;
}
default:
{
return INVALID_STATE_ERROR;
}
}
}
static inline const struct sockaddr *message_get_sender_sa(const message_data *mesg)
{
return &mesg->_sender.sa;
}
static inline sa_family_t message_get_sender_sa_family(const message_data *mesg)
{
return mesg->_sender.sa.sa_family;
}
static inline size_t message_get_sender_sa_family_size(const message_data *mesg)
{
switch(mesg->_sender.sa.sa_family)
{
case AF_INET:
{
return sizeof(struct sockaddr_in);
}
case AF_INET6:
{
return sizeof(struct sockaddr_in6);
}
default:
{
return 0;
}
}
}
static inline const struct sockaddr_in *message_get_sender_sa4(const message_data *mesg)
{
return &mesg->_sender.sa4;
}
static inline const struct sockaddr_in6 *message_get_sender_sa6(const message_data *mesg)
{
return &mesg->_sender.sa6;
}
static inline void message_copy_sender_from(message_data *mesg, const message_data *original)
{
memcpy(&mesg->_sender, &original->_sender, message_get_sender_size(original));
mesg->_msghdr.msg_name = &mesg->_sender;
mesg->_msghdr.msg_namelen = original->_msghdr.msg_namelen;
}
static inline void message_copy_sender_from_sa(message_data *mesg, const struct sockaddr *sa, socklen_t sa_len)
{
memcpy(&mesg->_sender, sa, sa_len);
mesg->_msghdr.msg_namelen = sa_len;
}
static inline ya_result message_copy_sender_from_socket(message_data *mesg, int client_sockfd)
{
mesg->_msghdr.msg_namelen = sizeof(mesg->_sender);
if(getpeername(client_sockfd, (struct sockaddr*)&mesg->_sender, &mesg->_msghdr.msg_namelen) >= 0)
{
mesg->_msghdr.msg_name = &mesg->_sender;
return SUCCESS;
}
else
{
return ERRNO_ERROR;
}
}
static inline void message_copy_sender_to_sa(const message_data *mesg, struct sockaddr *bigenoughforipv6)
{
memcpy(bigenoughforipv6, message_get_sender_sa(mesg), message_get_sender_size(mesg));
}
static inline u16 message_get_u16_at(const message_data *mesg, int offset)
{
return GET_U16_AT(mesg->_buffer[offset]);
}
static inline void message_send_udp_reset(message_data *mesg)
{
mesg->_msghdr.msg_namelen = sizeof(mesg->_sender);
mesg->_iovec.iov_len = mesg->_buffer_size;
}
#if !DEBUG
static inline ssize_t message_send_udp(const message_data *mesg, int sockfd)
{
return sendmsg(sockfd, &mesg->_msghdr, 0);
}
#else
ssize_t message_send_udp_debug(const message_data *mesg, int sockfd);
static inline ssize_t message_send_udp(const message_data *mesg, int sockfd)
{
ssize_t ret = message_send_udp_debug(mesg, sockfd);
if(ret < 0)
{
ret = ERRNO_ERROR;
}
return ret;
}
#endif
static inline void message_recv_udp_reset(message_data *mesg)
{
mesg->_msghdr.msg_namelen = sizeof(mesg->_sender);
mesg->_iovec.iov_len = mesg->_buffer_size;
}
static inline ssize_t message_recv_udp(message_data *mesg, int sockfd)
{
ssize_t ret = recvmsg(sockfd, &mesg->_msghdr, 0);
if(ret >= 0)
{
message_set_size(mesg, ret);
#if __FreeBSD__
if(mesg->_msghdr.msg_controllen == 0)
{
mesg->_msghdr.msg_control = NULL;
}
#endif
}
return ret;
}
/*
static inline ssize_t message_send_udp(message_data *mesg, int sockfd)
{
mesg->_iovec.iov_len = message_get_size(mesg);
ssize_t ret = sendmsg(sockfd, &mesg->_msghdr, 0);
return ret;
}
*/
static inline const u8 *message_parse_query_fqdn(const message_data *mesg)
{
if(message_get_query_count_ne(mesg) != 0)
{
return &mesg->_buffer[DNS_HEADER_LENGTH];
}
else
{
return NULL;
}
}
static inline u16 message_parse_query_type(const message_data *mesg)
{
if(message_get_query_count_ne(mesg) != 0)
{
const u8 *fqdn = &mesg->_buffer[DNS_HEADER_LENGTH];
fqdn += dnsname_len(fqdn);
return GET_U16_AT_P(fqdn);
}
else
{
return TYPE_NONE;
}
}
static inline u16 message_parse_query_class(const message_data *mesg)
{
if(message_get_query_count_ne(mesg) != 0)
{
const u8 *fqdn = &mesg->_buffer[DNS_HEADER_LENGTH];
fqdn += dnsname_len(fqdn) + 2;
return GET_U16_AT_P(fqdn);
}
else
{
return TYPE_NONE;
}
}
static inline const u8 *message_get_canonised_fqdn(const message_data *mesg)
{
return mesg->_canonised_fqdn;
}
static inline void message_set_canonised_fqdn(message_data *mesg, const u8 *canonised_fqdn)
{
dnsname_copy(mesg->_canonised_fqdn, canonised_fqdn);
}
static inline int message_get_maximum_size(const message_data *mesg)
{
return mesg->_buffer_size;
}
static inline u8* message_get_query_section_ptr(message_data *mesg)
{
return &mesg->_buffer[DNS_HEADER_LENGTH];
}
static inline u8* message_get_additional_section_ptr(message_data *mesg)
{
return mesg->_ar_start;
}
static inline const u8* message_get_additional_section_ptr_const(const message_data *mesg)
{
return mesg->_ar_start;
}
static inline bool message_is_additional_section_ptr_set(const message_data *mesg)
{
return mesg->_ar_start != NULL;
}
static inline void message_set_additional_section_ptr(message_data *mesg, void *ptr)
{
mesg->_ar_start = (u8*)ptr;
}
static inline finger_print message_get_status(const message_data *mesg)
{
return mesg->_status;
}
static inline void message_set_status(message_data *mesg, finger_print fp)
{
mesg->_status = fp;
}
static inline void message_set_error_status_from_result(message_data *mesg, ya_result error_code)
{
finger_print fp;
if(YA_ERROR_BASE(error_code) == RCODE_ERROR_BASE)
{
fp = RCODE_ERROR_GETCODE(error_code);
}
else
{
fp = FP_RCODE_SERVFAIL;
}
message_set_status(mesg, fp);
}
static inline void message_set_status_from_result(message_data *mesg, ya_result error_code)
{
finger_print fp;
if(ISOK(error_code))
{
fp = RCODE_NOERROR;
}
else if(YA_ERROR_BASE(error_code) == RCODE_ERROR_BASE)
{
fp = RCODE_ERROR_GETCODE(error_code);
}
else
{
fp = FP_RCODE_SERVFAIL;
}
message_set_status(mesg, fp);
}
static inline void message_update_answer_status(message_data *mesg)
{
MESSAGE_FLAGS_OR(mesg->_buffer, QR_BITS, mesg->_status);
}
static inline void message_update_truncated_answer_status(message_data *mesg)
{
MESSAGE_FLAGS_OR(mesg->_buffer, QR_BITS|TC_BITS, mesg->_status);
}
static inline u16 message_get_id(const message_data *mesg)
{
return MESSAGE_ID(mesg->_buffer);
}
#if MESSAGE_PAYLOAD_IS_POINTER
static inline ssize_t message_recv_tcp(message_data *mesg, int sockfd)
{
u16 tcp_len;
ssize_t ret = readfully(sockfd, &tcp_len, 2);
if(ret < 0)
{
return ret;
}
tcp_len = ntohs(tcp_len);
if(tcp_len < message_get_maximum_size(mesg))
{
ret = readfully(sockfd, mesg->_buffer, tcp_len);
if(ISOK(ret))
{
message_set_size(mesg, ret);
}
return ret;
}
else
{
return BUFFER_WOULD_OVERFLOW;
}
}
static inline ssize_t message_write_tcp(const message_data *mesg, output_stream *os)
{
ssize_t ret;
u16 tcp_len = htons(message_get_size_u16(mesg));
if(ISOK(ret = output_stream_write_fully(os, &tcp_len, 2)))
{
ret = output_stream_write_fully(os, message_get_buffer_const(mesg), message_get_size(mesg));
}
return ret;
}
static inline ssize_t message_read_tcp(message_data *mesg, input_stream *is)
{
u16 tcp_len;
ssize_t ret = input_stream_read_fully(is, &tcp_len, 2);
if(ret < 0)
{
return ret;
}
tcp_len = ntohs(tcp_len);
if(tcp_len < message_get_maximum_size(mesg))
{
ret = input_stream_read_fully(is, mesg->_buffer, tcp_len);
if(ISOK(ret))
{
message_set_size(mesg, ret);
}
return ret;
}
else
{
return BUFFER_WOULD_OVERFLOW;
}
}
#if 0
static inline ssize_t message_send_tcp(const message_data *mesg, int sockfd)
{
ssize_t ret;
u16 tcp_len = htons(message_get_size_u16(mesg));
if(ISOK(ret = writefully(sockfd, &tcp_len, 2)))
{
if(ISOK(ret = writefully(sockfd, message_get_buffer_const(mesg), message_get_size(mesg))))
{
ret += 2;
}
}
return ret;
}
#else
ssize_t message_send_tcp(const message_data *mesg, int sockfd);
#endif
static inline ssize_t message_send_tcp_with_minimum_throughput(const message_data *mesg, int sockfd, double minimum_rate)
{
ssize_t ret;
u16 tcp_len = htons(message_get_size_u16(mesg));
if(ISOK(ret = writefully_limited(sockfd, &tcp_len, 2, minimum_rate)))
{
assert(ret == 2);
if(ISOK(ret = writefully_limited(sockfd, message_get_buffer_const(mesg), message_get_size(mesg), minimum_rate)))
{
assert(ret == (ssize_t)message_get_size(mesg));
return ret + 2;
}
}
return ret;
}
static inline ssize_t message_update_length_send_tcp_with_minimum_throughput(message_data *mesg, int sockfd, double minimum_rate)
{
ssize_t ret = message_send_tcp_with_minimum_throughput(mesg, sockfd, minimum_rate);
return ret;
}
extern double g_message_data_minimum_troughput_default;
static inline ssize_t message_update_length_send_tcp_with_default_minimum_throughput(message_data *mesg, int sockfd)
{
ssize_t ret = message_send_tcp_with_minimum_throughput(mesg, sockfd, g_message_data_minimum_troughput_default);
return ret;
}
#else
static inline void message_update_tcp_length(message_data *mesg)
{
u16 len = message_get_size_u16(mesg);
SET_U16_AT(mesg->_buffer_tcp_len[0], htons(len));
}
static inline u32 message_get_tcp_length(const message_data *mesg)
{
u16 len = GET_U16_AT(mesg->_buffer_tcp_len[0]);
return ntohs(len);
}
static inline const u8 *message_get_tcp_buffer_const(const message_data *mesg)
{
return mesg->_buffer_tcp_len;
}
static inline u8 *message_get_tcp_buffer(message_data *mesg)
{
return mesg->_buffer_tcp_len;
}
static inline ssize_t message_recv_tcp(message_data *mesg, int sockfd)
{
ssize_t ret = readfully(sockfd, mesg->_buffer_tcp_len, 2);
if(ret < 0)
{
return ret;
}
ret = message_get_tcp_length(mesg);
if(ret > 0)
{
ret = readfully(sockfd, mesg->_buffer, ret);
if(ISOK(ret))
{
message_set_size(mesg, ret);
}
}
return ret;
}
static inline ssize_t message_write_tcp(const message_data *mesg, output_stream *os)
{
message_update_tcp_length(mesg);
ssize_t ret = output_stream_write(os, message_get_tcp_buffer_const(mesg), message_get_size_u16(mesg) + 2);
return ret;
}
static inline ssize_t message_read_tcp(message_data *mesg, input_stream *is)
{
ssize_t ret = input_stream_read(is, mesg->_buffer_tcp_len, 2);
if(ret < 0)
{
return ret;
}
ret = message_get_tcp_length(mesg);
if(ret > 0)
{
ret = input_stream_read(is, message_get_buffer(mesg), ret);
if(ISOK(ret))
{
message_set_size(mesg, ret);
}
}
return ret;
}
static inline ssize_t message_send_tcp(const message_data *mesg, int sockfd)
{
ssize_t ret = writefully(sockfd, message_get_tcp_buffer_const(mesg), message_get_size_u16(mesg) + 2);
return ret;
}
static inline ssize_t message_send_tcp_with_minimum_throughput(const message_data *mesg, int sockfd, double minimum_rate)
{
ssize_t ret = writefully_limited(sockfd, message_get_tcp_buffer_const(mesg), message_get_size_u16(mesg) + 2, minimum_rate);
return ret;
}
static inline ssize_t message_update_length_send_tcp_with_minimum_throughput(message_data *mesg, int sockfd, double minimum_rate)
{
message_update_tcp_length(mesg);
ssize_t ret = message_send_tcp_with_minimum_throughput(mesg, sockfd, minimum_rate);
return ret;
}
extern double g_message_data_minimum_troughput_default;
static inline ssize_t message_update_length_send_tcp_with_default_minimum_throughput(message_data *mesg, int sockfd)
{
message_update_tcp_length(mesg);
ssize_t ret = message_send_tcp_with_minimum_throughput(mesg, sockfd, g_message_data_minimum_troughput_default);
return ret;
}
#endif
static inline void message_set_id(message_data *mesg, u16 id)
{
MESSAGE_SET_ID(mesg->_buffer, id);
}
static inline void message_make_truncated_empty_answer(message_data *mesg)
{
message_set_truncated_answer(mesg);
message_set_query_answer_authority_additional_counts_ne(mesg, 0, 0, 0, 0);
message_set_size(mesg, DNS_HEADER_LENGTH);
}
/**
* To be called on a message at the beginning of a TCP stream
*
* @param mesg
*/
static inline void message_tcp_serial_reset(message_data *mesg)
{
mesg->_tcp_serial = 0;
}
/**
* To be called on a message when reading a following TCP stream message
*
* @param mesg
*/
static inline void message_tcp_serial_increment(message_data *mesg)
{
++mesg->_tcp_serial;
}
ya_result message_query_tcp_with_timeout(message_data *mesg, const host_address *server, u8 to_sec);
ya_result message_query_tcp_with_timeout_ex(message_data *mesg, const host_address *server, message_data *answer, u8 to_sec);
ya_result message_query_tcp(message_data *mesg, const host_address *server);
ya_result message_query_tcp_ex(message_data *mesg, const host_address *server, message_data *answer);
ya_result message_query_udp(message_data *mesg, const host_address *server);
ya_result message_query_udp_with_timeout(message_data *mesg, const host_address *server, int seconds, int useconds);
#define MESSAGE_QUERY_UDP_FLAG_RESET_ID 1
ya_result message_query_udp_with_timeout_and_retries(message_data *mesg, const host_address *server, int seconds, int useconds, u8 retries, u8 flags);
ya_result message_query(message_data *mesg, const host_address *server);
ya_result message_query_serial(const u8 *origin, const host_address *server, u32 *serial_out);
ya_result message_get_ixfr_query_serial(message_data *mesg, u32 *serialp);
/**
* Writes the edns0 (if present),
* applies the TSIG for the right position in the stream (if needed),
*
* Write the message to the (tcp) stream.
*
* @param mesg
* @param tcpos
* @param pos
* @return
*/
#if ZDB_HAS_TSIG_SUPPORT
ya_result message_terminate_then_write(message_data *mesg, output_stream *tcpos, tsig_tcp_message_position pos);
#else
ya_result message_terminate_then_write(message_data *mesg, output_stream *tcpos, int unused);
#endif
#if MESSAGE_PAYLOAD_IS_POINTER
void message_init_ex(message_data* mesg, u32 mesg_size, void *buffer, size_t buffer_size);
static inline message_data *message_data_with_buffer_init(message_data_with_buffer *mesg_buff)
{
message_init_ex(&mesg_buff->message, sizeof(struct message_data_with_buffer), mesg_buff->_buffer, mesg_buff->_buffer_limit - mesg_buff->_buffer);
return &mesg_buff->message;
}
#else
void message_init(message_data* mesg);
static inline message_data *message_data_with_buffer_init(message_data_with_buffer *mesg_buff)
{
message_init(&mesg_buff->message);
return &mesg_buff->message;
}
#endif
/**
* If pointer is NULL, the structure and buffer will be allocated together
* Note that in the current implementation, 8 bytes are reserved for TCP
*/
message_data* message_new_instance_ex(void *ptr, u32 message_size); // should be size of edns0 or 64K for TCP
message_data* message_new_instance(); // message_new_instance_ex(64K)
void message_finalize(message_data *mesg);
void message_free(message_data *mesg);
/*
* Does not clone the pool.
*/
message_data* message_dup(const message_data *mesg);
ya_result message_ixfr_query_get_serial(const message_data *mesg, u32 *serial);
/**
* Maps records in a message to easily access them afterward.
*
* @param map the message map to initialise
* @param mesg the message to map
*
* @return an error code
*/
ya_result message_map_init(message_map *map, const message_data *mesg);
/**
* Gets the fqdn of the record at index
*
* @param map
* @param index
* @param fqdn
* @param fqdn_size
*
* @return an error code
*/
ya_result message_map_get_fqdn(const message_map *map, int index, u8 *fqdn, int fqdn_size);
/**
* Gets the type class ttl rdata_size of the record at index
*
* @param map
* @param index
* @param tctr
*
* @return an error code
*/
ya_result message_map_get_tctr(const message_map *map, int index, struct type_class_ttl_rdlen *tctr);
/**
* Gets the rdata of the record at index
*
* @param map
* @param index
* @param rdata
* @param rdata_size
*
* @return the rdata size or an error code
*/
ya_result message_map_get_rdata(const message_map *map, int index, u8 *rdata, int rdata_size);
/**
* Gets the type of the record at index
*
* @param map
* @param index
*
* @return the record type or an error code
*/
ya_result message_map_get_type(const message_map *map, int index);
/**
*
* @param map
*
* @return the number of records mapped
*/
int message_map_record_count(const message_map *map);
/**
* Returns the index of the next record with the given type
* from, and including, a given index.
*
* @param map
* @param index
* @param type
* @return
*/
int message_map_get_next_record_from(const message_map *map, int index, u16 type);
/**
* Returns the index of the next record with the given type
* from, and including, a given index in a given section (0 to 3).
*
* @param map
* @param index
* @param type
* @return
*/
int message_map_get_next_record_from_section(const message_map *map, int section, int index, u16 type);
/**
* Returns the base index of a section
*
* @param map
* @param section
* @return
*/
static inline int message_map_get_section_base(const message_map *map, int section)
{
return map->section_base[section];
}
/**
* Sorts records by section so that:
* _ SOA is first,
* _ NSEC is last,
* _ NSEC3 labels are at the end,
* _ RRSIG follows its RRSET
*
* @param map
*/
void message_map_reorder(message_map *map);
void message_map_print(const message_map *map, output_stream *os);
/**
* Releases the memory used by the map
*
* @param map
*/
void message_map_finalize(message_map *map);
/**
* Gets the global edns0 maximum size
*
* @return
*/
u16 message_edns0_getmaxsize();
static inline void message_set_rd_flag(message_data *mesg)
{
MESSAGE_HIFLAGS(mesg->_buffer) |= RD_BITS;
}
struct logger_handle;
void message_log(struct logger_handle *logger, int level, const message_data *mesg);
ya_result message_print_format_multiline(output_stream *os_, const u8 *buffer, u16 length, u16 view_mode_with, long time_duration);
ya_result message_print_format_short(output_stream *os_, const u8 *buffer, u16 length, u16 view_mode_with, long time_duration);
ya_result message_print_format_wire(output_stream *os_, const u8 *buffer, u16 length, u16 view_mode_with, long time_duration);
ya_result message_print_format_wire_ext(output_stream *os_, const u8 *buffer, u16 length, u16 view_mode_with, long time_duration);
ya_result message_print_format_dig(output_stream *os_, const u8 *buffer, u32 length, u16 view_mode_with, long time_duration);
ya_result message_print_format_dig_buffer(output_stream *os_, const u8 *buffer, u32 length, u16 view_mode_with);
ya_result message_print_format_json(output_stream *os_, const u8 *buffer, u16 length, u16 view_mode_with, long time_duration);
ya_result message_print_format_json_buffer(output_stream *os_, const u8 *buffer, u16 length, u16 view_mode_with);
ya_result message_print_format_parse(output_stream *os_, const u8 *buffer, u16 length, u16 view_mode_with, long time_duration);
ya_result message_print_buffer_format_parse(output_stream *os_, const u8 *buffer, u16 length, u16 view_mode_with);
ya_result message_print_format_xml(output_stream *os_, const u8 *buffer, u16 length, u16 view_mode_with, long time_duration);
ya_result message_print_format_xml_buffer(output_stream *os_, const u8 *buffer, u16 length, u16 view_mode_with);
#ifdef __cplusplus
}
#endif
/** @} */