Coverage Report

Created: 2022-03-10 07:56

/src/bind9/lib/dns/transport.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
#include <inttypes.h>
15
16
#include <isc/list.h>
17
#include <isc/mem.h>
18
#include <isc/refcount.h>
19
#include <isc/result.h>
20
#include <isc/rwlock.h>
21
#include <isc/util.h>
22
23
#include <dns/name.h>
24
#include <dns/rbt.h>
25
#include <dns/transport.h>
26
27
0
#define TRANSPORT_MAGIC      ISC_MAGIC('T', 'r', 'n', 's')
28
#define VALID_TRANSPORT(ptr) ISC_MAGIC_VALID(ptr, TRANSPORT_MAGIC)
29
30
0
#define TRANSPORT_LIST_MAGIC    ISC_MAGIC('T', 'r', 'L', 's')
31
#define VALID_TRANSPORT_LIST(ptr) ISC_MAGIC_VALID(ptr, TRANSPORT_LIST_MAGIC)
32
33
struct dns_transport_list {
34
  unsigned int magic;
35
  isc_refcount_t references;
36
  isc_mem_t *mctx;
37
  isc_rwlock_t lock;
38
  dns_rbt_t *transports[DNS_TRANSPORT_COUNT];
39
};
40
41
typedef enum ternary { ter_none = 0, ter_true = 1, ter_false = 2 } ternary_t;
42
43
struct dns_transport {
44
  unsigned int magic;
45
  isc_refcount_t references;
46
  isc_mem_t *mctx;
47
  dns_transport_type_t type;
48
  struct {
49
    char *tlsname;
50
    char *certfile;
51
    char *keyfile;
52
    char *cafile;
53
    char *hostname;
54
    char *ciphers;
55
    uint32_t protocol_versions;
56
    ternary_t prefer_server_ciphers;
57
  } tls;
58
  struct {
59
    char *endpoint;
60
    dns_http_mode_t mode;
61
  } doh;
62
};
63
64
static void
65
0
free_dns_transport(void *node, void *arg) {
66
0
  dns_transport_t *transport = node;
67
68
0
  REQUIRE(node != NULL);
69
70
0
  UNUSED(arg);
71
72
0
  dns_transport_detach(&transport);
73
0
}
74
75
static isc_result_t
76
list_add(dns_transport_list_t *list, const dns_name_t *name,
77
0
   const dns_transport_type_t type, dns_transport_t *transport) {
78
0
  isc_result_t result;
79
0
  dns_rbt_t *rbt = NULL;
80
81
0
  RWLOCK(&list->lock, isc_rwlocktype_write);
82
0
  rbt = list->transports[type];
83
0
  INSIST(rbt != NULL);
84
85
0
  result = dns_rbt_addname(rbt, name, transport);
86
87
0
  RWUNLOCK(&list->lock, isc_rwlocktype_write);
88
89
0
  return (result);
90
0
}
91
92
dns_transport_type_t
93
0
dns_transport_get_type(dns_transport_t *transport) {
94
0
  REQUIRE(VALID_TRANSPORT(transport));
95
96
0
  return (transport->type);
97
0
}
98
99
char *
100
0
dns_transport_get_certfile(dns_transport_t *transport) {
101
0
  REQUIRE(VALID_TRANSPORT(transport));
102
103
0
  return (transport->tls.certfile);
104
0
}
105
106
char *
107
0
dns_transport_get_keyfile(dns_transport_t *transport) {
108
0
  REQUIRE(VALID_TRANSPORT(transport));
109
110
0
  return (transport->tls.keyfile);
111
0
}
112
113
char *
114
0
dns_transport_get_cafile(dns_transport_t *transport) {
115
0
  REQUIRE(VALID_TRANSPORT(transport));
116
117
0
  return (transport->tls.cafile);
118
0
}
119
120
char *
121
0
dns_transport_get_hostname(dns_transport_t *transport) {
122
0
  REQUIRE(VALID_TRANSPORT(transport));
123
124
0
  return (transport->tls.hostname);
125
0
}
126
127
char *
128
0
dns_transport_get_endpoint(dns_transport_t *transport) {
129
0
  REQUIRE(VALID_TRANSPORT(transport));
130
131
0
  return (transport->doh.endpoint);
132
0
}
133
134
dns_http_mode_t
135
0
dns_transport_get_mode(dns_transport_t *transport) {
136
0
  REQUIRE(VALID_TRANSPORT(transport));
137
138
0
  return (transport->doh.mode);
139
0
}
140
141
dns_transport_t *
142
dns_transport_new(const dns_name_t *name, dns_transport_type_t type,
143
0
      dns_transport_list_t *list) {
144
0
  dns_transport_t *transport = isc_mem_get(list->mctx,
145
0
             sizeof(*transport));
146
0
  *transport = (dns_transport_t){ .type = type };
147
0
  isc_refcount_init(&transport->references, 1);
148
0
  isc_mem_attach(list->mctx, &transport->mctx);
149
0
  transport->magic = TRANSPORT_MAGIC;
150
151
0
  list_add(list, name, type, transport);
152
153
0
  return (transport);
154
0
}
155
156
void
157
0
dns_transport_set_certfile(dns_transport_t *transport, const char *certfile) {
158
0
  REQUIRE(VALID_TRANSPORT(transport));
159
0
  REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
160
0
    transport->type == DNS_TRANSPORT_HTTP);
161
162
0
  if (transport->tls.certfile != NULL) {
163
0
    isc_mem_free(transport->mctx, transport->tls.certfile);
164
0
  }
165
166
0
  if (certfile != NULL) {
167
0
    transport->tls.certfile = isc_mem_strdup(transport->mctx,
168
0
               certfile);
169
0
  }
170
0
}
171
172
void
173
0
dns_transport_set_keyfile(dns_transport_t *transport, const char *keyfile) {
174
0
  REQUIRE(VALID_TRANSPORT(transport));
175
0
  REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
176
0
    transport->type == DNS_TRANSPORT_HTTP);
177
178
0
  if (transport->tls.keyfile != NULL) {
179
0
    isc_mem_free(transport->mctx, transport->tls.keyfile);
180
0
  }
181
182
0
  if (keyfile != NULL) {
183
0
    transport->tls.keyfile = isc_mem_strdup(transport->mctx,
184
0
              keyfile);
185
0
  }
186
0
}
187
188
void
189
0
dns_transport_set_cafile(dns_transport_t *transport, const char *cafile) {
190
0
  REQUIRE(VALID_TRANSPORT(transport));
191
0
  REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
192
0
    transport->type == DNS_TRANSPORT_HTTP);
193
194
0
  if (transport->tls.cafile != NULL) {
195
0
    isc_mem_free(transport->mctx, transport->tls.cafile);
196
0
  }
197
198
0
  if (cafile != NULL) {
199
0
    transport->tls.cafile = isc_mem_strdup(transport->mctx, cafile);
200
0
  }
201
0
}
202
203
void
204
0
dns_transport_set_hostname(dns_transport_t *transport, const char *hostname) {
205
0
  REQUIRE(VALID_TRANSPORT(transport));
206
0
  REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
207
0
    transport->type == DNS_TRANSPORT_HTTP);
208
209
0
  if (transport->tls.hostname != NULL) {
210
0
    isc_mem_free(transport->mctx, transport->tls.hostname);
211
0
  }
212
213
0
  if (hostname != NULL) {
214
0
    transport->tls.hostname = isc_mem_strdup(transport->mctx,
215
0
               hostname);
216
0
  }
217
0
}
218
219
void
220
0
dns_transport_set_endpoint(dns_transport_t *transport, const char *endpoint) {
221
0
  REQUIRE(VALID_TRANSPORT(transport));
222
0
  REQUIRE(transport->type == DNS_TRANSPORT_HTTP);
223
224
0
  if (transport->doh.endpoint != NULL) {
225
0
    isc_mem_free(transport->mctx, transport->doh.endpoint);
226
0
  }
227
228
0
  if (endpoint != NULL) {
229
0
    transport->doh.endpoint = isc_mem_strdup(transport->mctx,
230
0
               endpoint);
231
0
  }
232
0
}
233
234
void
235
0
dns_transport_set_mode(dns_transport_t *transport, dns_http_mode_t mode) {
236
0
  REQUIRE(VALID_TRANSPORT(transport));
237
0
  REQUIRE(transport->type == DNS_TRANSPORT_HTTP);
238
239
0
  transport->doh.mode = mode;
240
0
}
241
242
void
243
dns_transport_set_tls_versions(dns_transport_t *transport,
244
0
             const uint32_t tls_versions) {
245
0
  REQUIRE(VALID_TRANSPORT(transport));
246
0
  REQUIRE(transport->type == DNS_TRANSPORT_HTTP ||
247
0
    transport->type == DNS_TRANSPORT_TLS);
248
249
0
  transport->tls.protocol_versions = tls_versions;
250
0
}
251
252
uint32_t
253
0
dns_transport_get_tls_versions(const dns_transport_t *transport) {
254
0
  REQUIRE(VALID_TRANSPORT(transport));
255
256
0
  return (transport->tls.protocol_versions);
257
0
}
258
259
void
260
0
dns_transport_set_ciphers(dns_transport_t *transport, const char *ciphers) {
261
0
  REQUIRE(VALID_TRANSPORT(transport));
262
0
  REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
263
0
    transport->type == DNS_TRANSPORT_HTTP);
264
265
0
  if (transport->tls.ciphers != NULL) {
266
0
    isc_mem_free(transport->mctx, transport->tls.ciphers);
267
0
  }
268
269
0
  if (ciphers != NULL) {
270
0
    transport->tls.ciphers = isc_mem_strdup(transport->mctx,
271
0
              ciphers);
272
0
  }
273
0
}
274
275
void
276
0
dns_transport_set_tlsname(dns_transport_t *transport, const char *tlsname) {
277
0
  REQUIRE(VALID_TRANSPORT(transport));
278
0
  REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
279
0
    transport->type == DNS_TRANSPORT_HTTP);
280
281
0
  if (transport->tls.tlsname != NULL) {
282
0
    isc_mem_free(transport->mctx, transport->tls.tlsname);
283
0
  }
284
285
0
  if (tlsname != NULL) {
286
0
    transport->tls.tlsname = isc_mem_strdup(transport->mctx,
287
0
              tlsname);
288
0
  }
289
0
}
290
291
char *
292
0
dns_transport_get_ciphers(dns_transport_t *transport) {
293
0
  REQUIRE(VALID_TRANSPORT(transport));
294
295
0
  return (transport->tls.ciphers);
296
0
}
297
298
char *
299
0
dns_transport_get_tlsname(dns_transport_t *transport) {
300
0
  REQUIRE(VALID_TRANSPORT(transport));
301
302
0
  return (transport->tls.tlsname);
303
0
}
304
305
void
306
dns_transport_set_prefer_server_ciphers(dns_transport_t *transport,
307
0
          const bool prefer) {
308
0
  REQUIRE(VALID_TRANSPORT(transport));
309
0
  REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
310
0
    transport->type == DNS_TRANSPORT_HTTP);
311
312
0
  transport->tls.prefer_server_ciphers = prefer ? ter_true : ter_false;
313
0
}
314
315
bool
316
dns_transport_get_prefer_server_ciphers(const dns_transport_t *transport,
317
0
          bool *preferp) {
318
0
  REQUIRE(VALID_TRANSPORT(transport));
319
0
  REQUIRE(preferp != NULL);
320
0
  if (transport->tls.prefer_server_ciphers == ter_none) {
321
0
    return (false);
322
0
  } else if (transport->tls.prefer_server_ciphers == ter_true) {
323
0
    *preferp = true;
324
0
    return (true);
325
0
  } else if (transport->tls.prefer_server_ciphers == ter_false) {
326
0
    *preferp = false;
327
0
    return (true);
328
0
  }
329
330
0
  INSIST(0);
331
0
  ISC_UNREACHABLE();
332
0
  return false;
333
0
}
334
335
static void
336
0
transport_destroy(dns_transport_t *transport) {
337
0
  isc_refcount_destroy(&transport->references);
338
0
  transport->magic = 0;
339
340
0
  if (transport->doh.endpoint != NULL) {
341
0
    isc_mem_free(transport->mctx, transport->doh.endpoint);
342
0
  }
343
0
  if (transport->tls.hostname != NULL) {
344
0
    isc_mem_free(transport->mctx, transport->tls.hostname);
345
0
  }
346
0
  if (transport->tls.cafile != NULL) {
347
0
    isc_mem_free(transport->mctx, transport->tls.cafile);
348
0
  }
349
0
  if (transport->tls.keyfile != NULL) {
350
0
    isc_mem_free(transport->mctx, transport->tls.keyfile);
351
0
  }
352
0
  if (transport->tls.certfile != NULL) {
353
0
    isc_mem_free(transport->mctx, transport->tls.certfile);
354
0
  }
355
0
  if (transport->tls.ciphers != NULL) {
356
0
    isc_mem_free(transport->mctx, transport->tls.ciphers);
357
0
  }
358
359
0
  if (transport->tls.tlsname != NULL) {
360
0
    isc_mem_free(transport->mctx, transport->tls.tlsname);
361
0
  }
362
363
0
  isc_mem_putanddetach(&transport->mctx, transport, sizeof(*transport));
364
0
}
365
366
void
367
0
dns_transport_attach(dns_transport_t *source, dns_transport_t **targetp) {
368
0
  REQUIRE(source != NULL);
369
0
  REQUIRE(targetp != NULL && *targetp == NULL);
370
371
0
  isc_refcount_increment(&source->references);
372
373
0
  *targetp = source;
374
0
}
375
376
void
377
0
dns_transport_detach(dns_transport_t **transportp) {
378
0
  dns_transport_t *transport = NULL;
379
380
0
  REQUIRE(transportp != NULL);
381
0
  REQUIRE(VALID_TRANSPORT(*transportp));
382
383
0
  transport = *transportp;
384
0
  *transportp = NULL;
385
386
0
  if (isc_refcount_decrement(&transport->references) == 1) {
387
0
    transport_destroy(transport);
388
0
  }
389
0
}
390
391
dns_transport_t *
392
dns_transport_find(const dns_transport_type_t type, const dns_name_t *name,
393
0
       dns_transport_list_t *list) {
394
0
  isc_result_t result;
395
0
  dns_transport_t *transport = NULL;
396
0
  dns_rbt_t *rbt = NULL;
397
398
0
  REQUIRE(VALID_TRANSPORT_LIST(list));
399
0
  REQUIRE(list->transports[type] != NULL);
400
401
0
  rbt = list->transports[type];
402
403
0
  RWLOCK(&list->lock, isc_rwlocktype_read);
404
0
  result = dns_rbt_findname(rbt, name, 0, NULL, (void *)&transport);
405
0
  if (result == ISC_R_SUCCESS) {
406
0
    isc_refcount_increment(&transport->references);
407
0
  }
408
0
  RWUNLOCK(&list->lock, isc_rwlocktype_read);
409
410
0
  return (transport);
411
0
}
412
413
dns_transport_list_t *
414
0
dns_transport_list_new(isc_mem_t *mctx) {
415
0
  dns_transport_list_t *list = isc_mem_get(mctx, sizeof(*list));
416
417
0
  *list = (dns_transport_list_t){ 0 };
418
419
0
  isc_rwlock_init(&list->lock, 0, 0);
420
421
0
  isc_mem_attach(mctx, &list->mctx);
422
0
  isc_refcount_init(&list->references, 1);
423
424
0
  list->magic = TRANSPORT_LIST_MAGIC;
425
426
0
  for (size_t type = 0; type < DNS_TRANSPORT_COUNT; type++) {
427
0
    isc_result_t result;
428
0
    result = dns_rbt_create(list->mctx, free_dns_transport, NULL,
429
0
          &list->transports[type]);
430
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
431
0
  }
432
433
0
  return (list);
434
0
}
435
436
void
437
dns_transport_list_attach(dns_transport_list_t *source,
438
0
        dns_transport_list_t **targetp) {
439
0
  REQUIRE(VALID_TRANSPORT_LIST(source));
440
0
  REQUIRE(targetp != NULL && *targetp == NULL);
441
442
0
  isc_refcount_increment(&source->references);
443
444
0
  *targetp = source;
445
0
}
446
447
static void
448
0
transport_list_destroy(dns_transport_list_t *list) {
449
0
  isc_refcount_destroy(&list->references);
450
0
  list->magic = 0;
451
452
0
  for (size_t type = 0; type < DNS_TRANSPORT_COUNT; type++) {
453
0
    if (list->transports[type] != NULL) {
454
0
      dns_rbt_destroy(&list->transports[type]);
455
0
    }
456
0
  }
457
0
  isc_rwlock_destroy(&list->lock);
458
0
  isc_mem_putanddetach(&list->mctx, list, sizeof(*list));
459
0
}
460
461
void
462
0
dns_transport_list_detach(dns_transport_list_t **listp) {
463
0
  dns_transport_list_t *list = NULL;
464
465
0
  REQUIRE(listp != NULL);
466
0
  REQUIRE(VALID_TRANSPORT_LIST(*listp));
467
468
0
  list = *listp;
469
0
  *listp = NULL;
470
471
0
  if (isc_refcount_decrement(&list->references) == 1) {
472
0
    transport_list_destroy(list);
473
0
  }
474
0
}