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. | |
| #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. | |
| #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. | |
| static struct compress_tree_node * | compress_tree_lookup (struct compress_tree_node **tree, uint8_t *dname, int labs, struct compress_tree_node ***insertpt) |
| Lookup a domain name in compression tree. | |
| static struct compress_tree_node * | compress_tree_newnode (uint8_t *dname, int labs, size_t offset, struct regional *region) |
| Create node for domain name compression tree. | |
| 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. | |
| 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_descriptor * | type_rdata_compressible (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_* | |
| 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. | |
| uint16_t | calc_edns_field_size (struct edns_data *edns) |
| Estimate size of EDNS record in packet. | |
| uint16_t | calc_edns_option_size (struct edns_data *edns, uint16_t code) |
| Calculate the size of a specific EDNS option in packet. | |
| uint16_t | calc_ede_option_size (struct edns_data *edns, uint16_t *txt_size) |
| Calculate the size of the EDE option(s) in packet. | |
| 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. | |
| 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. | |
| void | qinfo_query_encode (sldns_buffer *pkt, struct query_info *qinfo) |
| Encode query packet. | |
| 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. | |
| 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. | |
This file contains a routines to encode DNS messages.
| #define RETVAL_OUTMEM -2 |
return code that means the function ran out of memory.
negative so it does not conflict with DNS rcodes.
| #define RETVAL_OK 0 |
return code that means all is peachy keen.
Equal to DNS rcode NOERROR
|
static |
Find domain name in tree, returns exact and closest match.
| tree | root of tree. |
| dname | pointer to uncompressed dname. |
| labs | number of labels in domain name. |
| match | closest or exact match. guaranteed to be smaller or equal to the sought dname. can be null if the tree is empty. |
| matchlabels | number of labels that match with closest match. can be zero is there is no match. |
| insertpt | insert location for dname, if not found. |
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().
|
static |
Lookup a domain name in compression tree.
| tree | root of tree (not the node with '.'). |
| dname | pointer to uncompressed dname. |
| labs | number of labels in domain name. |
| insertpt | insert location for dname, if not found. |
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().
|
static |
Create node for domain name compression tree.
| dname | pointer to uncompressed dname (stored in tree). |
| labs | number of labels in dname. |
| offset | offset into packet for dname. |
| region | how to allocate memory for new node. |
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().
|
static |
Store domain name and ancestors into compression tree.
| dname | pointer to uncompressed dname (stored in tree). |
| labs | number of labels in dname. |
| offset | offset into packet for dname. |
| region | how to allocate memory for new node. |
| closest | match 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. |
| insertpt | where to insert the dname in tree. |
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().
|
static |
store rrset in buffer in wireformat, return RETVAL_*
Determine relative time adjustment for TTL values. For an rrset with a fixed TTL, use the rrset's TTL as given.
References compress_any_dname(), compress_owner(), compress_rdata(), packed_rrset_data::count, lruhash_entry::data, packed_rrset_key::dname, dname_count_labels(), ub_packed_rrset_key::entry, packed_rrset_key::flags, LDNS_RR_TYPE_RRSIG, PACKED_RRSET_FIXEDTTL, RETVAL_OK, RETVAL_TRUNC, ub_packed_rrset_key::rk, packed_rrset_data::rr_data, packed_rrset_data::rr_len, packed_rrset_data::rr_ttl, rrset_belongs_in_reply(), packed_rrset_key::rrset_class, packed_rrset_data::rrsig_count, SERVE_EXPIRED, SERVE_EXPIRED_REPLY_TTL, SERVE_ORIGINAL_TTL, sldns_buffer_position(), sldns_buffer_remaining(), sldns_buffer_write(), sldns_buffer_write_u16(), sldns_buffer_write_u32(), packed_rrset_data::ttl_add, packed_rrset_key::type, and type_rdata_compressible().
Referenced by insert_section().
| 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.
| qinfo | query info to store. |
| rep | reply to store. |
| id | id value to store, network order. |
| flags | flags value to store, host order. |
| buffer | buffer to store the packet into. |
| timenow | time now, to adjust ttl values. |
| region | to store temporary data in. |
| udpsize | size of the answer, 512, from EDNS, or 64k for TCP. |
| dnssec | if 0 DNSSEC records are omitted from the answer. |
| minimise | if true, the answer is a minimal response, with authority and additional removed if possible. |
References reply_info::an_numrrsets, reply_info::ar_numrrsets, BIT_AA, reply_info::flags, insert_query(), insert_section(), query_info::local_alias, reply_info::ns_numrrsets, reply_info::qdcount, query_info::qtype, RETVAL_OK, RETVAL_TRUNC, local_rrset::rrset, reply_info::rrset_count, RRSET_ROUNDROBIN, reply_info::rrsets, sldns_buffer_begin(), sldns_buffer_clear(), sldns_buffer_flip(), sldns_buffer_limit(), sldns_buffer_remaining(), sldns_buffer_set_limit(), sldns_buffer_write(), sldns_buffer_write_u16(), and sldns_buffer_write_u16_at().
Referenced by log_dns_msg(), perf_encode(), reply_info_answer_encode(), and testpkt().
| uint16_t calc_edns_field_size | ( | struct edns_data * | edns | ) |
Estimate size of EDNS record in packet.
EDNS record will be no larger.
| edns | edns data or NULL. |
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 chaos_replystr(), extended_error_encode(), reply_info_answer_encode(), testpkt(), and write_q().
| uint16_t calc_edns_option_size | ( | struct edns_data * | edns, |
| uint16_t | code | ||
| ) |
Calculate the size of a specific EDNS option in packet.
| edns | edns data or NULL. |
| code | the opt code to get the size of. |
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.
| 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 separately 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.
| edns | edns data or NULL. |
| txt_size | the size of the EXTRA-TEXT field(s); this includes LDNS_EDE_OTHER in their entirety since they are useless without extra text. |
References edns_data::edns_present, edns_option::next, edns_option::opt_code, edns_option::opt_data, edns_option::opt_len, edns_data::opt_list_inplace_cb_out, and edns_data::opt_list_out.
Referenced by reply_info_answer_encode().
| 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.
| pkt | packet added to. |
| edns | if NULL or present=0, nothing is added to the packet. |
References edns_data::edns_present, and edns_data::udp_size.
Referenced by chaos_replystr(), extended_error_encode(), perf_encode(), qlist_parse_line(), serviced_encode(), testpkt(), and write_q().
| 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.
| qinf | query information that provides query section in packet. |
| rep | reply to fill in. |
| id | id word from the query. |
| qflags | flags word from the query. |
| dest | buffer to put message into; will truncate if it does not fit. |
| timenow | time to subtract. |
| cached | set true if a cached reply (so no AA bit). set false for the first reply. |
| region | where to allocate temp variables (for compression). |
| udpsize | size of the answer, 512, from EDNS, or 64k for TCP. |
| edns | EDNS data included in the answer, NULL for none. or if edns_present = 0, it is not included. |
| dnssec | if 0 DNSSEC records are omitted from the answer. |
| secure | if 1, the AD bit is set in the reply. |
References reply_info::authoritative, BIT_AA, BIT_AD, BIT_CD, BIT_QR, BIT_RD, calc_ede_option_size(), calc_edns_field_size(), edns_opt_list_remove(), edns_data::edns_present, reply_info::flags, FLAGS_GET_RCODE, query_info::local_alias, log_assert, log_err(), MINIMAL_RESPONSES, edns_data::opt_list_inplace_cb_out, edns_data::opt_list_out, reply_info_encode(), sldns_buffer_capacity(), and sldns_buffer_limit().
Referenced by answer_from_cache(), answer_norec_from_cache(), auth_answer_encode(), local_encode(), mesh_do_callback(), mesh_send_reply(), and rpz_local_encode().
| void qinfo_query_encode | ( | struct sldns_buffer * | pkt, |
| struct query_info * | qinfo | ||
| ) |
Encode query packet.
Assumes the buffer is large enough.
| pkt | where to store the packet. |
| qinfo | query info. |
References packed_rrset_key::dname, packed_rrset_key::dname_len, query_info::local_alias, log_assert, 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_flip(), sldns_buffer_remaining(), sldns_buffer_skip(), sldns_buffer_write(), and sldns_buffer_write_u16().
Referenced by qlist_parse_line(), write_q(), xfr_create_ixfr_packet(), and xfr_create_soa_probe_packet().
| 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.
| pkt | where to store the packet. |
| rcode | Extended RCODE value to encode. |
| qinfo | if not NULL, the query is included. |
| qid | query ID to set in packet. network order. |
| qflags | original query flags (to copy RD and CD bits). host order. |
| xflags | extra flags to set (such as for example BIT_AA and/or BIT_TC) |
| edns | if 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 attach_edns_record(), 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, edns_data::opt_list_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(), and worker_handle_request().
| 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.
| pkt | where to store the packet. |
| r | RCODE value to encode (may contain extra flags). |
| qinfo | if not NULL, the query is included. |
| qid | query ID to set in packet. network order. |
| qflags | original query flags (to copy RD and CD bits). host order. |
| edns | if 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 answer_from_cache(), answer_norec_from_cache(), answer_notify(), auth_answer_encode(), auth_error_encode(), libworker_bg_done_cb(), local_encode(), local_error_encode(), mesh_new_client(), mesh_send_reply(), rpz_local_encode(), and worker_handle_request().