Coverage Report

Created: 2023-06-07 06:25

/src/unbound/util/data/msgreply.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * util/data/msgreply.c - store message and reply data. 
3
 *
4
 * Copyright (c) 2007, NLnet Labs. All rights reserved.
5
 *
6
 * This software is open source.
7
 * 
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 
12
 * Redistributions of source code must retain the above copyright notice,
13
 * this list of conditions and the following disclaimer.
14
 * 
15
 * Redistributions in binary form must reproduce the above copyright notice,
16
 * this list of conditions and the following disclaimer in the documentation
17
 * and/or other materials provided with the distribution.
18
 * 
19
 * Neither the name of the NLNET LABS nor the names of its contributors may
20
 * be used to endorse or promote products derived from this software without
21
 * specific prior written permission.
22
 * 
23
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
 */
35
36
/**
37
 * \file
38
 *
39
 * This file contains a data structure to store a message and its reply.
40
 */
41
42
#include "config.h"
43
#include "util/data/msgreply.h"
44
#include "util/storage/lookup3.h"
45
#include "util/log.h"
46
#include "util/alloc.h"
47
#include "util/netevent.h"
48
#include "util/net_help.h"
49
#include "util/data/dname.h"
50
#include "util/regional.h"
51
#include "util/data/msgparse.h"
52
#include "util/data/msgencode.h"
53
#include "sldns/sbuffer.h"
54
#include "sldns/wire2str.h"
55
#include "util/module.h"
56
#include "util/fptr_wlist.h"
57
58
/** MAX TTL default for messages and rrsets */
59
time_t MAX_TTL = 3600 * 24 * 10; /* ten days */
60
/** MIN TTL default for messages and rrsets */
61
time_t MIN_TTL = 0;
62
/** MAX Negative TTL, for SOA records in authority section */
63
time_t MAX_NEG_TTL = 3600; /* one hour */
64
/** If we serve expired entries and prefetch them */
65
int SERVE_EXPIRED = 0;
66
/** Time to serve records after expiration */
67
time_t SERVE_EXPIRED_TTL = 0;
68
/** TTL to use for expired records */
69
time_t SERVE_EXPIRED_REPLY_TTL = 30;
70
/** If we serve the original TTL or decrementing TTLs */
71
int SERVE_ORIGINAL_TTL = 0;
72
73
/** allocate qinfo, return 0 on error */
74
static int
75
parse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg, 
76
  struct query_info* qinf, struct regional* region)
77
0
{
78
0
  if(msg->qname) {
79
0
    if(region)
80
0
      qinf->qname = (uint8_t*)regional_alloc(region, 
81
0
        msg->qname_len);
82
0
    else  qinf->qname = (uint8_t*)malloc(msg->qname_len);
83
0
    if(!qinf->qname) return 0;
84
0
    dname_pkt_copy(pkt, qinf->qname, msg->qname);
85
0
  } else qinf->qname = 0;
86
0
  qinf->qname_len = msg->qname_len;
87
0
  qinf->qtype = msg->qtype;
88
0
  qinf->qclass = msg->qclass;
89
0
  qinf->local_alias = NULL;
90
0
  return 1;
91
0
}
92
93
/** constructor for replyinfo */
94
struct reply_info*
95
construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
96
  time_t ttl, time_t prettl, time_t expttl, size_t an, size_t ns,
97
  size_t ar, size_t total, enum sec_status sec)
98
0
{
99
0
  struct reply_info* rep;
100
  /* rrset_count-1 because the first ref is part of the struct. */
101
0
  size_t s = sizeof(struct reply_info) - sizeof(struct rrset_ref) +
102
0
    sizeof(struct ub_packed_rrset_key*) * total;
103
0
  if(total >= RR_COUNT_MAX) return NULL; /* sanity check on numRRS*/
104
0
  if(region)
105
0
    rep = (struct reply_info*)regional_alloc(region, s);
106
0
  else  rep = (struct reply_info*)malloc(s + 
107
0
      sizeof(struct rrset_ref) * (total));
108
0
  if(!rep) 
109
0
    return NULL;
110
0
  rep->flags = flags;
111
0
  rep->qdcount = qd;
112
0
  rep->ttl = ttl;
113
0
  rep->prefetch_ttl = prettl;
114
0
  rep->serve_expired_ttl = expttl;
115
0
  rep->an_numrrsets = an;
116
0
  rep->ns_numrrsets = ns;
117
0
  rep->ar_numrrsets = ar;
118
0
  rep->rrset_count = total;
119
0
  rep->security = sec;
120
0
  rep->reason_bogus = LDNS_EDE_NONE;
121
0
  rep->authoritative = 0;
122
  /* array starts after the refs */
123
0
  if(region)
124
0
    rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[0]);
125
0
  else  rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[total]);
126
  /* zero the arrays to assist cleanup in case of malloc failure */
127
0
  memset( rep->rrsets, 0, sizeof(struct ub_packed_rrset_key*) * total);
128
0
  if(!region)
129
0
    memset( &rep->ref[0], 0, sizeof(struct rrset_ref) * total);
130
0
  return rep;
131
0
}
132
133
/** allocate replyinfo, return 0 on error */
134
static int
135
parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep,
136
  struct regional* region)
137
0
{
138
0
  *rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0, 
139
0
    0, 0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets, 
140
0
    msg->rrset_count, sec_status_unchecked);
141
0
  if(!*rep)
142
0
    return 0;
143
0
  return 1;
144
0
}
145
146
int
147
reply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
148
  struct regional* region)
149
0
{
150
0
  size_t i;
151
0
  for(i=0; i<rep->rrset_count; i++) {
152
0
    if(region) {
153
0
      rep->rrsets[i] = (struct ub_packed_rrset_key*)
154
0
        regional_alloc(region, 
155
0
        sizeof(struct ub_packed_rrset_key));
156
0
      if(rep->rrsets[i]) {
157
0
        memset(rep->rrsets[i], 0, 
158
0
          sizeof(struct ub_packed_rrset_key));
159
0
        rep->rrsets[i]->entry.key = rep->rrsets[i];
160
0
      }
161
0
    }
162
0
    else  rep->rrsets[i] = alloc_special_obtain(alloc);
163
0
    if(!rep->rrsets[i])
164
0
      return 0;
165
0
    rep->rrsets[i]->entry.data = NULL;
166
0
  }
167
0
  return 1;
168
0
}
169
170
struct reply_info *
171
make_new_reply_info(const struct reply_info* rep, struct regional* region,
172
  size_t an_numrrsets, size_t copy_rrsets)
173
0
{
174
0
  struct reply_info* new_rep;
175
0
  size_t i;
176
177
  /* create a base struct.  we specify 'insecure' security status as
178
   * the modified response won't be DNSSEC-valid.  In our faked response
179
   * the authority and additional sections will be empty (except possible
180
   * EDNS0 OPT RR in the additional section appended on sending it out),
181
   * so the total number of RRsets is an_numrrsets. */
182
0
  new_rep = construct_reply_info_base(region, rep->flags,
183
0
    rep->qdcount, rep->ttl, rep->prefetch_ttl,
184
0
    rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets,
185
0
    sec_status_insecure);
186
0
  if(!new_rep)
187
0
    return NULL;
188
0
  if(!reply_info_alloc_rrset_keys(new_rep, NULL, region))
189
0
    return NULL;
190
0
  for(i=0; i<copy_rrsets; i++)
191
0
    new_rep->rrsets[i] = rep->rrsets[i];
192
193
0
  return new_rep;
194
0
}
195
196
/** find the minimumttl in the rdata of SOA record */
197
static time_t
198
soa_find_minttl(struct rr_parse* rr)
199
0
{
200
0
  uint16_t rlen = sldns_read_uint16(rr->ttl_data+4);
201
0
  if(rlen < 20)
202
0
    return 0; /* rdata too small for SOA (dname, dname, 5*32bit) */
203
  /* minimum TTL is the last 32bit value in the rdata of the record */
204
  /* at position ttl_data + 4(ttl) + 2(rdatalen) + rdatalen - 4(timeval)*/
205
0
  return (time_t)sldns_read_uint32(rr->ttl_data+6+rlen-4);
206
0
}
207
208
/** do the rdata copy */
209
static int
210
rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, 
211
  struct rr_parse* rr, time_t* rr_ttl, uint16_t type,
212
  sldns_pkt_section section)
213
0
{
214
0
  uint16_t pkt_len;
215
0
  const sldns_rr_descriptor* desc;
216
217
0
  *rr_ttl = sldns_read_uint32(rr->ttl_data);
218
  /* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */
219
0
  if(*rr_ttl & 0x80000000U)
220
0
    *rr_ttl = 0;
221
0
  if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
222
    /* negative response. see if TTL of SOA record larger than the
223
     * minimum-ttl in the rdata of the SOA record */
224
0
    if(*rr_ttl > soa_find_minttl(rr))
225
0
      *rr_ttl = soa_find_minttl(rr);
226
0
  }
227
0
  if(!SERVE_ORIGINAL_TTL && (*rr_ttl < MIN_TTL))
228
0
    *rr_ttl = MIN_TTL;
229
0
  if(!SERVE_ORIGINAL_TTL && (*rr_ttl > MAX_TTL))
230
0
    *rr_ttl = MAX_TTL;
231
0
  if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
232
    /* max neg ttl overrides the min and max ttl of everything
233
     * else, it is for a more specific record */
234
0
    if(*rr_ttl > MAX_NEG_TTL)
235
0
      *rr_ttl = MAX_NEG_TTL;
236
0
  }
237
0
  if(*rr_ttl < data->ttl)
238
0
    data->ttl = *rr_ttl;
239
240
0
  if(rr->outside_packet) {
241
    /* uncompressed already, only needs copy */
242
0
    memmove(to, rr->ttl_data+sizeof(uint32_t), rr->size);
243
0
    return 1;
244
0
  }
245
246
0
  sldns_buffer_set_position(pkt, (size_t)
247
0
    (rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t)));
248
  /* insert decompressed size into rdata len stored in memory */
249
  /* -2 because rdatalen bytes are not included. */
250
0
  pkt_len = htons(rr->size - 2);
251
0
  memmove(to, &pkt_len, sizeof(uint16_t));
252
0
  to += 2;
253
  /* read packet rdata len */
254
0
  pkt_len = sldns_buffer_read_u16(pkt);
255
0
  if(sldns_buffer_remaining(pkt) < pkt_len)
256
0
    return 0;
257
0
  desc = sldns_rr_descript(type);
258
0
  if(pkt_len > 0 && desc && desc->_dname_count > 0) {
259
0
    int count = (int)desc->_dname_count;
260
0
    int rdf = 0;
261
0
    size_t len;
262
0
    size_t oldpos;
263
    /* decompress dnames. */
264
0
    while(pkt_len > 0 && count) {
265
0
      switch(desc->_wireformat[rdf]) {
266
0
      case LDNS_RDF_TYPE_DNAME:
267
0
        oldpos = sldns_buffer_position(pkt);
268
0
        dname_pkt_copy(pkt, to, 
269
0
          sldns_buffer_current(pkt));
270
0
        to += pkt_dname_len(pkt);
271
0
        pkt_len -= sldns_buffer_position(pkt)-oldpos;
272
0
        count--;
273
0
        len = 0;
274
0
        break;
275
0
      case LDNS_RDF_TYPE_STR:
276
0
        len = sldns_buffer_current(pkt)[0] + 1;
277
0
        break;
278
0
      default:
279
0
        len = get_rdf_size(desc->_wireformat[rdf]);
280
0
        break;
281
0
      }
282
0
      if(len) {
283
0
        log_assert(len <= pkt_len);
284
0
        memmove(to, sldns_buffer_current(pkt), len);
285
0
        to += len;
286
0
        sldns_buffer_skip(pkt, (ssize_t)len);
287
0
        pkt_len -= len;
288
0
      }
289
0
      rdf++;
290
0
    }
291
0
  }
292
  /* copy remaining rdata */
293
0
  if(pkt_len >  0)
294
0
    memmove(to, sldns_buffer_current(pkt), pkt_len);
295
  
296
0
  return 1;
297
0
}
298
299
/** copy over the data into packed rrset */
300
static int
301
parse_rr_copy(sldns_buffer* pkt, struct rrset_parse* pset, 
302
  struct packed_rrset_data* data)
303
0
{
304
0
  size_t i;
305
0
  struct rr_parse* rr = pset->rr_first;
306
0
  uint8_t* nextrdata;
307
0
  size_t total = pset->rr_count + pset->rrsig_count;
308
0
  data->ttl = MAX_TTL;
309
0
  data->count = pset->rr_count;
310
0
  data->rrsig_count = pset->rrsig_count;
311
0
  data->trust = rrset_trust_none;
312
0
  data->security = sec_status_unchecked;
313
  /* layout: struct - rr_len - rr_data - rr_ttl - rdata - rrsig */
314
0
  data->rr_len = (size_t*)((uint8_t*)data + 
315
0
    sizeof(struct packed_rrset_data));
316
0
  data->rr_data = (uint8_t**)&(data->rr_len[total]);
317
0
  data->rr_ttl = (time_t*)&(data->rr_data[total]);
318
0
  nextrdata = (uint8_t*)&(data->rr_ttl[total]);
319
0
  for(i=0; i<data->count; i++) {
320
0
    data->rr_len[i] = rr->size;
321
0
    data->rr_data[i] = nextrdata;
322
0
    nextrdata += rr->size;
323
0
    if(!rdata_copy(pkt, data, data->rr_data[i], rr, 
324
0
      &data->rr_ttl[i], pset->type, pset->section))
325
0
      return 0;
326
0
    rr = rr->next;
327
0
  }
328
  /* if rrsig, its rdata is at nextrdata */
329
0
  rr = pset->rrsig_first;
330
0
  for(i=data->count; i<total; i++) {
331
0
    data->rr_len[i] = rr->size;
332
0
    data->rr_data[i] = nextrdata;
333
0
    nextrdata += rr->size;
334
0
    if(!rdata_copy(pkt, data, data->rr_data[i], rr, 
335
0
      &data->rr_ttl[i], LDNS_RR_TYPE_RRSIG, pset->section))
336
0
      return 0;
337
0
    rr = rr->next;
338
0
  }
339
0
  return 1;
340
0
}
341
342
/** create rrset return 0 on failure */
343
static int
344
parse_create_rrset(sldns_buffer* pkt, struct rrset_parse* pset,
345
  struct packed_rrset_data** data, struct regional* region)
346
0
{
347
  /* allocate */
348
0
  size_t s;
349
0
  if(pset->rr_count > RR_COUNT_MAX || pset->rrsig_count > RR_COUNT_MAX ||
350
0
    pset->size > RR_COUNT_MAX)
351
0
    return 0; /* protect against integer overflow */
352
0
  s = sizeof(struct packed_rrset_data) + 
353
0
    (pset->rr_count + pset->rrsig_count) * 
354
0
    (sizeof(size_t)+sizeof(uint8_t*)+sizeof(time_t)) + 
355
0
    pset->size;
356
0
  if(region)
357
0
    *data = regional_alloc_zero(region, s);
358
0
  else  *data = calloc(1, s);
359
0
  if(!*data)
360
0
    return 0;
361
  /* copy & decompress */
362
0
  if(!parse_rr_copy(pkt, pset, *data)) {
363
0
    if(!region) {
364
0
      free(*data);
365
0
      *data = NULL;
366
0
    }
367
0
    return 0;
368
0
  }
369
0
  return 1;
370
0
}
371
372
/** get trust value for rrset */
373
static enum rrset_trust
374
get_rrset_trust(struct msg_parse* msg, struct rrset_parse* rrset)
375
0
{
376
0
  uint16_t AA = msg->flags & BIT_AA;
377
0
  if(rrset->section == LDNS_SECTION_ANSWER) {
378
0
    if(AA) {
379
      /* RFC2181 says remainder of CNAME chain is nonauth*/
380
0
      if(msg->rrset_first && 
381
0
        msg->rrset_first->section==LDNS_SECTION_ANSWER
382
0
        && msg->rrset_first->type==LDNS_RR_TYPE_CNAME){
383
0
        if(rrset == msg->rrset_first)
384
0
          return rrset_trust_ans_AA;
385
0
        else  return rrset_trust_ans_noAA;
386
0
      }
387
0
      if(msg->rrset_first && 
388
0
        msg->rrset_first->section==LDNS_SECTION_ANSWER
389
0
        && msg->rrset_first->type==LDNS_RR_TYPE_DNAME){
390
0
        if(rrset == msg->rrset_first ||
391
0
           rrset == msg->rrset_first->rrset_all_next)
392
0
          return rrset_trust_ans_AA;
393
0
        else  return rrset_trust_ans_noAA;
394
0
      }
395
0
      return rrset_trust_ans_AA;
396
0
    }
397
0
    else  return rrset_trust_ans_noAA;
398
0
  } else if(rrset->section == LDNS_SECTION_AUTHORITY) {
399
0
    if(AA) return rrset_trust_auth_AA;
400
0
    else  return rrset_trust_auth_noAA;
401
0
  } else {
402
    /* addit section */
403
0
    if(AA) return rrset_trust_add_AA;
404
0
    else  return rrset_trust_add_noAA;
405
0
  }
406
  /* NOTREACHED */
407
0
  return rrset_trust_none;
408
0
}
409
410
int
411
parse_copy_decompress_rrset(sldns_buffer* pkt, struct msg_parse* msg,
412
  struct rrset_parse *pset, struct regional* region, 
413
  struct ub_packed_rrset_key* pk)
414
0
{
415
0
  struct packed_rrset_data* data;
416
0
  pk->rk.flags = pset->flags;
417
0
  pk->rk.dname_len = pset->dname_len;
418
0
  if(region)
419
0
    pk->rk.dname = (uint8_t*)regional_alloc(
420
0
      region, pset->dname_len);
421
0
  else  pk->rk.dname = 
422
0
      (uint8_t*)malloc(pset->dname_len);
423
0
  if(!pk->rk.dname)
424
0
    return 0;
425
  /** copy & decompress dname */
426
0
  dname_pkt_copy(pkt, pk->rk.dname, pset->dname);
427
  /** copy over type and class */
428
0
  pk->rk.type = htons(pset->type);
429
0
  pk->rk.rrset_class = pset->rrset_class;
430
  /** read data part. */
431
0
  if(!parse_create_rrset(pkt, pset, &data, region)) {
432
0
    if(!region) {
433
0
      free(pk->rk.dname);
434
0
      pk->rk.dname = NULL;
435
0
    }
436
0
    return 0;
437
0
  }
438
0
  pk->entry.data = (void*)data;
439
0
  pk->entry.key = (void*)pk;
440
0
  pk->entry.hash = pset->hash;
441
0
  data->trust = get_rrset_trust(msg, pset);
442
0
  return 1;
443
0
}
444
445
/** 
446
 * Copy and decompress rrs
447
 * @param pkt: the packet for compression pointer resolution.
448
 * @param msg: the parsed message
449
 * @param rep: reply info to put rrs into.
450
 * @param region: if not NULL, used for allocation.
451
 * @return 0 on failure.
452
 */
453
static int
454
parse_copy_decompress(sldns_buffer* pkt, struct msg_parse* msg,
455
  struct reply_info* rep, struct regional* region)
456
0
{
457
0
  size_t i;
458
0
  struct rrset_parse *pset = msg->rrset_first;
459
0
  struct packed_rrset_data* data;
460
0
  log_assert(rep);
461
0
  rep->ttl = MAX_TTL;
462
0
  rep->security = sec_status_unchecked;
463
0
  if(rep->rrset_count == 0)
464
0
    rep->ttl = NORR_TTL;
465
466
0
  for(i=0; i<rep->rrset_count; i++) {
467
0
    if(!parse_copy_decompress_rrset(pkt, msg, pset, region,
468
0
      rep->rrsets[i]))
469
0
      return 0;
470
0
    data = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
471
0
    if(data->ttl < rep->ttl)
472
0
      rep->ttl = data->ttl;
473
474
0
    pset = pset->rrset_all_next;
475
0
  }
476
0
  rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl);
477
0
  rep->serve_expired_ttl = rep->ttl + SERVE_EXPIRED_TTL;
478
0
  return 1;
479
0
}
480
481
int 
482
parse_create_msg(sldns_buffer* pkt, struct msg_parse* msg,
483
  struct alloc_cache* alloc, struct query_info* qinf, 
484
  struct reply_info** rep, struct regional* region)
485
0
{
486
0
  log_assert(pkt && msg);
487
0
  if(!parse_create_qinfo(pkt, msg, qinf, region))
488
0
    return 0;
489
0
  if(!parse_create_repinfo(msg, rep, region))
490
0
    return 0;
491
0
  if(!reply_info_alloc_rrset_keys(*rep, alloc, region)) {
492
0
    if(!region) reply_info_parsedelete(*rep, alloc);
493
0
    return 0;
494
0
  }
495
0
  if(!parse_copy_decompress(pkt, msg, *rep, region)) {
496
0
    if(!region) reply_info_parsedelete(*rep, alloc);
497
0
    return 0;
498
0
  }
499
0
  return 1;
500
0
}
501
502
int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc,
503
        struct query_info* qinf, struct reply_info** rep, 
504
  struct regional* region, struct edns_data* edns)
505
0
{
506
  /* use scratch pad region-allocator during parsing. */
507
0
  struct msg_parse* msg;
508
0
  int ret;
509
  
510
0
  qinf->qname = NULL;
511
0
  qinf->local_alias = NULL;
512
0
  *rep = NULL;
513
0
  if(!(msg = regional_alloc(region, sizeof(*msg)))) {
514
0
    return LDNS_RCODE_SERVFAIL;
515
0
  }
516
0
  memset(msg, 0, sizeof(*msg));
517
  
518
0
  sldns_buffer_set_position(pkt, 0);
519
0
  if((ret = parse_packet(pkt, msg, region)) != 0) {
520
0
    return ret;
521
0
  }
522
0
  if((ret = parse_extract_edns_from_response_msg(msg, edns, region)) != 0)
523
0
    return ret;
524
525
  /* parse OK, allocate return structures */
526
  /* this also performs dname decompression */
527
0
  if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) {
528
0
    query_info_clear(qinf);
529
0
    *rep = NULL;
530
0
    return LDNS_RCODE_SERVFAIL;
531
0
  }
532
0
  return 0;
533
0
}
534
535
/** helper compare function to sort in lock order */
536
static int
537
reply_info_sortref_cmp(const void* a, const void* b)
538
0
{
539
0
  struct rrset_ref* x = (struct rrset_ref*)a;
540
0
  struct rrset_ref* y = (struct rrset_ref*)b;
541
0
  if(x->key < y->key) return -1;
542
0
  if(x->key > y->key) return 1;
543
0
  return 0;
544
0
}
545
546
void 
547
reply_info_sortref(struct reply_info* rep)
548
0
{
549
0
  qsort(&rep->ref[0], rep->rrset_count, sizeof(struct rrset_ref),
550
0
    reply_info_sortref_cmp);
551
0
}
552
553
void 
554
reply_info_set_ttls(struct reply_info* rep, time_t timenow)
555
0
{
556
0
  size_t i, j;
557
0
  rep->ttl += timenow;
558
0
  rep->prefetch_ttl += timenow;
559
0
  rep->serve_expired_ttl += timenow;
560
0
  for(i=0; i<rep->rrset_count; i++) {
561
0
    struct packed_rrset_data* data = (struct packed_rrset_data*)
562
0
      rep->ref[i].key->entry.data;
563
0
    if(i>0 && rep->ref[i].key == rep->ref[i-1].key)
564
0
      continue;
565
0
    data->ttl += timenow;
566
0
    for(j=0; j<data->count + data->rrsig_count; j++) {
567
0
      data->rr_ttl[j] += timenow;
568
0
    }
569
0
    data->ttl_add = timenow;
570
0
  }
571
0
}
572
573
void 
574
reply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc)
575
0
{
576
0
  size_t i;
577
0
  if(!rep) 
578
0
    return;
579
  /* no need to lock, since not shared in hashtables. */
580
0
  for(i=0; i<rep->rrset_count; i++) {
581
0
    ub_packed_rrset_parsedelete(rep->rrsets[i], alloc);
582
0
  }
583
0
  free(rep);
584
0
}
585
586
int 
587
query_info_parse(struct query_info* m, sldns_buffer* query)
588
0
{
589
0
  uint8_t* q = sldns_buffer_begin(query);
590
  /* minimum size: header + \0 + qtype + qclass */
591
0
  if(sldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5)
592
0
    return 0;
593
0
  if((LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY && LDNS_OPCODE_WIRE(q) !=
594
0
    LDNS_PACKET_NOTIFY) || LDNS_QDCOUNT(q) != 1 ||
595
0
    sldns_buffer_position(query) != 0)
596
0
    return 0;
597
0
  sldns_buffer_skip(query, LDNS_HEADER_SIZE);
598
0
  m->qname = sldns_buffer_current(query);
599
0
  if((m->qname_len = query_dname_len(query)) == 0)
600
0
    return 0; /* parse error */
601
0
  if(sldns_buffer_remaining(query) < 4)
602
0
    return 0; /* need qtype, qclass */
603
0
  m->qtype = sldns_buffer_read_u16(query);
604
0
  m->qclass = sldns_buffer_read_u16(query);
605
0
  m->local_alias = NULL;
606
0
  return 1;
607
0
}
608
609
/** tiny subroutine for msgreply_compare */
610
#define COMPARE_IT(x, y) \
611
0
  if( (x) < (y) ) return -1; \
612
0
  else if( (x) > (y) ) return +1; \
613
0
  log_assert( (x) == (y) );
614
615
int 
616
query_info_compare(void* m1, void* m2)
617
0
{
618
0
  struct query_info* msg1 = (struct query_info*)m1;
619
0
  struct query_info* msg2 = (struct query_info*)m2;
620
0
  int mc;
621
  /* from most different to least different for speed */
622
0
  COMPARE_IT(msg1->qtype, msg2->qtype);
623
0
  if((mc = query_dname_compare(msg1->qname, msg2->qname)) != 0)
624
0
    return mc;
625
0
  log_assert(msg1->qname_len == msg2->qname_len);
626
0
  COMPARE_IT(msg1->qclass, msg2->qclass);
627
0
  return 0;
628
0
#undef COMPARE_IT
629
0
}
630
631
void 
632
query_info_clear(struct query_info* m)
633
0
{
634
0
  free(m->qname);
635
0
  m->qname = NULL;
636
0
}
637
638
size_t 
639
msgreply_sizefunc(void* k, void* d)
640
0
{
641
0
  struct msgreply_entry* q = (struct msgreply_entry*)k;
642
0
  struct reply_info* r = (struct reply_info*)d;
643
0
  size_t s = sizeof(struct msgreply_entry) + sizeof(struct reply_info)
644
0
    + q->key.qname_len + lock_get_mem(&q->entry.lock)
645
0
    - sizeof(struct rrset_ref);
646
0
  s += r->rrset_count * sizeof(struct rrset_ref);
647
0
  s += r->rrset_count * sizeof(struct ub_packed_rrset_key*);
648
0
  return s;
649
0
}
650
651
void 
652
query_entry_delete(void *k, void* ATTR_UNUSED(arg))
653
0
{
654
0
  struct msgreply_entry* q = (struct msgreply_entry*)k;
655
0
  lock_rw_destroy(&q->entry.lock);
656
0
  query_info_clear(&q->key);
657
0
  free(q);
658
0
}
659
660
void 
661
reply_info_delete(void* d, void* ATTR_UNUSED(arg))
662
0
{
663
0
  struct reply_info* r = (struct reply_info*)d;
664
0
  free(r);
665
0
}
666
667
hashvalue_type
668
query_info_hash(struct query_info *q, uint16_t flags)
669
0
{
670
0
  hashvalue_type h = 0xab;
671
0
  h = hashlittle(&q->qtype, sizeof(q->qtype), h);
672
0
  if(q->qtype == LDNS_RR_TYPE_AAAA && (flags&BIT_CD))
673
0
    h++;
674
0
  h = hashlittle(&q->qclass, sizeof(q->qclass), h);
675
0
  h = dname_query_hash(q->qname, h);
676
0
  return h;
677
0
}
678
679
struct msgreply_entry* 
680
query_info_entrysetup(struct query_info* q, struct reply_info* r, 
681
  hashvalue_type h)
682
0
{
683
0
  struct msgreply_entry* e = (struct msgreply_entry*)malloc( 
684
0
    sizeof(struct msgreply_entry));
685
0
  if(!e) return NULL;
686
0
  memcpy(&e->key, q, sizeof(*q));
687
0
  e->entry.hash = h;
688
0
  e->entry.key = e;
689
0
  e->entry.data = r;
690
0
  lock_rw_init(&e->entry.lock);
691
0
  lock_protect(&e->entry.lock, &e->key.qname, sizeof(e->key.qname));
692
0
  lock_protect(&e->entry.lock, &e->key.qname_len, sizeof(e->key.qname_len));
693
0
  lock_protect(&e->entry.lock, &e->key.qtype, sizeof(e->key.qtype));
694
0
  lock_protect(&e->entry.lock, &e->key.qclass, sizeof(e->key.qclass));
695
0
  lock_protect(&e->entry.lock, &e->key.local_alias, sizeof(e->key.local_alias));
696
0
  lock_protect(&e->entry.lock, &e->entry.hash, sizeof(e->entry.hash));
697
0
  lock_protect(&e->entry.lock, &e->entry.key, sizeof(e->entry.key));
698
0
  lock_protect(&e->entry.lock, &e->entry.data, sizeof(e->entry.data));
699
0
  lock_protect(&e->entry.lock, e->key.qname, e->key.qname_len);
700
0
  q->qname = NULL;
701
0
  return e;
702
0
}
703
704
/** copy rrsets from replyinfo to dest replyinfo */
705
static int
706
repinfo_copy_rrsets(struct reply_info* dest, struct reply_info* from, 
707
  struct regional* region)
708
0
{
709
0
  size_t i, s;
710
0
  struct packed_rrset_data* fd, *dd;
711
0
  struct ub_packed_rrset_key* fk, *dk;
712
0
  for(i=0; i<dest->rrset_count; i++) {
713
0
    fk = from->rrsets[i];
714
0
    dk = dest->rrsets[i];
715
0
    fd = (struct packed_rrset_data*)fk->entry.data;
716
0
    dk->entry.hash = fk->entry.hash;
717
0
    dk->rk = fk->rk;
718
0
    if(region) {
719
0
      dk->id = fk->id;
720
0
      dk->rk.dname = (uint8_t*)regional_alloc_init(region,
721
0
        fk->rk.dname, fk->rk.dname_len);
722
0
    } else 
723
0
      dk->rk.dname = (uint8_t*)memdup(fk->rk.dname, 
724
0
        fk->rk.dname_len);
725
0
    if(!dk->rk.dname)
726
0
      return 0;
727
0
    s = packed_rrset_sizeof(fd);
728
0
    if(region)
729
0
      dd = (struct packed_rrset_data*)regional_alloc_init(
730
0
        region, fd, s);
731
0
    else  dd = (struct packed_rrset_data*)memdup(fd, s);
732
0
    if(!dd) 
733
0
      return 0;
734
0
    packed_rrset_ptr_fixup(dd);
735
0
    dk->entry.data = (void*)dd;
736
0
  }
737
0
  return 1;
738
0
}
739
740
struct reply_info* 
741
reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc, 
742
  struct regional* region)
743
0
{
744
0
  struct reply_info* cp;
745
0
  cp = construct_reply_info_base(region, rep->flags, rep->qdcount, 
746
0
    rep->ttl, rep->prefetch_ttl, rep->serve_expired_ttl, 
747
0
    rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets,
748
0
    rep->rrset_count, rep->security);
749
0
  if(!cp)
750
0
    return NULL;
751
  /* allocate ub_key structures special or not */
752
0
  if(!reply_info_alloc_rrset_keys(cp, alloc, region)) {
753
0
    if(!region)
754
0
      reply_info_parsedelete(cp, alloc);
755
0
    return NULL;
756
0
  }
757
0
  if(!repinfo_copy_rrsets(cp, rep, region)) {
758
0
    if(!region)
759
0
      reply_info_parsedelete(cp, alloc);
760
0
    return NULL;
761
0
  }
762
0
  return cp;
763
0
}
764
765
uint8_t* 
766
reply_find_final_cname_target(struct query_info* qinfo, struct reply_info* rep)
767
0
{
768
0
  uint8_t* sname = qinfo->qname;
769
0
  size_t snamelen = qinfo->qname_len;
770
0
  size_t i;
771
0
  for(i=0; i<rep->an_numrrsets; i++) {
772
0
    struct ub_packed_rrset_key* s = rep->rrsets[i];
773
    /* follow CNAME chain (if any) */
774
0
    if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 
775
0
      ntohs(s->rk.rrset_class) == qinfo->qclass && 
776
0
      snamelen == s->rk.dname_len &&
777
0
      query_dname_compare(sname, s->rk.dname) == 0) {
778
0
      get_cname_target(s, &sname, &snamelen);
779
0
    }
780
0
  }
781
0
  if(sname != qinfo->qname)
782
0
    return sname;
783
0
  return NULL;
784
0
}
785
786
struct ub_packed_rrset_key* 
787
reply_find_answer_rrset(struct query_info* qinfo, struct reply_info* rep)
788
0
{
789
0
  uint8_t* sname = qinfo->qname;
790
0
  size_t snamelen = qinfo->qname_len;
791
0
  size_t i;
792
0
  for(i=0; i<rep->an_numrrsets; i++) {
793
0
    struct ub_packed_rrset_key* s = rep->rrsets[i];
794
    /* first match type, for query of qtype cname */
795
0
    if(ntohs(s->rk.type) == qinfo->qtype && 
796
0
      ntohs(s->rk.rrset_class) == qinfo->qclass && 
797
0
      snamelen == s->rk.dname_len &&
798
0
      query_dname_compare(sname, s->rk.dname) == 0) {
799
0
      return s;
800
0
    }
801
    /* follow CNAME chain (if any) */
802
0
    if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 
803
0
      ntohs(s->rk.rrset_class) == qinfo->qclass && 
804
0
      snamelen == s->rk.dname_len &&
805
0
      query_dname_compare(sname, s->rk.dname) == 0) {
806
0
      get_cname_target(s, &sname, &snamelen);
807
0
    }
808
0
  }
809
0
  return NULL;
810
0
}
811
812
struct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep,
813
  uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
814
0
{
815
0
  size_t i;
816
0
  for(i=0; i<rep->an_numrrsets; i++) {
817
0
    struct ub_packed_rrset_key* s = rep->rrsets[i];
818
0
    if(ntohs(s->rk.type) == type && 
819
0
      ntohs(s->rk.rrset_class) == dclass && 
820
0
      namelen == s->rk.dname_len &&
821
0
      query_dname_compare(name, s->rk.dname) == 0) {
822
0
      return s;
823
0
    }
824
0
  }
825
0
  return NULL;
826
0
}
827
828
struct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep,
829
  uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
830
0
{
831
0
  size_t i;
832
0
  for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
833
0
    struct ub_packed_rrset_key* s = rep->rrsets[i];
834
0
    if(ntohs(s->rk.type) == type && 
835
0
      ntohs(s->rk.rrset_class) == dclass && 
836
0
      namelen == s->rk.dname_len &&
837
0
      query_dname_compare(name, s->rk.dname) == 0) {
838
0
      return s;
839
0
    }
840
0
  }
841
0
  return NULL;
842
0
}
843
844
struct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep,
845
  uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
846
0
{
847
0
  size_t i;
848
0
  for(i=0; i<rep->rrset_count; i++) {
849
0
    struct ub_packed_rrset_key* s = rep->rrsets[i];
850
0
    if(ntohs(s->rk.type) == type && 
851
0
      ntohs(s->rk.rrset_class) == dclass && 
852
0
      namelen == s->rk.dname_len &&
853
0
      query_dname_compare(name, s->rk.dname) == 0) {
854
0
      return s;
855
0
    }
856
0
  }
857
0
  return NULL;
858
0
}
859
860
void 
861
log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep)
862
0
{
863
  /* not particularly fast but flexible, make wireformat and print */
864
0
  sldns_buffer* buf = sldns_buffer_new(65535);
865
0
  struct regional* region = regional_create();
866
0
  if(!(buf && region)) {
867
0
    log_err("%s: log_dns_msg: out of memory", str);
868
0
    sldns_buffer_free(buf);
869
0
    regional_destroy(region);
870
0
    return;
871
0
  }
872
0
  if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0,
873
0
    region, 65535, 1, 0)) {
874
0
    log_err("%s: log_dns_msg: out of memory", str);
875
0
  } else {
876
0
    char* s = sldns_wire2str_pkt(sldns_buffer_begin(buf),
877
0
      sldns_buffer_limit(buf));
878
0
    if(!s) {
879
0
      log_info("%s: log_dns_msg: ldns tostr failed", str);
880
0
    } else {
881
0
      log_info("%s %s", str, s);
882
0
    }
883
0
    free(s);
884
0
  }
885
0
  sldns_buffer_free(buf);
886
0
  regional_destroy(region);
887
0
}
888
889
void
890
log_reply_info(enum verbosity_value v, struct query_info *qinf,
891
  struct sockaddr_storage *addr, socklen_t addrlen, struct timeval dur,
892
  int cached, struct sldns_buffer *rmsg)
893
0
{
894
0
  char qname_buf[LDNS_MAX_DOMAINLEN+1];
895
0
  char clientip_buf[128];
896
0
  char rcode_buf[16];
897
0
  char type_buf[16];
898
0
  char class_buf[16];
899
0
  size_t pktlen;
900
0
  uint16_t rcode = FLAGS_GET_RCODE(sldns_buffer_read_u16_at(rmsg, 2));
901
902
0
  if(verbosity < v)
903
0
    return;
904
905
0
  sldns_wire2str_rcode_buf((int)rcode, rcode_buf, sizeof(rcode_buf));
906
0
  addr_to_str(addr, addrlen, clientip_buf, sizeof(clientip_buf));
907
0
  if(rcode == LDNS_RCODE_FORMERR)
908
0
  {
909
0
    if(LOG_TAG_QUERYREPLY)
910
0
      log_reply("%s - - - %s - - - ", clientip_buf, rcode_buf);
911
0
    else  log_info("%s - - - %s - - - ", clientip_buf, rcode_buf);
912
0
  } else {
913
0
    if(qinf->qname)
914
0
      dname_str(qinf->qname, qname_buf);
915
0
    else  snprintf(qname_buf, sizeof(qname_buf), "null");
916
0
    pktlen = sldns_buffer_limit(rmsg);
917
0
    sldns_wire2str_type_buf(qinf->qtype, type_buf, sizeof(type_buf));
918
0
    sldns_wire2str_class_buf(qinf->qclass, class_buf, sizeof(class_buf));
919
0
    if(LOG_TAG_QUERYREPLY)
920
0
         log_reply("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d",
921
0
      clientip_buf, qname_buf, type_buf, class_buf,
922
0
      rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, cached, (int)pktlen);
923
0
    else log_info("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d",
924
0
      clientip_buf, qname_buf, type_buf, class_buf,
925
0
      rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, cached, (int)pktlen);
926
0
  }
927
0
}
928
929
void
930
log_query_info(enum verbosity_value v, const char* str, 
931
  struct query_info* qinf)
932
0
{
933
0
  log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass);
934
0
}
935
936
int
937
reply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep) 
938
0
{
939
  /* check only answer section rrs for matching cname chain.
940
   * the cache may return changed rdata, but owner names are untouched.*/
941
0
  size_t i;
942
0
  uint8_t* sname = qinfo->qname;
943
0
  size_t snamelen = qinfo->qname_len;
944
0
  for(i=0; i<rep->an_numrrsets; i++) {
945
0
    uint16_t t = ntohs(rep->rrsets[i]->rk.type);
946
0
    if(t == LDNS_RR_TYPE_DNAME)
947
0
      continue; /* skip dnames; note TTL 0 not cached */
948
    /* verify that owner matches current sname */
949
0
    if(query_dname_compare(sname, rep->rrsets[i]->rk.dname) != 0){
950
      /* cname chain broken */
951
0
      return 0;
952
0
    }
953
    /* if this is a cname; move on */
954
0
    if(t == LDNS_RR_TYPE_CNAME) {
955
0
      get_cname_target(rep->rrsets[i], &sname, &snamelen);
956
0
    }
957
0
  }
958
0
  return 1;
959
0
}
960
961
int
962
reply_all_rrsets_secure(struct reply_info* rep) 
963
0
{
964
0
  size_t i;
965
0
  for(i=0; i<rep->rrset_count; i++) {
966
0
    if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
967
0
      ->security != sec_status_secure )
968
0
    return 0;
969
0
  }
970
0
  return 1;
971
0
}
972
973
struct reply_info*
974
parse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region,
975
  struct query_info* qi)
976
0
{
977
0
  struct reply_info* rep;
978
0
  struct msg_parse* msg;
979
0
  if(!(msg = regional_alloc(region, sizeof(*msg)))) {
980
0
    return NULL;
981
0
  }
982
0
  memset(msg, 0, sizeof(*msg));
983
0
  sldns_buffer_set_position(pkt, 0);
984
0
  if(parse_packet(pkt, msg, region) != 0){
985
0
    return 0;
986
0
  }
987
0
  if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) {
988
0
    return 0;
989
0
  }
990
0
  return rep;
991
0
}
992
993
int edns_opt_list_append_ede(struct edns_option** list, struct regional* region,
994
  sldns_ede_code code, const char *txt)
995
0
{
996
0
  struct edns_option** prevp;
997
0
  struct edns_option* opt;
998
0
  size_t txt_len = txt ? strlen(txt) : 0;
999
1000
  /* allocate new element */
1001
0
  opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
1002
0
  if(!opt)
1003
0
    return 0;
1004
0
  opt->next = NULL;
1005
0
  opt->opt_code = LDNS_EDNS_EDE;
1006
0
  opt->opt_len = txt_len + sizeof(uint16_t);
1007
0
  opt->opt_data = regional_alloc(region, txt_len + sizeof(uint16_t));
1008
0
  if(!opt->opt_data)
1009
0
    return 0;
1010
0
  sldns_write_uint16(opt->opt_data, (uint16_t)code);
1011
0
  if (txt_len)
1012
0
    memmove(opt->opt_data + 2, txt, txt_len);
1013
1014
  /* append at end of list */
1015
0
  prevp = list;
1016
0
  while(*prevp != NULL)
1017
0
    prevp = &((*prevp)->next);
1018
0
  verbose(VERB_ALGO, "attached EDE code: %d with message: %s", code, (txt?txt:"\"\""));
1019
0
  *prevp = opt;
1020
0
  return 1;
1021
0
}
1022
1023
int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
1024
  uint8_t* data, struct regional* region)
1025
0
{
1026
0
  struct edns_option** prevp;
1027
0
  struct edns_option* opt;
1028
1029
  /* allocate new element */
1030
0
  opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
1031
0
  if(!opt)
1032
0
    return 0;
1033
0
  opt->next = NULL;
1034
0
  opt->opt_code = code;
1035
0
  opt->opt_len = len;
1036
0
  opt->opt_data = NULL;
1037
0
  if(len > 0) {
1038
0
    opt->opt_data = regional_alloc_init(region, data, len);
1039
0
    if(!opt->opt_data)
1040
0
      return 0;
1041
0
  }
1042
1043
  /* append at end of list */
1044
0
  prevp = list;
1045
0
  while(*prevp != NULL) {
1046
0
    prevp = &((*prevp)->next);
1047
0
  }
1048
0
  *prevp = opt;
1049
0
  return 1;
1050
0
}
1051
1052
int edns_opt_list_remove(struct edns_option** list, uint16_t code)
1053
0
{
1054
  /* The list should already be allocated in a region. Freeing the
1055
   * allocated space in a region is not possible. We just unlink the
1056
   * required elements and they will be freed together with the region. */
1057
1058
0
  struct edns_option* prev;
1059
0
  struct edns_option* curr;
1060
0
  if(!list || !(*list)) return 0;
1061
1062
  /* Unlink and repoint if the element(s) are first in list */
1063
0
  while(list && *list && (*list)->opt_code == code) {
1064
0
    *list = (*list)->next;
1065
0
  }
1066
1067
0
  if(!list || !(*list)) return 1;
1068
  /* Unlink elements and reattach the list */
1069
0
  prev = *list;
1070
0
  curr = (*list)->next;
1071
0
  while(curr != NULL) {
1072
0
    if(curr->opt_code == code) {
1073
0
      prev->next = curr->next;
1074
0
      curr = curr->next;
1075
0
    } else {
1076
0
      prev = curr;
1077
0
      curr = curr->next;
1078
0
    }
1079
0
  }
1080
0
  return 1;
1081
0
}
1082
1083
static int inplace_cb_reply_call_generic(
1084
    struct inplace_cb* callback_list, enum inplace_cb_list_type type,
1085
  struct query_info* qinfo, struct module_qstate* qstate,
1086
  struct reply_info* rep, int rcode, struct edns_data* edns,
1087
  struct comm_reply* repinfo, struct regional* region,
1088
  struct timeval* start_time)
1089
0
{
1090
0
  struct inplace_cb* cb;
1091
0
  struct edns_option* opt_list_out = NULL;
1092
#if defined(EXPORT_ALL_SYMBOLS)
1093
  (void)type; /* param not used when fptr_ok disabled */
1094
#endif
1095
0
  if(qstate)
1096
0
    opt_list_out = qstate->edns_opts_front_out;
1097
0
  for(cb=callback_list; cb; cb=cb->next) {
1098
0
    fptr_ok(fptr_whitelist_inplace_cb_reply_generic(
1099
0
      (inplace_cb_reply_func_type*)cb->cb, type));
1100
0
    (void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep,
1101
0
      rcode, edns, &opt_list_out, repinfo, region, start_time, cb->id, cb->cb_arg);
1102
0
  }
1103
0
  edns->opt_list_inplace_cb_out = opt_list_out;
1104
0
  return 1;
1105
0
}
1106
1107
int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo,
1108
  struct module_qstate* qstate, struct reply_info* rep, int rcode,
1109
  struct edns_data* edns, struct comm_reply* repinfo, struct regional* region,
1110
  struct timeval* start_time)
1111
0
{
1112
0
  return inplace_cb_reply_call_generic(
1113
0
    env->inplace_cb_lists[inplace_cb_reply], inplace_cb_reply, qinfo,
1114
0
    qstate, rep, rcode, edns, repinfo, region, start_time);
1115
0
}
1116
1117
int inplace_cb_reply_cache_call(struct module_env* env,
1118
  struct query_info* qinfo, struct module_qstate* qstate,
1119
  struct reply_info* rep, int rcode, struct edns_data* edns,
1120
  struct comm_reply* repinfo, struct regional* region,
1121
  struct timeval* start_time)
1122
0
{
1123
0
  return inplace_cb_reply_call_generic(
1124
0
    env->inplace_cb_lists[inplace_cb_reply_cache], inplace_cb_reply_cache,
1125
0
    qinfo, qstate, rep, rcode, edns, repinfo, region, start_time);
1126
0
}
1127
1128
int inplace_cb_reply_local_call(struct module_env* env,
1129
  struct query_info* qinfo, struct module_qstate* qstate,
1130
  struct reply_info* rep, int rcode, struct edns_data* edns,
1131
  struct comm_reply* repinfo, struct regional* region,
1132
  struct timeval* start_time)
1133
0
{
1134
0
  return inplace_cb_reply_call_generic(
1135
0
    env->inplace_cb_lists[inplace_cb_reply_local], inplace_cb_reply_local,
1136
0
    qinfo, qstate, rep, rcode, edns, repinfo, region, start_time);
1137
0
}
1138
1139
int inplace_cb_reply_servfail_call(struct module_env* env,
1140
  struct query_info* qinfo, struct module_qstate* qstate,
1141
  struct reply_info* rep, int rcode, struct edns_data* edns,
1142
  struct comm_reply* repinfo, struct regional* region,
1143
  struct timeval* start_time)
1144
0
{
1145
  /* We are going to servfail. Remove any potential edns options. */
1146
0
  if(qstate)
1147
0
    qstate->edns_opts_front_out = NULL;
1148
0
  return inplace_cb_reply_call_generic(
1149
0
    env->inplace_cb_lists[inplace_cb_reply_servfail],
1150
0
    inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, repinfo,
1151
0
    region, start_time);
1152
0
}
1153
1154
int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo,
1155
  uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen,
1156
  uint8_t* zone, size_t zonelen, struct module_qstate* qstate,
1157
  struct regional* region)
1158
0
{
1159
0
  struct inplace_cb* cb = env->inplace_cb_lists[inplace_cb_query];
1160
0
  for(; cb; cb=cb->next) {
1161
0
    fptr_ok(fptr_whitelist_inplace_cb_query(
1162
0
      (inplace_cb_query_func_type*)cb->cb));
1163
0
    (void)(*(inplace_cb_query_func_type*)cb->cb)(qinfo, flags,
1164
0
      qstate, addr, addrlen, zone, zonelen, region,
1165
0
      cb->id, cb->cb_arg);
1166
0
  }
1167
0
  return 1;
1168
0
}
1169
1170
int inplace_cb_edns_back_parsed_call(struct module_env* env, 
1171
  struct module_qstate* qstate)
1172
0
{
1173
0
  struct inplace_cb* cb =
1174
0
    env->inplace_cb_lists[inplace_cb_edns_back_parsed];
1175
0
  for(; cb; cb=cb->next) {
1176
0
    fptr_ok(fptr_whitelist_inplace_cb_edns_back_parsed(
1177
0
      (inplace_cb_edns_back_parsed_func_type*)cb->cb));
1178
0
    (void)(*(inplace_cb_edns_back_parsed_func_type*)cb->cb)(qstate,
1179
0
      cb->id, cb->cb_arg);
1180
0
  }
1181
0
  return 1;
1182
0
}
1183
1184
int inplace_cb_query_response_call(struct module_env* env,
1185
0
  struct module_qstate* qstate, struct dns_msg* response) {
1186
0
  struct inplace_cb* cb =
1187
0
    env->inplace_cb_lists[inplace_cb_query_response];
1188
0
  for(; cb; cb=cb->next) {
1189
0
    fptr_ok(fptr_whitelist_inplace_cb_query_response(
1190
0
      (inplace_cb_query_response_func_type*)cb->cb));
1191
0
    (void)(*(inplace_cb_query_response_func_type*)cb->cb)(qstate,
1192
0
      response, cb->id, cb->cb_arg);
1193
0
  }
1194
0
  return 1;
1195
0
}
1196
1197
struct edns_option* edns_opt_copy_region(struct edns_option* list,
1198
        struct regional* region)
1199
0
{
1200
0
  struct edns_option* result = NULL, *cur = NULL, *s;
1201
0
  while(list) {
1202
    /* copy edns option structure */
1203
0
    s = regional_alloc_init(region, list, sizeof(*list));
1204
0
    if(!s) return NULL;
1205
0
    s->next = NULL;
1206
1207
    /* copy option data */
1208
0
    if(s->opt_data) {
1209
0
      s->opt_data = regional_alloc_init(region, s->opt_data,
1210
0
        s->opt_len);
1211
0
      if(!s->opt_data)
1212
0
        return NULL;
1213
0
    }
1214
1215
    /* link into list */
1216
0
    if(cur)
1217
0
      cur->next = s;
1218
0
    else  result = s;
1219
0
    cur = s;
1220
1221
    /* examine next element */
1222
0
    list = list->next;
1223
0
  }
1224
0
  return result;
1225
0
}
1226
1227
int edns_opt_compare(struct edns_option* p, struct edns_option* q)
1228
0
{
1229
0
  if(!p && !q) return 0;
1230
0
  if(!p) return -1;
1231
0
  if(!q) return 1;
1232
0
  log_assert(p && q);
1233
0
  if(p->opt_code != q->opt_code)
1234
0
    return (int)q->opt_code - (int)p->opt_code;
1235
0
  if(p->opt_len != q->opt_len)
1236
0
    return (int)q->opt_len - (int)p->opt_len;
1237
0
  if(p->opt_len != 0)
1238
0
    return memcmp(p->opt_data, q->opt_data, p->opt_len);
1239
0
  return 0;
1240
0
}
1241
1242
int edns_opt_list_compare(struct edns_option* p, struct edns_option* q)
1243
0
{
1244
0
  int r;
1245
0
  while(p && q) {
1246
0
    r = edns_opt_compare(p, q);
1247
0
    if(r != 0)
1248
0
      return r;
1249
0
    p = p->next;
1250
0
    q = q->next;
1251
0
  }
1252
0
  if(p || q) {
1253
    /* uneven length lists */
1254
0
    if(p) return 1;
1255
0
    if(q) return -1;
1256
0
  }
1257
0
  return 0;
1258
0
}
1259
1260
void edns_opt_list_free(struct edns_option* list)
1261
0
{
1262
0
  struct edns_option* n;
1263
0
  while(list) {
1264
0
    free(list->opt_data);
1265
0
    n = list->next;
1266
0
    free(list);
1267
0
    list = n;
1268
0
  }
1269
0
}
1270
1271
struct edns_option* edns_opt_copy_alloc(struct edns_option* list)
1272
0
{
1273
0
  struct edns_option* result = NULL, *cur = NULL, *s;
1274
0
  while(list) {
1275
    /* copy edns option structure */
1276
0
    s = memdup(list, sizeof(*list));
1277
0
    if(!s) {
1278
0
      edns_opt_list_free(result);
1279
0
      return NULL;
1280
0
    }
1281
0
    s->next = NULL;
1282
1283
    /* copy option data */
1284
0
    if(s->opt_data) {
1285
0
      s->opt_data = memdup(s->opt_data, s->opt_len);
1286
0
      if(!s->opt_data) {
1287
0
        free(s);
1288
0
        edns_opt_list_free(result);
1289
0
        return NULL;
1290
0
      }
1291
0
    }
1292
1293
    /* link into list */
1294
0
    if(cur)
1295
0
      cur->next = s;
1296
0
    else  result = s;
1297
0
    cur = s;
1298
1299
    /* examine next element */
1300
0
    list = list->next;
1301
0
  }
1302
0
  return result;
1303
0
}
1304
1305
struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code)
1306
0
{
1307
0
  struct edns_option* p;
1308
0
  for(p=list; p; p=p->next) {
1309
0
    if(p->opt_code == code)
1310
0
      return p;
1311
0
  }
1312
0
  return NULL;
1313
0
}