Merge from vendor branch LESS:
[dragonfly.git] / contrib / bind-9.3 / bin / named / sortlist.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000, 2001  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and 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.5.12.4 2004/03/08 04:04:19 marka Exp $ */
19
20 #include <config.h>
21
22 #include <isc/mem.h>
23 #include <isc/util.h>
24
25 #include <dns/acl.h>
26 #include <dns/result.h>
27
28 #include <named/globals.h>
29 #include <named/server.h>
30 #include <named/sortlist.h>
31
32 ns_sortlisttype_t
33 ns_sortlist_setup(dns_acl_t *acl, isc_netaddr_t *clientaddr, void **argp) {
34         unsigned int i;
35
36         if (acl == NULL)
37                 goto dont_sort;
38
39         for (i = 0; i < acl->length; i++) {
40                 /*
41                  * 'e' refers to the current 'top level statement'
42                  * in the sortlist (see ARM).
43                  */
44                 dns_aclelement_t *e = &acl->elements[i];
45                 dns_aclelement_t *try_elt;
46                 dns_aclelement_t *order_elt = NULL;
47                 dns_aclelement_t *matched_elt = NULL;
48
49                 if (e->type == dns_aclelementtype_nestedacl) {
50                         dns_acl_t *inner = e->u.nestedacl;
51
52                         if (inner->length < 1 || inner->length > 2)
53                                 goto dont_sort;
54                         if (inner->elements[0].negative)
55                                 goto dont_sort;
56                         try_elt = &inner->elements[0];
57                         if (inner->length == 2)
58                                 order_elt = &inner->elements[1];
59                 } else {
60                         /*
61                          * BIND 8 allows bare elements at the top level
62                          * as an undocumented feature.
63                          */
64                         try_elt = e;
65                 }
66
67                 if (dns_aclelement_match(clientaddr, NULL, try_elt,
68                                          &ns_g_server->aclenv,
69                                          &matched_elt)) {
70                         if (order_elt != NULL) {
71                                 if (order_elt->type ==
72                                     dns_aclelementtype_nestedacl) {
73                                         *argp = order_elt->u.nestedacl;
74                                         return (NS_SORTLISTTYPE_2ELEMENT);
75                                 } else if (order_elt->type ==
76                                            dns_aclelementtype_localhost &&
77                                            ns_g_server->aclenv.localhost != NULL) {
78                                         *argp = ns_g_server->aclenv.localhost;
79                                         return (NS_SORTLISTTYPE_2ELEMENT);
80                                 } else if (order_elt->type ==
81                                            dns_aclelementtype_localnets &&
82                                            ns_g_server->aclenv.localnets != NULL) {
83                                         *argp = ns_g_server->aclenv.localnets;
84                                         return (NS_SORTLISTTYPE_2ELEMENT);
85                                 } else {
86                                         /*
87                                          * BIND 8 allows a bare IP prefix as
88                                          * the 2nd element of a 2-element
89                                          * sortlist statement.
90                                          */
91                                         *argp = order_elt;
92                                         return (NS_SORTLISTTYPE_1ELEMENT);
93                                 }
94                         } else {
95                                 INSIST(matched_elt != NULL);
96                                 *argp = matched_elt;
97                                 return (NS_SORTLISTTYPE_1ELEMENT);
98                         }
99                 }
100         }
101
102         /* No match; don't sort. */
103  dont_sort:
104         *argp = NULL;
105         return (NS_SORTLISTTYPE_NONE);
106 }
107
108 int
109 ns_sortlist_addrorder2(isc_netaddr_t *addr, void *arg) {
110         dns_acl_t *sortacl = (dns_acl_t *) arg;
111         int match;
112
113         (void)dns_acl_match(addr, NULL, sortacl,
114                             &ns_g_server->aclenv,
115                             &match, NULL);
116         if (match > 0)
117                 return (match);
118         else if (match < 0)
119                 return (INT_MAX - (-match));
120         else
121                 return (INT_MAX / 2);
122 }
123
124 int
125 ns_sortlist_addrorder1(isc_netaddr_t *addr, void *arg) {
126         dns_aclelement_t *matchelt = (dns_aclelement_t *) arg;
127         if (dns_aclelement_match(addr, NULL, matchelt,
128                                  &ns_g_server->aclenv,
129                                  NULL)) {
130                 return (0);
131         } else {
132                 return (INT_MAX);
133         }
134 }
135
136 void
137 ns_sortlist_byaddrsetup(dns_acl_t *sortlist_acl, isc_netaddr_t *client_addr,
138                        dns_addressorderfunc_t *orderp,
139                        void **argp)
140 {
141         ns_sortlisttype_t sortlisttype;
142
143         sortlisttype = ns_sortlist_setup(sortlist_acl, client_addr, argp);
144
145         switch (sortlisttype) {
146         case NS_SORTLISTTYPE_1ELEMENT:
147                 *orderp = ns_sortlist_addrorder1;
148                 break;
149         case NS_SORTLISTTYPE_2ELEMENT:
150                 *orderp = ns_sortlist_addrorder2;
151                 break;
152         case NS_SORTLISTTYPE_NONE:
153                 *orderp = NULL;
154                 break;
155         default:
156                 UNEXPECTED_ERROR(__FILE__, __LINE__,
157                                  "unexpected return from ns_sortlist_setup(): "
158                                  "%d", sortlisttype);
159                 break;
160         }
161 }
162