|
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 |
}
|