Home | History | Annotate | Line # | Download | only in ns
      1 /*	$NetBSD: sortlist.c,v 1.9 2025/01/26 16:25: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 
     28 ns_sortlisttype_t
     29 ns_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 			rcu_read_lock();
     90 			dns_acl_t *inner = rcu_dereference(env->localhost);
     91 			if (inner != NULL) {
     92 				*argp = dns_acl_ref(inner);
     93 				rcu_read_unlock();
     94 				return NS_SORTLISTTYPE_2ELEMENT;
     95 			}
     96 			rcu_read_unlock();
     97 		}
     98 
     99 		if (order_elt->type == dns_aclelementtype_localnets) {
    100 			rcu_read_lock();
    101 			dns_acl_t *inner = rcu_dereference(env->localhost);
    102 			if (inner != NULL) {
    103 				*argp = dns_acl_ref(inner);
    104 				rcu_read_unlock();
    105 				return NS_SORTLISTTYPE_2ELEMENT;
    106 			}
    107 			rcu_read_unlock();
    108 		}
    109 
    110 		/*
    111 		 * BIND 8 allows a bare IP prefix as
    112 		 * the 2nd element of a 2-element
    113 		 * sortlist statement.
    114 		 */
    115 		*argp = order_elt;
    116 		return NS_SORTLISTTYPE_1ELEMENT;
    117 	}
    118 
    119 dont_sort:
    120 	*argp = NULL;
    121 	return NS_SORTLISTTYPE_NONE;
    122 }
    123 
    124 int
    125 ns_sortlist_addrorder2(const isc_netaddr_t *addr, const void *arg) {
    126 	const dns_sortlist_arg_t *sla = (const dns_sortlist_arg_t *)arg;
    127 	dns_aclenv_t *env = sla->env;
    128 	const dns_acl_t *sortacl = sla->acl;
    129 	int match;
    130 
    131 	(void)dns_acl_match(addr, NULL, sortacl, env, &match, NULL);
    132 	if (match > 0) {
    133 		return match;
    134 	} else if (match < 0) {
    135 		return INT_MAX - (-match);
    136 	} else {
    137 		return INT_MAX / 2;
    138 	}
    139 }
    140 
    141 int
    142 ns_sortlist_addrorder1(const isc_netaddr_t *addr, const void *arg) {
    143 	const dns_sortlist_arg_t *sla = (const dns_sortlist_arg_t *)arg;
    144 	dns_aclenv_t *env = sla->env;
    145 	const dns_aclelement_t *element = sla->element;
    146 
    147 	if (dns_aclelement_match(addr, NULL, element, env, NULL)) {
    148 		return 0;
    149 	}
    150 
    151 	return INT_MAX;
    152 }
    153