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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors