msgencode.c File Reference

This file contains a routines to encode DNS messages. More...

#include "config.h"
#include "util/data/msgencode.h"
#include "util/data/msgreply.h"
#include "util/data/msgparse.h"
#include "util/data/dname.h"
#include "util/log.h"
#include "util/regional.h"
#include "util/net_help.h"
#include "sldns/sbuffer.h"
#include "services/localzone.h"
#include <sys/time.h>

Data Structures

struct  compress_tree_node
 Data structure to help domain name compression in outgoing messages. More...
 

Macros

#define RETVAL_OUTMEM   -2
 return code that means the function ran out of memory. More...
 
#define RETVAL_TRUNC   -4
 return code that means the data did not fit (completely) in the packet
 
#define RETVAL_OK   0
 return code that means all is peachy keen. More...
 
#define MAX_COMPRESSION_PER_MESSAGE   120
 Max compressions we are willing to perform; more than that will result in semi-compressed messages, or truncated even on TCP for huge messages, to avoid locking the CPU for long.
 

Functions

static int compress_tree_search (struct compress_tree_node **tree, uint8_t *dname, int labs, struct compress_tree_node **match, int *matchlabels, struct compress_tree_node ***insertpt)
 Find domain name in tree, returns exact and closest match. More...
 
static struct compress_tree_nodecompress_tree_lookup (struct compress_tree_node **tree, uint8_t *dname, int labs, struct compress_tree_node ***insertpt)
 Lookup a domain name in compression tree. More...
 
static struct compress_tree_nodecompress_tree_newnode (uint8_t *dname, int labs, size_t offset, struct regional *region)
 Create node for domain name compression tree. More...
 
static int compress_tree_store (uint8_t *dname, int labs, size_t offset, struct regional *region, struct compress_tree_node *closest, struct compress_tree_node **insertpt)
 Store domain name and ancestors into compression tree. More...
 
static int write_compressed_dname (sldns_buffer *pkt, uint8_t *dname, int labs, struct compress_tree_node *p)
 compress a domain name
 
static int compress_owner (struct ub_packed_rrset_key *key, sldns_buffer *pkt, struct regional *region, struct compress_tree_node **tree, size_t owner_pos, uint16_t *owner_ptr, int owner_labs, size_t *compress_count)
 compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC
 
static int compress_any_dname (uint8_t *dname, sldns_buffer *pkt, int labs, struct regional *region, struct compress_tree_node **tree, size_t *compress_count)
 compress any domain name to the packet, return RETVAL_*
 
static const sldns_rr_descriptortype_rdata_compressable (struct ub_packed_rrset_key *key)
 return true if type needs domain name compression in rdata
 
static int compress_rdata (sldns_buffer *pkt, uint8_t *rdata, size_t todolen, struct regional *region, struct compress_tree_node **tree, const sldns_rr_descriptor *desc, size_t *compress_count)
 compress domain names in rdata, return RETVAL_*
 
static int rrset_belongs_in_reply (sldns_pkt_section s, uint16_t rrtype, uint16_t qtype, int dnssec)
 Returns true if RR type should be included.
 
static int packed_rrset_encode (struct ub_packed_rrset_key *key, sldns_buffer *pkt, uint16_t *num_rrs, time_t timenow, struct regional *region, int do_data, int do_sig, struct compress_tree_node **tree, sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset, size_t *compress_count)
 store rrset in buffer in wireformat, return RETVAL_* More...
 
static int insert_section (struct reply_info *rep, size_t num_rrsets, uint16_t *num_rrs, sldns_buffer *pkt, size_t rrsets_before, time_t timenow, struct regional *region, struct compress_tree_node **tree, sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset, size_t *compress_count)
 store msg section in wireformat buffer, return RETVAL_*
 
static int insert_query (struct query_info *qinfo, struct compress_tree_node **tree, sldns_buffer *buffer, struct regional *region)
 store query section in wireformat buffer, return RETVAL
 
static int positive_answer (struct reply_info *rep, uint16_t qtype)
 
static int negative_answer (struct reply_info *rep)
 
int reply_info_encode (struct query_info *qinfo, struct reply_info *rep, uint16_t id, uint16_t flags, sldns_buffer *buffer, time_t timenow, struct regional *region, uint16_t udpsize, int dnssec, int minimise)
 Regenerate the wireformat from the stored msg reply. More...
 
uint16_t calc_edns_field_size (struct edns_data *edns)
 Estimate size of EDNS record in packet. More...
 
uint16_t calc_edns_option_size (struct edns_data *edns, uint16_t code)
 Calculate the size of a specific EDNS option in packet. More...
 
uint16_t calc_ede_option_size (struct edns_data *edns, uint16_t *txt_size)
 Calculate the size of the EDE option(s) in packet. More...
 
static void ede_trim_text (struct edns_option **list)
 
static void attach_edns_record_max_msg_sz (sldns_buffer *pkt, struct edns_data *edns, uint16_t max_msg_sz)
 
void attach_edns_record (sldns_buffer *pkt, struct edns_data *edns)
 Attach EDNS record to buffer. More...
 
int reply_info_answer_encode (struct query_info *qinf, struct reply_info *rep, uint16_t id, uint16_t qflags, sldns_buffer *pkt, time_t timenow, int cached, struct regional *region, uint16_t udpsize, struct edns_data *edns, int dnssec, int secure)
 Generate answer from reply_info. More...
 
void qinfo_query_encode (sldns_buffer *pkt, struct query_info *qinfo)
 Encode query packet. More...
 
void extended_error_encode (sldns_buffer *buf, uint16_t rcode, struct query_info *qinfo, uint16_t qid, uint16_t qflags, uint16_t xflags, struct edns_data *edns)
 Encode an extended error. More...
 
void error_encode (sldns_buffer *buf, int r, struct query_info *qinfo, uint16_t qid, uint16_t qflags, struct edns_data *edns)
 Encode an error. More...
 

Detailed Description

This file contains a routines to encode DNS messages.

Macro Definition Documentation

◆ RETVAL_OUTMEM

#define RETVAL_OUTMEM   -2

return code that means the function ran out of memory.

negative so it does not conflict with DNS rcodes.

◆ RETVAL_OK

#define RETVAL_OK   0

return code that means all is peachy keen.

Equal to DNS rcode NOERROR

Function Documentation

◆ compress_tree_search()

static int compress_tree_search ( struct compress_tree_node **  tree,
uint8_t *  dname,
int  labs,
struct compress_tree_node **  match,
int *  matchlabels,
struct compress_tree_node ***  insertpt 
)
static

Find domain name in tree, returns exact and closest match.

Parameters
treeroot of tree.
dnamepointer to uncompressed dname.
labsnumber of labels in domain name.
matchclosest or exact match. guaranteed to be smaller or equal to the sought dname. can be null if the tree is empty.
matchlabelsnumber of labels that match with closest match. can be zero is there is no match.
insertptinsert location for dname, if not found.
Returns
: 0 if no exact match.

References compress_tree_node::dname, dname_lab_cmp(), compress_tree_node::labs, compress_tree_node::left, match(), and compress_tree_node::right.

Referenced by compress_tree_lookup().

◆ compress_tree_lookup()

static struct compress_tree_node* compress_tree_lookup ( struct compress_tree_node **  tree,
uint8_t *  dname,
int  labs,
struct compress_tree_node ***  insertpt 
)
static

Lookup a domain name in compression tree.

Parameters
treeroot of tree (not the node with '.').
dnamepointer to uncompressed dname.
labsnumber of labels in domain name.
insertptinsert location for dname, if not found.
Returns
: 0 if not found or compress treenode with best compression.

References compress_tree_search(), compress_tree_node::dname, compress_tree_node::labs, and compress_tree_node::parent.

Referenced by compress_any_dname(), and compress_owner().

◆ compress_tree_newnode()

static struct compress_tree_node* compress_tree_newnode ( uint8_t *  dname,
int  labs,
size_t  offset,
struct regional region 
)
static

Create node for domain name compression tree.

Parameters
dnamepointer to uncompressed dname (stored in tree).
labsnumber of labels in dname.
offsetoffset into packet for dname.
regionhow to allocate memory for new node.
Returns
new node or 0 on malloc failure.

References compress_tree_node::dname, compress_tree_node::labs, compress_tree_node::left, compress_tree_node::offset, compress_tree_node::parent, regional_alloc(), and compress_tree_node::right.

Referenced by compress_tree_store().

◆ compress_tree_store()

static int compress_tree_store ( uint8_t *  dname,
int  labs,
size_t  offset,
struct regional region,
struct compress_tree_node closest,
struct compress_tree_node **  insertpt 
)
static

Store domain name and ancestors into compression tree.

Parameters
dnamepointer to uncompressed dname (stored in tree).
labsnumber of labels in dname.
offsetoffset into packet for dname.
regionhow to allocate memory for new node.
closestmatch from previous lookup, used to compress dname. may be NULL if no previous match. if the tree has an ancestor of dname already, this must be it.
insertptwhere to insert the dname in tree.
Returns
: 0 on memory error.

References compress_tree_newnode(), compress_tree_node::dname, compress_tree_node::labs, log_assert, compress_tree_node::offset, compress_tree_node::parent, PTR_MAX_OFFSET, and compress_tree_node::right.

Referenced by compress_any_dname(), compress_owner(), and insert_query().

◆ packed_rrset_encode()

static int packed_rrset_encode ( struct ub_packed_rrset_key key,
sldns_buffer pkt,
uint16_t *  num_rrs,
time_t  timenow,
struct regional region,
int  do_data,
int  do_sig,
struct compress_tree_node **  tree,
sldns_pkt_section  s,
uint16_t  qtype,
int  dnssec,
size_t  rr_offset,
size_t *  compress_count 
)
static

◆ reply_info_encode()

int reply_info_encode ( struct query_info qinfo,
struct reply_info rep,
uint16_t  id,
uint16_t  flags,
struct sldns_buffer buffer,
time_t  timenow,
struct regional region,
uint16_t  udpsize,
int  dnssec,
int  minimise 
)

Regenerate the wireformat from the stored msg reply.

If the buffer is too small then the message is truncated at a whole rrset and the TC bit set, or whole rrsets are left out of the additional and the TC bit is not set.

Parameters
qinfoquery info to store.
repreply to store.
idid value to store, network order.
flagsflags value to store, host order.
bufferbuffer to store the packet into.
timenowtime now, to adjust ttl values.
regionto store temporary data in.
udpsizesize of the answer, 512, from EDNS, or 64k for TCP.
dnssecif 0 DNSSEC records are omitted from the answer.
minimiseif true, the answer is a minimal response, with authority and additional removed if possible.
Returns
: nonzero is success, or 0 on error: malloc failure (no log_err has been done).

References sldns_buffer_clear(), sldns_buffer_limit(), sldns_buffer_remaining(), and sldns_buffer_set_limit().

◆ calc_edns_field_size()

uint16_t calc_edns_field_size ( struct edns_data edns)

Estimate size of EDNS record in packet.

EDNS record will be no larger.

Parameters
ednsedns data or NULL.
Returns
octets to reserve for EDNS.

References edns_data::edns_present, edns_option::next, edns_option::opt_len, edns_data::opt_list_inplace_cb_out, and edns_data::opt_list_out.

Referenced by extended_error_encode().

◆ calc_edns_option_size()

uint16_t calc_edns_option_size ( struct edns_data edns,
uint16_t  code 
)

Calculate the size of a specific EDNS option in packet.

Parameters
ednsedns data or NULL.
codethe opt code to get the size of.
Returns
octets the option will take up.

References edns_data::edns_present, edns_option::next, edns_option::opt_code, edns_option::opt_len, edns_data::opt_list_inplace_cb_out, and edns_data::opt_list_out.

◆ calc_ede_option_size()

uint16_t calc_ede_option_size ( struct edns_data edns,
uint16_t *  txt_size 
)

Calculate the size of the EDE option(s) in packet.

Also calculate seperately the size of the EXTRA-TEXT field(s) in case we can trim them to fit. In this case include any LDNS_EDE_OTHER options in their entirety since they are useless without extra text.

Parameters
ednsedns data or NULL.
txt_sizethe size of the EXTRA-TEXT field(s); this includes LDNS_EDE_OTHER in their entirety since they are useless without extra text.
Returns
octets the option will take up.

References edns_data::edns_present, edns_option::next, edns_option::opt_code, and edns_data::opt_list_inplace_cb_out.

◆ attach_edns_record()

void attach_edns_record ( struct sldns_buffer pkt,
struct edns_data edns 
)

Attach EDNS record to buffer.

Buffer has complete packet. There must be enough room left for the EDNS record.

Parameters
pktpacket added to.
ednsif NULL or present=0, nothing is added to the packet.

References edns_data::edns_present.

◆ reply_info_answer_encode()

int reply_info_answer_encode ( struct query_info qinf,
struct reply_info rep,
uint16_t  id,
uint16_t  qflags,
struct sldns_buffer dest,
time_t  timenow,
int  cached,
struct regional region,
uint16_t  udpsize,
struct edns_data edns,
int  dnssec,
int  secure 
)

Generate answer from reply_info.

Parameters
qinfquery information that provides query section in packet.
repreply to fill in.
idid word from the query.
qflagsflags word from the query.
destbuffer to put message into; will truncate if it does not fit.
timenowtime to subtract.
cachedset true if a cached reply (so no AA bit). set false for the first reply.
regionwhere to allocate temp variables (for compression).
udpsizesize of the answer, 512, from EDNS, or 64k for TCP.
ednsEDNS data included in the answer, NULL for none. or if edns_present = 0, it is not included.
dnssecif 0 DNSSEC records are omitted from the answer.
secureif 1, the AD bit is set in the reply.
Returns
: 0 on error (server failure).

References reply_info::authoritative, BIT_AA, BIT_AD, BIT_CD, BIT_RD, reply_info::flags, FLAGS_GET_RCODE, and query_info::local_alias.

Referenced by auth_answer_encode(), and rpz_local_encode().

◆ qinfo_query_encode()

◆ extended_error_encode()

void extended_error_encode ( struct sldns_buffer pkt,
uint16_t  rcode,
struct query_info qinfo,
uint16_t  qid,
uint16_t  qflags,
uint16_t  xflags,
struct edns_data edns 
)

Encode an extended error.

With QR and RA set.

Parameters
pktwhere to store the packet.
rcodeExtended RCODE value to encode.
qinfoif not NULL, the query is included.
qidquery ID to set in packet. network order.
qflagsoriginal query flags (to copy RD and CD bits). host order.
xflagsextra flags to set (such as for example BIT_AA and/or BIT_TC)
ednsif not NULL, this is the query edns info, and an edns reply is attached. Only attached if EDNS record fits reply. Without edns extended errors (i.e. > 15) will not be conveyed.

References BIT_CD, BIT_QR, BIT_RA, BIT_RD, edns_data::bits, calc_edns_field_size(), packed_rrset_key::dname, packed_rrset_key::dname_len, EDNS_ADVERTISED_SIZE, EDNS_ADVERTISED_VERSION, EDNS_DO, edns_opt_list_remove(), edns_data::edns_version, edns_data::ext_rcode, query_info::local_alias, edns_data::opt_list_inplace_cb_out, query_info::qclass, query_info::qname, query_info::qname_len, query_info::qtype, ub_packed_rrset_key::rk, local_rrset::rrset, sldns_buffer_clear(), sldns_buffer_current(), sldns_buffer_flip(), sldns_buffer_limit(), sldns_buffer_skip(), sldns_buffer_write(), sldns_buffer_write_u16(), and edns_data::udp_size.

Referenced by error_encode().

◆ error_encode()

void error_encode ( struct sldns_buffer pkt,
int  r,
struct query_info qinfo,
uint16_t  qid,
uint16_t  qflags,
struct edns_data edns 
)

Encode an error.

With QR and RA set.

Parameters
pktwhere to store the packet.
rRCODE value to encode (may contain extra flags).
qinfoif not NULL, the query is included.
qidquery ID to set in packet. network order.
qflagsoriginal query flags (to copy RD and CD bits). host order.
ednsif not NULL, this is the query edns info, and an edns reply is attached. Only attached if EDNS record fits reply.

References extended_error_encode().

Referenced by auth_answer_encode(), auth_error_encode(), libworker_bg_done_cb(), and rpz_local_encode().