]> git.ipfire.org Git - thirdparty/squid.git/blame - src/dns_internal.cc
change debugging level
[thirdparty/squid.git] / src / dns_internal.cc
CommitLineData
7b724b86 1
2/*
ef523f99 3 * $Id: dns_internal.cc,v 1.4 1999/04/16 01:00:51 wessels Exp $
7b724b86 4 *
5 * DEBUG: section 78 DNS lookups; interacts with lib/rfc1035.c
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * the CREDITS file for full details.
19 *
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.
24 *
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.
29 *
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.
33 *
34 */
35
36#include "squid.h"
37
38#ifndef _PATH_RESOLV_CONF
39#define _PATH_RESOLV_CONF "/etc/resolv.conf"
40#endif
41#ifndef DOMAIN_PORT
42#define DOMAIN_PORT 53
43#endif
44
45typedef struct _ns ns;
46struct _ns {
47 struct sockaddr_in S;
48 int nqueries;
49 int nreplies;
50};
51static ns *nameservers = NULL;
52static int nns = 0;
53static int nns_alloc = 0;
7b724b86 54static dlink_list lru_list;
7cfc1c9a 55static int event_queued = 0;
7b724b86 56
57static OBJH idnsStats;
58static void idnsAddNameserver(const char *buf);
59static void idnsFreeNameservers(void);
60static void idnsParseResolvConf(void);
61static void idnsSendQuery(idns_query * q);
62static int idnsFromKnownNameserver(struct sockaddr_in *from);
63static idns_query *idnsFindQuery(unsigned short id);
64static void idnsGrokReply(const char *buf, size_t sz);
65static PF idnsRead;
7cfc1c9a 66static EVH idnsCheckQueue;
7b724b86 67
68static void
69idnsAddNameserver(const char *buf)
70{
71 if (nns == nns_alloc) {
72 int oldalloc = nns_alloc;
73 ns *oldptr = nameservers;
74 if (nns_alloc == 0)
75 nns_alloc = 2;
76 else
77 nns_alloc <<= 1;
78 nameservers = xcalloc(nns_alloc, sizeof(*nameservers));
79 if (oldptr && oldalloc)
80 xmemcpy(nameservers, oldptr, oldalloc * sizeof(*nameservers));
81 if (oldptr)
82 safe_free(oldptr);
83 }
84 assert(nns < nns_alloc);
85 nameservers[nns].S.sin_family = AF_INET;
86 nameservers[nns].S.sin_port = htons(DOMAIN_PORT);
87 nameservers[nns].S.sin_addr.s_addr = inet_addr(buf);
88 debug(78, 1) ("idnsAddNameserver: Added nameserver #%d: %s\n",
89 nns, inet_ntoa(nameservers[nns].S.sin_addr));
90 nns++;
91}
92
93static void
94idnsFreeNameservers(void)
95{
96 safe_free(nameservers);
97 nns = nns_alloc = 0;
98}
99
100static void
101idnsParseResolvConf(void)
102{
103 FILE *fp;
104 char buf[512];
105 char *t;
106 fp = fopen(_PATH_RESOLV_CONF, "r");
107 if (fp == NULL) {
108 debug(78, 1) ("%s: %s\n", _PATH_RESOLV_CONF, xstrerror());
109 return;
110 }
111 idnsFreeNameservers();
112 while (fgets(buf, 512, fp)) {
113 t = strtok(buf, w_space);
114 if (strcasecmp(t, "nameserver"))
115 continue;
116 t = strtok(NULL, w_space);
117 if (t == NULL)
118 continue;;
119 debug(78, 1) ("idnsParseResolvConf: nameserver %s\n", t);
120 idnsAddNameserver(t);
121 }
122 fclose(fp);
123}
124
125static void
126idnsStats(StoreEntry * sentry)
127{
a16b4aa0 128 dlink_node *n;
129 idns_query *q;
7cfc1c9a 130 int i;
7b724b86 131 storeAppendPrintf(sentry, "Internal DNS Statistics:\n");
a16b4aa0 132 storeAppendPrintf(sentry, "\nThe Queue:\n");
7cfc1c9a 133 storeAppendPrintf(sentry, " ID SIZE SENDS DELAY\n");
134 storeAppendPrintf(sentry, "------ ---- ----- --------\n");
a16b4aa0 135 for (n = lru_list.head; n; n = n->next) {
136 q = n->data;
ef523f99 137 storeAppendPrintf(sentry, "%#06x %4d %5d %8.3f\n",
138 (int) q->id, q->sz, q->nsends,
7cfc1c9a 139 tvSubDsec(q->start_t, current_time));
140 }
141 storeAppendPrintf(sentry, "\nNameservers:\n");
142 storeAppendPrintf(sentry, "IP ADDRESS # QUERIES # REPLIES\n");
143 storeAppendPrintf(sentry, "--------------- --------- ---------\n");
144 for (i = 0; i < nns; i++) {
145 storeAppendPrintf(sentry, "%-15s %9d %9d\n",
146 inet_ntoa(nameservers[i].S.sin_addr),
147 nameservers[i].nqueries,
148 nameservers[i].nreplies);
a16b4aa0 149 }
7b724b86 150}
151
152static void
153idnsSendQuery(idns_query * q)
154{
155 int x;
ef523f99 156 int ns;
7b724b86 157 /* XXX Select nameserver */
158 assert(nns > 0);
159 assert(q->lru.next == NULL);
160 assert(q->lru.prev == NULL);
ef523f99 161 ns = q->nsends % nns;
162 x = comm_udp_sendto(DnsSocket,
7b724b86 163 &nameservers[ns].S,
164 sizeof(nameservers[ns].S),
165 q->buf,
166 q->sz);
a16b4aa0 167 q->nsends++;
7cfc1c9a 168 q->sent_t = current_time;
169 nameservers[ns].nqueries++;
7b724b86 170 dlinkAdd(q, &q->lru, &lru_list);
7cfc1c9a 171 if (!event_queued) {
172 eventAdd("idnsCheckQueue", idnsCheckQueue, NULL, 1.0, 1);
173 event_queued = 1;
174 }
7b724b86 175}
176
177static int
178idnsFromKnownNameserver(struct sockaddr_in *from)
179{
180 int i;
181 for (i = 0; i < nns; i++) {
182 if (nameservers[i].S.sin_addr.s_addr != from->sin_addr.s_addr)
183 continue;
184 if (nameservers[i].S.sin_port != from->sin_port)
185 continue;
7cfc1c9a 186 return i;
7b724b86 187 }
7cfc1c9a 188 return -1;
7b724b86 189}
190
191static idns_query *
192idnsFindQuery(unsigned short id)
193{
194 dlink_node *n;
195 idns_query *q;
196 for (n = lru_list.tail; n; n = n->prev) {
197 q = n->data;
198 if (q->id == id)
199 return q;
200 }
201 return NULL;
202}
203
204static void
205idnsGrokReply(const char *buf, size_t sz)
206{
207 int n;
208 int valid;
209 rfc1035_rr *answers = NULL;
210 unsigned short rid = 0xFFFF;
211 idns_query *q;
212 n = rfc1035AnswersUnpack(buf,
213 sz,
214 &answers,
215 &rid);
a16b4aa0 216 debug(78, 3) ("idnsGrokReply: ID %#hx, %d answers\n", rid, n);
7b724b86 217 if (rid == 0xFFFF) {
218 debug(78, 1) ("idnsGrokReply: Unknown error\n");
219 /* XXX leak answers? */
220 return;
221 }
222 q = idnsFindQuery(rid);
223 if (q == NULL) {
224 debug(78, 1) ("idnsGrokReply: Didn't find query!\n");
225 rfc1035RRDestroy(answers, n);
226 return;
227 }
a16b4aa0 228 dlinkDelete(&q->lru, &lru_list);
7b724b86 229 if (n < 0)
230 debug(78, 1) ("idnsGrokReply: error %d\n", rfc1035_errno);
231 valid = cbdataValid(q->callback_data);
232 cbdataUnlock(q->callback_data);
233 if (valid)
234 q->callback(q->callback_data, answers, n);
235 rfc1035RRDestroy(answers, n);
a16b4aa0 236 memFree(q, MEM_IDNS_QUERY);
7b724b86 237}
238
239static void
240idnsRead(int fd, void *data)
241{
ef523f99 242 int *N = data;
7b724b86 243 ssize_t len;
244 struct sockaddr_in from;
245 socklen_t from_len;
246 int max = 10;
247 static char rbuf[512];
7cfc1c9a 248 int ns;
7b724b86 249 commSetSelect(fd, COMM_SELECT_READ, idnsRead, NULL, 0);
250 while (max--) {
251 from_len = sizeof(from);
252 memset(&from, '\0', from_len);
253 Counter.syscalls.sock.recvfroms++;
254 len = recvfrom(fd, rbuf, 512, 0, (struct sockaddr *) &from, &from_len);
255 if (len == 0)
256 break;
257 if (len < 0) {
258 if (ignoreErrno(errno))
259 break;
260#ifdef _SQUID_LINUX_
261 /* Some Linux systems seem to set the FD for reading and then
262 * return ECONNREFUSED when sendto() fails and generates an ICMP
263 * port unreachable message. */
264 /* or maybe an EHOSTUNREACH "No route to host" message */
265 if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
266#endif
267 debug(50, 1) ("idnsRead: FD %d recvfrom: %s\n",
268 fd, xstrerror());
269 break;
270 }
ef523f99 271 (*N)++;
a16b4aa0 272 debug(78, 3) ("idnsRead: FD %d: received %d bytes from %s.\n",
7b724b86 273 fd,
274 len,
275 inet_ntoa(from.sin_addr));
7cfc1c9a 276 ns = idnsFromKnownNameserver(&from);
277 if (ns < 0) {
7b724b86 278 debug(78, 1) ("idnsRead: Reply from unknown nameserver [%s]\n",
279 inet_ntoa(from.sin_addr));
280 continue;
281 }
7cfc1c9a 282 nameservers[ns].nreplies++;
7b724b86 283 idnsGrokReply(rbuf, len);
284 }
285}
286
7cfc1c9a 287static void
288idnsCheckQueue(void *unused)
289{
290 dlink_node *n;
291 idns_query *q;
292 event_queued = 0;
293 for (n = lru_list.tail; n; n = n->prev) {
294 q = n->data;
295 if (tvSubDsec(q->sent_t, current_time) < 5.0)
296 break;
297 debug(78, 1) ("idnsCheckQueue: ID %#04x timeout\n",
298 q->id);
299 dlinkDelete(&q->lru, &lru_list);
300 idnsSendQuery(q);
301 }
302}
303
7b724b86 304/* ====================================================================== */
305
306void
307idnsInit(void)
308{
309 static int init = 0;
ef523f99 310 if (DnsSocket < 0) {
311 DnsSocket = comm_open(SOCK_DGRAM,
7b724b86 312 0,
313 Config.Addrs.udp_outgoing,
314 0,
315 COMM_NONBLOCKING,
316 "DNS Socket");
ef523f99 317 if (DnsSocket < 0)
7b724b86 318 fatal("Could not create a DNS socket");
ef523f99 319 debug(78, 1) ("DNS Socket created on FD %d\n", DnsSocket);
320 commSetSelect(DnsSocket, COMM_SELECT_READ, idnsRead, NULL, 0);
7b724b86 321 }
322 if (nns == 0)
323 idnsParseResolvConf();
324 if (!init) {
325 cachemgrRegister("idns",
326 "Internal DNS Statistics",
327 idnsStats, 0, 1);
328 }
329 init++;
330}
331
332void
333idnsShutdown(void)
334{
ef523f99 335 if (DnsSocket < 0)
7b724b86 336 return;
ef523f99 337 comm_close(DnsSocket);
338 DnsSocket = -1;
7b724b86 339}
340
341void
342idnsALookup(const char *name, IDNSCB * callback, void *data)
343{
344 idns_query *q = memAllocate(MEM_IDNS_QUERY);
345 q->sz = sizeof(q->buf);
346 q->id = rfc1035BuildAQuery(name, q->buf, &q->sz);
a16b4aa0 347 debug(78, 3) ("idnsALookup: buf is %d bytes for %s, id = %#hx\n",
7b724b86 348 (int) q->sz, name, q->id);
349 q->callback = callback;
350 q->callback_data = data;
351 cbdataLock(q->callback_data);
7cfc1c9a 352 q->start_t = current_time;
7b724b86 353 idnsSendQuery(q);
354}