sortlist.c revision 1.6
1/* $NetBSD: sortlist.c,v 1.6 2022/09/23 12:15:36 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/util.h> 20 21#include <dns/acl.h> 22#include <dns/message.h> 23#include <dns/result.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 const void **argp) { 31 unsigned int i; 32 33 if (acl == NULL) { 34 goto dont_sort; 35 } 36 37 for (i = 0; i < acl->length; i++) { 38 /* 39 * 'e' refers to the current 'top level statement' 40 * in the sortlist (see ARM). 41 */ 42 dns_aclelement_t *e = &acl->elements[i]; 43 dns_aclelement_t *try_elt; 44 dns_aclelement_t *order_elt = NULL; 45 const dns_aclelement_t *matched_elt = NULL; 46 47 if (e->type == dns_aclelementtype_nestedacl) { 48 dns_acl_t *inner = e->nestedacl; 49 50 if (inner->length == 0) { 51 try_elt = e; 52 } else if (inner->length > 2) { 53 goto dont_sort; 54 } else if (inner->elements[0].negative) { 55 goto dont_sort; 56 } else { 57 try_elt = &inner->elements[0]; 58 if (inner->length == 2) { 59 order_elt = &inner->elements[1]; 60 } 61 } 62 } else { 63 /* 64 * BIND 8 allows bare elements at the top level 65 * as an undocumented feature. 66 */ 67 try_elt = e; 68 } 69 70 if (dns_aclelement_match(clientaddr, NULL, try_elt, env, 71 &matched_elt)) { 72 if (order_elt != NULL) { 73 if (order_elt->type == 74 dns_aclelementtype_nestedacl) { 75 *argp = order_elt->nestedacl; 76 return (NS_SORTLISTTYPE_2ELEMENT); 77 } else if (order_elt->type == 78 dns_aclelementtype_localhost && 79 env->localhost != NULL) 80 { 81 *argp = env->localhost; 82 return (NS_SORTLISTTYPE_2ELEMENT); 83 } else if (order_elt->type == 84 dns_aclelementtype_localnets && 85 env->localnets != NULL) 86 { 87 *argp = env->localnets; 88 return (NS_SORTLISTTYPE_2ELEMENT); 89 } else { 90 /* 91 * BIND 8 allows a bare IP prefix as 92 * the 2nd element of a 2-element 93 * sortlist statement. 94 */ 95 *argp = order_elt; 96 return (NS_SORTLISTTYPE_1ELEMENT); 97 } 98 } else { 99 INSIST(matched_elt != NULL); 100 *argp = matched_elt; 101 return (NS_SORTLISTTYPE_1ELEMENT); 102 } 103 } 104 } 105 106 /* No match; don't sort. */ 107dont_sort: 108 *argp = NULL; 109 return (NS_SORTLISTTYPE_NONE); 110} 111 112int 113ns_sortlist_addrorder2(const isc_netaddr_t *addr, const void *arg) { 114 const dns_sortlist_arg_t *sla = (const dns_sortlist_arg_t *)arg; 115 const dns_aclenv_t *env = sla->env; 116 const dns_acl_t *sortacl = sla->acl; 117 int match; 118 119 (void)dns_acl_match(addr, NULL, sortacl, env, &match, NULL); 120 if (match > 0) { 121 return (match); 122 } else if (match < 0) { 123 return (INT_MAX - (-match)); 124 } else { 125 return (INT_MAX / 2); 126 } 127} 128 129int 130ns_sortlist_addrorder1(const isc_netaddr_t *addr, const void *arg) { 131 const dns_sortlist_arg_t *sla = (const dns_sortlist_arg_t *)arg; 132 const dns_aclenv_t *env = sla->env; 133 const dns_aclelement_t *element = sla->element; 134 135 if (dns_aclelement_match(addr, NULL, element, env, NULL)) { 136 return (0); 137 } 138 139 return (INT_MAX); 140} 141 142void 143ns_sortlist_byaddrsetup(dns_acl_t *sortlist_acl, dns_aclenv_t *env, 144 isc_netaddr_t *client_addr, 145 dns_addressorderfunc_t *orderp, const void **argp) { 146 ns_sortlisttype_t sortlisttype; 147 148 sortlisttype = ns_sortlist_setup(sortlist_acl, env, client_addr, argp); 149 150 switch (sortlisttype) { 151 case NS_SORTLISTTYPE_1ELEMENT: 152 *orderp = ns_sortlist_addrorder1; 153 break; 154 case NS_SORTLISTTYPE_2ELEMENT: 155 *orderp = ns_sortlist_addrorder2; 156 break; 157 case NS_SORTLISTTYPE_NONE: 158 *orderp = NULL; 159 break; 160 default: 161 UNEXPECTED_ERROR(__FILE__, __LINE__, 162 "unexpected return from ns_sortlist_setup(): " 163 "%d", 164 sortlisttype); 165 break; 166 } 167} 168