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