1 #if !defined(lint) && !defined(SABER)
2 static const char sccsid[] = "@(#)ns_sort.c 4.10 (Berkeley) 3/3/91";
3 static const char rcsid[] = "$Id: ns_sort.c,v 8.5 1999/10/13 16:39:12 vixie Exp $";
7 * Copyright (c) 1986, 1990
8 * The Regents of the University of California. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
42 * Permission to use, copy, modify, and distribute this software for any
43 * purpose with or without fee is hereby granted, provided that the above
44 * copyright notice and this permission notice appear in all copies, and that
45 * the name of Digital Equipment Corporation not be used in advertising or
46 * publicity pertaining to distribution of the document or software without
47 * specific, written prior permission.
49 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
50 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
51 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
52 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
53 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
54 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
55 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
60 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
62 * Permission to use, copy, modify, and distribute this software for any
63 * purpose with or without fee is hereby granted, provided that the above
64 * copyright notice and this permission notice appear in all copies.
66 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
67 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
68 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
69 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
70 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
71 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
72 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
77 * Sorting should really be handled by the resolver, but:
78 * 1) There are too many brain dead resolvers out there that can't be replaced.
79 * 2) It would be a pain to individually configure all those resolvers anyway.
83 * To enable address sorting in responses, you need to supply the sortlist
84 * statement in the config file. The sortlist statement takes an
85 * address match list and interprets it even more specially than the
86 * topology statement does.
88 * Each top level statement in the sortlist must itself be an explicit
89 * address match list with one or two elements. The first element
90 * (which may be an IP address, an IP prefix, an ACL name or nested
91 * address match list) of each top level list is checked against the
92 * source address of the query until a match is found.
94 * Once the source address of the query has been matched, if the top level
95 * statement contains only one element, the actual primitive element that
96 * matched the source address is used to select the address in the response
97 * to move to the beginning of the response. If the statement is a list
98 * of two elements, then the second element is treated like the address
99 * match list in a topology statement. Each top level element is assigned
100 * a distance and the address in the response with the minimum distance is
101 * moved to the beginning of the response.
103 * In the following example, any queries received from any of the addresses
104 * of the host itself will get responses preferring addresses on any of
105 * the locally connected networks. Next most preferred are addresses on
106 * the 192.168.1/24 network, and after that either the 192.168.2/24 or
107 * 192.168.3/24 network with no preference shown between these two networks.
108 * Queries received from a host on the 192.168.1/24 network will prefer
109 * other addresses on that network to the 192.168.2/24 and 192.168.3/24
110 * networks. Queries received from a host on the 192.168.4/24 or the
111 * 192.168.5/24 network will only prefer other addresses on their
112 * directly connected networks.
120 * { 192,168.2/24; 192.168.3/24; };
127 * { 192.168.2/24; 192.168.3/24; };
134 * { 192.168.1/24; 192.168.3/24; };
141 * { 192.168.1/24; 192.168.2/24; };
145 * { 192.168.4/24; 192.168.5/24; };
150 * The following example will give reasonable behaviour for the local host
151 * and hosts on directly connected networks. It is similar to the behavior
152 * of the address sort in BIND 4.9.x. Responses sent to queries from the
153 * local host will favor any of the directly connected networks. Responses
154 * sent to queries from any other hosts on a directly connected network will
155 * prefer addresses on that same network. Responses to other queries will
159 * { localhost; localnets; };
163 * XXX - it wouldb e nice to have an ACL called "source" that matched the
164 * source address of a query so that a host could be configured to
165 * automatically prefer itself, and an ACL called "sourcenet", that
166 * would return the primitive IP match element that matched the source
167 * address so that you could do:
168 * { localnets; { sourcenet; { other stuff ...}; };
169 * and automatically get similar behaviour to what you get with:
174 #include "port_before.h"
176 #include <sys/param.h>
177 #include <sys/types.h>
178 #include <sys/socket.h>
179 #include <sys/file.h>
180 #include <netinet/in.h>
181 #include <arpa/nameser.h>
182 #include <arpa/inet.h>
187 #include <isc/eventlib.h>
188 #include <isc/logging.h>
190 #include "port_after.h"
194 static int sort_rr(u_char *cp, u_char *eom, int ancount, ip_match_list iml);
196 static int ip_match_address_elt(ip_match_list, struct in_addr,
200 sort_response(u_char *cp, u_char *eom, int ancount, struct sockaddr_in *from) {
201 struct in_addr address;
202 struct ip_match_element imelement;
203 ip_match_element imetl, imematch, imeprimitive;
204 struct ip_match_list imlist;
206 int indirect, matched;
208 if (server_options->sortlist == NULL)
211 if (from->sin_family != AF_INET)
214 address = from->sin_addr;
216 for (imetl = server_options->sortlist->first; imetl != NULL;
217 imetl = imetl->next) {
218 if (imetl->type == ip_match_indirect)
219 imematch = imetl->u.indirect.list->first;
222 * allow a bare pattern as a top level statement
223 * and treat it like {pattern;};
227 switch (imematch->type) {
228 case ip_match_pattern:
231 case ip_match_indirect:
234 case ip_match_localhost:
235 imematch->u.indirect.list = local_addresses;
238 case ip_match_localnets:
239 imematch->u.indirect.list = local_networks;
243 panic("unexpected ime type in ip_match_address()",
248 matched = ip_match_address_elt(imematch->u.indirect.list,
249 address, &imeprimitive);
251 if (imematch->flags & IP_MATCH_NEGATE)
257 if (ina_onnet(address, imematch->u.direct.address,
258 imematch->u.direct.mask)) {
259 if (imematch->flags & IP_MATCH_NEGATE)
263 imeprimitive = imematch;
267 if (imetl != imematch && imematch->next != NULL) {
269 * Not a bare pattern at the top level, but a two
272 switch (imematch->next->type) {
273 case ip_match_pattern:
274 case ip_match_localhost:
275 case ip_match_localnets:
276 imelement = *(imematch->next);
277 imelement.next = NULL;
279 iml->first = iml->last = &imelement;
281 case ip_match_indirect:
282 iml = imematch->next->u.indirect.list;
285 panic("unexpected ime type in ip_match_address()",
288 } else if (imeprimitive) {
289 imelement = *imeprimitive;
290 imelement.next = NULL;
292 iml->first = iml->last = &imelement;
294 /* Don't sort because we'd just use "any" */
297 sort_rr(cp, eom, ancount, iml);
305 sort_rr(u_char *cp, u_char *eom, int ancount, ip_match_list iml) {
306 int type, class, dlen, n, c, distance, closest;
307 struct in_addr inaddr;
308 u_char *rr1 = NULL, *rrbest, *cpstart;
312 for (c = ancount; c > 0; --c) {
313 n = dn_skipname(cp, eom);
315 return (1); /* bogus, stop processing */
317 if (cp + QFIXEDSZ > eom)
324 return (1); /* bogus, stop processing */
330 memcpy((char *)&inaddr, cp, INADDRSZ);
331 /* Find the address with the minimum distance */
335 closest = distance_of_address(iml, inaddr);
337 distance = distance_of_address(iml, inaddr);
338 if (distance < closest) {
349 if (rr1 != rrbest && rr1 != NULL) {
350 memcpy((char *)&inaddr, rrbest, INADDRSZ);
351 memcpy(rrbest, rr1, INADDRSZ);
352 memcpy(rr1, (char *)&inaddr, INADDRSZ);
358 * Just like ip_match_address(), but also returns a pointer to the primitive
359 * element that matched.
363 ip_match_address_elt(ip_match_list iml, struct in_addr address,
364 ip_match_element *imep) {
365 ip_match_element ime;
370 for (ime = iml->first; ime != NULL; ime = ime->next) {
372 case ip_match_pattern:
375 case ip_match_indirect:
378 case ip_match_localhost:
379 ime->u.indirect.list = local_addresses;
382 case ip_match_localnets:
383 ime->u.indirect.list = local_networks;
387 panic("unexpected ime type in ip_match_address()",
391 ret = ip_match_address_elt(ime->u.indirect.list,
394 if (ime->flags & IP_MATCH_NEGATE)
399 if (ina_onnet(address, ime->u.direct.address,
400 ime->u.direct.mask)) {
402 if (ime->flags & IP_MATCH_NEGATE)