2 * ircd/res.c (C)opyright 1992, 1993, 1994 Darren Reed. All rights reserved.
3 * This file may not be distributed without the author's prior permission in
4 * any shape or form. The author takes no responsibility for any damage or
5 * loss of property which results from the use of this software. Distribution
6 * of this file must include this notice.
11 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
17 #include <arpa/nameser.h>
19 /* dn_skipname is really an internal function,
20 we shouldn't be using it in res.c */
21 #if !defined(dn_skipname) && !defined(__dn_skipname)
22 extern int dn_skipname(const unsigned char *, const unsigned char *);
35 #include "sprintf_irc.h"
39 #define MAXPACKET 1024
41 #define RES_MAXADDRS 35
42 #define RES_MAXALIASES 35
44 #define ALIASBLEN ((RES_MAXALIASES + 1) * sizeof(char *))
45 #define ADDRSBLEN ((RES_MAXADDRS + 1) * sizeof(struct in_addr *))
46 #define ADDRSDLEN (RES_MAXADDRS * sizeof(struct in_addr))
47 #define ALIASDLEN (MAXPACKET)
48 #define MAXGETHOSTLEN (ALIASBLEN + ADDRSBLEN + ADDRSDLEN + ALIASDLEN)
50 #define AR_TTL 600 /* TTL in seconds for dns cache entries */
52 #define ARES_CACSIZE 512
53 #define MAXCACHED 2048
63 * Building the Hostent
64 * The Hostent struct is arranged like this:
65 * +-------------------------------+
66 * Hostent: | struct hostent h |
67 * |-------------------------------|
69 * +-------------------------------+
73 * +-------------------------------+
74 * buf: | h_aliases pointer array | Max size: ALIASBLEN;
75 * | NULL | contains `char *'s
76 * |-------------------------------|
77 * | h_addr_list pointer array | Max size: ADDRSBLEN;
78 * | NULL | contains `struct in_addr *'s
79 * |-------------------------------|
80 * | h_addr_list addresses | Max size: ADDRSDLEN;
81 * | | contains `struct in_addr's
82 * |-------------------------------|
83 * | storage for hostname strings | Max size: ALIASDLEN;
84 * +-------------------------------+ contains `char's
86 * For requests the size of the h_aliases, and h_addr_list pointer
87 * array sizes are set to MAXALISES and MAXADDRS respectively, and
88 * buf is a fixed size with enough space to hold the largest expected
89 * reply from a nameserver, see RFC 1034 and RFC 1035.
90 * For cached entries the sizes are dependent on the actual number
91 * of aliases and addresses. If new aliases and addresses are found
92 * for cached entries, the buffer is grown and the new entries are added.
93 * The hostent struct is filled in with the addresses of the entries in
94 * the Hostent buf as follows:
95 * h_name - contains a pointer to the start of the hostname string area,
96 * or NULL if none is set. The h_name is followed by the
97 * aliases, in the storage for hostname strings area.
98 * h_aliases - contains a pointer to the start of h_aliases pointer array.
99 * This array contains pointers to the storage for hostname
100 * strings area and is terminated with a NULL. The first alias
101 * is stored directly after the h_name.
102 * h_addr_list - contains a pointer to the start of h_addr_list pointer array.
103 * This array contains pointers to in_addr structures in the
104 * h_addr_list addresses area and is terminated with a NULL.
106 * Filling the buffer this way allows for proper alignment of the h_addr_list
109 * This arrangement allows us to alias a Hostent struct pointer as a
110 * real struct hostent* without lying. It also allows us to change the
111 * values contained in the cached entries and requests without changing
112 * the actual hostent pointer, which is saved in a client struct and can't
113 * be changed without blowing things up or a lot more fiddling around.
114 * It also allows for defered allocation of the fixed size buffers until
115 * they are really needed.
116 * Nov. 17, 1997 --Bleep
119 typedef struct Hostent {
124 typedef struct reslist {
126 int sent; /* number of requests sent */
130 char retries; /* retry counter */
131 char sends; /* number of sends (>1 means resent) */
132 char resend; /* send flag. 0 == dont resend */
137 struct reslist *next;
142 typedef struct cache {
146 struct cache *hname_next, *hnum_next, *list_next;
149 typedef struct cachetable {
154 extern int resfd; /* defined in s_bsd.c */
156 static char hostbuf[HOSTLEN + 1];
157 static char dot[] = ".";
158 static int incache = 0;
159 static CacheTable hashtable[ARES_CACSIZE];
160 static aCache *cachetop = NULL;
161 static ResRQ *last, *first;
163 static void rem_cache(aCache *);
164 static void rem_request(ResRQ *);
165 static int do_query_name(Link *, char *, ResRQ *);
166 static int do_query_number(Link *, struct in_addr *, ResRQ *);
167 static void resend_query(ResRQ *);
168 static int proc_answer(ResRQ *, HEADER *, unsigned char *, unsigned char *);
169 static int query_name(char *, int, int, ResRQ *);
170 static aCache *make_cache(ResRQ *);
171 static aCache *find_cache_name(char *);
172 static aCache *find_cache_number(ResRQ *, struct in_addr *);
173 static int add_request(ResRQ *);
174 static ResRQ *make_request(Link *);
175 static int send_res_msg(char *, int, int);
176 static ResRQ *find_id(int);
177 static int hash_number(unsigned char *);
178 static void update_list(ResRQ *, aCache *);
179 static int hash_name(const char *);
181 static struct cacheinfo {
191 static struct resinfo {
204 int init_resolver(void)
209 memset(&reinfo, 0, sizeof(reinfo));
210 memset(&cainfo, 0, sizeof(cainfo));
211 memset(hashtable, 0, sizeof(hashtable));
215 /* res_init() always returns 0 */
221 _res.nsaddr_list[0].sin_addr.s_addr = inet_addr("127.0.0.1");
224 _res.options |= RES_DEBUG;
228 fd = socket(AF_INET, SOCK_DGRAM, 0);
232 if (errno == EMFILE || errno == ENOBUFS)
235 * Only try this one more time, if we can't create the resolver
236 * socket at initialization time, it's pointless to continue.
239 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
242 Debug((DEBUG_ERROR, "init_resolver: socket: No more sockets"));
249 Debug((DEBUG_ERROR, "init_resolver: socket: %s", strerror(errno)));
253 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (OPT_TYPE *)&on, sizeof(on));
257 static int add_request(ResRQ *new_request)
262 first = last = new_request;
265 last->next = new_request;
268 new_request->next = NULL;
269 reinfo.re_requests++;
274 * Remove a request from the list. This must also free any memory that has
275 * been allocated for temporary storage of DNS results.
277 static void rem_request(ResRQ *old_request)
284 for (rptr = &first; *rptr; r2ptr = *rptr, rptr = &(*rptr)->next)
286 if (*rptr == old_request)
288 *rptr = old_request->next;
289 if (last == old_request)
294 Debug((DEBUG_DNS, "rem_request:Remove %p at %p %p",
295 old_request, *rptr, r2ptr));
297 if (old_request->he.buf)
298 RunFree(old_request->he.buf);
299 if (old_request->name)
300 RunFree(old_request->name);
301 RunFree(old_request);
306 * Create a DNS request record for the server.
308 static ResRQ *make_request(Link *lp)
312 if ((nreq = (ResRQ *)RunMalloc(sizeof(ResRQ))) == NULL)
314 memset(nreq, 0, sizeof(ResRQ));
320 memcpy(&nreq->cinfo, lp, sizeof(Link));
322 memset(&nreq->cinfo, 0, sizeof(Link));
323 nreq->timeout = 4; /* start at 4 and exponential inc. */
324 nreq->addr.s_addr = INADDR_NONE;
326 nreq->he.h.h_addrtype = AF_INET;
327 nreq->he.h.h_length = sizeof(struct in_addr);
333 * Remove queries from the list which have been there too long without
336 time_t timeout_query_list(void)
344 Debug((DEBUG_DNS, "timeout_query_list at %s", myctime(now)));
345 for (rptr = first; rptr; rptr = r2ptr)
348 tout = rptr->sentat + rptr->timeout;
351 if (--rptr->retries <= 0)
353 Debug((DEBUG_DNS, "timeout %p now " TIME_T_FMT " cptr %p",
354 rptr, now, rptr->cinfo.value.cptr));
355 reinfo.re_timeouts++;
356 cptr = rptr->cinfo.value.cptr;
357 switch (rptr->cinfo.flags)
361 if (!DoingAuth(cptr))
365 sendto_ops("Host %s unknown", rptr->name);
369 sendto_ops("Host %s unknown", rptr->name);
379 rptr->timeout += rptr->timeout;
381 tout = now + rptr->timeout;
382 Debug((DEBUG_DNS, "r %p now " TIME_T_FMT " retry %d c %p",
383 rptr, now, rptr->retries, rptr->cinfo.value.cptr));
386 if (!next || tout < next)
389 Debug((DEBUG_DNS, "Next timeout_query_list() at %s, %ld",
390 myctime((next > now) ? next : (now + AR_TTL)),
391 (next > now) ? (next - now) : AR_TTL));
392 return (next > now) ? next : (now + AR_TTL);
398 * Called by the server to cleanup outstanding queries for
399 * which there no longer exist clients or conf lines.
401 void del_queries(char *cp)
405 for (rptr = first; rptr; rptr = r2ptr)
408 if (cp == rptr->cinfo.value.cp)
416 * sends msg to all nameservers found in the "_res" structure.
417 * This should reflect /etc/resolv.conf. We will get responses
418 * which arent needed but is easier than checking to see if nameserver
419 * isnt present. Returns number of messages successfully sent to
420 * nameservers or -1 if no successful sends.
422 static int send_res_msg(char *msg, int len, int rcount)
430 max = MIN(_res.nscount, rcount);
431 if (_res.options & RES_PRIMARY)
436 for (i = 0; i < max; ++i)
438 _res.nsaddr_list[i].sin_family = AF_INET;
439 if (sendto(resfd, msg, len, 0, (struct sockaddr *)&(_res.nsaddr_list[i]),
440 sizeof(struct sockaddr)) == len)
446 Debug((DEBUG_ERROR, "s_r_m:sendto: %s on %d", strerror(errno), resfd));
448 return (sent) ? sent : -1;
452 * find a dns request id (id is determined by dn_mkquery)
454 static ResRQ *find_id(int id)
458 for (rptr = first; rptr; rptr = rptr->next)
467 * Add the domain to hostname, if it is missing
468 * (as suggested by eps@TOASTER.SFSU.EDU)
470 void add_local_domain(char *hname, int size)
472 /* try to fix up unqualified names */
473 if (!strchr(hname, '.'))
475 if (_res.defdname[0] && size > 0)
478 strncat(hname, _res.defdname, size - 1);
483 struct hostent *gethost_byname(char *name, Link *lp)
488 if ((cp = find_cache_name(name)))
491 do_query_name(lp, name, NULL);
495 struct hostent *gethost_byaddr(struct in_addr *addr, Link *lp)
500 if ((cp = find_cache_number(NULL, addr)))
504 do_query_number(lp, addr, NULL);
508 static int do_query_name(Link *lp, char *name, ResRQ *rptr)
510 char hname[HOSTLEN + 1];
513 strncpy(hname, name, sizeof(hname) - 1);
514 hname[sizeof(hname) - 1] = 0;
517 if (rptr && !strchr(hname, '.') && _res.options & RES_DEFNAMES)
519 strncat(hname, dot, sizeof(hname) - len - 1);
521 strncat(hname, _res.defdname, sizeof(hname) - len - 1);
525 * Store the name passed as the one to lookup and generate other host
526 * names to pass onto the nameserver(s) for lookups.
530 if ((rptr = make_request(lp)) == NULL)
533 rptr->name = (char *)RunMalloc(strlen(name) + 1);
534 strcpy(rptr->name, name);
536 return (query_name(hname, C_IN, T_A, rptr));
540 * Use this to do reverse IP# lookups.
542 static int do_query_number(Link *lp, struct in_addr *numb, ResRQ *rptr)
545 Reg2 unsigned char *cp = (unsigned char *)&numb->s_addr;
547 sprintf_irc(ipbuf, "%u.%u.%u.%u.in-addr.arpa.",
548 (unsigned int)(cp[3]), (unsigned int)(cp[2]),
549 (unsigned int)(cp[1]), (unsigned int)(cp[0]));
553 if ((rptr = make_request(lp)) == NULL)
556 rptr->addr.s_addr = numb->s_addr;
558 return (query_name(ipbuf, C_IN, T_PTR, rptr));
562 * generate a query based on class, type and name.
564 static int query_name(char *name, int q_class, int type, ResRQ *rptr)
571 Debug((DEBUG_DNS, "query_name: na %s cl %d ty %d", name, q_class, type));
572 memset(buf, 0, sizeof(buf));
573 r = res_mkquery(QUERY, name, q_class, type, NULL, 0, NULL,
574 (unsigned char *)buf, sizeof(buf));
577 h_errno = NO_RECOVERY;
580 hptr = (HEADER *) buf;
581 gettimeofday(&tv, NULL);
584 /* htons/ntohs can be assembler macros, which cannot
585 be nested. Thus two lines. -Vesa */
586 unsigned short int nstmp = ntohs(hptr->id) + k
587 + (unsigned short int)(tv.tv_usec & 0xffff);
588 hptr->id = htons(nstmp);
591 while (find_id(ntohs(hptr->id)));
592 rptr->id = ntohs(hptr->id);
594 s = send_res_msg(buf, r, rptr->sends);
605 static void resend_query(ResRQ *rptr)
607 if (rptr->resend == 0)
613 do_query_number(NULL, &rptr->addr, rptr);
616 do_query_name(NULL, rptr->name, rptr);
627 * Process name server reply.
629 static int proc_answer(ResRQ *rptr, HEADER * hptr, unsigned char *buf,
632 unsigned char *cp = buf + sizeof(HEADER);
635 char *p; /* pointer to strings */
636 char *a; /* pointer to address list */
637 char *endp; /* end of our buffer */
638 struct hostent *hp = &rptr->he.h;
639 int addr_class, type, dlen, ans = 0, n;
644 * Lazy allocation of rptr->he.buf, we don't allocate a buffer
645 * unless there's something to put in it.
649 if ((rptr->he.buf = (char *)RunMalloc(MAXGETHOSTLEN)) == NULL)
652 * Array of alias list pointers starts at beginning of buf
654 rptr->he.h.h_aliases = (char **)rptr->he.buf;
655 rptr->he.h.h_aliases[0] = NULL;
657 * Array of address list pointers starts after alias list pointers.
658 * The actual addresses follow the address list pointers.
660 rptr->he.h.h_addr_list = (char **)(rptr->he.buf + ALIASBLEN);
661 a = (char *)rptr->he.h.h_addr_list + ADDRSBLEN;
663 * don't copy the host address to the beginning of h_addr_list
664 * make it just a little bit harder for the script kiddies
666 rptr->he.h.h_addr_list[0] = NULL;
668 endp = &rptr->he.buf[MAXGETHOSTLEN];
670 /* find the end of the address list */
671 addr = hp->h_addr_list;
677 /* make 'a' point to the first available empty address slot */
678 a = (char *)hp->h_addr_list + ADDRSBLEN +
679 (addr_count * sizeof(struct in_addr));
681 /* find the end of the alias list */
682 alias = hp->h_aliases;
688 /* make p point to the first available space in rptr->buf */
691 p = (char *)hp->h_aliases[alias_count - 1];
692 p += (strlen(p) + 1);
695 p = (char *)(hp->h_name + strlen(hp->h_name) + 1);
697 p = (char *)rptr->he.h.h_addr_list + ADDRSBLEN + ADDRSDLEN;
702 #ifdef SOL2 /* brain damaged compiler (Solaris2) it seems */
703 for (; hptr->qdcount > 0; hptr->qdcount--)
705 while (hptr->qdcount-- > 0)
708 if ((n = dn_skipname(cp, eob)) == -1)
711 cp += (n + QFIXEDSZ);
714 * Proccess each answer sent to us blech.
716 while (hptr->ancount-- > 0 && cp && cp < eob && p < endp)
718 if ((n = dn_expand(buf, eob, cp, hostbuf, sizeof(hostbuf))) <= 0)
720 Debug((DEBUG_DNS, "dn_expand failed"));
725 /* XXX magic numbers, this checks for truncated packets */
726 if ((cp + INT16SZ + INT16SZ + INT32SZ + INT16SZ) >= eob)
730 * I have no idea why - maybe a bug in the linker? But _getshort
731 * and _getlong don't work anymore. So lets do it ourselfs:
735 type = ((u_int16_t) cp[0] << 8) | ((u_int16_t) cp[1]);
737 addr_class = ((u_int16_t) cp[0] << 8) | ((u_int16_t) cp[1]);
740 ((u_int32_t) cp[0] << 24) | ((u_int32_t) cp[1] << 16) | ((u_int32_t)
741 cp[2] << 8) | ((u_int32_t) cp[3]);
743 dlen = ((u_int16_t) cp[0] << 8) | ((u_int16_t) cp[1]);
748 /* check for bad dlen */
749 if ((cp + dlen) > eob)
753 * Add default domain name to returned host name if host name
754 * doesn't contain any dot separators.
755 * Name server never returns with trailing '.'
757 if (!strchr(hostbuf, '.') && (_res.options & RES_DEFNAMES))
759 strcat(hostbuf, dot);
760 strncat(hostbuf, _res.defdname, HOSTLEN - strlen(hostbuf));
761 hostbuf[HOSTLEN] = 0;
767 /* check for invalid dlen or too many addresses */
768 if (dlen != sizeof(struct in_addr) || ++addr_count >= RES_MAXADDRS)
771 hp->h_addrtype = (addr_class == C_IN) ? AF_INET : AF_UNSPEC;
773 memcpy(a, cp, sizeof(struct in_addr));
776 a += sizeof(struct in_addr);
780 strncpy(p, hostbuf, endp - p);
782 p += (strlen(p) + 1);
785 Debug((DEBUG_DNS, "got ip # %s for %s",
786 inetntoa(*((struct in_addr *)hp->h_addr_list[addr_count - 1])),
791 if ((n = dn_expand(buf, eob, cp, hostbuf, sizeof(hostbuf))) < 0)
797 Debug((DEBUG_DNS, "got host %s", hostbuf));
799 * Copy the returned hostname into the host name or alias field if
800 * there is a known hostname already.
804 if (++alias_count >= RES_MAXALIASES)
806 strncpy(p, hostbuf, endp - p);
813 strncpy(p, hostbuf, endp - p);
816 p += (strlen(p) + 1);
821 Debug((DEBUG_DNS, "got cname %s", hostbuf));
822 if (++alias_count >= RES_MAXALIASES)
824 strncpy(p, hostbuf, endp - p);
828 p += (strlen(p) + 1);
832 Debug((DEBUG_DNS, "proc_answer: type:%d for:%s", type, hostbuf));
840 * Read a dns reply from the nameserver and process it.
842 struct hostent *get_res(char *lp)
844 static unsigned char buf[sizeof(HEADER) + MAXPACKET];
846 Reg2 ResRQ *rptr = NULL;
848 struct sockaddr_in sin;
850 size_t rc, len = sizeof(sin);
853 rc = recvfrom(resfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &len);
856 if (rc <= sizeof(HEADER))
859 * Convert DNS reply reader from Network byte order to CPU byte order.
861 hptr = (HEADER *) buf;
862 hptr->id = ntohs(hptr->id);
863 hptr->ancount = ntohs(hptr->ancount);
864 hptr->qdcount = ntohs(hptr->qdcount);
865 hptr->nscount = ntohs(hptr->nscount);
866 hptr->arcount = ntohs(hptr->arcount);
868 Debug((DEBUG_NOTICE, "get_res:id = %d rcode = %d ancount = %d",
869 hptr->id, hptr->rcode, hptr->ancount));
873 * Response for an id which we have already received an answer for
874 * just ignore this response.
876 if ((rptr = find_id(hptr->id)) == NULL)
878 Debug((DEBUG_DNS, "find_id %d failed", hptr->id));
882 * Check against possibly fake replies
884 max = MIN(_res.nscount, rptr->sends);
888 for (a = 0; a < max; a++)
890 if (!_res.nsaddr_list[a].sin_addr.s_addr ||
891 !memcmp((char *)&sin.sin_addr, (char *)&_res.nsaddr_list[a].sin_addr,
892 sizeof(struct in_addr)))
898 Debug((DEBUG_DNS, "got response from unknown ns"));
902 if ((hptr->rcode != NOERROR) || (hptr->ancount == 0))
919 h_errno = NO_RECOVERY;
924 * If a bad error was returned, we stop here and dont send
925 * send any more (no retries granted).
927 if (h_errno != TRY_AGAIN)
929 Debug((DEBUG_DNS, "Fatal DNS error %d for %d", h_errno, hptr->rcode));
936 * If this fails we didn't get a buffer to hold the hostent or
937 * there was an error decoding the received packet, try it again
938 * and hope it works the next time.
940 a = proc_answer(rptr, hptr, buf, &buf[rc]);
941 Debug((DEBUG_DNS, "get_res:Proc answer = %d", a));
943 if (a && rptr->type == T_PTR)
945 struct hostent *hp2 = NULL;
947 if (BadPtr(rptr->he.h.h_name)) /* Kludge! 960907/Vesa */
950 Debug((DEBUG_DNS, "relookup %s <-> %s", rptr->he.h.h_name,
951 inetntoa(rptr->addr)));
953 * Lookup the 'authoritive' name that we were given for the
954 * ip#. By using this call rather than regenerating the
955 * type we automatically gain the use of the cache with no
958 if ((hp2 = gethost_byname((char *)rptr->he.h.h_name, &rptr->cinfo)))
961 memcpy(lp, &rptr->cinfo, sizeof(Link));
964 * If name wasn't found, a request has been queued and it will
965 * be the last one queued. This is rather nasty way to keep
966 * a host alias with the query. -avalon
968 else if (*rptr->he.h.h_aliases)
971 RunFree(last->he.buf);
972 last->he.buf = rptr->he.buf;
974 memcpy(&last->he.h, &rptr->he.h, sizeof(struct hostent));
983 memcpy(lp, &rptr->cinfo, sizeof(Link));
984 cp = make_cache(rptr);
985 Debug((DEBUG_DNS, "get_res:cp=%p rptr=%p (made)", cp, rptr));
988 else if (!rptr->sent)
990 return cp ? &cp->he.h : NULL;
994 * Reprocess an error if the nameserver didnt tell us to "TRY_AGAIN".
998 if (h_errno != TRY_AGAIN)
1001 * If we havent tried with the default domain and its
1002 * set, then give it a try next.
1004 if (_res.options & RES_DEFNAMES && ++rptr->srch == 0)
1006 rptr->retries = _res.retry;
1015 memcpy(lp, &rptr->cinfo, sizeof(Link));
1021 * Duplicate a hostent struct, allocate only enough memory for
1022 * the data we're putting in it.
1024 static int dup_hostent(aHostent *new_hp, struct hostent *hp)
1029 int alias_count = 0;
1031 size_t bytes_needed = 0;
1036 /* how much buffer do we need? */
1037 bytes_needed += (strlen(hp->h_name) + 1);
1042 bytes_needed += (strlen(*pp++) + 1 + sizeof(void *));
1045 pp = hp->h_addr_list;
1048 bytes_needed += (hp->h_length + sizeof(void *));
1051 /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
1052 bytes_needed += (2 * sizeof(void *));
1054 /* Allocate memory */
1055 if ((new_hp->buf = (char *)RunMalloc(bytes_needed)) == NULL)
1058 new_hp->h.h_addrtype = hp->h_addrtype;
1059 new_hp->h.h_length = hp->h_length;
1061 /* first write the address list */
1062 pp = hp->h_addr_list;
1063 ap = new_hp->h.h_addr_list =
1064 (char **)(new_hp->buf + ((alias_count + 1) * sizeof(void *)));
1065 p = (char *)ap + ((addr_count + 1) * sizeof(void *));
1069 memcpy(p, *pp++, hp->h_length);
1073 /* next write the name */
1074 new_hp->h.h_name = p;
1075 strcpy(p, hp->h_name);
1076 p += (strlen(p) + 1);
1078 /* last write the alias list */
1080 ap = new_hp->h.h_aliases = (char **)new_hp->buf;
1085 p += (strlen(p) + 1);
1093 * Add records to a Hostent struct in place.
1095 static int update_hostent(aHostent *hp, char **addr, char **alias)
1100 int alias_count = 0;
1103 size_t bytes_needed = 0;
1105 if (!hp || !hp->buf)
1108 /* how much buffer do we need? */
1109 bytes_needed = strlen(hp->h.h_name) + 1;
1110 pp = hp->h.h_aliases;
1113 bytes_needed += (strlen(*pp++) + 1 + sizeof(void *));
1121 bytes_needed += (strlen(*pp++) + 1 + sizeof(void *));
1125 pp = hp->h.h_addr_list;
1128 bytes_needed += (hp->h.h_length + sizeof(void *));
1136 bytes_needed += (hp->h.h_length + sizeof(void *));
1140 /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
1141 bytes_needed += 2 * sizeof(void *);
1143 /* Allocate memory */
1144 if ((buf = (char *)RunMalloc(bytes_needed)) == NULL)
1147 /* first write the address list */
1148 pp = hp->h.h_addr_list;
1149 ap = hp->h.h_addr_list =
1150 (char **)(buf + ((alias_count + 1) * sizeof(void *)));
1151 p = (char *)ap + ((addr_count + 1) * sizeof(void *));
1154 memcpy(p, *pp++, hp->h.h_length);
1156 p += hp->h.h_length;
1162 memcpy(p, *addr++, hp->h.h_length);
1164 p += hp->h.h_length;
1169 /* next write the name */
1170 strcpy(p, hp->h.h_name);
1172 p += (strlen(p) + 1);
1174 /* last write the alias list */
1175 pp = hp->h.h_aliases;
1176 ap = hp->h.h_aliases = (char **)buf;
1181 p += (strlen(p) + 1);
1187 strcpy(p, *alias++);
1189 p += (strlen(p) + 1);
1193 /* release the old buffer */
1200 static int hash_number(unsigned char *ip)
1202 unsigned int hashv = 0;
1204 /* could use loop but slower */
1205 hashv += (int)*ip++;
1206 hashv += hashv + (int)*ip++;
1207 hashv += hashv + (int)*ip++;
1208 hashv += hashv + (int)*ip++;
1209 hashv %= ARES_CACSIZE;
1213 static int hash_name(const char *name)
1215 unsigned int hashv = 0;
1217 for (; *name && *name != '.'; name++)
1219 hashv %= ARES_CACSIZE;
1224 * Add a new cache item to the queue and hash table.
1226 static aCache *add_to_cache(aCache *ocp)
1232 "add_to_cache:ocp %p he %p name %p addrl %p 0 %p",
1233 ocp, &ocp->he, ocp->he.h.h_name, ocp->he.h.h_addr_list,
1234 ocp->he.h.h_addr_list[0]));
1236 ocp->list_next = cachetop;
1239 hashv = hash_name(ocp->he.h.h_name);
1240 ocp->hname_next = hashtable[hashv].name_list;
1241 hashtable[hashv].name_list = ocp;
1243 hashv = hash_number((unsigned char *)ocp->he.h.h_addr_list[0]);
1244 ocp->hnum_next = hashtable[hashv].num_list;
1245 hashtable[hashv].num_list = ocp;
1247 Debug((DEBUG_DNS, "add_to_cache:added %s[%p] cache %p.",
1248 ocp->he.h.h_name, ocp->he.h.h_addr_list[0], ocp));
1250 "add_to_cache:h1 %d h2 %#x lnext %p namnext %p numnext %p",
1251 hash_name(ocp->he.h.h_name), hashv, ocp->list_next,
1252 ocp->hname_next, ocp->hnum_next));
1255 * LRU deletion of excessive cache entries.
1257 if (++incache > MAXCACHED)
1259 for (cp = cachetop; cp->list_next; cp = cp->list_next);
1270 * Does not alter the cache structure passed. It is assumed that
1271 * it already contains the correct expire time, if it is a new entry. Old
1272 * entries have the expirey time updated.
1274 static void update_list(ResRQ *rptr, aCache *cp)
1281 static char *addrs[RES_MAXADDRS + 1];
1282 static char *aliases[RES_MAXALIASES + 1];
1285 * Search for the new cache item in the cache list by hostname.
1286 * If found, move the entry to the top of the list and return.
1288 cainfo.ca_updates++;
1290 for (cpp = &cachetop; *cpp; cpp = &((*cpp)->list_next))
1297 *cpp = cp->list_next;
1298 cp->list_next = cachetop;
1303 Debug((DEBUG_DNS, "u_l:cp %p na %p al %p ad %p",
1304 cp, cp->he.h.h_name, cp->he.h.h_aliases, cp->he.h.h_addr_list[0]));
1305 Debug((DEBUG_DNS, "u_l:rptr %p h_n %p", rptr, rptr->he.h.h_name));
1307 * Compare the cache entry against the new record. Add any
1308 * previously missing names for this entry.
1313 for (i = 0, s = (char *)rptr->he.h.h_name; s; s = rptr->he.h.h_aliases[i++])
1315 for (j = 0, t = cp->he.h.h_name; t; t = cp->he.h.h_aliases[j++])
1317 if (!strCasediff(t, s))
1328 * Do the same again for IP#'s.
1332 for (i = 0; (s = rptr->he.h.h_addr_list[i]); i++)
1334 for (j = 0; (t = cp->he.h.h_addr_list[j]); j++)
1336 if (!memcmp(t, s, sizeof(struct in_addr)))
1345 if (*addrs || *aliases)
1346 update_hostent(&cp->he, addrs, aliases);
1349 static aCache *find_cache_name(char *name)
1356 hashv = hash_name(name);
1358 cp = hashtable[hashv].name_list;
1359 Debug((DEBUG_DNS, "find_cache_name:find %s : hashv = %d", name, hashv));
1361 for (; cp; cp = cp->hname_next)
1363 for (i = 0, s = cp->he.h.h_name; s; s = cp->he.h.h_aliases[i++])
1365 if (strCasediff(s, name) == 0)
1367 cainfo.ca_na_hits++;
1374 for (cp = cachetop; cp; cp = cp->list_next)
1377 * If no aliases or the hash value matches, we've already
1378 * done this entry and all possiblilities concerning it.
1380 if (!*cp->he.h.h_aliases)
1382 if (hashv == hash_name(cp->he.h.h_name))
1384 for (i = 0; (s = cp->he.h.h_aliases[i]); ++i)
1386 if (!strCasediff(name, s))
1388 cainfo.ca_na_hits++;
1398 * Find a cache entry by ip# and update its expire time
1400 static aCache *find_cache_number(ResRQ *rptr, struct in_addr *numb)
1405 hashv = hash_number((unsigned char *)numb);
1407 cp = hashtable[hashv].num_list;
1408 Debug((DEBUG_DNS, "find_cache_number:find %s[%08x]: hashv = %d",
1409 inetntoa(*numb), ntohl(numb->s_addr), hashv));
1411 for (; cp; cp = cp->hnum_next)
1413 for (i = 0; cp->he.h.h_addr_list[i]; ++i)
1415 if (!memcmp(cp->he.h.h_addr_list[i], (char *)numb,
1416 sizeof(struct in_addr)))
1418 cainfo.ca_nu_hits++;
1419 update_list(rptr, cp);
1425 for (cp = cachetop; cp; cp = cp->list_next)
1428 * Single address entry...would have been done by hashed search above...
1430 if (!cp->he.h.h_addr_list[1])
1433 * If the first IP# has the same hashnumber as the IP# we
1434 * are looking for, its been done already.
1436 if (hashv == hash_number((unsigned char *)cp->he.h.h_addr_list[0]))
1438 for (i = 1; cp->he.h.h_addr_list[i]; ++i)
1440 if (!memcmp(cp->he.h.h_addr_list[i], (char *)numb,
1441 sizeof(struct in_addr)))
1443 cainfo.ca_nu_hits++;
1444 update_list(rptr, cp);
1452 static aCache *make_cache(ResRQ *rptr)
1456 struct hostent *hp = &rptr->he.h;
1459 * Shouldn't happen but it just might...
1461 if (!hp->h_name || !hp->h_addr_list[0])
1464 * Make cache entry. First check to see if the cache already exists
1465 * and if so, return a pointer to it.
1467 for (i = 0; hp->h_addr_list[i]; ++i)
1469 if ((cp = find_cache_number(rptr, (struct in_addr *)hp->h_addr_list[i])))
1474 * A matching entry wasnt found in the cache so go and make one up.
1476 if ((cp = (aCache *)RunMalloc(sizeof(aCache))) == NULL)
1478 memset(cp, 0, sizeof(aCache));
1479 dup_hostent(&cp->he, hp);
1481 if (rptr->ttl < 600)
1483 reinfo.re_shortttl++;
1487 cp->ttl = rptr->ttl;
1488 cp->expireat = now + cp->ttl;
1489 Debug((DEBUG_INFO, "make_cache:made cache %p", cp));
1490 return add_to_cache(cp);
1496 * Delete a cache entry from the cache structures and lists and return
1497 * all memory used for the cache back to the memory pool.
1499 static void rem_cache(aCache *ocp)
1502 struct hostent *hp = &ocp->he.h;
1506 Debug((DEBUG_DNS, "rem_cache: ocp %p hp %p l_n %p aliases %p",
1507 ocp, hp, ocp->list_next, hp->h_aliases));
1510 * Cleanup any references to this structure by destroying the pointer.
1512 for (hashv = highest_fd; hashv >= 0; --hashv)
1514 if ((cptr = loc_clients[hashv]) && (cptr->hostp == hp))
1518 * Remove cache entry from linked list.
1520 for (cp = &cachetop; *cp; cp = &((*cp)->list_next))
1524 *cp = ocp->list_next;
1529 * Remove cache entry from hashed name lists.
1531 hashv = hash_name(hp->h_name);
1533 Debug((DEBUG_DNS, "rem_cache: h_name %s hashv %d next %p first %p",
1534 hp->h_name, hashv, ocp->hname_next, hashtable[hashv].name_list));
1536 for (cp = &hashtable[hashv].name_list; *cp; cp = &((*cp)->hname_next))
1540 *cp = ocp->hname_next;
1545 * Remove cache entry from hashed number list
1547 hashv = hash_number((unsigned char *)hp->h_addr_list[0]);
1549 Debug((DEBUG_DNS, "rem_cache: h_addr %s hashv %d next %p first %p",
1550 inetntoa(*((struct in_addr *)hp->h_addr_list[0])), hashv,
1551 ocp->hnum_next, hashtable[hashv].num_list));
1552 for (cp = &hashtable[hashv].num_list; *cp; cp = &((*cp)->hnum_next))
1556 *cp = ocp->hnum_next;
1562 RunFree(ocp->he.buf);
1563 RunFree((char *)ocp);
1570 * Removes entries from the cache which are older than their expirey times.
1571 * returns the time at which the server should next poll the cache.
1573 time_t expire_cache(void)
1575 Reg1 aCache *cp, *cp2;
1576 Reg2 time_t next = 0;
1578 for (cp = cachetop; cp; cp = cp2)
1580 cp2 = cp->list_next;
1582 if (now >= cp->expireat)
1584 cainfo.ca_expires++;
1587 else if (!next || next > cp->expireat)
1588 next = cp->expireat;
1590 return (next > now) ? next : (now + AR_TTL);
1594 * Remove all dns cache entries.
1596 void flush_cache(void)
1600 while ((cp = cachetop))
1604 int m_dns(aClient *cptr, aClient *sptr, int UNUSED(parc), char *parv[])
1610 if (parv[1] && *parv[1] == 'l')
1612 if (!IsAnOper(cptr))
1616 for (cp = cachetop; cp; cp = cp->list_next)
1619 sendto_one(sptr, "NOTICE %s :Ex %d ttl %d host %s(%s)",
1620 parv[0], (int)(cp->expireat - now), (int)cp->ttl,
1621 h->h_name, inetntoa(*((struct in_addr *)h->h_addr_list[0])));
1622 for (i = 0; h->h_aliases[i]; i++)
1623 sendto_one(sptr, "NOTICE %s : %s = %s (CN)",
1624 parv[0], h->h_name, h->h_aliases[i]);
1625 for (i = 1; h->h_addr_list[i]; i++)
1626 sendto_one(sptr, "NOTICE %s : %s = %s (IP)", parv[0],
1627 h->h_name, inetntoa(*((struct in_addr *)h->h_addr_list[i])));
1631 sendto_one(sptr, "NOTICE %s :Ca %d Cd %d Ce %d Cl %d Ch %d:%d Cu %d",
1632 sptr->name, cainfo.ca_adds, cainfo.ca_dels, cainfo.ca_expires,
1633 cainfo.ca_lookups, cainfo.ca_na_hits, cainfo.ca_nu_hits,
1635 sendto_one(sptr, "NOTICE %s :Re %d Rl %d/%d Rp %d Rq %d",
1636 sptr->name, reinfo.re_errors, reinfo.re_nu_look,
1637 reinfo.re_na_look, reinfo.re_replies, reinfo.re_requests);
1638 sendto_one(sptr, "NOTICE %s :Ru %d Rsh %d Rs %d(%d) Rt %d", sptr->name,
1639 reinfo.re_unkrep, reinfo.re_shortttl, reinfo.re_sent,
1640 reinfo.re_resends, reinfo.re_timeouts);
1644 size_t cres_mem(aClient *sptr)
1646 aCache *c = cachetop;
1649 size_t nm = 0, im = 0, sm = 0, ts = 0;
1651 for (; c; c = c->list_next)
1655 for (i = 0; h->h_addr_list[i]; i++)
1657 im += sizeof(char *);
1658 im += sizeof(struct in_addr);
1660 im += sizeof(char *);
1661 for (i = 0; h->h_aliases[i]; i++)
1663 nm += sizeof(char *);
1664 nm += strlen(h->h_aliases[i]);
1667 nm += sizeof(char *);
1669 nm += strlen(h->h_name);
1671 ts = ARES_CACSIZE * sizeof(CacheTable);
1672 sendto_one(sptr, ":%s %d %s :RES table " SIZE_T_FMT,
1673 me.name, RPL_STATSDEBUG, sptr->name, ts);
1674 sendto_one(sptr, ":%s %d %s :Structs " SIZE_T_FMT
1675 " IP storage " SIZE_T_FMT " Name storage " SIZE_T_FMT,
1676 me.name, RPL_STATSDEBUG, sptr->name, sm, im, nm);
1677 return ts + sm + im + nm;