1/* $NetBSD: sortlist.c,v 1.8 2024/02/21 22:52:46 christos Exp $ */ 2 3/* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16/*! \file */ 17 18#include <isc/mem.h> 19#include <isc/result.h> 20#include <isc/util.h> 21 22#include <dns/acl.h> 23#include <dns/message.h> 24 25#include <ns/server.h> 26#include <ns/sortlist.h> 27 28ns_sortlisttype_t 29ns_sortlist_setup(dns_acl_t *acl, dns_aclenv_t *env, isc_netaddr_t *clientaddr, 30 void **argp) { 31 if (acl == NULL) { 32 goto dont_sort; 33 } 34 35 for (size_t i = 0; i < acl->length; i++) { 36 /* 37 * 'e' refers to the current 'top level statement' 38 * in the sortlist (see ARM). 39 */ 40 dns_aclelement_t *e = &acl->elements[i]; 41 dns_aclelement_t *try_elt; 42 dns_aclelement_t *order_elt = NULL; 43 dns_aclelement_t *matched_elt = NULL; 44 45 if (e->type == dns_aclelementtype_nestedacl) { 46 dns_acl_t *inner = e->nestedacl; 47 48 if (inner->length == 0) { 49 try_elt = e; 50 } else if (inner->length > 2) { 51 goto dont_sort; 52 } else if (inner->elements[0].negative) { 53 goto dont_sort; 54 } else { 55 try_elt = &inner->elements[0]; 56 if (inner->length == 2) { 57 order_elt = &inner->elements[1]; 58 } 59 } 60 } else { 61 /* 62 * BIND 8 allows bare elements at the top level 63 * as an undocumented feature. 64 */ 65 try_elt = e; 66 } 67 68 if (!dns_aclelement_match( 69 clientaddr, NULL, try_elt, env, 70 (const dns_aclelement_t **)&matched_elt)) 71 { 72 continue; 73 } 74 75 if (order_elt == NULL) { 76 INSIST(matched_elt != NULL); 77 *argp = matched_elt; 78 return (NS_SORTLISTTYPE_1ELEMENT); 79 } 80 81 if (order_elt->type == dns_aclelementtype_nestedacl) { 82 dns_acl_t *inner = NULL; 83 dns_acl_attach(order_elt->nestedacl, &inner); 84 *argp = inner; 85 return (NS_SORTLISTTYPE_2ELEMENT); 86 } 87 88 if (order_elt->type == dns_aclelementtype_localhost) { 89 dns_acl_t *inner = NULL; 90 RWLOCK(&env->rwlock, isc_rwlocktype_read); 91 if (env->localhost != NULL) { 92 dns_acl_attach(env->localhost, &inner); 93 } 94 RWUNLOCK(&env->rwlock, isc_rwlocktype_read); 95 96 if (inner != NULL) { 97 *argp = inner; 98 return (NS_SORTLISTTYPE_2ELEMENT); 99 } 100 } 101 102 if (order_elt->type == dns_aclelementtype_localnets) { 103 dns_acl_t *inner = NULL; 104 RWLOCK(&env->rwlock, isc_rwlocktype_read); 105 if (env->localnets != NULL) { 106 dns_acl_attach(env->localnets, &inner); 107 } 108 RWUNLOCK(&env->rwlock, isc_rwlocktype_read); 109 if (inner != NULL) { 110 *argp = inner; 111 return (NS_SORTLISTTYPE_2ELEMENT); 112 } 113 } 114 115 /* 116 * BIND 8 allows a bare IP prefix as 117 * the 2nd element of a 2-element 118 * sortlist statement. 119 */ 120 *argp = order_elt; 121 return (NS_SORTLISTTYPE_1ELEMENT); 122 } 123 124dont_sort: 125 *argp = NULL; 126 return (NS_SORTLISTTYPE_NONE); 127} 128 129int 130ns_sortlist_addrorder2(const isc_netaddr_t *addr, const void *arg) { 131 const dns_sortlist_arg_t *sla = (const dns_sortlist_arg_t *)arg; 132 dns_aclenv_t *env = sla->env; 133 const dns_acl_t *sortacl = sla->acl; 134 int match; 135 136 (void)dns_acl_match(addr, NULL, sortacl, env, &match, NULL); 137 if (match > 0) { 138 return (match); 139 } else if (match < 0) { 140 return (INT_MAX - (-match)); 141 } else { 142 return (INT_MAX / 2); 143 } 144} 145 146int 147ns_sortlist_addrorder1(const isc_netaddr_t *addr, const void *arg) { 148 const dns_sortlist_arg_t *sla = (const dns_sortlist_arg_t *)arg; 149 dns_aclenv_t *env = sla->env; 150 const dns_aclelement_t *element = sla->element; 151 152 if (dns_aclelement_match(addr, NULL, element, env, NULL)) { 153 return (0); 154 } 155 156 return (INT_MAX); 157} 158 159void 160ns_sortlist_byaddrsetup(dns_acl_t *sortlist_acl, dns_aclenv_t *env, 161 isc_netaddr_t *client_addr, 162 dns_addressorderfunc_t *orderp, void **argp) { 163 ns_sortlisttype_t sortlisttype; 164 165 sortlisttype = ns_sortlist_setup(sortlist_acl, env, client_addr, argp); 166 167 switch (sortlisttype) { 168 case NS_SORTLISTTYPE_1ELEMENT: 169 *orderp = ns_sortlist_addrorder1; 170 break; 171 case NS_SORTLISTTYPE_2ELEMENT: 172 *orderp = ns_sortlist_addrorder2; 173 break; 174 case NS_SORTLISTTYPE_NONE: 175 *orderp = NULL; 176 break; 177 default: 178 UNEXPECTED_ERROR( 179 "unexpected return from ns_sortlist_setup(): %d", 180 sortlisttype); 181 break; 182 } 183} 184