Merge from vendor branch ZLIB:
[dragonfly.git] / contrib / bind-9.2.4rc7 / 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.2.1 2004/03/09 06:09:20 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 *matchelt = NULL;
46                 dns_acl_t *inner;
47
48                 if (e->type != dns_aclelementtype_nestedacl)
49                         goto dont_sort;
50
51                 inner = e->u.nestedacl;
52
53                 if (inner->length < 1 || inner->length > 2)
54                         goto dont_sort;
55
56                 if (inner->elements[0].negative)
57                         goto dont_sort;
58
59                 if (dns_aclelement_match(clientaddr, NULL,
60                                          &inner->elements[0],
61                                          &ns_g_server->aclenv,
62                                          &matchelt)) {
63                         if (inner->length == 2) {
64                                 dns_aclelement_t *elt1 = &inner->elements[1];
65                                 if (elt1->type == dns_aclelementtype_nestedacl)
66                                         *argp = elt1->u.nestedacl;
67                                 else if (elt1->type == dns_aclelementtype_localhost &&
68                                          ns_g_server->aclenv.localhost != NULL)
69                                         *argp = ns_g_server->aclenv.localhost;
70                                 else if (elt1->type == dns_aclelementtype_localnets &&
71                                          ns_g_server->aclenv.localnets != NULL)
72                                         *argp = ns_g_server->aclenv.localnets;
73                                 else
74                                         goto dont_sort;
75                                 return (NS_SORTLISTTYPE_2ELEMENT);
76                         } else {
77                                 INSIST(matchelt != NULL);
78                                 *argp = matchelt;
79                                 return (NS_SORTLISTTYPE_1ELEMENT);
80                         }
81                 }
82         }
83
84         /* No match; don't sort. */
85  dont_sort:
86         *argp = NULL;
87         return (NS_SORTLISTTYPE_NONE);
88 }
89
90 int
91 ns_sortlist_addrorder2(isc_netaddr_t *addr, void *arg) {
92         dns_acl_t *sortacl = (dns_acl_t *) arg;
93         int match;
94
95         (void)dns_acl_match(addr, NULL, sortacl,
96                             &ns_g_server->aclenv,
97                             &match, NULL);
98         if (match > 0)
99                 return (match);
100         else if (match < 0)
101                 return (INT_MAX - (-match));
102         else
103                 return (INT_MAX / 2);
104 }
105
106 int
107 ns_sortlist_addrorder1(isc_netaddr_t *addr, void *arg) {
108         dns_aclelement_t *matchelt = (dns_aclelement_t *) arg;
109         if (dns_aclelement_match(addr, NULL, matchelt,
110                                  &ns_g_server->aclenv,
111                                  NULL)) {
112                 return (0);
113         } else {
114                 return (INT_MAX);
115         }
116 }
117
118 void
119 ns_sortlist_byaddrsetup(dns_acl_t *sortlist_acl, isc_netaddr_t *client_addr,
120                        dns_addressorderfunc_t *orderp,
121                        void **argp)
122 {
123         ns_sortlisttype_t sortlisttype;
124
125         sortlisttype = ns_sortlist_setup(sortlist_acl, client_addr, argp);
126
127         switch (sortlisttype) {
128         case NS_SORTLISTTYPE_1ELEMENT:
129                 *orderp = ns_sortlist_addrorder1;
130                 break;
131         case NS_SORTLISTTYPE_2ELEMENT:
132                 *orderp = ns_sortlist_addrorder2;
133                 break;
134         case NS_SORTLISTTYPE_NONE:
135                 *orderp = NULL;
136                 break;
137         default:
138                 UNEXPECTED_ERROR(__FILE__, __LINE__,
139                                  "unexpected return from ns_sortlist_setup(): "
140                                  "%d", sortlisttype);
141                 break;
142         }
143 }
144