]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/dnsserver.cc
3 * $Id: dnsserver.cc,v 1.74 2008/02/26 21:49:34 amosjeffries Exp $
5 * DEBUG: section 0 DNS Resolver
6 * AUTHOR: Harvest Derived
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
48 #include <sys/types.h>
63 #include <gnumalloc.h>
70 #if HAVE_NETDB_H && !defined(_SQUID_NETDB_H_) /* protect NEXTSTEP */
71 #define _SQUID_NETDB_H_
84 #include <sys/param.h>
89 #if HAVE_SYS_RESOURCE_H
90 #include <sys/resource.h> /* needs sys/time.h above it */
93 #include <sys/socket.h>
96 #include <netinet/in.h>
99 #include <arpa/inet.h>
102 #include <sys/stat.h>
108 #include <sys/wait.h>
113 #ifdef HAVE_SYS_SYSCALL_H
114 #include <sys/syscall.h>
119 #ifdef HAVE_STRINGS_H
128 #if HAVE_SYS_SELECT_H
129 #include <sys/select.h>
135 #if HAVE_ARPA_NAMESER_H
136 #include <arpa/nameser.h>
145 \defgroup dnsserver dnsserver
146 \ingroup ExternalPrograms
148 Because the standard gethostbyname() library call
149 blocks, Squid must use external processes to actually make
150 these calls. Typically there will be ten dnsserver
151 processes spawned from Squid. Communication occurs via
152 TCP sockets bound to the loopback interface. The functions
153 in dns.cc are primarily concerned with starting and
154 stopping the dnsservers. Reading and writing to and from
155 the dnsservers occurs in the \link IPCacheAPI IP\endlink and
156 \link FQDNCacheAPI FQDN\endlink cache modules.
158 \section dnsserverInterface Command Line Interface
160 usage: dnsserver -Dhv -s nameserver
161 -D Enable resolver RES_DEFNAMES and RES_DNSRCH options
164 -s nameserver Specify alternate name server(s). 'nameserver'
165 must be an IP address, -s option may be repeated
169 #include "IPAddress.h"
171 #if LIBRESOLV_DNS_TTL_HACK
172 /// \ingroup dnsserver
173 extern int _dns_ttl_
; /* this is a really *dirty* hack - bne */
177 * res_init() is a macro re-definition of __res_init on: Debian
179 #if !defined(HAVE_RES_INIT) && defined(HAVE___RES_INIT)
181 #define res_init __res_init
183 #define HAVE_RES_INIT HAVE___RES_INIT
186 /// \ingroup dnsserver
193 lookup(const char *buf
)
199 char ntoabuf
[MAX_IPSTRLEN
];
200 struct addrinfo hints
;
201 struct addrinfo
*AI
= NULL
;
202 struct addrinfo
*aiptr
= NULL
;
203 struct addrinfo
*prev_addr
= NULL
;
206 if (0 == strcmp(buf
, "$shutdown"))
209 if (0 == strcmp(buf
, "$hello")) {
214 /* setup 'hints' for the system lookup */
215 memset(&hints
, '\0', sizeof(struct addrinfo
));
216 hints
.ai_family
= AF_UNSPEC
;
217 hints
.ai_flags
= AI_CANONNAME
;
223 if( 0 == (res
= xgetaddrinfo(buf
,NULL
,&hints
,&AI
)) )
226 if (res
!= EAI_AGAIN
)
235 /* check if it's already an IP address in text form. */
237 if( ipa
.IsAnyAddr() ) {
238 /* its a domain name. Use the forward-DNS lookup already done */
241 #if LIBRESOLV_DNS_TTL_HACK
242 /* DNS TTL handling - bne@CareNet.hu
243 * for first try it's a dirty hack, by hacking getanswer
244 * to place the ttl in a global variable */
248 printf("$addr %d", ttl
);
252 while(NULL
!= aiptr
&& 32 >= i
) {
253 memset(ntoabuf
, 0, MAX_IPSTRLEN
);
255 /* getaddrinfo given a host has a nasty tendency to return duplicate addr's */
256 /* BUT sorted fortunately, so we can drop most of them easily */
258 prev_addr
->ai_family
==aiptr
->ai_family
&&
259 memcmp(aiptr
->ai_addr
, prev_addr
->ai_addr
, aiptr
->ai_addrlen
)==0
262 aiptr
= aiptr
->ai_next
;
269 /* annoying inet_ntop breaks the nice code by requiring the in*_addr */
270 switch(aiptr
->ai_family
) {
272 xinet_ntop(aiptr
->ai_family
, &((struct sockaddr_in
*)aiptr
->ai_addr
)->sin_addr
, ntoabuf
, MAX_IPSTRLEN
);
276 xinet_ntop(aiptr
->ai_family
, &((struct sockaddr_in6
*)aiptr
->ai_addr
)->sin6_addr
, ntoabuf
, MAX_IPSTRLEN
);
280 aiptr
= aiptr
->ai_next
;
283 printf(" %s", ntoabuf
);
285 aiptr
= aiptr
->ai_next
;
292 else /* its an IPA in text form. perform rDNS */
294 /* You'd expect getaddrinfo given AI_CANONNAME would do a lookup on
295 * missing FQDN. But no, it only copies the input string to that
296 * position regardless of its content.
298 if(NULL
!= AI
&& NULL
!= AI
->ai_addr
) {
300 if( 0 == (res
= xgetnameinfo(AI
->ai_addr
, AI
->ai_addrlen
, ntoabuf
, MAX_IPSTRLEN
, NULL
,0,0)) )
303 if (res
!= EAI_AGAIN
)
314 #if LIBRESOLV_DNS_TTL_HACK
315 /* DNS TTL handling - bne@CareNet.hu
316 * for first try it's a dirty hack, by hacking getanswer
317 * to place the ttl in a global variable */
322 printf("$name %d %s\n", ttl
, ntoabuf
);
332 printf("$fail Name Server for domain '%s' is unavailable.\n", buf
);
336 printf("$fail DNS Domain/IP '%s' does not exist: %s.\n", buf
, xgai_strerror(res
));
339 #if defined(EAI_NODATA) || defined(EAI_NONAME)
341 /* deprecated. obsolete on some OS */
347 printf("$fail DNS Domain/IP '%s' exists without any FQDN/IPs: %s.\n", buf
, xgai_strerror(res
));
351 printf("$fail A system error occured looking up Domain/IP '%s': %s.\n", buf
, xgai_strerror(res
));
363 fprintf(stderr
, "usage: dnsserver -hv -s nameserver\n"
366 "\t-s nameserver Specify alternate name server(s). 'nameserver'\n"
367 "\t must be an IPv4 address, -s option may be repeated\n"
371 #ifdef _SQUID_RES_NSADDR6_LARRAY
372 /// \ingroup dnsserver
373 #define _SQUID_RES_NSADDR6_LIST(i) _SQUID_RES_NSADDR6_LARRAY[i].sin6_addr
375 #ifdef _SQUID_RES_NSADDR6_LPTR
376 /// \ingroup dnsserver
377 #define _SQUID_RES_NSADDR6_LIST(i) _SQUID_RES_NSADDR6_LPTR[i]->sin6_addr
383 * This is the external dnsserver process.
386 main(int argc
, char *argv
[])
391 #if defined(_SQUID_FREEBSD_) && defined(_SQUID_RES_NSADDR6_COUNT)
392 /* Only seems to be valid on FreeBSD 5.5 where _res_ext was provided without an ns6addr counter! */
393 /* Gone again on FreeBSD 6.2 along with _res_ext itself in any form. */
400 #ifdef _SQUID_RES_NSADDR_LIST
411 /* perform AAAA lookups *before* A lookups in IPv6 mode. */
412 _res
.options
|= RES_USE_INET6
;
415 while ((c
= getopt(argc
, argv
, "Dhs:v")) != -1) {
419 fprintf(stderr
, "-D is now default behaviour from this tool.\n");
423 #if HAVE_RES_INIT && (defined(_SQUID_RES_NSADDR_LIST) || defined(_SQUID_RES_NSADDR6_LIST))
426 #if defined(_SQUID_RES_NSADDR_COUNT)
427 _SQUID_RES_NSADDR_COUNT
= 0;
428 /* because I don't trust the nscount super-count entirely, make sure these are ALL invalid */
429 memset(_SQUID_RES_NSADDR_LIST
, 0, sizeof(struct sockaddr_in
)*MAXNS
);
431 #if defined(_SQUID_RES_NSADDR6_COUNT)
432 _SQUID_RES_NSADDR6_COUNT
= 0;
438 * I experimented with all the permutations of mixed/unmixed nscount/nscount6 IPv4/IPv6/Both/invalid
440 * I'm not sure if splitting them really helps.
441 * I've seen no evidence of IPv4 resolver *ever* being used when some IPv6 are set (or not even)
442 * BUT, have seen segfault when IPv4 is added to NSADDR6 list (_res._u._ext).
443 * It also appears to not do ANY lookup when _res.nscount==0.
445 * BUT, even if _res.nsaddrs is memset to NULL, it resolves IFF IPv6 set in _ext.
447 * SO, am splittig the IPv4/v6 into the seperate _res fields
448 * and making nscount a total of IPv4+IPv6 /w nscount6 the IPv6 sub-counter
449 * ie. nscount = count(NSv4)+count(NSv6) & nscount6 = count(NSv6)
451 * If ANYONE knows better please let us know.
454 if( !(ipa
= optarg
) ) {
455 fprintf(stderr
, "%s appears to be a bad nameserver FQDN/IP.\n",optarg
);
457 else if( ipa
.IsIPv4() ) {
458 if (_SQUID_RES_NSADDR_COUNT
== MAXNS
) {
459 fprintf(stderr
, "Too many -s options, only %d are allowed\n", MAXNS
);
462 _SQUID_RES_NSADDR_LIST
[_SQUID_RES_NSADDR_COUNT
] = _SQUID_RES_NSADDR_LIST
[0];
463 ipa
.GetInAddr(_SQUID_RES_NSADDR_LIST
[_SQUID_RES_NSADDR_COUNT
++].sin_addr
);
465 else if( ipa
.IsIPv6() ) {
466 #if USE_IPV6 && defined(_SQUID_RES_NSADDR6_LIST)
468 /* because things NEVER seem to resolve in tests without _res.nscount being a total. */
469 if (_SQUID_RES_NSADDR_COUNT
== MAXNS
) {
470 fprintf(stderr
, "Too many -s options, only %d are allowed\n", MAXNS
);
473 _SQUID_RES_NSADDR_COUNT
++;
475 ipa
.GetInAddr(_SQUID_RES_NSADDR6_LIST(_SQUID_RES_NSADDR6_COUNT
++));
477 fprintf(stderr
, "IPv6 nameservers not supported on this resolver\n");
481 #else /* !HAVE_RES_INIT || !defined(_SQUID_RES_NSADDR_LIST) */
483 fprintf(stderr
, "-s is not supported on this resolver\n");
485 #endif /* HAVE_RES_INIT */
490 printf("dnsserver version %s\n", VERSION
);
511 WSAStartup(2, &wsaData
);
518 memset(request
, '\0', REQ_SZ
);
520 if (fgets(request
, REQ_SZ
, stdin
) == NULL
) {
527 t
= strrchr(request
, '\n');
529 if (t
== NULL
) /* Ignore if no newline */
532 *t
= '\0'; /* strip NL */
534 if ((t
= strrchr(request
, '\r')) != NULL
)
535 *t
= '\0'; /* strip CR */