Coverage Report

Created: 2025-07-11 06:08

/src/unbound/util/edns.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * util/edns.c - handle base EDNS options.
3
 *
4
 * Copyright (c) 2018, 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 functions for base EDNS options.
40
 */
41
42
#include "config.h"
43
#include "util/edns.h"
44
#include "util/config_file.h"
45
#include "util/netevent.h"
46
#include "util/net_help.h"
47
#include "util/regional.h"
48
#include "util/rfc_1982.h"
49
#include "util/siphash.h"
50
#include "util/data/msgparse.h"
51
#include "util/data/msgreply.h"
52
#include "sldns/sbuffer.h"
53
54
struct edns_strings* edns_strings_create(void)
55
0
{
56
0
  struct edns_strings* edns_strings = calloc(1,
57
0
    sizeof(struct edns_strings));
58
0
  if(!edns_strings)
59
0
    return NULL;
60
0
  if(!(edns_strings->region = regional_create())) {
61
0
    edns_strings_delete(edns_strings);
62
0
    return NULL;
63
0
  }
64
0
  return edns_strings;
65
0
}
66
67
void edns_strings_delete(struct edns_strings* edns_strings)
68
0
{
69
0
  if(!edns_strings)
70
0
    return;
71
0
  regional_destroy(edns_strings->region);
72
0
  free(edns_strings);
73
0
}
74
75
static int
76
edns_strings_client_insert(struct edns_strings* edns_strings,
77
  struct sockaddr_storage* addr, socklen_t addrlen, int net,
78
  const char* string)
79
0
{
80
0
  struct edns_string_addr* esa = regional_alloc_zero(edns_strings->region,
81
0
    sizeof(struct edns_string_addr));
82
0
  if(!esa)
83
0
    return 0;
84
0
  esa->string_len = strlen(string);
85
0
  esa->string = regional_alloc_init(edns_strings->region, string,
86
0
    esa->string_len);
87
0
  if(!esa->string)
88
0
    return 0;
89
0
  if(!addr_tree_insert(&edns_strings->client_strings, &esa->node, addr,
90
0
    addrlen, net)) {
91
0
    verbose(VERB_QUERY, "duplicate EDNS client string ignored.");
92
0
  }
93
0
  return 1;
94
0
}
95
96
int edns_strings_apply_cfg(struct edns_strings* edns_strings,
97
  struct config_file* config)
98
0
{
99
0
  struct config_str2list* c;
100
0
  regional_free_all(edns_strings->region);
101
0
  addr_tree_init(&edns_strings->client_strings);
102
103
0
  for(c=config->edns_client_strings; c; c=c->next) {
104
0
    struct sockaddr_storage addr;
105
0
    socklen_t addrlen;
106
0
    int net;
107
0
    log_assert(c->str && c->str2);
108
109
0
    if(!netblockstrtoaddr(c->str, UNBOUND_DNS_PORT, &addr, &addrlen,
110
0
      &net)) {
111
0
      log_err("cannot parse EDNS client string IP netblock: "
112
0
        "%s", c->str);
113
0
      return 0;
114
0
    }
115
0
    if(!edns_strings_client_insert(edns_strings, &addr, addrlen,
116
0
      net, c->str2)) {
117
0
      log_err("out of memory while adding EDNS strings");
118
0
      return 0;
119
0
    }
120
0
  }
121
0
  edns_strings->client_string_opcode = config->edns_client_string_opcode;
122
123
0
  addr_tree_init_parents(&edns_strings->client_strings);
124
0
  return 1;
125
0
}
126
127
struct edns_string_addr*
128
edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr,
129
  socklen_t addrlen)
130
0
{
131
0
  return (struct edns_string_addr*)addr_tree_lookup(tree, addr, addrlen);
132
0
}
133
134
size_t
135
edns_strings_get_mem(struct edns_strings* edns_strings)
136
0
{
137
0
  if(!edns_strings) return 0;
138
0
  return regional_get_mem(edns_strings->region) + sizeof(*edns_strings);
139
0
}
140
141
void
142
edns_strings_swap_tree(struct edns_strings* edns_strings,
143
  struct edns_strings* data)
144
0
{
145
0
  rbtree_type tree = edns_strings->client_strings;
146
0
  uint16_t opcode = edns_strings->client_string_opcode;
147
0
  struct regional* region = edns_strings->region;
148
149
0
  edns_strings->client_strings = data->client_strings;
150
0
  edns_strings->client_string_opcode = data->client_string_opcode;
151
0
  edns_strings->region = data->region;
152
0
  data->client_strings = tree;
153
0
  data->client_string_opcode = opcode;
154
0
  data->region = region;
155
0
}
156
157
uint8_t*
158
edns_cookie_server_hash(const uint8_t* in, const uint8_t* secret, int v4,
159
  uint8_t* hash)
160
0
{
161
0
  v4?siphash(in, 20, secret, hash, 8):siphash(in, 32, secret, hash, 8);
162
0
  return hash;
163
0
}
164
165
void
166
edns_cookie_server_write(uint8_t* buf, const uint8_t* secret, int v4,
167
  uint32_t timestamp)
168
0
{
169
0
  uint8_t hash[8];
170
0
  buf[ 8] = 1;   /* Version */
171
0
  buf[ 9] = 0;   /* Reserved */
172
0
  buf[10] = 0;   /* Reserved */
173
0
  buf[11] = 0;   /* Reserved */
174
0
  sldns_write_uint32(buf + 12, timestamp);
175
0
  (void)edns_cookie_server_hash(buf, secret, v4, hash);
176
0
  memcpy(buf + 16, hash, 8);
177
0
}
178
179
enum edns_cookie_val_status
180
edns_cookie_server_validate(const uint8_t* cookie, size_t cookie_len,
181
  const uint8_t* secret, size_t secret_len, int v4,
182
  const uint8_t* hash_input, uint32_t now)
183
0
{
184
0
  uint8_t hash[8];
185
0
  uint32_t timestamp;
186
0
  uint32_t subt_1982 = 0; /* Initialize for the compiler; unused value */
187
0
  int comp_1982;
188
0
  if(cookie_len != 24)
189
    /* RFC9018 cookies are 24 bytes long */
190
0
    return COOKIE_STATUS_CLIENT_ONLY;
191
0
  if(secret_len != 16 ||  /* RFC9018 cookies have 16 byte secrets */
192
0
    cookie[8] != 1) /* RFC9018 cookies are cookie version 1 */
193
0
    return COOKIE_STATUS_INVALID;
194
0
  timestamp = sldns_read_uint32(cookie + 12);
195
0
  if((comp_1982 = compare_1982(now, timestamp)) > 0
196
0
    && (subt_1982 = subtract_1982(timestamp, now)) > 3600)
197
    /* Cookie is older than 1 hour (see RFC9018 Section 4.3.) */
198
0
    return COOKIE_STATUS_EXPIRED;
199
0
  if(comp_1982 <= 0 && subtract_1982(now, timestamp) > 300)
200
    /* Cookie time is more than 5 minutes in the future.
201
     * (see RFC9018 Section 4.3.) */
202
0
    return COOKIE_STATUS_FUTURE;
203
0
  if(memcmp(edns_cookie_server_hash(hash_input, secret, v4, hash),
204
0
    cookie + 16, 8) != 0)
205
    /* Hashes do not match */
206
0
    return COOKIE_STATUS_INVALID;
207
0
  if(comp_1982 > 0 && subt_1982 > 1800)
208
    /* Valid cookie but older than 30 minutes, so create a new one
209
     * anyway */
210
0
    return COOKIE_STATUS_VALID_RENEW;
211
0
  return COOKIE_STATUS_VALID;
212
0
}
213
214
struct cookie_secrets*
215
cookie_secrets_create(void)
216
0
{
217
0
  struct cookie_secrets* cookie_secrets = calloc(1,
218
0
    sizeof(*cookie_secrets));
219
0
  if(!cookie_secrets)
220
0
    return NULL;
221
0
  lock_basic_init(&cookie_secrets->lock);
222
0
  lock_protect(&cookie_secrets->lock, &cookie_secrets->cookie_count,
223
0
    sizeof(cookie_secrets->cookie_count));
224
0
  lock_protect(&cookie_secrets->lock, cookie_secrets->cookie_secrets,
225
0
    sizeof(cookie_secret_type)*UNBOUND_COOKIE_HISTORY_SIZE);
226
0
  return cookie_secrets;
227
0
}
228
229
void
230
cookie_secrets_delete(struct cookie_secrets* cookie_secrets)
231
0
{
232
0
  if(!cookie_secrets)
233
0
    return;
234
0
  lock_basic_destroy(&cookie_secrets->lock);
235
0
  explicit_bzero(cookie_secrets->cookie_secrets,
236
0
    sizeof(cookie_secret_type)*UNBOUND_COOKIE_HISTORY_SIZE);
237
0
  free(cookie_secrets);
238
0
}
239
240
/** Read the cookie secret file */
241
static int
242
cookie_secret_file_read(struct cookie_secrets* cookie_secrets,
243
  char* cookie_secret_file)
244
0
{
245
0
  char secret[UNBOUND_COOKIE_SECRET_SIZE * 2 + 2/*'\n' and '\0'*/];
246
0
  FILE* f;
247
0
  int corrupt = 0;
248
0
  size_t count;
249
250
0
  log_assert(cookie_secret_file != NULL);
251
0
  cookie_secrets->cookie_count = 0;
252
0
  f = fopen(cookie_secret_file, "r");
253
  /* a non-existing cookie file is not an error */
254
0
  if( f == NULL ) {
255
0
    if(errno != EPERM) {
256
0
      log_err("Could not read cookie-secret-file '%s': %s",
257
0
        cookie_secret_file, strerror(errno));
258
0
      return 0;
259
0
    }
260
0
    return 1;
261
0
  }
262
  /* cookie secret file exists and is readable */
263
0
  for( count = 0; count < UNBOUND_COOKIE_HISTORY_SIZE; count++ ) {
264
0
    size_t secret_len = 0;
265
0
    ssize_t decoded_len = 0;
266
0
    if( fgets(secret, sizeof(secret), f) == NULL ) { break; }
267
0
    secret_len = strlen(secret);
268
0
    if( secret_len == 0 ) { break; }
269
0
    log_assert( secret_len <= sizeof(secret) );
270
0
    secret_len = secret[secret_len - 1] == '\n' ? secret_len - 1 : secret_len;
271
0
    if( secret_len != UNBOUND_COOKIE_SECRET_SIZE * 2 ) { corrupt++; break; }
272
    /* needed for `hex_pton`; stripping potential `\n` */
273
0
    secret[secret_len] = '\0';
274
0
    decoded_len = hex_pton(secret, cookie_secrets->cookie_secrets[count].cookie_secret,
275
0
                           UNBOUND_COOKIE_SECRET_SIZE);
276
0
    if( decoded_len != UNBOUND_COOKIE_SECRET_SIZE ) { corrupt++; break; }
277
0
    cookie_secrets->cookie_count++;
278
0
  }
279
0
  fclose(f);
280
0
  return corrupt == 0;
281
0
}
282
283
int
284
cookie_secrets_apply_cfg(struct cookie_secrets* cookie_secrets,
285
  char* cookie_secret_file)
286
0
{
287
0
  if(!cookie_secrets) {
288
0
    if(!cookie_secret_file || !cookie_secret_file[0])
289
0
      return 1; /* There is nothing to read anyway */
290
0
    log_err("Could not read cookie secrets, no structure alloced");
291
0
    return 0;
292
0
  }
293
0
  if(!cookie_secret_file_read(cookie_secrets, cookie_secret_file))
294
0
    return 0;
295
0
  return 1;
296
0
}
297
298
enum edns_cookie_val_status
299
cookie_secrets_server_validate(const uint8_t* cookie, size_t cookie_len,
300
  struct cookie_secrets* cookie_secrets, int v4,
301
  const uint8_t* hash_input, uint32_t now)
302
0
{
303
0
  size_t i;
304
0
  enum edns_cookie_val_status cookie_val_status,
305
0
    last = COOKIE_STATUS_INVALID;
306
0
  if(!cookie_secrets)
307
0
    return COOKIE_STATUS_INVALID; /* There are no cookie secrets.*/
308
0
  lock_basic_lock(&cookie_secrets->lock);
309
0
  if(cookie_secrets->cookie_count == 0) {
310
0
    lock_basic_unlock(&cookie_secrets->lock);
311
0
    return COOKIE_STATUS_INVALID; /* There are no cookie secrets.*/
312
0
  }
313
0
  for(i=0; i<cookie_secrets->cookie_count; i++) {
314
0
    cookie_val_status = edns_cookie_server_validate(cookie,
315
0
      cookie_len,
316
0
      cookie_secrets->cookie_secrets[i].cookie_secret,
317
0
      UNBOUND_COOKIE_SECRET_SIZE, v4, hash_input, now);
318
0
    if(cookie_val_status == COOKIE_STATUS_VALID ||
319
0
      cookie_val_status == COOKIE_STATUS_VALID_RENEW) {
320
0
      lock_basic_unlock(&cookie_secrets->lock);
321
      /* For staging cookies, write a fresh cookie. */
322
0
      if(i != 0)
323
0
        return COOKIE_STATUS_VALID_RENEW;
324
0
      return cookie_val_status;
325
0
    }
326
0
    if(last == COOKIE_STATUS_INVALID)
327
0
      last = cookie_val_status; /* Store more interesting
328
        failure to return. */
329
0
  }
330
0
  lock_basic_unlock(&cookie_secrets->lock);
331
0
  return last;
332
0
}
333
334
void add_cookie_secret(struct cookie_secrets* cookie_secrets,
335
  uint8_t* secret, size_t secret_len)
336
0
{
337
0
  log_assert(secret_len == UNBOUND_COOKIE_SECRET_SIZE);
338
0
  (void)secret_len;
339
0
  if(!cookie_secrets)
340
0
    return;
341
342
  /* New cookie secret becomes the staging secret (position 1)
343
   * unless there is no active cookie yet, then it becomes the active
344
   * secret.  If the UNBOUND_COOKIE_HISTORY_SIZE > 2 then all staging cookies
345
   * are moved one position down.
346
   */
347
0
  if(cookie_secrets->cookie_count == 0) {
348
0
    memcpy( cookie_secrets->cookie_secrets->cookie_secret
349
0
           , secret, UNBOUND_COOKIE_SECRET_SIZE);
350
0
    cookie_secrets->cookie_count = 1;
351
0
    explicit_bzero(secret, UNBOUND_COOKIE_SECRET_SIZE);
352
0
    return;
353
0
  }
354
#if UNBOUND_COOKIE_HISTORY_SIZE > 2
355
  memmove( &cookie_secrets->cookie_secrets[2], &cookie_secrets->cookie_secrets[1]
356
         , sizeof(struct cookie_secret) * (UNBOUND_COOKIE_HISTORY_SIZE - 2));
357
#endif
358
0
  memcpy( cookie_secrets->cookie_secrets[1].cookie_secret
359
0
        , secret, UNBOUND_COOKIE_SECRET_SIZE);
360
0
  cookie_secrets->cookie_count = cookie_secrets->cookie_count     < UNBOUND_COOKIE_HISTORY_SIZE
361
0
                    ? cookie_secrets->cookie_count + 1 : UNBOUND_COOKIE_HISTORY_SIZE;
362
0
  explicit_bzero(secret, UNBOUND_COOKIE_SECRET_SIZE);
363
0
}
364
365
void activate_cookie_secret(struct cookie_secrets* cookie_secrets)
366
0
{
367
0
  uint8_t active_secret[UNBOUND_COOKIE_SECRET_SIZE];
368
0
  if(!cookie_secrets)
369
0
    return;
370
  /* The staging secret becomes the active secret.
371
   * The active secret becomes a staging secret.
372
   * If the UNBOUND_COOKIE_HISTORY_SIZE > 2 then all staging secrets are moved
373
   * one position up and the previously active secret becomes the last
374
   * staging secret.
375
   */
376
0
  if(cookie_secrets->cookie_count < 2)
377
0
    return;
378
0
  memcpy( active_secret, cookie_secrets->cookie_secrets[0].cookie_secret
379
0
        , UNBOUND_COOKIE_SECRET_SIZE);
380
0
  memmove( &cookie_secrets->cookie_secrets[0], &cookie_secrets->cookie_secrets[1]
381
0
         , sizeof(struct cookie_secret) * (UNBOUND_COOKIE_HISTORY_SIZE - 1));
382
0
  memcpy( cookie_secrets->cookie_secrets[cookie_secrets->cookie_count - 1].cookie_secret
383
0
        , active_secret, UNBOUND_COOKIE_SECRET_SIZE);
384
0
  explicit_bzero(active_secret, UNBOUND_COOKIE_SECRET_SIZE);
385
0
}
386
387
void drop_cookie_secret(struct cookie_secrets* cookie_secrets)
388
0
{
389
0
  if(!cookie_secrets)
390
0
    return;
391
  /* Drops a staging cookie secret. If there are more than one, it will
392
   * drop the last staging secret. */
393
0
  if(cookie_secrets->cookie_count < 2)
394
0
    return;
395
0
  explicit_bzero( cookie_secrets->cookie_secrets[cookie_secrets->cookie_count - 1].cookie_secret
396
0
                , UNBOUND_COOKIE_SECRET_SIZE);
397
0
  cookie_secrets->cookie_count -= 1;
398
0
}