mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
EDNS for the client.
git-svn-id: file:///svn/unbound/trunk@288 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
841d09ff08
commit
f3c0cd34d8
8 changed files with 156 additions and 16 deletions
|
|
@ -51,6 +51,7 @@
|
||||||
#include "util/storage/slabhash.h"
|
#include "util/storage/slabhash.h"
|
||||||
#include "services/listen_dnsport.h"
|
#include "services/listen_dnsport.h"
|
||||||
#include "services/outside_network.h"
|
#include "services/outside_network.h"
|
||||||
|
#include "util/data/msgparse.h"
|
||||||
|
|
||||||
#ifdef HAVE_SYS_TYPES_H
|
#ifdef HAVE_SYS_TYPES_H
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
|
|
@ -62,6 +63,11 @@
|
||||||
#define DNS_ID_AND_FLAGS 4
|
#define DNS_ID_AND_FLAGS 4
|
||||||
/** timeout in seconds for UDP queries to auth servers. TODO: proper rtt */
|
/** timeout in seconds for UDP queries to auth servers. TODO: proper rtt */
|
||||||
#define UDP_QUERY_TIMEOUT 4
|
#define UDP_QUERY_TIMEOUT 4
|
||||||
|
/** Advertised version of EDNS capabilities */
|
||||||
|
#define EDNS_ADVERTISED_VERSION 0
|
||||||
|
/** Advertised size of EDNS capabilities */
|
||||||
|
#define EDNS_ADVERTISED_SIZE 4096
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
worker_send_cmd(struct worker* worker, ldns_buffer* buffer,
|
worker_send_cmd(struct worker* worker, ldns_buffer* buffer,
|
||||||
|
|
@ -206,6 +212,8 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
|
||||||
struct query_info qinf;
|
struct query_info qinf;
|
||||||
struct reply_info* rep;
|
struct reply_info* rep;
|
||||||
struct msgreply_entry* e;
|
struct msgreply_entry* e;
|
||||||
|
struct edns_data svr_edns; /* unused server edns advertisement */
|
||||||
|
uint16_t us;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
verbose(VERB_DETAIL, "reply to query with stored ID %d",
|
verbose(VERB_DETAIL, "reply to query with stored ID %d",
|
||||||
|
|
@ -223,7 +231,7 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
|
||||||
return 0; /* too much in the query section */
|
return 0; /* too much in the query section */
|
||||||
/* woohoo a reply! */
|
/* woohoo a reply! */
|
||||||
if((r=reply_info_parse(c->buffer, &w->worker->alloc, &qinf, &rep,
|
if((r=reply_info_parse(c->buffer, &w->worker->alloc, &qinf, &rep,
|
||||||
w->worker->scratchpad))!=0) {
|
w->worker->scratchpad, &svr_edns))!=0) {
|
||||||
if(r == LDNS_RCODE_SERVFAIL)
|
if(r == LDNS_RCODE_SERVFAIL)
|
||||||
log_err("reply_info_parse: out of memory");
|
log_err("reply_info_parse: out of memory");
|
||||||
/* formerr on my parse gives servfail to my client */
|
/* formerr on my parse gives servfail to my client */
|
||||||
|
|
@ -231,8 +239,14 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
|
||||||
region_free_all(w->worker->scratchpad);
|
region_free_all(w->worker->scratchpad);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
us = w->edns.udp_size;
|
||||||
|
w->edns.edns_version = EDNS_ADVERTISED_VERSION;
|
||||||
|
w->edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||||
|
w->edns.ext_rcode = 0;
|
||||||
|
w->edns.bits &= EDNS_DO;
|
||||||
if(!reply_info_answer_encode(&qinf, rep, w->query_id, w->query_flags,
|
if(!reply_info_answer_encode(&qinf, rep, w->query_id, w->query_flags,
|
||||||
w->query_reply.c->buffer, 0, 0, w->worker->scratchpad)) {
|
w->query_reply.c->buffer, 0, 0, w->worker->scratchpad, us,
|
||||||
|
&w->edns)) {
|
||||||
replyerror(LDNS_RCODE_SERVFAIL, w);
|
replyerror(LDNS_RCODE_SERVFAIL, w);
|
||||||
query_info_clear(&qinf);
|
query_info_clear(&qinf);
|
||||||
reply_info_parsedelete(rep, &w->worker->alloc);
|
reply_info_parsedelete(rep, &w->worker->alloc);
|
||||||
|
|
@ -308,7 +322,7 @@ worker_check_request(ldns_buffer* pkt)
|
||||||
LDNS_NSCOUNT(ldns_buffer_begin(pkt)));
|
LDNS_NSCOUNT(ldns_buffer_begin(pkt)));
|
||||||
return LDNS_RCODE_FORMERR;
|
return LDNS_RCODE_FORMERR;
|
||||||
}
|
}
|
||||||
if(LDNS_ARCOUNT(ldns_buffer_begin(pkt)) != 0) {
|
if(LDNS_ARCOUNT(ldns_buffer_begin(pkt)) > 1) {
|
||||||
verbose(VERB_DETAIL, "request wrong nr ar=%d",
|
verbose(VERB_DETAIL, "request wrong nr ar=%d",
|
||||||
LDNS_ARCOUNT(ldns_buffer_begin(pkt)));
|
LDNS_ARCOUNT(ldns_buffer_begin(pkt)));
|
||||||
return LDNS_RCODE_FORMERR;
|
return LDNS_RCODE_FORMERR;
|
||||||
|
|
@ -349,11 +363,12 @@ worker_handle_control_cmd(struct comm_point* c, void* arg, int error,
|
||||||
/** answer query from the cache */
|
/** answer query from the cache */
|
||||||
static int
|
static int
|
||||||
answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
|
answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
|
||||||
uint16_t flags, struct comm_reply* repinfo)
|
uint16_t flags, struct comm_reply* repinfo, struct edns_data* edns)
|
||||||
{
|
{
|
||||||
struct msgreply_entry* mrentry = (struct msgreply_entry*)e->key;
|
struct msgreply_entry* mrentry = (struct msgreply_entry*)e->key;
|
||||||
struct reply_info* rep = (struct reply_info*)e->data;
|
struct reply_info* rep = (struct reply_info*)e->data;
|
||||||
uint32_t timenow = time(0);
|
uint32_t timenow = time(0);
|
||||||
|
uint16_t udpsize = edns->udp_size;
|
||||||
size_t i;
|
size_t i;
|
||||||
/* see if it is possible */
|
/* see if it is possible */
|
||||||
if(rep->ttl <= timenow) {
|
if(rep->ttl <= timenow) {
|
||||||
|
|
@ -361,6 +376,10 @@ answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
|
||||||
/* but this ignores it */
|
/* but this ignores it */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
edns->edns_version = EDNS_ADVERTISED_VERSION;
|
||||||
|
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||||
|
edns->ext_rcode = 0;
|
||||||
|
edns->bits &= EDNS_DO;
|
||||||
/* check rrsets */
|
/* check rrsets */
|
||||||
for(i=0; i<rep->rrset_count; i++) {
|
for(i=0; i<rep->rrset_count; i++) {
|
||||||
if(i>0 && rep->ref[i].key == rep->ref[i-1].key)
|
if(i>0 && rep->ref[i].key == rep->ref[i-1].key)
|
||||||
|
|
@ -377,7 +396,8 @@ answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
|
||||||
}
|
}
|
||||||
/* locked and ids and ttls are OK. */
|
/* locked and ids and ttls are OK. */
|
||||||
if(!reply_info_answer_encode(&mrentry->key, rep, id, flags,
|
if(!reply_info_answer_encode(&mrentry->key, rep, id, flags,
|
||||||
repinfo->c->buffer, timenow, 1, worker->scratchpad)) {
|
repinfo->c->buffer, timenow, 1, worker->scratchpad,
|
||||||
|
udpsize, edns)) {
|
||||||
replyerror_fillbuf(LDNS_RCODE_SERVFAIL, repinfo, id,
|
replyerror_fillbuf(LDNS_RCODE_SERVFAIL, repinfo, id,
|
||||||
flags, &mrentry->key);
|
flags, &mrentry->key);
|
||||||
}
|
}
|
||||||
|
|
@ -403,6 +423,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||||
struct lruhash_entry* e;
|
struct lruhash_entry* e;
|
||||||
struct query_info qinfo;
|
struct query_info qinfo;
|
||||||
struct work_query* w;
|
struct work_query* w;
|
||||||
|
struct edns_data edns;
|
||||||
|
|
||||||
verbose(VERB_DETAIL, "worker handle request");
|
verbose(VERB_DETAIL, "worker handle request");
|
||||||
if(error != NETEVENT_NOERROR) {
|
if(error != NETEVENT_NOERROR) {
|
||||||
|
|
@ -427,12 +448,27 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
h = query_info_hash(&qinfo);
|
h = query_info_hash(&qinfo);
|
||||||
|
if((ret=parse_edns_from_pkt(c->buffer, &edns)) != 0) {
|
||||||
|
LDNS_QR_SET(ldns_buffer_begin(c->buffer));
|
||||||
|
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), ret);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(edns.edns_present && edns.edns_version != 0) {
|
||||||
|
/* TODO BADVERS errcode */
|
||||||
|
LDNS_QR_SET(ldns_buffer_begin(c->buffer));
|
||||||
|
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer),
|
||||||
|
LDNS_RCODE_NOTIMPL);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(c->type != comm_udp)
|
||||||
|
edns.udp_size = 65535; /* max size for TCP replies */
|
||||||
if((e=slabhash_lookup(worker->daemon->msg_cache, h, &qinfo, 0))) {
|
if((e=slabhash_lookup(worker->daemon->msg_cache, h, &qinfo, 0))) {
|
||||||
/* answer from cache - we have acquired a readlock on it */
|
/* answer from cache - we have acquired a readlock on it */
|
||||||
log_info("answer from the cache");
|
log_info("answer from the cache");
|
||||||
if(answer_from_cache(worker, e,
|
if(answer_from_cache(worker, e,
|
||||||
*(uint16_t*)ldns_buffer_begin(c->buffer),
|
*(uint16_t*)ldns_buffer_begin(c->buffer),
|
||||||
ldns_buffer_read_u16_at(c->buffer, 2), repinfo)) {
|
ldns_buffer_read_u16_at(c->buffer, 2), repinfo,
|
||||||
|
&edns)) {
|
||||||
lock_rw_unlock(&e->lock);
|
lock_rw_unlock(&e->lock);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -458,6 +494,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||||
query_info_clear(&qinfo);
|
query_info_clear(&qinfo);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
w->edns = edns;
|
||||||
worker->free_queries = w->next;
|
worker->free_queries = w->next;
|
||||||
worker->num_requests ++;
|
worker->num_requests ++;
|
||||||
log_assert(worker->num_requests <= worker->request_size);
|
log_assert(worker->num_requests <= worker->request_size);
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@
|
||||||
#include "util/locks.h"
|
#include "util/locks.h"
|
||||||
#include "util/alloc.h"
|
#include "util/alloc.h"
|
||||||
#include "util/data/msgreply.h"
|
#include "util/data/msgreply.h"
|
||||||
|
#include "util/data/msgparse.h"
|
||||||
#include "daemon/stats.h"
|
#include "daemon/stats.h"
|
||||||
struct listen_dnsport;
|
struct listen_dnsport;
|
||||||
struct outside_network;
|
struct outside_network;
|
||||||
|
|
@ -84,6 +85,8 @@ struct work_query {
|
||||||
uint16_t query_id;
|
uint16_t query_id;
|
||||||
/** flags uint16 from query */
|
/** flags uint16 from query */
|
||||||
uint16_t query_flags;
|
uint16_t query_flags;
|
||||||
|
/** edns data from the query */
|
||||||
|
struct edns_data edns;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
7 May 2007: Wouter
|
||||||
|
- EDNS read from query, used to make reply smaller.
|
||||||
|
- advertised edns value constants.
|
||||||
|
|
||||||
4 May 2007: Wouter
|
4 May 2007: Wouter
|
||||||
- msgreply sizefunc is more accurate.
|
- msgreply sizefunc is more accurate.
|
||||||
- config settings for rrset cache size and slabs.
|
- config settings for rrset cache size and slabs.
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,7 @@ testpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
uint32_t timenow = 0;
|
uint32_t timenow = 0;
|
||||||
region_type *region = region_create(malloc, free);
|
region_type *region = region_create(malloc, free);
|
||||||
|
struct edns_data edns;
|
||||||
|
|
||||||
hex_to_buf(pkt, hex);
|
hex_to_buf(pkt, hex);
|
||||||
memmove(&id, ldns_buffer_begin(pkt), sizeof(id));
|
memmove(&id, ldns_buffer_begin(pkt), sizeof(id));
|
||||||
|
|
@ -258,7 +259,7 @@ testpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
|
||||||
flags = 0;
|
flags = 0;
|
||||||
else memmove(&flags, ldns_buffer_at(pkt, 2), sizeof(flags));
|
else memmove(&flags, ldns_buffer_at(pkt, 2), sizeof(flags));
|
||||||
flags = ntohs(flags);
|
flags = ntohs(flags);
|
||||||
ret = reply_info_parse(pkt, alloc, &qi, &rep, region);
|
ret = reply_info_parse(pkt, alloc, &qi, &rep, region, &edns);
|
||||||
if(ret != 0) {
|
if(ret != 0) {
|
||||||
if(vbmp) printf("parse code %d: %s\n", ret,
|
if(vbmp) printf("parse code %d: %s\n", ret,
|
||||||
ldns_lookup_by_id(ldns_rcodes, ret)->name);
|
ldns_lookup_by_id(ldns_rcodes, ret)->name);
|
||||||
|
|
@ -267,7 +268,7 @@ testpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
|
||||||
unit_assert(ret != LDNS_RCODE_SERVFAIL);
|
unit_assert(ret != LDNS_RCODE_SERVFAIL);
|
||||||
} else {
|
} else {
|
||||||
ret = reply_info_encode(&qi, rep, id, flags, out, timenow,
|
ret = reply_info_encode(&qi, rep, id, flags, out, timenow,
|
||||||
region);
|
region, 65535);
|
||||||
unit_assert(ret != 0); /* udp packets should fit */
|
unit_assert(ret != 0); /* udp packets should fit */
|
||||||
if(vbmp) printf("inlen %u outlen %u\n",
|
if(vbmp) printf("inlen %u outlen %u\n",
|
||||||
(unsigned)ldns_buffer_limit(pkt),
|
(unsigned)ldns_buffer_limit(pkt),
|
||||||
|
|
|
||||||
|
|
@ -904,3 +904,34 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns)
|
||||||
/* ignore rdata and rrsigs */
|
/* ignore rdata and rrsigs */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
parse_edns_from_pkt(ldns_buffer* pkt, struct edns_data* edns)
|
||||||
|
{
|
||||||
|
log_assert(LDNS_QDCOUNT(ldns_buffer_begin(pkt)) == 1);
|
||||||
|
log_assert(LDNS_ANCOUNT(ldns_buffer_begin(pkt)) == 0);
|
||||||
|
log_assert(LDNS_NSCOUNT(ldns_buffer_begin(pkt)) == 0);
|
||||||
|
/* check edns section is present */
|
||||||
|
if(LDNS_ARCOUNT(ldns_buffer_begin(pkt)) > 1) {
|
||||||
|
return LDNS_RCODE_FORMERR;
|
||||||
|
}
|
||||||
|
if(LDNS_ARCOUNT(ldns_buffer_begin(pkt)) == 0) {
|
||||||
|
memset(edns, 0, sizeof(*edns));
|
||||||
|
edns->udp_size = 512;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* domain name must be the root of length 1. */
|
||||||
|
if(pkt_dname_len(pkt) != 1)
|
||||||
|
return LDNS_RCODE_FORMERR;
|
||||||
|
if(ldns_buffer_remaining(pkt) < 10) /* type, class, ttl, rdatalen */
|
||||||
|
return LDNS_RCODE_FORMERR;
|
||||||
|
if(ldns_buffer_read_u16(pkt) != LDNS_RR_TYPE_OPT)
|
||||||
|
return LDNS_RCODE_FORMERR;
|
||||||
|
edns->edns_present = 1;
|
||||||
|
edns->udp_size = ldns_buffer_read_u16(pkt); /* class is udp size */
|
||||||
|
edns->ext_rcode = ldns_buffer_read_u8(pkt); /* ttl used for bits */
|
||||||
|
edns->edns_version = ldns_buffer_read_u8(pkt);
|
||||||
|
edns->bits = ldns_buffer_read_u16(pkt);
|
||||||
|
/* ignore rdata and rrsigs */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,8 @@ struct rr_parse {
|
||||||
#define EDNS_RCODE_BADVERS 16 /** bad EDNS version */
|
#define EDNS_RCODE_BADVERS 16 /** bad EDNS version */
|
||||||
/** largest valid compression offset */
|
/** largest valid compression offset */
|
||||||
#define PTR_MAX_OFFSET 0x3fff
|
#define PTR_MAX_OFFSET 0x3fff
|
||||||
|
/** bits for EDNS bitfield */
|
||||||
|
#define EDNS_DO 0x8000 /* Dnssec Ok */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EDNS data storage
|
* EDNS data storage
|
||||||
|
|
@ -244,4 +246,15 @@ int parse_packet(ldns_buffer* pkt, struct msg_parse* msg,
|
||||||
*/
|
*/
|
||||||
int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns);
|
int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If EDNS data follows a query section, extract it and initialize edns struct.
|
||||||
|
* @param pkt: the packet. position at start must be right after the query
|
||||||
|
* section. At end, right after EDNS data or no movement if failed.
|
||||||
|
* @param edns: the edns data allocated by the caller. Does not have to be
|
||||||
|
* initialised.
|
||||||
|
* @return: 0 on success, or an RCODE on error.
|
||||||
|
* RCODE formerr if OPT is badly formatted and so on.
|
||||||
|
*/
|
||||||
|
int parse_edns_from_pkt(ldns_buffer* pkt, struct edns_data* edns);
|
||||||
|
|
||||||
#endif /* UTIL_DATA_MSGPARSE_H */
|
#endif /* UTIL_DATA_MSGPARSE_H */
|
||||||
|
|
|
||||||
|
|
@ -343,7 +343,8 @@ parse_create_msg(ldns_buffer* pkt, struct msg_parse* msg,
|
||||||
}
|
}
|
||||||
|
|
||||||
int reply_info_parse(ldns_buffer* pkt, struct alloc_cache* alloc,
|
int reply_info_parse(ldns_buffer* pkt, struct alloc_cache* alloc,
|
||||||
struct query_info* qinf, struct reply_info** rep, struct region* region)
|
struct query_info* qinf, struct reply_info** rep, struct region* region,
|
||||||
|
struct edns_data* edns)
|
||||||
{
|
{
|
||||||
/* use scratch pad region-allocator during parsing. */
|
/* use scratch pad region-allocator during parsing. */
|
||||||
struct msg_parse* msg;
|
struct msg_parse* msg;
|
||||||
|
|
@ -360,6 +361,8 @@ int reply_info_parse(ldns_buffer* pkt, struct alloc_cache* alloc,
|
||||||
if((ret = parse_packet(pkt, msg, region)) != 0) {
|
if((ret = parse_packet(pkt, msg, region)) != 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
if((ret = parse_extract_edns(msg, edns)) != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* parse OK, allocate return structures */
|
/* parse OK, allocate return structures */
|
||||||
/* this also performs dname decompression */
|
/* this also performs dname decompression */
|
||||||
|
|
@ -986,13 +989,15 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
|
||||||
|
|
||||||
int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
|
int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
|
||||||
uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow,
|
uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow,
|
||||||
region_type* region)
|
region_type* region, uint16_t udpsize)
|
||||||
{
|
{
|
||||||
uint16_t ancount=0, nscount=0, arcount=0;
|
uint16_t ancount=0, nscount=0, arcount=0;
|
||||||
struct compress_tree_node* tree = 0;
|
struct compress_tree_node* tree = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
ldns_buffer_clear(buffer);
|
ldns_buffer_clear(buffer);
|
||||||
|
if(udpsize < ldns_buffer_limit(buffer))
|
||||||
|
ldns_buffer_set_limit(buffer, udpsize);
|
||||||
if(ldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE)
|
if(ldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
@ -1061,10 +1066,45 @@ int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** estimate size of EDNS field in packet */
|
||||||
|
static uint16_t
|
||||||
|
calc_edns_field_size(struct edns_data* edns)
|
||||||
|
{
|
||||||
|
if(!edns || !edns->edns_present)
|
||||||
|
return 0;
|
||||||
|
/* domain root '.' + type + class + ttl + rdatalen(=0) */
|
||||||
|
return 1 + 2 + 2 + 4 + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** append EDNS field as last record in packet */
|
||||||
|
static void
|
||||||
|
attach_edns_field(ldns_buffer* pkt, struct edns_data* edns)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
if(!edns || !edns->edns_present)
|
||||||
|
return;
|
||||||
|
/* inc additional count */
|
||||||
|
ldns_buffer_write_u16_at(pkt, 10,
|
||||||
|
ldns_buffer_read_u16_at(pkt, 10) + 1);
|
||||||
|
len = ldns_buffer_limit(pkt);
|
||||||
|
ldns_buffer_clear(pkt);
|
||||||
|
ldns_buffer_set_position(pkt, len);
|
||||||
|
/* write EDNS record */
|
||||||
|
ldns_buffer_write_u8(pkt, 0); /* '.' label */
|
||||||
|
ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */
|
||||||
|
ldns_buffer_write_u16(pkt, edns->udp_size); /* class */
|
||||||
|
ldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
|
||||||
|
ldns_buffer_write_u8(pkt, edns->edns_version);
|
||||||
|
ldns_buffer_write_u16(pkt, edns->bits);
|
||||||
|
ldns_buffer_write_u16(pkt, 0); /* rdatalen */
|
||||||
|
ldns_buffer_flip(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
|
reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
|
||||||
uint16_t id, uint16_t qflags, ldns_buffer* pkt, uint32_t timenow,
|
uint16_t id, uint16_t qflags, ldns_buffer* pkt, uint32_t timenow,
|
||||||
int cached, struct region* region)
|
int cached, struct region* region, uint16_t udpsize,
|
||||||
|
struct edns_data* edns)
|
||||||
{
|
{
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
|
|
||||||
|
|
@ -1076,11 +1116,15 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
|
||||||
flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD));
|
flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD));
|
||||||
}
|
}
|
||||||
log_assert(flags & BIT_QR); /* QR bit must be on in our replies */
|
log_assert(flags & BIT_QR); /* QR bit must be on in our replies */
|
||||||
|
if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns))
|
||||||
if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region)) {
|
return 0; /* packet too small to contain edns... */
|
||||||
|
udpsize -= calc_edns_field_size(edns);
|
||||||
|
if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region,
|
||||||
|
udpsize)) {
|
||||||
log_err("reply encode: out of memory");
|
log_err("reply encode: out of memory");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
attach_edns_field(pkt, edns);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ struct comm_reply;
|
||||||
struct alloc_cache;
|
struct alloc_cache;
|
||||||
struct iovec;
|
struct iovec;
|
||||||
struct region;
|
struct region;
|
||||||
|
struct edns_data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structure to store query information that makes answers to queries
|
* Structure to store query information that makes answers to queries
|
||||||
|
|
@ -185,13 +186,14 @@ int query_info_parse(struct query_info* m, ldns_buffer* query);
|
||||||
* @param rep: allocated reply_info is returned (only on no error).
|
* @param rep: allocated reply_info is returned (only on no error).
|
||||||
* @param qinf: query_info is returned (only on no error).
|
* @param qinf: query_info is returned (only on no error).
|
||||||
* @param region: where to store temporary data (for parsing).
|
* @param region: where to store temporary data (for parsing).
|
||||||
|
* @param edns: where to store edns information, does not need to be inited.
|
||||||
* @return: zero is OK, or DNS error code in case of error
|
* @return: zero is OK, or DNS error code in case of error
|
||||||
* o FORMERR for parse errors.
|
* o FORMERR for parse errors.
|
||||||
* o SERVFAIL for memory allocation errors.
|
* o SERVFAIL for memory allocation errors.
|
||||||
*/
|
*/
|
||||||
int reply_info_parse(ldns_buffer* pkt, struct alloc_cache* alloc,
|
int reply_info_parse(ldns_buffer* pkt, struct alloc_cache* alloc,
|
||||||
struct query_info* qinf, struct reply_info** rep,
|
struct query_info* qinf, struct reply_info** rep,
|
||||||
struct region* region);
|
struct region* region, struct edns_data* edns);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts the ref array.
|
* Sorts the ref array.
|
||||||
|
|
@ -256,11 +258,15 @@ hashvalue_t query_info_hash(struct query_info *q);
|
||||||
* @param cached: set true if a cached reply (so no AA bit).
|
* @param cached: set true if a cached reply (so no AA bit).
|
||||||
* set false for the first reply.
|
* set false for the first reply.
|
||||||
* @param region: where to allocate temp variables (for compression).
|
* @param region: where to allocate temp variables (for compression).
|
||||||
|
* @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP.
|
||||||
|
* @param edns: EDNS data included in the answer, NULL for none.
|
||||||
|
* or if edns_present = 0, it is not included.
|
||||||
* @return: 0 on error (server failure).
|
* @return: 0 on error (server failure).
|
||||||
*/
|
*/
|
||||||
int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
|
int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
|
||||||
uint16_t id, uint16_t qflags, ldns_buffer* dest, uint32_t timenow,
|
uint16_t id, uint16_t qflags, ldns_buffer* dest, uint32_t timenow,
|
||||||
int cached, struct region* region);
|
int cached, struct region* region, uint16_t udpsize,
|
||||||
|
struct edns_data* edns);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regenerate the wireformat from the stored msg reply.
|
* Regenerate the wireformat from the stored msg reply.
|
||||||
|
|
@ -274,12 +280,13 @@ int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
|
||||||
* @param buffer: buffer to store the packet into.
|
* @param buffer: buffer to store the packet into.
|
||||||
* @param timenow: time now, to adjust ttl values.
|
* @param timenow: time now, to adjust ttl values.
|
||||||
* @param region: to store temporary data in.
|
* @param region: to store temporary data in.
|
||||||
|
* @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP.
|
||||||
* @return: nonzero is success, or
|
* @return: nonzero is success, or
|
||||||
* 0 on error: malloc failure (no log_err has been done).
|
* 0 on error: malloc failure (no log_err has been done).
|
||||||
*/
|
*/
|
||||||
int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
|
int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
|
||||||
uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow,
|
uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow,
|
||||||
struct region* region);
|
struct region* region, uint16_t udpsize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup query info entry
|
* Setup query info entry
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue