1/* 2 * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000, 2001 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: sortlist.c,v 1.17 2007/09/14 01:46:05 marka Exp $ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <isc/mem.h> 25#include <isc/util.h> 26 27#include <dns/acl.h> 28#include <dns/result.h> 29 30#include <named/globals.h> 31#include <named/server.h> 32#include <named/sortlist.h> 33 34ns_sortlisttype_t 35ns_sortlist_setup(dns_acl_t *acl, isc_netaddr_t *clientaddr, 36 const void **argp) 37{ 38 unsigned int i; 39 40 if (acl == NULL) 41 goto dont_sort; 42 43 for (i = 0; i < acl->length; i++) { 44 /* 45 * 'e' refers to the current 'top level statement' 46 * in the sortlist (see ARM). 47 */ 48 dns_aclelement_t *e = &acl->elements[i]; 49 dns_aclelement_t *try_elt; 50 dns_aclelement_t *order_elt = NULL; 51 const dns_aclelement_t *matched_elt = NULL; 52 53 if (e->type == dns_aclelementtype_nestedacl) { 54 dns_acl_t *inner = e->nestedacl; 55 56 if (inner->length == 0) 57 try_elt = e; 58 else if (inner->length > 2) 59 goto dont_sort; 60 else if (inner->elements[0].negative) 61 goto dont_sort; 62 else { 63 try_elt = &inner->elements[0]; 64 if (inner->length == 2) 65 order_elt = &inner->elements[1]; 66 } 67 } else { 68 /* 69 * BIND 8 allows bare elements at the top level 70 * as an undocumented feature. 71 */ 72 try_elt = e; 73 } 74 75 if (dns_aclelement_match(clientaddr, NULL, try_elt, 76 &ns_g_server->aclenv, 77 &matched_elt)) { 78 if (order_elt != NULL) { 79 if (order_elt->type == 80 dns_aclelementtype_nestedacl) { 81 *argp = order_elt->nestedacl; 82 return (NS_SORTLISTTYPE_2ELEMENT); 83 } else if (order_elt->type == 84 dns_aclelementtype_localhost && 85 ns_g_server->aclenv.localhost != NULL) { 86 *argp = ns_g_server->aclenv.localhost; 87 return (NS_SORTLISTTYPE_2ELEMENT); 88 } else if (order_elt->type == 89 dns_aclelementtype_localnets && 90 ns_g_server->aclenv.localnets != NULL) { 91 *argp = ns_g_server->aclenv.localnets; 92 return (NS_SORTLISTTYPE_2ELEMENT); 93 } else { 94 /* 95 * BIND 8 allows a bare IP prefix as 96 * the 2nd element of a 2-element 97 * sortlist statement. 98 */ 99 *argp = order_elt; 100 return (NS_SORTLISTTYPE_1ELEMENT); 101 } 102 } else { 103 INSIST(matched_elt != NULL); 104 *argp = matched_elt; 105 return (NS_SORTLISTTYPE_1ELEMENT); 106 } 107 } 108 } 109 110 /* No match; don't sort. */ 111 dont_sort: 112 *argp = NULL; 113 return (NS_SORTLISTTYPE_NONE); 114} 115 116int 117ns_sortlist_addrorder2(const isc_netaddr_t *addr, const void *arg) { 118 const dns_acl_t *sortacl = (const dns_acl_t *) arg; 119 int match; 120 121 (void)dns_acl_match(addr, NULL, sortacl, 122 &ns_g_server->aclenv, 123 &match, NULL); 124 if (match > 0) 125 return (match); 126 else if (match < 0) 127 return (INT_MAX - (-match)); 128 else 129 return (INT_MAX / 2); 130} 131 132int 133ns_sortlist_addrorder1(const isc_netaddr_t *addr, const void *arg) { 134 const dns_aclelement_t *matchelt = (const dns_aclelement_t *) arg; 135 if (dns_aclelement_match(addr, NULL, matchelt, 136 &ns_g_server->aclenv, 137 NULL)) { 138 return (0); 139 } else { 140 return (INT_MAX); 141 } 142} 143 144void 145ns_sortlist_byaddrsetup(dns_acl_t *sortlist_acl, isc_netaddr_t *client_addr, 146 dns_addressorderfunc_t *orderp, 147 const void **argp) 148{ 149 ns_sortlisttype_t sortlisttype; 150 151 sortlisttype = ns_sortlist_setup(sortlist_acl, client_addr, argp); 152 153 switch (sortlisttype) { 154 case NS_SORTLISTTYPE_1ELEMENT: 155 *orderp = ns_sortlist_addrorder1; 156 break; 157 case NS_SORTLISTTYPE_2ELEMENT: 158 *orderp = ns_sortlist_addrorder2; 159 break; 160 case NS_SORTLISTTYPE_NONE: 161 *orderp = NULL; 162 break; 163 default: 164 UNEXPECTED_ERROR(__FILE__, __LINE__, 165 "unexpected return from ns_sortlist_setup(): " 166 "%d", sortlisttype); 167 break; 168 } 169} 170 171