Home | History | Annotate | Line # | Download | only in dns
forward.c revision 1.1
      1  1.1  christos /*	$NetBSD: forward.c,v 1.1 2018/08/12 12:08:13 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.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
      7  1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
      8  1.1  christos  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9  1.1  christos  *
     10  1.1  christos  * See the COPYRIGHT file distributed with this work for additional
     11  1.1  christos  * information regarding copyright ownership.
     12  1.1  christos  */
     13  1.1  christos 
     14  1.1  christos /*! \file */
     15  1.1  christos 
     16  1.1  christos #include <config.h>
     17  1.1  christos 
     18  1.1  christos #include <isc/magic.h>
     19  1.1  christos #include <isc/mem.h>
     20  1.1  christos #include <isc/rwlock.h>
     21  1.1  christos #include <isc/util.h>
     22  1.1  christos 
     23  1.1  christos #include <dns/forward.h>
     24  1.1  christos #include <dns/rbt.h>
     25  1.1  christos #include <dns/result.h>
     26  1.1  christos #include <dns/types.h>
     27  1.1  christos 
     28  1.1  christos struct dns_fwdtable {
     29  1.1  christos 	/* Unlocked. */
     30  1.1  christos 	unsigned int		magic;
     31  1.1  christos 	isc_mem_t		*mctx;
     32  1.1  christos 	isc_rwlock_t		rwlock;
     33  1.1  christos 	/* Locked by lock. */
     34  1.1  christos 	dns_rbt_t		*table;
     35  1.1  christos };
     36  1.1  christos 
     37  1.1  christos #define FWDTABLEMAGIC		ISC_MAGIC('F', 'w', 'd', 'T')
     38  1.1  christos #define VALID_FWDTABLE(ft) 	ISC_MAGIC_VALID(ft, FWDTABLEMAGIC)
     39  1.1  christos 
     40  1.1  christos static void
     41  1.1  christos auto_detach(void *, void *);
     42  1.1  christos 
     43  1.1  christos isc_result_t
     44  1.1  christos dns_fwdtable_create(isc_mem_t *mctx, dns_fwdtable_t **fwdtablep) {
     45  1.1  christos 	dns_fwdtable_t *fwdtable;
     46  1.1  christos 	isc_result_t result;
     47  1.1  christos 
     48  1.1  christos 	REQUIRE(fwdtablep != NULL && *fwdtablep == NULL);
     49  1.1  christos 
     50  1.1  christos 	fwdtable = isc_mem_get(mctx, sizeof(dns_fwdtable_t));
     51  1.1  christos 	if (fwdtable == NULL)
     52  1.1  christos 		return (ISC_R_NOMEMORY);
     53  1.1  christos 
     54  1.1  christos 	fwdtable->table = NULL;
     55  1.1  christos 	result = dns_rbt_create(mctx, auto_detach, fwdtable, &fwdtable->table);
     56  1.1  christos 	if (result != ISC_R_SUCCESS)
     57  1.1  christos 		goto cleanup_fwdtable;
     58  1.1  christos 
     59  1.1  christos 	result = isc_rwlock_init(&fwdtable->rwlock, 0, 0);
     60  1.1  christos 	if (result != ISC_R_SUCCESS)
     61  1.1  christos 		goto cleanup_rbt;
     62  1.1  christos 
     63  1.1  christos 	fwdtable->mctx = NULL;
     64  1.1  christos 	isc_mem_attach(mctx, &fwdtable->mctx);
     65  1.1  christos 	fwdtable->magic = FWDTABLEMAGIC;
     66  1.1  christos 	*fwdtablep = fwdtable;
     67  1.1  christos 
     68  1.1  christos 	return (ISC_R_SUCCESS);
     69  1.1  christos 
     70  1.1  christos    cleanup_rbt:
     71  1.1  christos 	dns_rbt_destroy(&fwdtable->table);
     72  1.1  christos 
     73  1.1  christos    cleanup_fwdtable:
     74  1.1  christos 	isc_mem_put(mctx, fwdtable, sizeof(dns_fwdtable_t));
     75  1.1  christos 
     76  1.1  christos 	return (result);
     77  1.1  christos }
     78  1.1  christos 
     79  1.1  christos isc_result_t
     80  1.1  christos dns_fwdtable_addfwd(dns_fwdtable_t *fwdtable, const dns_name_t *name,
     81  1.1  christos 		    dns_forwarderlist_t *fwdrs, dns_fwdpolicy_t fwdpolicy)
     82  1.1  christos {
     83  1.1  christos 	isc_result_t result;
     84  1.1  christos 	dns_forwarders_t *forwarders;
     85  1.1  christos 	dns_forwarder_t *fwd, *nfwd;
     86  1.1  christos 
     87  1.1  christos 	REQUIRE(VALID_FWDTABLE(fwdtable));
     88  1.1  christos 
     89  1.1  christos 	forwarders = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarders_t));
     90  1.1  christos 	if (forwarders == NULL)
     91  1.1  christos 		return (ISC_R_NOMEMORY);
     92  1.1  christos 
     93  1.1  christos 	ISC_LIST_INIT(forwarders->fwdrs);
     94  1.1  christos 	for (fwd = ISC_LIST_HEAD(*fwdrs);
     95  1.1  christos 	     fwd != NULL;
     96  1.1  christos 	     fwd = ISC_LIST_NEXT(fwd, link))
     97  1.1  christos 	{
     98  1.1  christos 		nfwd = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarder_t));
     99  1.1  christos 		if (nfwd == NULL) {
    100  1.1  christos 			result = ISC_R_NOMEMORY;
    101  1.1  christos 			goto cleanup;
    102  1.1  christos 		}
    103  1.1  christos 		*nfwd = *fwd;
    104  1.1  christos 		ISC_LINK_INIT(nfwd, link);
    105  1.1  christos 		ISC_LIST_APPEND(forwarders->fwdrs, nfwd, link);
    106  1.1  christos 	}
    107  1.1  christos 	forwarders->fwdpolicy = fwdpolicy;
    108  1.1  christos 
    109  1.1  christos 	RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
    110  1.1  christos 	result = dns_rbt_addname(fwdtable->table, name, forwarders);
    111  1.1  christos 	RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
    112  1.1  christos 
    113  1.1  christos 	if (result != ISC_R_SUCCESS)
    114  1.1  christos 		goto cleanup;
    115  1.1  christos 
    116  1.1  christos 	return (ISC_R_SUCCESS);
    117  1.1  christos 
    118  1.1  christos  cleanup:
    119  1.1  christos 	while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
    120  1.1  christos 		fwd = ISC_LIST_HEAD(forwarders->fwdrs);
    121  1.1  christos 		ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
    122  1.1  christos 		isc_mem_put(fwdtable->mctx, fwd, sizeof(isc_sockaddr_t));
    123  1.1  christos 	}
    124  1.1  christos 	isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
    125  1.1  christos 	return (result);
    126  1.1  christos }
    127  1.1  christos 
    128  1.1  christos isc_result_t
    129  1.1  christos dns_fwdtable_add(dns_fwdtable_t *fwdtable, const dns_name_t *name,
    130  1.1  christos 		 isc_sockaddrlist_t *addrs, dns_fwdpolicy_t fwdpolicy)
    131  1.1  christos {
    132  1.1  christos 	isc_result_t result;
    133  1.1  christos 	dns_forwarders_t *forwarders;
    134  1.1  christos 	dns_forwarder_t *fwd;
    135  1.1  christos 	isc_sockaddr_t *sa;
    136  1.1  christos 
    137  1.1  christos 	REQUIRE(VALID_FWDTABLE(fwdtable));
    138  1.1  christos 
    139  1.1  christos 	forwarders = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarders_t));
    140  1.1  christos 	if (forwarders == NULL)
    141  1.1  christos 		return (ISC_R_NOMEMORY);
    142  1.1  christos 
    143  1.1  christos 	ISC_LIST_INIT(forwarders->fwdrs);
    144  1.1  christos 	for (sa = ISC_LIST_HEAD(*addrs);
    145  1.1  christos 	     sa != NULL;
    146  1.1  christos 	     sa = ISC_LIST_NEXT(sa, link))
    147  1.1  christos 	{
    148  1.1  christos 		fwd = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarder_t));
    149  1.1  christos 		if (fwd == NULL) {
    150  1.1  christos 			result = ISC_R_NOMEMORY;
    151  1.1  christos 			goto cleanup;
    152  1.1  christos 		}
    153  1.1  christos 		fwd->addr = *sa;
    154  1.1  christos 		fwd->dscp = -1;
    155  1.1  christos 		ISC_LINK_INIT(fwd, link);
    156  1.1  christos 		ISC_LIST_APPEND(forwarders->fwdrs, fwd, link);
    157  1.1  christos 	}
    158  1.1  christos 	forwarders->fwdpolicy = fwdpolicy;
    159  1.1  christos 
    160  1.1  christos 	RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
    161  1.1  christos 	result = dns_rbt_addname(fwdtable->table, name, forwarders);
    162  1.1  christos 	RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
    163  1.1  christos 
    164  1.1  christos 	if (result != ISC_R_SUCCESS)
    165  1.1  christos 		goto cleanup;
    166  1.1  christos 
    167  1.1  christos 	return (ISC_R_SUCCESS);
    168  1.1  christos 
    169  1.1  christos  cleanup:
    170  1.1  christos 	while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
    171  1.1  christos 		fwd = ISC_LIST_HEAD(forwarders->fwdrs);
    172  1.1  christos 		ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
    173  1.1  christos 		isc_mem_put(fwdtable->mctx, fwd, sizeof(dns_forwarder_t));
    174  1.1  christos 	}
    175  1.1  christos 	isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
    176  1.1  christos 	return (result);
    177  1.1  christos }
    178  1.1  christos 
    179  1.1  christos isc_result_t
    180  1.1  christos dns_fwdtable_delete(dns_fwdtable_t *fwdtable, const dns_name_t *name) {
    181  1.1  christos 	isc_result_t result;
    182  1.1  christos 
    183  1.1  christos 	REQUIRE(VALID_FWDTABLE(fwdtable));
    184  1.1  christos 
    185  1.1  christos 	RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
    186  1.1  christos 	result = dns_rbt_deletename(fwdtable->table, name, ISC_FALSE);
    187  1.1  christos 	RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
    188  1.1  christos 
    189  1.1  christos 	if (result == DNS_R_PARTIALMATCH)
    190  1.1  christos 		result = ISC_R_NOTFOUND;
    191  1.1  christos 
    192  1.1  christos 	return (result);
    193  1.1  christos }
    194  1.1  christos 
    195  1.1  christos isc_result_t
    196  1.1  christos dns_fwdtable_find(dns_fwdtable_t *fwdtable, const dns_name_t *name,
    197  1.1  christos 		  dns_forwarders_t **forwardersp)
    198  1.1  christos {
    199  1.1  christos 	return (dns_fwdtable_find2(fwdtable, name, NULL, forwardersp));
    200  1.1  christos }
    201  1.1  christos 
    202  1.1  christos isc_result_t
    203  1.1  christos dns_fwdtable_find2(dns_fwdtable_t *fwdtable, const dns_name_t *name,
    204  1.1  christos 		   dns_name_t *foundname, dns_forwarders_t **forwardersp)
    205  1.1  christos {
    206  1.1  christos 	isc_result_t result;
    207  1.1  christos 
    208  1.1  christos 	REQUIRE(VALID_FWDTABLE(fwdtable));
    209  1.1  christos 
    210  1.1  christos 	RWLOCK(&fwdtable->rwlock, isc_rwlocktype_read);
    211  1.1  christos 
    212  1.1  christos 	result = dns_rbt_findname(fwdtable->table, name, 0, foundname,
    213  1.1  christos 				  (void **)forwardersp);
    214  1.1  christos 	if (result == DNS_R_PARTIALMATCH)
    215  1.1  christos 		result = ISC_R_SUCCESS;
    216  1.1  christos 
    217  1.1  christos 	RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_read);
    218  1.1  christos 
    219  1.1  christos 	return (result);
    220  1.1  christos }
    221  1.1  christos 
    222  1.1  christos void
    223  1.1  christos dns_fwdtable_destroy(dns_fwdtable_t **fwdtablep) {
    224  1.1  christos 	dns_fwdtable_t *fwdtable;
    225  1.1  christos 	isc_mem_t *mctx;
    226  1.1  christos 
    227  1.1  christos 	REQUIRE(fwdtablep != NULL && VALID_FWDTABLE(*fwdtablep));
    228  1.1  christos 
    229  1.1  christos 	fwdtable = *fwdtablep;
    230  1.1  christos 
    231  1.1  christos 	dns_rbt_destroy(&fwdtable->table);
    232  1.1  christos 	isc_rwlock_destroy(&fwdtable->rwlock);
    233  1.1  christos 	fwdtable->magic = 0;
    234  1.1  christos 	mctx = fwdtable->mctx;
    235  1.1  christos 	isc_mem_put(mctx, fwdtable, sizeof(dns_fwdtable_t));
    236  1.1  christos 	isc_mem_detach(&mctx);
    237  1.1  christos 
    238  1.1  christos 	*fwdtablep = NULL;
    239  1.1  christos }
    240  1.1  christos 
    241  1.1  christos /***
    242  1.1  christos  *** Private
    243  1.1  christos  ***/
    244  1.1  christos 
    245  1.1  christos static void
    246  1.1  christos auto_detach(void *data, void *arg) {
    247  1.1  christos 	dns_forwarders_t *forwarders = data;
    248  1.1  christos 	dns_fwdtable_t *fwdtable = arg;
    249  1.1  christos 	dns_forwarder_t *fwd;
    250  1.1  christos 
    251  1.1  christos 	UNUSED(arg);
    252  1.1  christos 
    253  1.1  christos 	while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
    254  1.1  christos 		fwd = ISC_LIST_HEAD(forwarders->fwdrs);
    255  1.1  christos 		ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
    256  1.1  christos 		isc_mem_put(fwdtable->mctx, fwd, sizeof(dns_forwarder_t));
    257  1.1  christos 	}
    258  1.1  christos 	isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
    259  1.1  christos }
    260