Squid Web Cache v8/master
Loading...
Searching...
No Matches
support_resolv.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2026 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/*
10 * -----------------------------------------------------------------------------
11 *
12 * Author: Markus Moeller (markus_moeller at compuserve.com)
13 *
14 * Copyright (C) 2007 Markus Moeller. All rights reserved.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, see <https://www.gnu.org/licenses/>.
28 *
29 * -----------------------------------------------------------------------------
30 */
31
32#include "squid.h"
33#include "util.h"
34
35#if HAVE_LDAP
36
37#include "support.h"
38#include <cerrno>
39#if HAVE_NETDB_H
40#include <netdb.h>
41#endif
42#if HAVE_NETINET_IN_H
43#include <netinet/in.h>
44#endif
45#if HAVE_RESOLV_H
46#include <resolv.h>
47#endif
48#if HAVE_ARPA_NAMESER_H
49#include <arpa/nameser.h>
50#endif
51
52void nsError(int nserror, char *server);
53static int compare_hosts(struct hstruct *h1, struct hstruct *h2);
54static void swap(struct hstruct *a, struct hstruct *b);
55static void sort(struct hstruct *array, int nitems, int (*cmp) (struct hstruct *, struct hstruct *), int begin, int end);
56static void msort(struct hstruct *array, size_t nitems, int (*cmp) (struct hstruct *, struct hstruct *));
57
58/*
59 * See http://www.ietf.org/rfc/rfc1035.txt
60 */
61/*
62 * See http://www.ietf.org/rfc/rfc2782.txt
63 *
64 */
65void
66nsError(int nserror, char *service)
67{
68 switch (nserror) {
69 case HOST_NOT_FOUND:
70 error((char *) "%s| %s: ERROR: res_search: Unknown service record: %s\n", LogTime(), PROGRAM, service);
71 break;
72 case NO_DATA:
73 error((char *) "%s| %s: ERROR: res_search: No SRV record for %s\n", LogTime(), PROGRAM, service);
74 break;
75 case TRY_AGAIN:
76 error((char *) "%s| %s: ERROR: res_search: No response for SRV query\n", LogTime(), PROGRAM);
77 break;
78 default:
79 error((char *) "%s| %s: ERROR: res_search: Unexpected error: %s\n", LogTime(), PROGRAM, strerror(nserror));
80 }
81}
82
83static void
84swap(struct hstruct *a, struct hstruct *b)
85{
86 struct hstruct c;
87
88 c.host = a->host;
89 c.priority = a->priority;
90 c.weight = a->weight;
91 a->host = b->host;
92 a->priority = b->priority;
93 a->weight = b->weight;
94 b->host = c.host;
95 b->priority = c.priority;
96 b->weight = c.weight;
97}
98
99static void
100sort(struct hstruct *array, int nitems, int (*cmp) (struct hstruct *, struct hstruct *), int begin, int end)
101{
102 if (end > begin) {
103 int l = begin + 1;
104 int r = end;
105 while (l < r) {
106 int pivot = begin;
107 if (cmp(&array[l], &array[pivot]) <= 0) {
108 l += 1;
109 } else {
110 r -= 1;
111 swap(&array[l], &array[r]);
112 }
113 }
114 l -= 1;
115 swap(&array[begin], &array[l]);
116 sort(array, nitems, cmp, begin, l);
117 sort(array, nitems, cmp, r, end);
118 }
119}
120
121static void
122msort(struct hstruct *array, size_t nitems, int (*cmp) (struct hstruct *, struct hstruct *))
123{
124 sort(array, (int)nitems, cmp, 0, (int)(nitems - 1));
125}
126
127static int
128compare_hosts(struct hstruct *host1, struct hstruct *host2)
129{
130 /*
131 *
132 * The comparison function must return an integer less than, equal to,
133 * or greater than zero if the first argument is considered to be
134 * respectively less than, equal to, or greater than the second.
135 */
136 if ((host1->priority < host2->priority) && (host1->priority != -1))
137 return -1;
138 if ((host1->priority < host2->priority) && (host1->priority == -1))
139 return 1;
140 if ((host1->priority > host2->priority) && (host2->priority != -1))
141 return 1;
142 if ((host1->priority > host2->priority) && (host2->priority == -1))
143 return -1;
144 if (host1->priority == host2->priority) {
145 if (host1->weight > host2->weight)
146 return -1;
147 if (host1->weight < host2->weight)
148 return 1;
149 }
150 return 0;
151}
152
153size_t
154free_hostname_list(struct hstruct **hlist, size_t nhosts)
155{
156 struct hstruct *hp = nullptr;
157 size_t i;
158
159 hp = *hlist;
160 for (i = 0; i < nhosts; ++i) {
161 xfree(hp[i].host);
162 }
163
164 safe_free(hp);
165 *hlist = hp;
166 return 0;
167}
168
169size_t
170get_hostname_list(struct hstruct **hlist, size_t nhosts, char *name)
171{
172 struct addrinfo *hres = nullptr, *hres_list;
173 int rc, count;
174 struct hstruct *hp = nullptr;
175
176 if (!name)
177 return (nhosts);
178
179 hp = *hlist;
180 rc = getaddrinfo((const char *) name, nullptr, nullptr, &hres);
181 if (rc != 0) {
182 error((char *) "%s| %s: ERROR: Error while resolving hostname with getaddrinfo: %s\n", LogTime(), PROGRAM, gai_strerror(rc));
183 return (nhosts);
184 }
185 hres_list = hres;
186 count = 0;
187 while (hres_list) {
188 ++count;
189 hres_list = hres_list->ai_next;
190 }
191 hres_list = hres;
192 count = 0;
193 while (hres_list) {
194 /*
195 * char host[sysconf(_SC_HOST_NAME_MAX)];
196 */
197 char host[1024];
198 rc = getnameinfo(hres_list->ai_addr, hres_list->ai_addrlen, host, sizeof(host), nullptr, 0, 0);
199 if (rc != 0) {
200 error((char *) "%s| %s: ERROR: Error while resolving ip address with getnameinfo: %s\n", LogTime(), PROGRAM, gai_strerror(rc));
201 freeaddrinfo(hres);
202 *hlist = hp;
203 return (nhosts);
204 }
205 ++count;
206 debug((char *) "%s| %s: DEBUG: Resolved address %d of %s to %s\n", LogTime(), PROGRAM, count, name, host);
207
208 hp = (struct hstruct *) xrealloc(hp, sizeof(struct hstruct) * (nhosts + 1));
209 hp[nhosts].host = xstrdup(host);
210 hp[nhosts].port = -1;
211 hp[nhosts].priority = -1;
212 hp[nhosts].weight = -1;
213 ++nhosts;
214
215 hres_list = hres_list->ai_next;
216 }
217
218 freeaddrinfo(hres);
219 *hlist = hp;
220 return (nhosts);
221}
222
223size_t
224get_ldap_hostname_list(struct main_args *margs, struct hstruct **hlist, size_t nh, char *domain)
225{
226
227 /*
228 * char name[sysconf(_SC_HOST_NAME_MAX)];
229 */
230 char name[1024];
231 char *service = nullptr;
232 struct hstruct *hp = nullptr;
233 struct lsstruct *ls = nullptr;
234 size_t nhosts = 0;
235 int size;
236 int len, olen;
237 size_t i, j, k;
238 u_char *buffer = nullptr;
239 u_char *p;
240
241 ls = margs->lservs;
242 while (ls) {
243 debug((char *) "%s| %s: DEBUG: Ldap server loop: lserver@domain %s@%s\n", LogTime(), PROGRAM, ls->lserver, ls->domain?ls->domain:"NULL");
244 if (ls->domain && !strcasecmp(ls->domain, domain)) {
245 debug((char *) "%s| %s: DEBUG: Found lserver@domain %s@%s\n", LogTime(), PROGRAM, ls->lserver, ls->domain);
246 hp = (struct hstruct *) xrealloc(hp, sizeof(struct hstruct) * (nhosts + 1));
247 hp[nhosts].host = xstrdup(ls->lserver);
248 hp[nhosts].port = -1;
249 hp[nhosts].priority = -2;
250 hp[nhosts].weight = -2;
251 ++nhosts;
252 } else if ( !ls->domain || !strcasecmp(ls->domain, "") ) {
253 debug((char *) "%s| %s: DEBUG: Found lserver@domain %s@%s\n", LogTime(), PROGRAM, ls->lserver, ls->domain?ls->domain:"NULL");
254 hp = (struct hstruct *) xrealloc(hp, sizeof(struct hstruct) * (nhosts + 1));
255 hp[nhosts].host = xstrdup(ls->lserver);
256 hp[nhosts].port = -1;
257 hp[nhosts].priority = -2;
258 hp[nhosts].weight = -2;
259 ++nhosts;
260
261 }
262 ls = ls->next;
263 }
264 /* found ldap servers in predefined list -> exit */
265 if (nhosts > 0)
266 goto cleanup;
267
268 if (margs->ssl) {
269 service = (char *) xmalloc(strlen("_ldaps._tcp.") + strlen(domain) + 1);
270 strcpy(service, "_ldaps._tcp.");
271 } else {
272 service = (char *) xmalloc(strlen("_ldap._tcp.") + strlen(domain) + 1);
273 strcpy(service, "_ldap._tcp.");
274 }
275 strcat(service, domain);
276
277#ifndef PACKETSZ_MULT
278 /*
279 * It seems Solaris doesn't give back the real length back when res_search uses a to small buffer
280 * Set a bigger one here
281 */
282#define PACKETSZ_MULT 10
283#endif
284
285 hp = *hlist;
286 buffer = (u_char *) xmalloc(PACKETSZ_MULT * NS_PACKETSZ);
287 if ((len = res_search(service, ns_c_in, ns_t_srv, (u_char *) buffer, PACKETSZ_MULT * NS_PACKETSZ)) < 0) {
288 error((char *) "%s| %s: ERROR: Error while resolving service record %s with res_search\n", LogTime(), PROGRAM, service);
289 nsError(h_errno, service);
290 if (margs->ssl) {
291 xfree(service);
292 service = (char *) xmalloc(strlen("_ldap._tcp.") + strlen(domain) + 1);
293 strcpy(service, "_ldap._tcp.");
294 strcat(service, domain);
295 if ((len = res_search(service, ns_c_in, ns_t_srv, (u_char *) buffer, PACKETSZ_MULT * NS_PACKETSZ)) < 0) {
296 error((char *) "%s| %s: ERROR: Error while resolving service record %s with res_search\n", LogTime(), PROGRAM, service);
297 nsError(h_errno, service);
298 goto finalise;
299 }
300 } else {
301 goto finalise;
302 }
303 }
304 if (len > PACKETSZ_MULT * NS_PACKETSZ) {
305 olen = len;
306 buffer = (u_char *) xrealloc(buffer, (size_t)len);
307 if ((len = res_search(service, ns_c_in, ns_t_srv, (u_char *) buffer, len)) < 0) {
308 error((char *) "%s| %s: ERROR: Error while resolving service record %s with res_search\n", LogTime(), PROGRAM, service);
309 nsError(h_errno, service);
310 goto finalise;
311 }
312 if (len > olen) {
313 error((char *) "%s| %s: ERROR: Reply to big: buffer: %d reply length: %d\n", LogTime(), PROGRAM, olen, len);
314 goto finalise;
315 }
316 }
317 p = buffer;
318 p += 6 * NS_INT16SZ; /* Header(6*16bit) = id + flags + 4*section count */
319 if (p > buffer + len) {
320 error((char *) "%s| %s: ERROR: Message to small: %d < header size\n", LogTime(), PROGRAM, len);
321 goto finalise;
322 }
323 if ((size = dn_expand(buffer, buffer + len, p, name, sizeof(name))) < 0) {
324 error((char *) "%s| %s: ERROR: Error while expanding query name with dn_expand: %s\n", LogTime(), PROGRAM, strerror(errno));
325 goto finalise;
326 }
327 p += size; /* Query name */
328 p += 2 * NS_INT16SZ; /* Query type + class (2*16bit) */
329 if (p > buffer + len) {
330 error((char *) "%s| %s: ERROR: Message to small: %d < header + query name,type,class \n", LogTime(), PROGRAM, len);
331 goto finalise;
332 }
333 while (p < buffer + len) {
334 int type, rdlength;
335 if ((size = dn_expand(buffer, buffer + len, p, name, sizeof(name))) < 0) {
336 error((char *) "%s| %s: ERROR: Error while expanding answer name with dn_expand: %s\n", LogTime(), PROGRAM, strerror(errno));
337 goto finalise;
338 }
339 p += size; /* Resource Record name */
340 if (p > buffer + len) {
341 error((char *) "%s| %s: ERROR: Message to small: %d < header + query name,type,class + answer name\n", LogTime(), PROGRAM, len);
342 goto finalise;
343 }
344 NS_GET16(type, p); /* RR type (16bit) */
345 p += NS_INT16SZ + NS_INT32SZ; /* RR class + ttl (16bit+32bit) */
346 if (p > buffer + len) {
347 error((char *) "%s| %s: ERROR: Message to small: %d < header + query name,type,class + answer name + RR type,class,ttl\n", LogTime(), PROGRAM, len);
348 goto finalise;
349 }
350 NS_GET16(rdlength, p); /* RR data length (16bit) */
351
352 if (type == ns_t_srv) { /* SRV record */
353 int priority, weight, port;
354 char host[NS_MAXDNAME];
355 if (p > buffer + len) {
356 error((char *) "%s| %s: ERROR: Message to small: %d < header + query name,type,class + answer name + RR type,class,ttl + RR data length\n", LogTime(), PROGRAM, len);
357 goto finalise;
358 }
359 NS_GET16(priority, p); /* Priority (16bit) */
360 if (p > buffer + len) {
361 error((char *) "%s| %s: ERROR: Message to small: %d < SRV RR + priority\n", LogTime(), PROGRAM, len);
362 goto finalise;
363 }
364 NS_GET16(weight, p); /* Weight (16bit) */
365 if (p > buffer + len) {
366 error((char *) "%s| %s: ERROR: Message to small: %d < SRV RR + priority + weight\n", LogTime(), PROGRAM, len);
367 goto finalise;
368 }
369 NS_GET16(port, p); /* Port (16bit) */
370 if (p > buffer + len) {
371 error((char *) "%s| %s: ERROR: Message to small: %d < SRV RR + priority + weight + port\n", LogTime(), PROGRAM, len);
372 goto finalise;
373 }
374 if ((size = dn_expand(buffer, buffer + len, p, host, NS_MAXDNAME)) < 0) {
375 error((char *) "%s| %s: ERROR: Error while expanding SRV RR name with dn_expand: %s\n", LogTime(), PROGRAM, strerror(errno));
376 goto finalise;
377 }
378 debug((char *) "%s| %s: DEBUG: Resolved SRV %s record to %s\n", LogTime(), PROGRAM, service, host);
379 hp = (struct hstruct *) xrealloc(hp, sizeof(struct hstruct) * (nh + 1));
380 hp[nh].host = xstrdup(host);
381 hp[nh].port = port;
382 hp[nh].priority = priority;
383 hp[nh].weight = weight;
384 ++nh;
385 p += size;
386 } else {
387 p += rdlength;
388 }
389 if (p > buffer + len) {
390 error((char *) "%s| %s: ERROR: Message to small: %d < SRV RR + priority + weight + port + name\n", LogTime(), PROGRAM, len);
391 goto finalise;
392 }
393 }
394 if (p != buffer + len) {
395#if (SIZEOF_LONG == 8)
396 error("%s| %s: ERROR: Inconsistence message length: %ld!=0\n", LogTime(), PROGRAM, buffer + len - p);
397#else
398 error((char *) "%s| %s: ERROR: Inconsistence message length: %d!=0\n", LogTime(), PROGRAM, buffer + len - p);
399#endif
400 goto finalise;
401 }
402
403finalise:
404 nhosts = get_hostname_list(&hp, nh, domain);
405
406 debug("%s| %s: DEBUG: Adding %s to list\n", LogTime(), PROGRAM, domain);
407
408 hp = (struct hstruct *) xrealloc(hp, sizeof(struct hstruct) * (nhosts + 1));
409 hp[nhosts].host = xstrdup(domain);
410 hp[nhosts].port = -1;
411 hp[nhosts].priority = -2;
412 hp[nhosts].weight = -2;
413 ++nhosts;
414
415cleanup:
416 /* Remove duplicates */
417 for (i = 0; i < nhosts; ++i) {
418 for (j = i + 1; j < nhosts; ++j) {
419 if (!strcasecmp(hp[i].host, hp[j].host)) {
420 if (hp[i].port == hp[j].port ||
421 (hp[i].port == -1 && hp[j].port == 389) ||
422 (hp[i].port == 389 && hp[j].port == -1)) {
423 xfree(hp[j].host);
424 for (k = j + 1; k < nhosts; ++k) {
425 hp[k - 1].host = hp[k].host;
426 hp[k - 1].port = hp[k].port;
427 hp[k - 1].priority = hp[k].priority;
428 hp[k - 1].weight = hp[k].weight;
429 }
430 --j;
431 --nhosts;
432 hp = (struct hstruct *) xrealloc(hp, sizeof(struct hstruct) * (nhosts + 1));
433 }
434 }
435 }
436 }
437
438 /* Sort by Priority / Weight */
439 msort(hp, (size_t)nhosts, compare_hosts);
440
441 if (debug_enabled) {
442 debug((char *) "%s| %s: DEBUG: Sorted ldap server names for domain %s:\n", LogTime(), PROGRAM, domain);
443 for (i = 0; i < nhosts; ++i) {
444 debug((char *) "%s| %s: DEBUG: Host: %s Port: %d Priority: %d Weight: %d\n", LogTime(), PROGRAM, hp[i].host, hp[i].port, hp[i].priority, hp[i].weight);
445 }
446 }
447 xfree(buffer);
448 xfree(service);
449 *hlist = hp;
450 return (nhosts);
451}
452#endif
453
int size
Definition ModDevPoll.cc:70
void error(char *format,...)
size_t get_hostname_list(struct hstruct **hlist, size_t nhosts, char *name)
#define PROGRAM
Definition support.h:168
const char * LogTime(void)
size_t free_hostname_list(struct hstruct **hlist, size_t nhosts)
size_t get_ldap_hostname_list(struct main_args *margs, struct hstruct **hlist, size_t nhosts, char *domain)
static char server[MAXLINE]
int debug_enabled
Definition debug.cc:13
void debug(const char *format,...)
Definition debug.cc:19
#define NS_MAXDNAME
static int port
#define xfree
#define xstrdup
#define xmalloc
char * strerror(int ern)
Definition strerror.c:22
int port
Definition support.h:124
char * host
Definition support.h:123
int priority
Definition support.h:125
int weight
Definition support.h:126
struct lsstruct * next
Definition support.h:70
char * domain
Definition support.h:69
char * lserver
Definition support.h:68
struct lsstruct * lservs
Definition support.h:91
char * ssl
Definition support.h:83
void * xrealloc(void *s, size_t sz)
Definition xalloc.cc:126
#define safe_free(x)
Definition xalloc.h:73