Blame src/Resolver.cc

Packit 8f70b4
/*
Packit 8f70b4
 * lftp - file transfer program
Packit 8f70b4
 *
Packit 8f70b4
 * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net)
Packit 8f70b4
 *
Packit 8f70b4
 * This program is free software; you can redistribute it and/or modify
Packit 8f70b4
 * it under the terms of the GNU General Public License as published by
Packit 8f70b4
 * the Free Software Foundation; either version 3 of the License, or
Packit 8f70b4
 * (at your option) any later version.
Packit 8f70b4
 *
Packit 8f70b4
 * This program is distributed in the hope that it will be useful,
Packit 8f70b4
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8f70b4
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8f70b4
 * GNU General Public License for more details.
Packit 8f70b4
 *
Packit 8f70b4
 * You should have received a copy of the GNU General Public License
Packit 8f70b4
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 8f70b4
 */
Packit 8f70b4
Packit 8f70b4
#include <config.h>
Packit 8f70b4
Packit 8f70b4
#include <stddef.h>
Packit 8f70b4
#include "Resolver.h"
Packit 8f70b4
#include "SignalHook.h"
Packit 8f70b4
#include <errno.h>
Packit 8f70b4
#include <unistd.h>
Packit 8f70b4
#include "trio.h"
Packit 8f70b4
#include <time.h>
Packit 8f70b4
#include <sys/types.h>
Packit 8f70b4
#include <sys/socket.h>
Packit 8f70b4
#include <netdb.h>
Packit 8f70b4
#include <ctype.h>
Packit 8f70b4
#include <fcntl.h>
Packit 8f70b4
Packit 8f70b4
#include <netinet/in.h>
Packit 8f70b4
#ifdef HAVE_ARPA_NAMESER_H
Packit 8f70b4
# define class _class // workaround for FreeBSD 3.2.
Packit 8f70b4
# include <arpa/nameser.h>
Packit 8f70b4
# undef class
Packit 8f70b4
#endif
Packit 8f70b4
#ifdef HAVE_RESOLV_H
Packit 8f70b4
# include <resolv.h>
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#if LIBIDN2
Packit 8f70b4
# include <idn2.h>
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#ifdef DNSSEC_LOCAL_VALIDATION
Packit 8f70b4
# include "validator/validator.h"
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#include "xstring.h"
Packit 8f70b4
#include "ResMgr.h"
Packit 8f70b4
#include "log.h"
Packit 8f70b4
#include "plural.h"
Packit 8f70b4
Packit 8f70b4
#ifndef C_IN
Packit 8f70b4
# define C_IN 1
Packit 8f70b4
#endif
Packit 8f70b4
#ifndef T_SRV
Packit 8f70b4
# define T_SRV 33
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#if !HAVE_DECL_HSTRERROR
Packit 8f70b4
extern "C" { const char *hstrerror(int); }
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#ifdef HAVE_H_ERRNO
Packit 8f70b4
#if !HAVE_DECL_H_ERRNO
Packit 8f70b4
CDECL int h_errno;
Packit 8f70b4
#endif
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#if HAVE_RES_SEARCH && !HAVE_DECL_RES_SEARCH
Packit 8f70b4
CDECL int res_search(const char*,int,int,unsigned char*,int);
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#if INET6
Packit 8f70b4
# define DEFAULT_ORDER "inet inet6"
Packit 8f70b4
#else
Packit 8f70b4
# define DEFAULT_ORDER "inet"
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
struct address_family
Packit 8f70b4
{
Packit 8f70b4
   int number;
Packit 8f70b4
   const char *name;
Packit 8f70b4
};
Packit 8f70b4
static const address_family af_list[]=
Packit 8f70b4
{
Packit 8f70b4
   { AF_INET,  "inet"  },
Packit 8f70b4
#if INET6
Packit 8f70b4
   { AF_INET6, "inet6" },
Packit 8f70b4
#endif
Packit 8f70b4
   { -1, 0 }
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
ResolverCache *Resolver::cache;
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
Resolver::Resolver(const char *h,const char *p,const char *defp,
Packit 8f70b4
		   const char *ser,const char *pr)
Packit 8f70b4
   : hostname(h), portname(p), service(ser), proto(pr), defport(defp)
Packit 8f70b4
{
Packit 8f70b4
   port_number=0;
Packit 8f70b4
Packit 8f70b4
   pipe_to_child[0]=pipe_to_child[1]=-1;
Packit 8f70b4
   done=false;
Packit 8f70b4
   timeout_timer.SetResource("dns:fatal-timeout",hostname);
Packit 8f70b4
   Reconfig();
Packit 8f70b4
   use_fork=ResMgr::QueryBool("dns:use-fork",0);
Packit 8f70b4
Packit 8f70b4
   error=0;
Packit 8f70b4
Packit 8f70b4
   no_cache=false;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Resolver::~Resolver()
Packit 8f70b4
{
Packit 8f70b4
   if(pipe_to_child[0]!=-1)
Packit 8f70b4
      close(pipe_to_child[0]);
Packit 8f70b4
   if(pipe_to_child[1]!=-1)
Packit 8f70b4
      close(pipe_to_child[1]);
Packit 8f70b4
Packit 8f70b4
   if(w)
Packit 8f70b4
   {
Packit 8f70b4
      w->Kill(SIGKILL);
Packit 8f70b4
      w.borrow()->Auto();
Packit 8f70b4
   }
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
int   Resolver::Do()
Packit 8f70b4
{
Packit 8f70b4
   if(done)
Packit 8f70b4
      return STALL;
Packit 8f70b4
Packit 8f70b4
   int m=STALL;
Packit 8f70b4
Packit 8f70b4
   if(!no_cache && cache)
Packit 8f70b4
   {
Packit 8f70b4
      const sockaddr_u *a;
Packit 8f70b4
      int n;
Packit 8f70b4
      cache->Find(hostname,portname,defport,service,proto,&a,&n);
Packit 8f70b4
      if(a && n>0)
Packit 8f70b4
      {
Packit 8f70b4
	 LogNote(10,"dns cache hit");
Packit 8f70b4
	 addr.nset(a,n);
Packit 8f70b4
	 done=true;
Packit 8f70b4
	 return MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      no_cache=true;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(use_fork)
Packit 8f70b4
   {
Packit 8f70b4
      if(pipe_to_child[0]==-1)
Packit 8f70b4
      {
Packit 8f70b4
	 int res=pipe(pipe_to_child);
Packit 8f70b4
	 if(res==-1)
Packit 8f70b4
	 {
Packit 8f70b4
	    if(NonFatalError(errno))
Packit 8f70b4
	       return m;
Packit 8f70b4
	    MakeErrMsg("pipe()");
Packit 8f70b4
	    return MOVED;
Packit 8f70b4
	 }
Packit 8f70b4
	 fcntl(pipe_to_child[0],F_SETFL,O_NONBLOCK);
Packit 8f70b4
	 fcntl(pipe_to_child[0],F_SETFD,FD_CLOEXEC);
Packit 8f70b4
	 fcntl(pipe_to_child[1],F_SETFD,FD_CLOEXEC);
Packit 8f70b4
	 m=MOVED;
Packit 8f70b4
	 LogNote(4,_("Resolving host address..."));
Packit 8f70b4
      }
Packit 8f70b4
Packit 8f70b4
      if(!w && !buf)
Packit 8f70b4
      {
Packit 8f70b4
	 pid_t proc=fork();
Packit 8f70b4
	 if(proc==-1)
Packit 8f70b4
	 {
Packit 8f70b4
	    TimeoutS(1);
Packit 8f70b4
	    return m;
Packit 8f70b4
	 }
Packit 8f70b4
	 if(proc==0)
Packit 8f70b4
	 {	 // child
Packit 8f70b4
	    SignalHook::Ignore(SIGINT);
Packit 8f70b4
	    SignalHook::Ignore(SIGTSTP);
Packit 8f70b4
	    SignalHook::Ignore(SIGQUIT);
Packit 8f70b4
	    SignalHook::Ignore(SIGHUP);
Packit 8f70b4
	    close(0);	// no input will be needed.
Packit 8f70b4
	    close(pipe_to_child[0]);
Packit 8f70b4
	    pipe_to_child[0]=-1;
Packit 8f70b4
	    buf=new IOBufferFDStream(new FDStream(pipe_to_child[1],"<pipe-out>"),IOBuffer::PUT);
Packit 8f70b4
	    DoGethostbyname();
Packit 8f70b4
	    buf->PutEOF();
Packit 8f70b4
	    while(buf->Size()>0 && !buf->Error() && !buf->Broken())
Packit 8f70b4
	       buf->Roll();  // should flush quickly.
Packit 8f70b4
	    _exit(0);
Packit 8f70b4
	 }
Packit 8f70b4
	 // parent
Packit 8f70b4
	 close(pipe_to_child[1]);
Packit 8f70b4
	 pipe_to_child[1]=-1;
Packit 8f70b4
Packit 8f70b4
	 w=new ProcWait(proc);
Packit 8f70b4
	 m=MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      if(!buf)
Packit 8f70b4
      {
Packit 8f70b4
	 buf=new IOBufferFDStream(new FDStream(pipe_to_child[0],"<pipe-in>"),IOBuffer::GET);
Packit 8f70b4
// 	 Roll(buf);
Packit 8f70b4
	 m=MOVED;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   else /* !use_fork */
Packit 8f70b4
   {
Packit 8f70b4
      if(!buf)
Packit 8f70b4
      {
Packit 8f70b4
	 LogNote(4,_("Resolving host address..."));
Packit 8f70b4
	 buf=new IOBuffer(IOBuffer::GET);
Packit 8f70b4
	 DoGethostbyname();
Packit 8f70b4
	 if(Deleted())
Packit 8f70b4
	    return MOVED;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(buf->Error())
Packit 8f70b4
   {
Packit 8f70b4
      err_msg.set(buf->ErrorText());
Packit 8f70b4
      done=true;
Packit 8f70b4
      return MOVED;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(!buf->Eof())   // wait for all data to arrive (not too much)
Packit 8f70b4
   {
Packit 8f70b4
      if(timeout_timer.Stopped())
Packit 8f70b4
      {
Packit 8f70b4
	 err_msg.set(_("host name resolve timeout"));
Packit 8f70b4
	 done=true;
Packit 8f70b4
	 return MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      return m;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   const char *s;
Packit 8f70b4
   char c;
Packit 8f70b4
   int n;
Packit 8f70b4
Packit 8f70b4
   buf->Get(&s,&n);
Packit 8f70b4
   if(n<1)
Packit 8f70b4
      goto proto_error;
Packit 8f70b4
   c=*s;
Packit 8f70b4
   buf->Skip(1);
Packit 8f70b4
   buf->Get(&s,&n);
Packit 8f70b4
   if(c=='E' || c=='P') // error
Packit 8f70b4
   {
Packit 8f70b4
      const char *tport=portname?portname.get():defport.get();
Packit 8f70b4
      err_msg.vset(c=='E'?hostname.get():tport,": ",s,NULL);
Packit 8f70b4
      done=true;
Packit 8f70b4
      return MOVED;
Packit 8f70b4
   }
Packit 8f70b4
   if((unsigned)n
Packit 8f70b4
   {
Packit 8f70b4
   proto_error:
Packit 8f70b4
      if(use_fork)
Packit 8f70b4
      {
Packit 8f70b4
	 // e.g. under gdb child fails.
Packit 8f70b4
	 LogError(4,"child failed, retrying with dns:use-fork=no");
Packit 8f70b4
	 use_fork=false;
Packit 8f70b4
	 buf=0;
Packit 8f70b4
	 return MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      err_msg.set("BUG: internal class Resolver error");
Packit 8f70b4
      done=true;
Packit 8f70b4
      return MOVED;
Packit 8f70b4
   }
Packit 8f70b4
   addr.nset((const sockaddr_u*)s,n/addr.get_element_size());
Packit 8f70b4
   done=true;
Packit 8f70b4
   if(!cache)
Packit 8f70b4
      cache=new ResolverCache;
Packit 8f70b4
   cache->Add(hostname,portname,defport,service,proto,addr.get(),addr.count());
Packit 8f70b4
Packit 8f70b4
   xstring report;
Packit 8f70b4
   report.set(xstring::format(plural("%d address$|es$ found",addr.count()),addr.count()));
Packit 8f70b4
   if(addr.count()>0) {
Packit 8f70b4
      report.append(": ");
Packit 8f70b4
      for(int i=0; i
Packit 8f70b4
	 report.append(addr[i].address());
Packit 8f70b4
	 if(i
Packit 8f70b4
	    report.append(", ");
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   LogNote(4,"%s",report.get());
Packit 8f70b4
Packit 8f70b4
   return MOVED;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Resolver::MakeErrMsg(const char *f)
Packit 8f70b4
{
Packit 8f70b4
   const char *e=strerror(errno);
Packit 8f70b4
   err_msg.vset(f,": ",e,NULL);
Packit 8f70b4
   done=true;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Resolver::AddAddress(int family,const char *address,int len, unsigned int scope)
Packit 8f70b4
{
Packit 8f70b4
   sockaddr_u add;
Packit 8f70b4
   memset(&add,0,sizeof(add));
Packit 8f70b4
Packit 8f70b4
   add.sa.sa_family=family;
Packit 8f70b4
   switch(family)
Packit 8f70b4
   {
Packit 8f70b4
   case AF_INET:
Packit 8f70b4
      if(sizeof(add.in.sin_addr) != len)
Packit 8f70b4
         return;
Packit 8f70b4
      memcpy(&add.in.sin_addr,address,len);
Packit 8f70b4
      add.in.sin_port=port_number;
Packit 8f70b4
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
Packit 8f70b4
      add.sa.sa_len=sizeof(add.in);
Packit 8f70b4
#endif
Packit 8f70b4
      break;
Packit 8f70b4
Packit 8f70b4
#if INET6
Packit 8f70b4
   case AF_INET6:
Packit 8f70b4
      if(sizeof(add.in6.sin6_addr) != len)
Packit 8f70b4
         return;
Packit 8f70b4
      memcpy(&add.in6.sin6_addr,address,len);
Packit 8f70b4
      if(IN6_IS_ADDR_LINKLOCAL(&add.in6.sin6_addr) && scope==0) {
Packit 8f70b4
	 error=_("Link-local IPv6 address should have a scope");
Packit 8f70b4
	 return;
Packit 8f70b4
      }
Packit 8f70b4
      add.in6.sin6_port=port_number;
Packit 8f70b4
# ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
Packit 8f70b4
      add.in6.sin6_scope_id=scope;
Packit 8f70b4
# endif
Packit 8f70b4
# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
Packit 8f70b4
      add.sa.sa_len=sizeof(add.in6);
Packit 8f70b4
# endif
Packit 8f70b4
      break;
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
   default:
Packit 8f70b4
      return;
Packit 8f70b4
   }
Packit 8f70b4
   if(addr.count()>0 && addr.last()==add)
Packit 8f70b4
      return;
Packit 8f70b4
   addr.append(add);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
int Resolver::FindAddressFamily(const char *name)
Packit 8f70b4
{
Packit 8f70b4
   for(const address_family *f=af_list; f->name; f++)
Packit 8f70b4
   {
Packit 8f70b4
      if(!strcasecmp(name,f->name))
Packit 8f70b4
	 return f->number;
Packit 8f70b4
   }
Packit 8f70b4
   return -1;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Resolver::ParseOrder(const char *s,int *o)
Packit 8f70b4
{
Packit 8f70b4
   const char * const delim="\t ";
Packit 8f70b4
   char *s1=alloca_strdup(s);
Packit 8f70b4
   int idx=0;
Packit 8f70b4
Packit 8f70b4
   for(s1=strtok(s1,delim); s1; s1=strtok(0,delim))
Packit 8f70b4
   {
Packit 8f70b4
      int af=FindAddressFamily(s1);
Packit 8f70b4
      if(af!=-1 && idx<15)
Packit 8f70b4
      {
Packit 8f70b4
	 if(o) o[idx]=af;
Packit 8f70b4
	 idx++;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   if(o) o[idx]=-1;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
#if defined(HAVE_DN_EXPAND) && !HAVE_DECL_DN_EXPAND
Packit 8f70b4
CDECL int dn_expand(const unsigned char *msg,const unsigned char *eomorig,const unsigned char *comp_dn,char *exp_dn,int length);
Packit 8f70b4
CDECL int dn_skipname(const unsigned char *msg,const unsigned char *eomorig);
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#ifdef HAVE_RES_SEARCH
Packit 8f70b4
static
Packit 8f70b4
int extract_domain(const unsigned char *answer,const unsigned char *scan,int len,
Packit 8f70b4
		     char *store,int store_len)
Packit 8f70b4
{
Packit 8f70b4
#ifdef HAVE_DN_EXPAND // newer resolver versions have dn_expand and dn_skipname
Packit 8f70b4
   if(store)
Packit 8f70b4
      dn_expand(answer,scan+len,scan,store,store_len);
Packit 8f70b4
   return dn_skipname(scan,scan+len);
Packit 8f70b4
#else // ...older don't.
Packit 8f70b4
   int count=1;	  // reserve space for \0
Packit 8f70b4
   int refs=0;
Packit 8f70b4
   int consumed=0;
Packit 8f70b4
   const unsigned char *start=scan;
Packit 8f70b4
   for(;;)
Packit 8f70b4
   {
Packit 8f70b4
      if(len<=0)
Packit 8f70b4
	 break;
Packit 8f70b4
      int label_len=*scan;
Packit 8f70b4
      scan++;
Packit 8f70b4
      len--;
Packit 8f70b4
Packit 8f70b4
      if((label_len & 0xC0) == 0xC0)   // compression
Packit 8f70b4
      {
Packit 8f70b4
	 if(len<=0)
Packit 8f70b4
	    break;
Packit 8f70b4
	 int offset=((label_len&0x3F)<<8) + *scan;
Packit 8f70b4
	 scan++;
Packit 8f70b4
	 len--;
Packit 8f70b4
Packit 8f70b4
	 if(refs==0)
Packit 8f70b4
	    consumed=scan-start;
Packit 8f70b4
Packit 8f70b4
	 if(answer+offset>=scan+len)
Packit 8f70b4
	    break; // error
Packit 8f70b4
Packit 8f70b4
	 len=scan+len-answer+offset;
Packit 8f70b4
	 scan=answer+offset;
Packit 8f70b4
	 if(++refs > 256)
Packit 8f70b4
	    break;   // too many hops.
Packit 8f70b4
	 continue;
Packit 8f70b4
      }
Packit 8f70b4
Packit 8f70b4
      if(label_len==0)
Packit 8f70b4
	 break;
Packit 8f70b4
Packit 8f70b4
      while(label_len>0)
Packit 8f70b4
      {
Packit 8f70b4
	 if(len<=0)
Packit 8f70b4
	    break;
Packit 8f70b4
	 if(store && count
Packit 8f70b4
	    *store++=*scan;
Packit 8f70b4
	 count++;
Packit 8f70b4
	 scan++;
Packit 8f70b4
	 len--;
Packit 8f70b4
	 label_len--;
Packit 8f70b4
      }
Packit 8f70b4
      if(store && count
Packit 8f70b4
	 *store++='.';
Packit 8f70b4
      count++;
Packit 8f70b4
   }
Packit 8f70b4
   if(store)
Packit 8f70b4
      *store=0;
Packit 8f70b4
   if(refs==0)
Packit 8f70b4
      consumed=scan-start;
Packit 8f70b4
   return consumed;
Packit 8f70b4
#endif // DN_EXPAND
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
#ifndef NS_MAXDNAME
Packit 8f70b4
# define NS_MAXDNAME 1025
Packit 8f70b4
#endif
Packit 8f70b4
#ifndef NS_HFIXEDSZ
Packit 8f70b4
# define NS_HFIXEDSZ 12
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
struct SRV
Packit 8f70b4
{
Packit 8f70b4
   char domain[NS_MAXDNAME];
Packit 8f70b4
   int port;
Packit 8f70b4
   int priority;
Packit 8f70b4
   int weight;
Packit 8f70b4
   int order;
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
static
Packit 8f70b4
int SRV_compare(const SRV *sa,const SRV *sb)
Packit 8f70b4
{
Packit 8f70b4
   if(sa->priority < sb->priority)
Packit 8f70b4
      return -1;
Packit 8f70b4
   if(sa->priority > sb->priority)
Packit 8f70b4
      return 1;
Packit 8f70b4
   if(sa->order < sb->order)
Packit 8f70b4
      return -1;
Packit 8f70b4
   if(sa->order > sb->order)
Packit 8f70b4
      return 1;
Packit 8f70b4
   if(sa->weight > sb->weight)
Packit 8f70b4
      return -1;
Packit 8f70b4
   if(sa->weight < sb->weight)
Packit 8f70b4
      return 1;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
#endif // RES_SEARCH
Packit 8f70b4
Packit 8f70b4
void Resolver::LookupSRV_RR()
Packit 8f70b4
{
Packit 8f70b4
   if(!ResMgr::QueryBool("dns:SRV-query",hostname))
Packit 8f70b4
      return;
Packit 8f70b4
#ifdef HAVE_RES_SEARCH
Packit 8f70b4
   const char *tproto=proto?proto.get():"tcp";
Packit 8f70b4
   time_t try_time;
Packit 8f70b4
   unsigned char answer[0x1000];
Packit 8f70b4
   const char *srv_name=xstring::format("_%s._%s.%s",service.get(),tproto,hostname.get());
Packit 8f70b4
   srv_name=alloca_strdup(srv_name);
Packit 8f70b4
Packit 8f70b4
   int retries=0;
Packit 8f70b4
   int max_retries=ResMgr::Query("dns:max-retries",hostname);
Packit 8f70b4
   int len;
Packit 8f70b4
   for(;;)
Packit 8f70b4
   {
Packit 8f70b4
      if(!use_fork)
Packit 8f70b4
      {
Packit 8f70b4
	 Schedule();
Packit 8f70b4
	 if(Deleted())
Packit 8f70b4
	    return;
Packit 8f70b4
      }
Packit 8f70b4
      time(&try_time);
Packit 8f70b4
Packit 8f70b4
#ifndef DNSSEC_LOCAL_VALIDATION
Packit 8f70b4
      len=res_search(srv_name, C_IN, T_SRV, answer, sizeof(answer));
Packit 8f70b4
      if(len>=0)
Packit 8f70b4
	 break;
Packit 8f70b4
#else
Packit 8f70b4
      val_status_t val_status;
Packit 8f70b4
      bool require_trust = ResMgr::QueryBool("dns:strict-dnssec",hostname);
Packit 8f70b4
      len=val_res_search(NULL, srv_name, C_IN, T_SRV, answer, sizeof(answer), &val_status);
Packit 8f70b4
      if(len>=0) {
Packit 8f70b4
          if(require_trust && !val_istrusted(val_status))
Packit 8f70b4
              return;
Packit 8f70b4
          else
Packit 8f70b4
              break;
Packit 8f70b4
      }
Packit 8f70b4
#endif
Packit 8f70b4
#ifdef HAVE_H_ERRNO
Packit 8f70b4
      if(h_errno!=TRY_AGAIN)
Packit 8f70b4
	 return;
Packit 8f70b4
      if(++retries>=max_retries && max_retries)
Packit 8f70b4
	 return;
Packit 8f70b4
      time_t t=time(0);
Packit 8f70b4
      if(t-try_time<5)
Packit 8f70b4
	 sleep(5-(t-try_time));
Packit 8f70b4
#else // no h_errno
Packit 8f70b4
      return;
Packit 8f70b4
#endif
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(len>(int)sizeof(answer))
Packit 8f70b4
      len=sizeof(answer);
Packit 8f70b4
Packit 8f70b4
   if(len
Packit 8f70b4
      return;
Packit 8f70b4
Packit 8f70b4
   int question_count=(answer[4]<<8)+answer[5];
Packit 8f70b4
   int answer_count  =(answer[6]<<8)+answer[7];
Packit 8f70b4
Packit 8f70b4
   // skip header
Packit 8f70b4
   unsigned char *scan=answer+NS_HFIXEDSZ;
Packit 8f70b4
   len-=NS_HFIXEDSZ;
Packit 8f70b4
Packit 8f70b4
   // skip questions section
Packit 8f70b4
   for( ; question_count>0; question_count--)
Packit 8f70b4
   {
Packit 8f70b4
      int dom_len=extract_domain(answer,scan,len,0,0);
Packit 8f70b4
      if(dom_len<0)
Packit 8f70b4
	 return;
Packit 8f70b4
      scan+=dom_len;
Packit 8f70b4
      len-=dom_len;
Packit 8f70b4
      if(len<4)
Packit 8f70b4
	 return;
Packit 8f70b4
      scan+=4;
Packit 8f70b4
      len-=4;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   xarray<SRV> SRVs;
Packit 8f70b4
Packit 8f70b4
   // now process answers section
Packit 8f70b4
   for( ; answer_count>0; answer_count--)
Packit 8f70b4
   {
Packit 8f70b4
      int dom_len=extract_domain(answer,scan,len,0,0);
Packit 8f70b4
      if(dom_len<0)
Packit 8f70b4
	 return;
Packit 8f70b4
      scan+=dom_len;
Packit 8f70b4
      len-=dom_len;
Packit 8f70b4
      if(len<8)
Packit 8f70b4
	 return;
Packit 8f70b4
      scan+=8;
Packit 8f70b4
      len-=8;  // skip type,class,ttl
Packit 8f70b4
Packit 8f70b4
      if(len<2)
Packit 8f70b4
	 return;
Packit 8f70b4
Packit 8f70b4
      int data_len=(scan[0]<<8)+scan[1];
Packit 8f70b4
      scan+=2;
Packit 8f70b4
      len-=2;
Packit 8f70b4
Packit 8f70b4
      if(len
Packit 8f70b4
	 return;
Packit 8f70b4
Packit 8f70b4
      if(data_len<6)
Packit 8f70b4
	 return;
Packit 8f70b4
Packit 8f70b4
      struct SRV t;
Packit 8f70b4
      t.priority=(scan[0]<<8)+scan[1];
Packit 8f70b4
      t.weight  =(scan[2]<<8)+scan[3];
Packit 8f70b4
      t.port    =(scan[4]<<8)+scan[5];
Packit 8f70b4
      t.order=0;
Packit 8f70b4
Packit 8f70b4
      scan+=6;
Packit 8f70b4
      len-=6;
Packit 8f70b4
Packit 8f70b4
      dom_len=extract_domain(answer,scan,len,t.domain,sizeof(t.domain));
Packit 8f70b4
      if(dom_len<0)
Packit 8f70b4
	 return;
Packit 8f70b4
Packit 8f70b4
      scan+=dom_len;
Packit 8f70b4
      len-=dom_len;
Packit 8f70b4
Packit 8f70b4
      // add unless the service is decidedly not available at this domain.
Packit 8f70b4
      if(strcmp(t.domain,"."))
Packit 8f70b4
	 SRVs.append(t);
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   // now sort and randomize the list.
Packit 8f70b4
   SRVs.qsort(SRV_compare);
Packit 8f70b4
Packit 8f70b4
   srand(time(0));
Packit 8f70b4
Packit 8f70b4
   int SRVscan;
Packit 8f70b4
   int base=0;
Packit 8f70b4
   int curr_priority=-1;
Packit 8f70b4
   int weight_sum=0;
Packit 8f70b4
   for(SRVscan=0; ; SRVscan++)
Packit 8f70b4
   {
Packit 8f70b4
      if(SRVscan==SRVs.count() || SRVs[SRVscan].priority!=curr_priority)
Packit 8f70b4
      {
Packit 8f70b4
	 if(base)
Packit 8f70b4
	 {
Packit 8f70b4
	    int o=1;
Packit 8f70b4
	    int s;
Packit 8f70b4
	    while(weight_sum>0)
Packit 8f70b4
	    {
Packit 8f70b4
	       int r=int(rand()/(RAND_MAX+1.0)*weight_sum);
Packit 8f70b4
	       if(r>=weight_sum)
Packit 8f70b4
		  r=weight_sum-1;
Packit 8f70b4
	       int w=0;
Packit 8f70b4
	       for(s=base; s
Packit 8f70b4
	       {
Packit 8f70b4
		  if(SRVs[s].order!=0)
Packit 8f70b4
		     continue;
Packit 8f70b4
		  w+=SRVs[s].weight;
Packit 8f70b4
		  if(r
Packit 8f70b4
		  {
Packit 8f70b4
		     SRVs[s].order=o;
Packit 8f70b4
		     o++;
Packit 8f70b4
		     weight_sum-=SRVs[s].weight;
Packit 8f70b4
		     break;
Packit 8f70b4
		  }
Packit 8f70b4
	       }
Packit 8f70b4
	    }
Packit 8f70b4
	 }
Packit 8f70b4
	 if(SRVscan==SRVs.count())
Packit 8f70b4
	    break;
Packit 8f70b4
	 base=SRVscan;
Packit 8f70b4
	 curr_priority=SRVs[SRVscan].priority;
Packit 8f70b4
	 weight_sum=0;
Packit 8f70b4
      }
Packit 8f70b4
      weight_sum+=SRVs[SRVscan].weight;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   SRVs.qsort(SRV_compare);
Packit 8f70b4
Packit 8f70b4
   int oldport=port_number;
Packit 8f70b4
   for(SRVscan=0; SRVscan
Packit 8f70b4
   {
Packit 8f70b4
      port_number=htons(SRVs[SRVscan].port);
Packit 8f70b4
      LookupOne(SRVs[SRVscan].domain);
Packit 8f70b4
   }
Packit 8f70b4
   port_number=oldport;
Packit 8f70b4
Packit 8f70b4
#endif // HAVE_RES_SEARCH
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Resolver::LookupOne(const char *name)
Packit 8f70b4
{
Packit 8f70b4
   time_t try_time;
Packit 8f70b4
   int af_index=0;
Packit 8f70b4
   int af_order[16];
Packit 8f70b4
Packit 8f70b4
   const char *order=ResMgr::Query("dns:order",name);
Packit 8f70b4
Packit 8f70b4
   const char *proto_delim=strchr(name,',');
Packit 8f70b4
   if(proto_delim)
Packit 8f70b4
   {
Packit 8f70b4
      char *o=string_alloca(proto_delim-name+1);
Packit 8f70b4
      memcpy(o,name,proto_delim-name);
Packit 8f70b4
      o[proto_delim-name]=0;
Packit 8f70b4
      // check if the protocol name is valid.
Packit 8f70b4
      if(FindAddressFamily(o)!=-1)
Packit 8f70b4
	 order=o;
Packit 8f70b4
      name=proto_delim+1;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
#if LIBIDN2
Packit 8f70b4
   xstring_c ascii_name;
Packit 8f70b4
   int rc=idn2_lookup_ul(name,ascii_name.buf_ptr(),0);
Packit 8f70b4
   if(rc!=IDN2_OK) {
Packit 8f70b4
      error=idn2_strerror(rc);
Packit 8f70b4
      return;
Packit 8f70b4
   }
Packit 8f70b4
   name=ascii_name;
Packit 8f70b4
#endif//LIBIDN2
Packit 8f70b4
Packit 8f70b4
   ParseOrder(order,af_order);
Packit 8f70b4
Packit 8f70b4
   int retries=0;
Packit 8f70b4
   int max_retries=ResMgr::Query("dns:max-retries",name);
Packit 8f70b4
   for(;;)
Packit 8f70b4
   {
Packit 8f70b4
      if(!use_fork)
Packit 8f70b4
      {
Packit 8f70b4
	 Schedule();
Packit 8f70b4
	 if(Deleted())
Packit 8f70b4
	    return;
Packit 8f70b4
      }
Packit 8f70b4
Packit 8f70b4
      time(&try_time);
Packit 8f70b4
Packit 8f70b4
// Prefer getaddrinfo over gethostbyname2 and getipnodebyname, as
Packit 8f70b4
// approach with multiple lookups works badly when host name is in hosts file
Packit 8f70b4
// and no dns servers are reachable.
Packit 8f70b4
#if defined(HAVE_GETADDRINFO) && INET6
Packit 8f70b4
/* && !defined(HAVE_GETHOSTBYNAME2) \
Packit 8f70b4
   && !defined(HAVE_GETIPNODEBYNAME) */
Packit 8f70b4
Packit 8f70b4
      // getaddrinfo support by Brandon Hume
Packit 8f70b4
      struct addrinfo	    *ainfo=0,
Packit 8f70b4
			    *a_res,
Packit 8f70b4
			    a_hint;
Packit 8f70b4
      int		    ainfo_res;
Packit 8f70b4
      struct sockaddr	    *sockname;
Packit 8f70b4
      struct sockaddr_in    *inet_addr;
Packit 8f70b4
      struct sockaddr_in6   *inet6_addr;
Packit 8f70b4
      const char	    *addr_data;
Packit 8f70b4
      int		    addr_len;
Packit 8f70b4
      unsigned int          addr_scope;
Packit 8f70b4
Packit 8f70b4
      memset(&a_hint, 0, sizeof(a_hint));
Packit 8f70b4
      a_hint.ai_flags	    = AI_PASSIVE;
Packit 8f70b4
      a_hint.ai_family	    = PF_UNSPEC;
Packit 8f70b4
Packit 8f70b4
#ifndef DNSSEC_LOCAL_VALIDATION
Packit 8f70b4
      ainfo_res	= getaddrinfo(name, NULL, &a_hint, &ainfo);
Packit 8f70b4
#else
Packit 8f70b4
      val_status_t val_status;
Packit 8f70b4
      bool require_trust=ResMgr::QueryBool("dns:strict-dnssec",name);
Packit 8f70b4
      ainfo_res	= val_getaddrinfo(NULL, name, NULL, &a_hint, &ainfo,
Packit 8f70b4
                                  &val_status);
Packit 8f70b4
      if(VAL_GETADDRINFO_HAS_STATUS(ainfo_res) && !val_istrusted(val_status))
Packit 8f70b4
      {
Packit 8f70b4
          if(require_trust) {
Packit 8f70b4
              // untrusted answer
Packit 8f70b4
              error = _("DNS resolution not trusted.");
Packit 8f70b4
              break;
Packit 8f70b4
          } else {
Packit 8f70b4
              fprintf(stderr,"\nWARNING: DNS lookup failed validation: %s\n",
Packit 8f70b4
                      p_val_status(val_status));
Packit 8f70b4
	      fflush(stderr);
Packit 8f70b4
          }
Packit 8f70b4
      }
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
      if(ainfo_res == 0)
Packit 8f70b4
      {
Packit 8f70b4
        // by lav: add addresses in specified order.
Packit 8f70b4
	for(int af=af_order[af_index]; af!=-1; af=af_order[++af_index])
Packit 8f70b4
	{
Packit 8f70b4
	    for(a_res = ainfo; a_res != NULL; a_res = a_res->ai_next)
Packit 8f70b4
	    {
Packit 8f70b4
	       if(a_res->ai_family!=af)
Packit 8f70b4
		  continue;
Packit 8f70b4
Packit 8f70b4
	       sockname	= a_res->ai_addr;
Packit 8f70b4
	       addr_scope = 0;
Packit 8f70b4
Packit 8f70b4
	       switch(a_res->ai_family)
Packit 8f70b4
	       {
Packit 8f70b4
	       case AF_INET:
Packit 8f70b4
		  inet_addr   = (sockaddr_in *)sockname;
Packit 8f70b4
		  addr_data   = (const char *)&(inet_addr->sin_addr.s_addr);
Packit 8f70b4
		  addr_len    = sizeof(inet_addr->sin_addr.s_addr);
Packit 8f70b4
		  break;
Packit 8f70b4
	       case AF_INET6:
Packit 8f70b4
		  inet6_addr  = (sockaddr_in6 *)sockname;
Packit 8f70b4
		  addr_data   = (const char *)&(inet6_addr->sin6_addr.s6_addr);
Packit 8f70b4
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
Packit 8f70b4
		  addr_scope  = inet6_addr->sin6_scope_id;
Packit 8f70b4
#endif
Packit 8f70b4
		  addr_len    = sizeof(inet6_addr->sin6_addr.s6_addr);
Packit 8f70b4
		  break;
Packit 8f70b4
	       default:
Packit 8f70b4
		  continue;
Packit 8f70b4
	       }
Packit 8f70b4
	       AddAddress(a_res->ai_family, addr_data, addr_len, addr_scope);
Packit 8f70b4
	    }
Packit 8f70b4
	 }
Packit 8f70b4
Packit 8f70b4
	 freeaddrinfo(ainfo);
Packit 8f70b4
	 break;
Packit 8f70b4
      }
Packit 8f70b4
Packit 8f70b4
      if(ainfo_res != EAI_AGAIN
Packit 8f70b4
      || (++retries>=max_retries && max_retries))
Packit 8f70b4
      {
Packit 8f70b4
	 error = gai_strerror(ainfo_res);
Packit 8f70b4
	 break;
Packit 8f70b4
      }
Packit 8f70b4
Packit 8f70b4
#else // !HAVE_GETADDRINFO
Packit 8f70b4
Packit 8f70b4
      int af=af_order[af_index];
Packit 8f70b4
      if(af==-1)
Packit 8f70b4
	 break;
Packit 8f70b4
Packit 8f70b4
      struct hostent *ha;
Packit 8f70b4
# if defined(HAVE_GETIPNODEBYNAME)
Packit 8f70b4
#  ifndef HAVE_H_ERRNO
Packit 8f70b4
#   define HAVE_H_ERRNO 1
Packit 8f70b4
#  endif
Packit 8f70b4
#  undef h_errno // it could be a macro, but we want it to be local variable.
Packit 8f70b4
      int h_errno=0;
Packit 8f70b4
      ha=getipnodebyname(name,af,0,&h_errno);
Packit 8f70b4
# elif defined(HAVE_GETHOSTBYNAME2)
Packit 8f70b4
      ha=gethostbyname2(name,af);
Packit 8f70b4
# else
Packit 8f70b4
      if(af==AF_INET)
Packit 8f70b4
	 ha=gethostbyname(name);
Packit 8f70b4
      else
Packit 8f70b4
      {
Packit 8f70b4
	 retries=0;
Packit 8f70b4
	 af_index++;
Packit 8f70b4
	 continue;
Packit 8f70b4
      }
Packit 8f70b4
# endif
Packit 8f70b4
Packit 8f70b4
      if(ha)
Packit 8f70b4
      {
Packit 8f70b4
	 const char * const *a;
Packit 8f70b4
	 for(a=ha->h_addr_list; *a; a++)
Packit 8f70b4
	    AddAddress(ha->h_addrtype, *a, ha->h_length, 0);
Packit 8f70b4
	 retries=0;
Packit 8f70b4
	 af_index++;
Packit 8f70b4
# if defined(HAVE_GETIPNODEBYNAME)
Packit 8f70b4
	 freehostent(ha);
Packit 8f70b4
# endif
Packit 8f70b4
	 continue;
Packit 8f70b4
      }
Packit 8f70b4
Packit 8f70b4
# ifdef HAVE_H_ERRNO
Packit 8f70b4
      if(h_errno!=TRY_AGAIN
Packit 8f70b4
      || (++retries>=max_retries && max_retries))
Packit 8f70b4
# endif
Packit 8f70b4
      {
Packit 8f70b4
	 if(error==0)
Packit 8f70b4
	 {
Packit 8f70b4
# ifdef HAVE_H_ERRNO
Packit 8f70b4
	    error=hstrerror(h_errno);
Packit 8f70b4
# else
Packit 8f70b4
	    error=_("Host name lookup failure");
Packit 8f70b4
# endif
Packit 8f70b4
	 }
Packit 8f70b4
	 retries=0;
Packit 8f70b4
	 af_index++;
Packit 8f70b4
	 continue; // try other address families
Packit 8f70b4
      }
Packit 8f70b4
#endif /* HAVE_GETADDRINFO */
Packit 8f70b4
Packit 8f70b4
      time_t t;
Packit 8f70b4
      if((t=time(0))-try_time<5)
Packit 8f70b4
	 sleep(5-(t-try_time));
Packit 8f70b4
   }
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Resolver::DoGethostbyname()
Packit 8f70b4
{
Packit 8f70b4
   if(port_number==0)
Packit 8f70b4
   {
Packit 8f70b4
      const char *tproto=proto?proto.get():"tcp";
Packit 8f70b4
      const char *tport=portname?portname.get():defport.get();
Packit 8f70b4
Packit 8f70b4
      if(isdigit((unsigned char)tport[0]))
Packit 8f70b4
	 port_number=htons(atoi(tport));
Packit 8f70b4
      else
Packit 8f70b4
      {
Packit 8f70b4
	 struct servent *se=getservbyname(tport,tproto);
Packit 8f70b4
	 if(se)
Packit 8f70b4
	    port_number=se->s_port;
Packit 8f70b4
	 else
Packit 8f70b4
	 {
Packit 8f70b4
	    buf->Put("P");
Packit 8f70b4
	    buf->Format(_("no such %s service"),tproto);
Packit 8f70b4
	    return;
Packit 8f70b4
	 }
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(service && !portname && !isdigit((unsigned char)hostname[0]))
Packit 8f70b4
      LookupSRV_RR();
Packit 8f70b4
Packit 8f70b4
   if(!use_fork && Deleted())
Packit 8f70b4
      return;
Packit 8f70b4
Packit 8f70b4
   const char *h=ResMgr::Query("dns:name",hostname);
Packit 8f70b4
   if(!h || !*h)
Packit 8f70b4
      h=hostname;
Packit 8f70b4
   char *hs=alloca_strdup(h);
Packit 8f70b4
   char *tok;
Packit 8f70b4
   for(hs=strtok_r(hs,",",&tok;; hs; hs=strtok_r(NULL,",",&tok))
Packit 8f70b4
      LookupOne(hs);
Packit 8f70b4
Packit 8f70b4
   if(!use_fork && Deleted())
Packit 8f70b4
      return;
Packit 8f70b4
Packit 8f70b4
   if(addr.count()==0)
Packit 8f70b4
   {
Packit 8f70b4
      buf->Put("E");
Packit 8f70b4
      if(error==0)
Packit 8f70b4
	 error=_("No address found");
Packit 8f70b4
      buf->Put(error);
Packit 8f70b4
      return;
Packit 8f70b4
   }
Packit 8f70b4
   buf->Put("O");
Packit 8f70b4
   buf->Put((const char*)addr.get(),addr.count()*addr.get_element_size());
Packit 8f70b4
   addr.unset();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void Resolver::Reconfig(const char *name)
Packit 8f70b4
{
Packit 8f70b4
   if(!name || strncmp(name,"dns:",4))
Packit 8f70b4
      return;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
ResolverCache::ResolverCache()
Packit 8f70b4
   : Cache(ResMgr::FindRes("dns:cache-size"),ResMgr::FindRes("dns:cache-enable"))
Packit 8f70b4
{
Packit 8f70b4
}
Packit 8f70b4
void ResolverCache::Reconfig(const char *r)
Packit 8f70b4
{
Packit 8f70b4
   if(!xstrcmp(r,"dns:SRV-query")
Packit 8f70b4
   || !xstrcmp(r,"dns:order"))
Packit 8f70b4
      Flush();
Packit 8f70b4
}
Packit 8f70b4
ResolverCacheEntry *ResolverCache::Find(const char *h,const char *p,const char *defp,const char *ser,const char *pr)
Packit 8f70b4
{
Packit 8f70b4
   for(ResolverCacheEntry *c=IterateFirst(); c; c=IterateNext())
Packit 8f70b4
   {
Packit 8f70b4
      if(c->Matches(h,p,defp,ser,pr))
Packit 8f70b4
	 return c;
Packit 8f70b4
   }
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
void ResolverCache::Add(const char *h,const char *p,const char *defp,
Packit 8f70b4
	 const char *ser,const char *pr,const sockaddr_u *a,int n)
Packit 8f70b4
{
Packit 8f70b4
   Trim();
Packit 8f70b4
   ResolverCacheEntry *c=Find(h,p,defp,ser,pr);
Packit 8f70b4
   if(c)
Packit 8f70b4
      c->SetData(a,n);
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      if(!IsEnabled(h))
Packit 8f70b4
	 return;
Packit 8f70b4
      AddCacheEntry(new ResolverCacheEntry(h,p,defp,ser,pr,a,n));
Packit 8f70b4
   }
Packit 8f70b4
}
Packit 8f70b4
bool ResolverCacheEntryLoc::Matches(const char *h,const char *p,
Packit 8f70b4
	 const char *defp,const char *ser,const char *pr)
Packit 8f70b4
{
Packit 8f70b4
   return (!xstrcasecmp(hostname,h)
Packit 8f70b4
      && !xstrcmp(portname,p)
Packit 8f70b4
      && !xstrcmp(defport,defp)
Packit 8f70b4
      && !xstrcmp(service,ser)
Packit 8f70b4
      && !xstrcmp(proto,pr));
Packit 8f70b4
}
Packit 8f70b4
void ResolverCache::Find(const char *h,const char *p,const char *defp,
Packit 8f70b4
	 const char *ser,const char *pr,const sockaddr_u **a,int *n)
Packit 8f70b4
{
Packit 8f70b4
   *a=0;
Packit 8f70b4
   *n=0;
Packit 8f70b4
Packit 8f70b4
   // if cache is disabled for this host, return nothing.
Packit 8f70b4
   if(!IsEnabled(h))
Packit 8f70b4
      return;
Packit 8f70b4
Packit 8f70b4
   ResolverCacheEntry *c=Find(h,p,defp,ser,pr);
Packit 8f70b4
   if(c)
Packit 8f70b4
   {
Packit 8f70b4
      if(c->Stopped())
Packit 8f70b4
      {
Packit 8f70b4
	 Trim();
Packit 8f70b4
	 return;
Packit 8f70b4
      }
Packit 8f70b4
      c->GetData(a,n);
Packit 8f70b4
   }
Packit 8f70b4
}