]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/dnsserver.cc
2 * DEBUG: section 00 DNS Resolver Daemon
3 * AUTHOR: Harvest Derived
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
54 #include <gnumalloc.h>
74 #include <sys/param.h>
77 #include <sys/socket.h>
80 #include <netinet/in.h>
83 #include <arpa/inet.h>
97 #if HAVE_SYS_SYSCALL_H
98 #include <sys/syscall.h>
116 #if HAVE_ARPA_NAMESER_H
117 #include <arpa/nameser.h>
124 \defgroup dnsserver dnsserver
125 \ingroup ExternalPrograms
127 Because the standard gethostbyname() library call
128 blocks, Squid must use external processes to actually make
129 these calls. Typically there will be ten dnsserver
130 processes spawned from Squid. Communication occurs via
131 TCP sockets bound to the loopback interface. The functions
132 in dns.cc are primarily concerned with starting and
133 stopping the dnsservers. Reading and writing to and from
134 the dnsservers occurs in the \link IPCacheAPI IP\endlink and
135 \link FQDNCacheAPI FQDN\endlink cache modules.
137 \section dnsserverInterface Command Line Interface
139 usage: dnsserver -Dhv -s nameserver
140 -D Enable resolver RES_DEFNAMES and RES_DNSRCH options
143 -s nameserver Specify alternate name server(s). 'nameserver'
144 must be an IP address, -s option may be repeated
148 #if LIBRESOLV_DNS_TTL_HACK
149 /// \ingroup dnsserver
150 extern int _dns_ttl_
; /* this is a really *dirty* hack - bne */
154 * res_init() is a macro re-definition of __res_init on: Debian
156 #if !defined(HAVE_RES_INIT) && defined(HAVE___RES_INIT)
158 #define res_init __res_init
160 #define HAVE_RES_INIT HAVE___RES_INIT
163 /// \ingroup dnsserver
170 lookup(const char *buf
)
176 struct addrinfo hints
;
177 struct addrinfo
*AI
= NULL
;
178 struct addrinfo
*aiptr
= NULL
;
179 struct addrinfo
*prev_addr
= NULL
;
182 if (0 == strcmp(buf
, "$shutdown"))
185 if (0 == strcmp(buf
, "$hello")) {
190 /* check if it's already an IP address in text form. */
191 memset(&hints
, '\0', sizeof(struct addrinfo
));
192 hints
.ai_family
= AF_UNSPEC
;
193 hints
.ai_flags
= AI_NUMERICHOST
; // only succeed if its numeric.
194 const bool isDomain
= (getaddrinfo(buf
,NULL
,&hints
,&AI
) != 0);
196 // reset for real lookup
202 // resolve the address/name
203 memset(&hints
, '\0', sizeof(struct addrinfo
));
204 hints
.ai_family
= AF_UNSPEC
;
205 hints
.ai_flags
= AI_CANONNAME
;
212 if ( 0 == (res
= getaddrinfo(buf
,NULL
,&hints
,&AI
)) )
215 if (res
!= EAI_AGAIN
)
225 /* its a domain name. Use the forward-DNS lookup already done */
228 #if LIBRESOLV_DNS_TTL_HACK
229 /* DNS TTL handling - bne@CareNet.hu
230 * for first try it's a dirty hack, by hacking getanswer
231 * to place the ttl in a global variable */
235 printf("$addr %d", ttl
);
239 while (NULL
!= aiptr
&& 32 >= i
) {
240 memset(ntoabuf
, 0, sizeof(ntoabuf
));
242 /* getaddrinfo given a host has a nasty tendency to return duplicate addr's */
243 /* BUT sorted fortunately, so we can drop most of them easily */
245 prev_addr
->ai_family
==aiptr
->ai_family
&&
246 memcmp(aiptr
->ai_addr
, prev_addr
->ai_addr
, aiptr
->ai_addrlen
)==0
249 aiptr
= aiptr
->ai_next
;
255 /* annoying inet_ntop breaks the nice code by requiring the in*_addr */
256 switch (aiptr
->ai_family
) {
258 inet_ntop(aiptr
->ai_family
, &((struct sockaddr_in
*)aiptr
->ai_addr
)->sin_addr
, ntoabuf
, sizeof(ntoabuf
));
261 inet_ntop(aiptr
->ai_family
, &((struct sockaddr_in6
*)aiptr
->ai_addr
)->sin6_addr
, ntoabuf
, sizeof(ntoabuf
));
264 aiptr
= aiptr
->ai_next
;
267 printf(" %s", ntoabuf
);
269 aiptr
= aiptr
->ai_next
;
275 } else { /* its an IPA in text form. perform rDNS */
276 /* You'd expect getaddrinfo given AI_CANONNAME would do a lookup on
277 * missing FQDN. But no, it only copies the input string to that
278 * position regardless of its content.
280 if (NULL
!= AI
&& NULL
!= AI
->ai_addr
) {
282 if ( 0 == (res
= getnameinfo(AI
->ai_addr
, AI
->ai_addrlen
, ntoabuf
, sizeof(ntoabuf
), NULL
,0,0)) )
285 if (res
!= EAI_AGAIN
)
296 #if LIBRESOLV_DNS_TTL_HACK
297 /* DNS TTL handling - bne@CareNet.hu
298 * for first try it's a dirty hack, by hacking getanswer
299 * to place the ttl in a global variable */
304 printf("$name %d %s\n", ttl
, ntoabuf
);
314 printf("$fail Name Server for domain '%s' is unavailable.\n", buf
);
318 printf("$fail DNS Domain/IP '%s' does not exist: %s.\n", buf
, gai_strerror(res
));
321 #if defined(EAI_NODATA) || defined(EAI_NONAME)
323 /* deprecated. obsolete on some OS */
329 printf("$fail DNS Domain/IP '%s' exists without any FQDN/IPs: %s.\n", buf
, gai_strerror(res
));
333 printf("$fail A system error occured looking up Domain/IP '%s': %s.\n", buf
, gai_strerror(res
));
346 fprintf(stderr
, "usage: dnsserver -hv -s nameserver\n"
349 "\t-s nameserver Specify alternate name server(s). 'nameserver'\n"
350 "\t must be an IPv4 address, -s option may be repeated\n"
354 #if defined(_SQUID_RES_NSADDR6_LARRAY)
355 /// \ingroup dnsserver
356 #define _SQUID_RES_NSADDR6_LIST(i) _SQUID_RES_NSADDR6_LARRAY[i].sin6_addr
358 #if defined(_SQUID_RES_NSADDR6_LPTR)
359 /// \ingroup dnsserver
360 #define _SQUID_RES_NSADDR6_LIST(i) _SQUID_RES_NSADDR6_LPTR[i]->sin6_addr
366 * Override the system DNS nameservers with some local ones.
367 * Equivalent to the bind res_setservers() call but for any
368 * system where we can find the needed _res fields.
371 squid_res_setservers(int reset
)
373 #if _SQUID_FREEBSD_ && defined(_SQUID_RES_NSADDR6_COUNT)
374 /* Only seems to be valid on FreeBSD 5.5 where _res_ext was provided without an ns6addr counter! */
375 /* Gone again on FreeBSD 6.2 along with _res_ext itself in any form. */
378 #if HAVE_RES_INIT && defined(_SQUID_RES_NSADDR_LIST)
382 #if HAVE_RES_INIT && (defined(_SQUID_RES_NSADDR_LIST) || defined(_SQUID_RES_NSADDR6_LIST))
385 #if defined(_SQUID_RES_NSADDR_COUNT)
386 _SQUID_RES_NSADDR_COUNT
= 0;
387 /* because I don't trust the nscount super-count entirely, make sure these are ALL invalid */
388 memset(_SQUID_RES_NSADDR_LIST
, 0, sizeof(struct sockaddr_in
)*MAXNS
);
390 #if defined(_SQUID_RES_NSADDR6_COUNT)
391 _SQUID_RES_NSADDR6_COUNT
= 0;
396 * I experimented with all the permutations of mixed/unmixed nscount/nscount6 IPv4/IPv6/Both/invalid
398 * I'm not sure if splitting them really helps.
399 * I've seen no evidence of IPv4 resolver *ever* being used when some IPv6 are set (or not even)
400 * BUT, have seen segfault when IPv4 is added to NSADDR6 list (_res._u._ext).
401 * It also appears to not do ANY lookup when _res.nscount==0.
403 * BUT, even if _res.nsaddrs is memset to NULL, it resolves IFF IPv6 set in _ext.
405 * SO, am splitting the IPv4/v6 into the seperate _res fields
406 * and making nscount a total of IPv4+IPv6 /w nscount6 the IPv6 sub-counter
407 * ie. nscount = count(NSv4)+count(NSv6) & nscount6 = count(NSv6)
409 * If ANYONE knows better please let us know.
411 struct addrinfo hints
;
412 memset(&hints
, '\0', sizeof(struct addrinfo
));
413 hints
.ai_family
= AF_UNSPEC
;
414 hints
.ai_flags
= AI_NUMERICHOST
; // prevent repeated DNS lookups!
415 struct addrinfo
*AI
= NULL
;
416 if ( getaddrinfo(optarg
, NULL
, &hints
, &AI
) != 0) {
417 fprintf(stderr
, "%s appears to be a bad nameserver FQDN/IP.\n",optarg
);
418 } else if ( AI
->ai_family
== AF_INET
) {
419 if (_SQUID_RES_NSADDR_COUNT
== MAXNS
) {
420 fprintf(stderr
, "Too many -s options, only %d are allowed\n", MAXNS
);
422 _SQUID_RES_NSADDR_LIST
[_SQUID_RES_NSADDR_COUNT
] = _SQUID_RES_NSADDR_LIST
[0];
423 memcpy(&_SQUID_RES_NSADDR_LIST
[_SQUID_RES_NSADDR_COUNT
++].sin_addr
, &((struct sockaddr_in
*)AI
->ai_addr
)->sin_addr
, sizeof(struct in_addr
));
425 } else if ( AI
->ai_family
== AF_INET6
) {
426 #if USE_IPV6 && defined(_SQUID_RES_NSADDR6_LIST)
427 /* because things NEVER seem to resolve in tests without _res.nscount being a total. */
428 if (_SQUID_RES_NSADDR_COUNT
== MAXNS
) {
429 fprintf(stderr
, "Too many -s options, only %d are allowed\n", MAXNS
);
431 ++ _SQUID_RES_NSADDR_COUNT
;
432 memcpy(&_SQUID_RES_NSADDR6_LIST(_SQUID_RES_NSADDR6_COUNT
++), &((struct sockaddr_in6
*)AI
->ai_addr
)->sin6_addr
, sizeof(struct in6_addr
));
435 fprintf(stderr
, "IPv6 nameservers not supported on this resolver\n");
441 #else /* !HAVE_RES_INIT || !defined(_SQUID_RES_NSADDR_LIST) */
443 fprintf(stderr
, "-s is not supported on this resolver\n");
445 #endif /* HAVE_RES_INIT */
451 * This is the external dnsserver process.
454 main(int argc
, char *argv
[])
466 /* perform AAAA lookups *before* A lookups in IPv6 mode. */
467 _res
.options
|= RES_USE_INET6
;
470 while ((c
= getopt(argc
, argv
, "Dhs:v")) != -1) {
474 fprintf(stderr
, "-D is now default behaviour from this tool.\n");
478 squid_res_setservers(opt_s
);
483 printf("dnsserver version %s\n", VERSION
);
504 WSAStartup(2, &wsaData
);
511 memset(request
, '\0', REQ_SZ
);
513 if (fgets(request
, REQ_SZ
, stdin
) == NULL
) {
520 t
= strrchr(request
, '\n');
522 if (t
== NULL
) /* Ignore if no newline */
525 *t
= '\0'; /* strip NL */
527 if ((t
= strrchr(request
, '\r')) != NULL
)
528 *t
= '\0'; /* strip CR */