Home | History | Annotate | Line # | Download | only in dns
      1  1.10  christos /*	$NetBSD: forward.c,v 1.10 2025/01/26 16:25:22 christos Exp $	*/
      2   1.1  christos 
      3   1.1  christos /*
      4   1.1  christos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5   1.1  christos  *
      6   1.7  christos  * SPDX-License-Identifier: MPL-2.0
      7   1.7  christos  *
      8   1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
      9   1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10   1.5  christos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11   1.1  christos  *
     12   1.1  christos  * See the COPYRIGHT file distributed with this work for additional
     13   1.1  christos  * information regarding copyright ownership.
     14   1.1  christos  */
     15   1.1  christos 
     16   1.1  christos /*! \file */
     17   1.1  christos 
     18   1.1  christos #include <isc/magic.h>
     19   1.1  christos #include <isc/mem.h>
     20   1.9  christos #include <isc/result.h>
     21   1.1  christos #include <isc/util.h>
     22   1.1  christos 
     23  1.10  christos #include <dns/fixedname.h>
     24   1.1  christos #include <dns/forward.h>
     25  1.10  christos #include <dns/name.h>
     26  1.10  christos #include <dns/qp.h>
     27   1.1  christos #include <dns/types.h>
     28  1.10  christos #include <dns/view.h>
     29   1.1  christos 
     30   1.1  christos struct dns_fwdtable {
     31   1.1  christos 	/* Unlocked. */
     32   1.4  christos 	unsigned int magic;
     33   1.4  christos 	isc_mem_t *mctx;
     34  1.10  christos 	dns_qpmulti_t *table;
     35   1.1  christos };
     36   1.1  christos 
     37   1.4  christos #define FWDTABLEMAGIC	   ISC_MAGIC('F', 'w', 'd', 'T')
     38   1.4  christos #define VALID_FWDTABLE(ft) ISC_MAGIC_VALID(ft, FWDTABLEMAGIC)
     39   1.1  christos 
     40   1.1  christos static void
     41  1.10  christos qp_attach(void *uctx, void *pval, uint32_t ival);
     42  1.10  christos static void
     43  1.10  christos qp_detach(void *uctx, void *pval, uint32_t ival);
     44  1.10  christos static size_t
     45  1.10  christos qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
     46  1.10  christos static void
     47  1.10  christos qp_triename(void *uctx, char *buf, size_t size);
     48  1.10  christos 
     49  1.10  christos static dns_qpmethods_t qpmethods = {
     50  1.10  christos 	qp_attach,
     51  1.10  christos 	qp_detach,
     52  1.10  christos 	qp_makekey,
     53  1.10  christos 	qp_triename,
     54  1.10  christos };
     55   1.1  christos 
     56  1.10  christos void
     57  1.10  christos dns_fwdtable_create(isc_mem_t *mctx, dns_view_t *view,
     58  1.10  christos 		    dns_fwdtable_t **fwdtablep) {
     59  1.10  christos 	dns_fwdtable_t *fwdtable = NULL;
     60   1.1  christos 
     61   1.1  christos 	REQUIRE(fwdtablep != NULL && *fwdtablep == NULL);
     62   1.1  christos 
     63   1.8  christos 	fwdtable = isc_mem_get(mctx, sizeof(*fwdtable));
     64  1.10  christos 	*fwdtable = (dns_fwdtable_t){ .magic = FWDTABLEMAGIC };
     65   1.1  christos 
     66  1.10  christos 	dns_qpmulti_create(mctx, &qpmethods, view, &fwdtable->table);
     67   1.1  christos 
     68   1.1  christos 	isc_mem_attach(mctx, &fwdtable->mctx);
     69   1.1  christos 	*fwdtablep = fwdtable;
     70  1.10  christos }
     71   1.1  christos 
     72  1.10  christos static dns_forwarders_t *
     73  1.10  christos new_forwarders(isc_mem_t *mctx, const dns_name_t *name,
     74  1.10  christos 	       dns_fwdpolicy_t fwdpolicy) {
     75  1.10  christos 	dns_forwarders_t *forwarders = NULL;
     76  1.10  christos 
     77  1.10  christos 	forwarders = isc_mem_get(mctx, sizeof(*forwarders));
     78  1.10  christos 	*forwarders = (dns_forwarders_t){
     79  1.10  christos 		.fwdpolicy = fwdpolicy,
     80  1.10  christos 		.name = DNS_NAME_INITEMPTY,
     81  1.10  christos 		.fwdrs = ISC_LIST_INITIALIZER,
     82  1.10  christos 	};
     83  1.10  christos 	isc_mem_attach(mctx, &forwarders->mctx);
     84  1.10  christos 	isc_refcount_init(&forwarders->references, 1);
     85   1.1  christos 
     86  1.10  christos 	dns_name_dupwithoffsets(name, mctx, &forwarders->name);
     87   1.1  christos 
     88  1.10  christos 	return forwarders;
     89   1.1  christos }
     90   1.1  christos 
     91   1.1  christos isc_result_t
     92   1.1  christos dns_fwdtable_addfwd(dns_fwdtable_t *fwdtable, const dns_name_t *name,
     93   1.4  christos 		    dns_forwarderlist_t *fwdrs, dns_fwdpolicy_t fwdpolicy) {
     94   1.1  christos 	isc_result_t result;
     95  1.10  christos 	dns_forwarders_t *forwarders = NULL;
     96  1.10  christos 	dns_forwarder_t *fwd = NULL, *nfwd = NULL;
     97  1.10  christos 	dns_qp_t *qp = NULL;
     98   1.1  christos 
     99   1.1  christos 	REQUIRE(VALID_FWDTABLE(fwdtable));
    100   1.1  christos 
    101  1.10  christos 	forwarders = new_forwarders(fwdtable->mctx, name, fwdpolicy);
    102   1.1  christos 
    103   1.4  christos 	for (fwd = ISC_LIST_HEAD(*fwdrs); fwd != NULL;
    104   1.8  christos 	     fwd = ISC_LIST_NEXT(fwd, link))
    105   1.8  christos 	{
    106   1.8  christos 		nfwd = isc_mem_get(fwdtable->mctx, sizeof(*nfwd));
    107   1.1  christos 		*nfwd = *fwd;
    108  1.10  christos 
    109  1.10  christos 		if (fwd->tlsname != NULL) {
    110  1.10  christos 			nfwd->tlsname = isc_mem_get(fwdtable->mctx,
    111  1.10  christos 						    sizeof(*nfwd->tlsname));
    112  1.10  christos 			dns_name_init(nfwd->tlsname, NULL);
    113  1.10  christos 			dns_name_dup(fwd->tlsname, fwdtable->mctx,
    114  1.10  christos 				     nfwd->tlsname);
    115  1.10  christos 		}
    116  1.10  christos 
    117   1.1  christos 		ISC_LINK_INIT(nfwd, link);
    118   1.1  christos 		ISC_LIST_APPEND(forwarders->fwdrs, nfwd, link);
    119   1.1  christos 	}
    120   1.1  christos 
    121  1.10  christos 	dns_qpmulti_write(fwdtable->table, &qp);
    122  1.10  christos 	result = dns_qp_insert(qp, forwarders, 0);
    123  1.10  christos 	dns_qp_compact(qp, DNS_QPGC_MAYBE);
    124  1.10  christos 	dns_qpmulti_commit(fwdtable->table, &qp);
    125   1.1  christos 
    126  1.10  christos 	dns_forwarders_detach(&forwarders);
    127   1.1  christos 
    128  1.10  christos 	return result;
    129   1.1  christos }
    130   1.1  christos 
    131   1.1  christos isc_result_t
    132   1.1  christos dns_fwdtable_add(dns_fwdtable_t *fwdtable, const dns_name_t *name,
    133   1.4  christos 		 isc_sockaddrlist_t *addrs, dns_fwdpolicy_t fwdpolicy) {
    134   1.1  christos 	isc_result_t result;
    135  1.10  christos 	dns_forwarders_t *forwarders = NULL;
    136  1.10  christos 	dns_forwarder_t *fwd = NULL;
    137  1.10  christos 	isc_sockaddr_t *sa = NULL;
    138  1.10  christos 	dns_qp_t *qp = NULL;
    139   1.1  christos 
    140   1.1  christos 	REQUIRE(VALID_FWDTABLE(fwdtable));
    141   1.1  christos 
    142  1.10  christos 	forwarders = new_forwarders(fwdtable->mctx, name, fwdpolicy);
    143   1.1  christos 
    144   1.4  christos 	for (sa = ISC_LIST_HEAD(*addrs); sa != NULL;
    145   1.8  christos 	     sa = ISC_LIST_NEXT(sa, link))
    146   1.8  christos 	{
    147   1.8  christos 		fwd = isc_mem_get(fwdtable->mctx, sizeof(*fwd));
    148  1.10  christos 		*fwd = (dns_forwarder_t){ .addr = *sa,
    149  1.10  christos 					  .link = ISC_LINK_INITIALIZER };
    150   1.1  christos 		ISC_LIST_APPEND(forwarders->fwdrs, fwd, link);
    151   1.1  christos 	}
    152   1.1  christos 
    153  1.10  christos 	dns_qpmulti_write(fwdtable->table, &qp);
    154  1.10  christos 	result = dns_qp_insert(qp, forwarders, 0);
    155  1.10  christos 	dns_qp_compact(qp, DNS_QPGC_MAYBE);
    156  1.10  christos 	dns_qpmulti_commit(fwdtable->table, &qp);
    157   1.1  christos 
    158  1.10  christos 	dns_forwarders_detach(&forwarders);
    159   1.1  christos 
    160  1.10  christos 	return result;
    161   1.1  christos }
    162   1.1  christos 
    163   1.1  christos isc_result_t
    164   1.1  christos dns_fwdtable_find(dns_fwdtable_t *fwdtable, const dns_name_t *name,
    165  1.10  christos 		  dns_forwarders_t **forwardersp) {
    166   1.1  christos 	isc_result_t result;
    167  1.10  christos 	dns_qpread_t qpr;
    168  1.10  christos 	void *pval = NULL;
    169   1.1  christos 
    170   1.1  christos 	REQUIRE(VALID_FWDTABLE(fwdtable));
    171   1.1  christos 
    172  1.10  christos 	dns_qpmulti_query(fwdtable->table, &qpr);
    173  1.10  christos 	result = dns_qp_lookup(&qpr, name, NULL, NULL, NULL, &pval, NULL);
    174  1.10  christos 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
    175  1.10  christos 		dns_forwarders_t *fwdrs = pval;
    176  1.10  christos 		*forwardersp = fwdrs;
    177  1.10  christos 		dns_forwarders_ref(fwdrs);
    178  1.10  christos 	}
    179  1.10  christos 	dns_qpread_destroy(fwdtable->table, &qpr);
    180   1.1  christos 
    181  1.10  christos 	return result;
    182   1.1  christos }
    183   1.1  christos 
    184   1.1  christos void
    185   1.1  christos dns_fwdtable_destroy(dns_fwdtable_t **fwdtablep) {
    186  1.10  christos 	dns_fwdtable_t *fwdtable = NULL;
    187   1.1  christos 
    188   1.1  christos 	REQUIRE(fwdtablep != NULL && VALID_FWDTABLE(*fwdtablep));
    189   1.1  christos 
    190   1.1  christos 	fwdtable = *fwdtablep;
    191   1.4  christos 	*fwdtablep = NULL;
    192   1.1  christos 
    193  1.10  christos 	dns_qpmulti_destroy(&fwdtable->table);
    194   1.1  christos 	fwdtable->magic = 0;
    195   1.1  christos 
    196   1.8  christos 	isc_mem_putanddetach(&fwdtable->mctx, fwdtable, sizeof(*fwdtable));
    197   1.1  christos }
    198   1.1  christos 
    199   1.1  christos /***
    200   1.1  christos  *** Private
    201   1.1  christos  ***/
    202   1.1  christos 
    203   1.1  christos static void
    204  1.10  christos destroy_forwarders(dns_forwarders_t *forwarders) {
    205  1.10  christos 	dns_forwarder_t *fwd = NULL;
    206   1.1  christos 
    207   1.1  christos 	while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
    208   1.1  christos 		fwd = ISC_LIST_HEAD(forwarders->fwdrs);
    209   1.1  christos 		ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
    210  1.10  christos 		if (fwd->tlsname != NULL) {
    211  1.10  christos 			dns_name_free(fwd->tlsname, forwarders->mctx);
    212  1.10  christos 			isc_mem_put(forwarders->mctx, fwd->tlsname,
    213  1.10  christos 				    sizeof(*fwd->tlsname));
    214  1.10  christos 		}
    215  1.10  christos 		isc_mem_put(forwarders->mctx, fwd, sizeof(*fwd));
    216  1.10  christos 	}
    217  1.10  christos 	dns_name_free(&forwarders->name, forwarders->mctx);
    218  1.10  christos 	isc_mem_putanddetach(&forwarders->mctx, forwarders,
    219  1.10  christos 			     sizeof(*forwarders));
    220  1.10  christos }
    221  1.10  christos 
    222  1.10  christos #if DNS_FORWARD_TRACE
    223  1.10  christos ISC_REFCOUNT_TRACE_IMPL(dns_forwarders, destroy_forwarders);
    224  1.10  christos #else
    225  1.10  christos ISC_REFCOUNT_IMPL(dns_forwarders, destroy_forwarders);
    226  1.10  christos #endif
    227  1.10  christos 
    228  1.10  christos static void
    229  1.10  christos qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
    230  1.10  christos 	  uint32_t ival ISC_ATTR_UNUSED) {
    231  1.10  christos 	dns_forwarders_t *forwarders = pval;
    232  1.10  christos 	dns_forwarders_ref(forwarders);
    233  1.10  christos }
    234  1.10  christos 
    235  1.10  christos static void
    236  1.10  christos qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
    237  1.10  christos 	  uint32_t ival ISC_ATTR_UNUSED) {
    238  1.10  christos 	dns_forwarders_t *forwarders = pval;
    239  1.10  christos 	dns_forwarders_detach(&forwarders);
    240  1.10  christos }
    241  1.10  christos 
    242  1.10  christos static size_t
    243  1.10  christos qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
    244  1.10  christos 	   uint32_t ival ISC_ATTR_UNUSED) {
    245  1.10  christos 	dns_forwarders_t *fwd = pval;
    246  1.10  christos 	return dns_qpkey_fromname(key, &fwd->name);
    247  1.10  christos }
    248  1.10  christos 
    249  1.10  christos static void
    250  1.10  christos qp_triename(void *uctx, char *buf, size_t size) {
    251  1.10  christos 	dns_view_t *view = uctx;
    252  1.10  christos 	snprintf(buf, size, "view %s forwarder table", view->name);
    253   1.1  christos }
    254