1 /*
2  * lftp - file transfer program
3  *
4  * Copyright (c) 1996-2020 by Alexander V. Lukyanov (lav@yars.free.net)
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <config.h>
21 
22 #include <stddef.h>
23 #include "Resolver.h"
24 #include "SignalHook.h"
25 #include <errno.h>
26 #include <unistd.h>
27 #include "trio.h"
28 #include <time.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netdb.h>
32 #include <ctype.h>
33 #include <fcntl.h>
34 
35 #include <netinet/in.h>
36 #ifdef HAVE_ARPA_NAMESER_H
37 # define class _class // workaround for FreeBSD 3.2.
38 # include <arpa/nameser.h>
39 # undef class
40 #endif
41 #ifdef HAVE_RESOLV_H
42 # include <resolv.h>
43 #endif
44 
45 #if LIBIDN2
46 # include <idn2.h>
47 #endif
48 
49 #ifdef DNSSEC_LOCAL_VALIDATION
50 # include "validator/validator.h"
51 #endif
52 
53 #include "xstring.h"
54 #include "ResMgr.h"
55 #include "log.h"
56 #include "plural.h"
57 
58 #ifndef C_IN
59 # define C_IN 1
60 #endif
61 #ifndef T_SRV
62 # define T_SRV 33
63 #endif
64 
65 #if !HAVE_DECL_HSTRERROR
66 extern "C" { const char *hstrerror(int); }
67 #endif
68 
69 #ifdef HAVE_H_ERRNO
70 #if !HAVE_DECL_H_ERRNO
71 CDECL int h_errno;
72 #endif
73 #endif
74 
75 #if HAVE_RES_SEARCH && !HAVE_DECL_RES_SEARCH
76 CDECL int res_search(const char*,int,int,unsigned char*,int);
77 #endif
78 
79 #if INET6
80 # define DEFAULT_ORDER "inet inet6"
81 #else
82 # define DEFAULT_ORDER "inet"
83 #endif
84 
85 
86 struct address_family
87 {
88    int number;
89    const char *name;
90 };
91 static const address_family af_list[]=
92 {
93    { AF_INET,  "inet"  },
94 #if INET6
95    { AF_INET6, "inet6" },
96 #endif
97    { -1, 0 }
98 };
99 
100 ResolverCache *Resolver::cache;
101 
102 
Resolver(const char * h,const char * p,const char * defp,const char * ser,const char * pr)103 Resolver::Resolver(const char *h,const char *p,const char *defp,
104 		   const char *ser,const char *pr)
105    : hostname(h), portname(p), service(ser), proto(pr), defport(defp)
106 {
107    port_number=0;
108 
109    pipe_to_child[0]=pipe_to_child[1]=-1;
110    done=false;
111    timeout_timer.SetResource("dns:fatal-timeout",hostname);
112    Reconfig();
113    use_fork=ResMgr::QueryBool("dns:use-fork",0);
114 
115    error=0;
116 
117    no_cache=false;
118 }
119 
~Resolver()120 Resolver::~Resolver()
121 {
122    if(pipe_to_child[0]!=-1)
123       close(pipe_to_child[0]);
124    if(pipe_to_child[1]!=-1)
125       close(pipe_to_child[1]);
126 
127    if(w)
128    {
129       w->Kill(SIGKILL);
130       w.borrow()->Auto();
131    }
132 }
133 
Do()134 int   Resolver::Do()
135 {
136    if(done)
137       return STALL;
138 
139    int m=STALL;
140 
141    if(!no_cache && cache)
142    {
143       const sockaddr_u *a;
144       int n;
145       cache->Find(hostname,portname,defport,service,proto,&a,&n);
146       if(a && n>0)
147       {
148 	 LogNote(10,"dns cache hit");
149 	 addr.nset(a,n);
150 	 done=true;
151 	 return MOVED;
152       }
153       no_cache=true;
154    }
155 
156    if(use_fork)
157    {
158       if(pipe_to_child[0]==-1)
159       {
160 	 int res=pipe(pipe_to_child);
161 	 if(res==-1)
162 	 {
163 	    if(NonFatalError(errno))
164 	       return m;
165 	    MakeErrMsg("pipe()");
166 	    return MOVED;
167 	 }
168 	 fcntl(pipe_to_child[0],F_SETFL,O_NONBLOCK);
169 	 fcntl(pipe_to_child[0],F_SETFD,FD_CLOEXEC);
170 	 fcntl(pipe_to_child[1],F_SETFD,FD_CLOEXEC);
171 	 m=MOVED;
172 	 LogNote(4,_("Resolving host address..."));
173       }
174 
175       if(!w && !buf)
176       {
177 	 pid_t proc=fork();
178 	 if(proc==-1)
179 	 {
180 	    TimeoutS(1);
181 	    return m;
182 	 }
183 	 if(proc==0)
184 	 {	 // child
185 	    SignalHook::Ignore(SIGINT);
186 	    SignalHook::Ignore(SIGTSTP);
187 	    SignalHook::Ignore(SIGQUIT);
188 	    SignalHook::Ignore(SIGHUP);
189 	    close(0);	// no input will be needed.
190 	    close(pipe_to_child[0]);
191 	    pipe_to_child[0]=-1;
192 	    buf=new IOBufferFDStream(new FDStream(pipe_to_child[1],"<pipe-out>"),IOBuffer::PUT);
193 	    DoGethostbyname();
194 	    buf->PutEOF();
195 	    while(buf->Size()>0 && !buf->Error() && !buf->Broken())
196 	       buf->Roll();  // should flush quickly.
197 	    _exit(0);
198 	 }
199 	 // parent
200 	 close(pipe_to_child[1]);
201 	 pipe_to_child[1]=-1;
202 
203 	 w=new ProcWait(proc);
204 	 m=MOVED;
205       }
206       if(!buf)
207       {
208 	 buf=new IOBufferFDStream(new FDStream(pipe_to_child[0],"<pipe-in>"),IOBuffer::GET);
209 // 	 Roll(buf);
210 	 m=MOVED;
211       }
212    }
213    else /* !use_fork */
214    {
215       if(!buf)
216       {
217 	 LogNote(4,_("Resolving host address..."));
218 	 buf=new IOBuffer(IOBuffer::GET);
219 	 DoGethostbyname();
220 	 if(Deleted())
221 	    return MOVED;
222       }
223    }
224 
225    if(buf->Error())
226    {
227       err_msg.set(buf->ErrorText());
228       done=true;
229       return MOVED;
230    }
231 
232    if(!buf->Eof())   // wait for all data to arrive (not too much)
233    {
234       if(timeout_timer.Stopped())
235       {
236 	 err_msg.set(_("host name resolve timeout"));
237 	 done=true;
238 	 return MOVED;
239       }
240       return m;
241    }
242 
243    const char *s;
244    char c;
245    int n;
246 
247    buf->Get(&s,&n);
248    if(n<1)
249       goto proto_error;
250    c=*s;
251    buf->Skip(1);
252    buf->Get(&s,&n);
253    if(c=='E' || c=='P') // error
254    {
255       const char *tport=portname?portname.get():defport.get();
256       err_msg.vset(c=='E'?hostname.get():tport,": ",s,NULL);
257       done=true;
258       return MOVED;
259    }
260    if((unsigned)n<addr.get_element_size())
261    {
262    proto_error:
263       if(use_fork)
264       {
265 	 // e.g. under gdb child fails.
266 	 LogError(4,"child failed, retrying with dns:use-fork=no");
267 	 use_fork=false;
268 	 buf=0;
269 	 return MOVED;
270       }
271       err_msg.set("BUG: internal class Resolver error");
272       done=true;
273       return MOVED;
274    }
275    addr.nset((const sockaddr_u*)s,n/addr.get_element_size());
276    done=true;
277    if(!cache)
278       cache=new ResolverCache;
279    cache->Add(hostname,portname,defport,service,proto,addr.get(),addr.count());
280 
281    xstring report;
282    report.set(xstring::format(plural("%d address$|es$ found",addr.count()),addr.count()));
283    if(addr.count()>0) {
284       report.append(": ");
285       for(int i=0; i<addr.count(); i++) {
286 	 report.append(addr[i].address());
287 	 if(i<addr.count()-1)
288 	    report.append(", ");
289       }
290    }
291    LogNote(4,"%s",report.get());
292 
293    return MOVED;
294 }
295 
MakeErrMsg(const char * f)296 void Resolver::MakeErrMsg(const char *f)
297 {
298    const char *e=strerror(errno);
299    err_msg.vset(f,": ",e,NULL);
300    done=true;
301 }
302 
AddAddress(int family,const char * address,int len,unsigned int scope)303 void Resolver::AddAddress(int family,const char *address,int len, unsigned int scope)
304 {
305    sockaddr_u add;
306    memset(&add,0,sizeof(add));
307 
308    add.sa.sa_family=family;
309    switch(family)
310    {
311    case AF_INET:
312       if(sizeof(add.in.sin_addr) != len)
313          return;
314       memcpy(&add.in.sin_addr,address,len);
315       add.in.sin_port=port_number;
316 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
317       add.sa.sa_len=sizeof(add.in);
318 #endif
319       break;
320 
321 #if INET6
322    case AF_INET6:
323       if(sizeof(add.in6.sin6_addr) != len)
324          return;
325       memcpy(&add.in6.sin6_addr,address,len);
326       if(IN6_IS_ADDR_LINKLOCAL(&add.in6.sin6_addr) && scope==0) {
327 	 error=_("Link-local IPv6 address should have a scope");
328 	 return;
329       }
330       add.in6.sin6_port=port_number;
331 # ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
332       add.in6.sin6_scope_id=scope;
333 # endif
334 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
335       add.sa.sa_len=sizeof(add.in6);
336 # endif
337       break;
338 #endif
339 
340    default:
341       return;
342    }
343    if(addr.count()>0 && addr.last()==add)
344       return;
345    addr.append(add);
346 }
347 
FindAddressFamily(const char * name)348 int Resolver::FindAddressFamily(const char *name)
349 {
350    for(const address_family *f=af_list; f->name; f++)
351    {
352       if(!strcasecmp(name,f->name))
353 	 return f->number;
354    }
355    return -1;
356 }
357 
IsAddressFamilySupporded(int af)358 bool Resolver::IsAddressFamilySupporded(int af)
359 {
360 #if INET6
361    // check if ipv6 is really supported
362    if(af==AF_INET6 && (!FindGlobalIPv6Address() || !CanCreateIpv6Socket()))
363    {
364       LogNote(4, "IPv6 is not supported or configured");
365       return false;
366    }
367 #endif // INET6
368    return true;
369 }
370 
ParseOrder(const char * s,int * o)371 void Resolver::ParseOrder(const char *s,int *o)
372 {
373    const char * const delim="\t ";
374    char *s1=alloca_strdup(s);
375    int idx=0;
376 
377    for(s1=strtok(s1,delim); s1; s1=strtok(0,delim))
378    {
379       int af=FindAddressFamily(s1);
380       if(af!=-1 && idx<15 && IsAddressFamilySupporded(af))
381       {
382 	 if(o) o[idx]=af;
383 	 idx++;
384       }
385    }
386    if(o) o[idx]=-1;
387 }
388 
389 #if defined(HAVE_DN_EXPAND) && !HAVE_DECL_DN_EXPAND
390 CDECL int dn_expand(const unsigned char *msg,const unsigned char *eomorig,const unsigned char *comp_dn,char *exp_dn,int length);
391 CDECL int dn_skipname(const unsigned char *msg,const unsigned char *eomorig);
392 #endif
393 
394 #ifdef HAVE_RES_SEARCH
395 static
extract_domain(const unsigned char * answer,const unsigned char * scan,int len,char * store,int store_len)396 int extract_domain(const unsigned char *answer,const unsigned char *scan,int len,
397 		     char *store,int store_len)
398 {
399 #ifdef HAVE_DN_EXPAND // newer resolver versions have dn_expand and dn_skipname
400    if(store)
401       dn_expand(answer,scan+len,scan,store,store_len);
402    return dn_skipname(scan,scan+len);
403 #else // ...older don't.
404    int count=1;	  // reserve space for \0
405    int refs=0;
406    int consumed=0;
407    const unsigned char *start=scan;
408    for(;;)
409    {
410       if(len<=0)
411 	 break;
412       int label_len=*scan;
413       scan++;
414       len--;
415 
416       if((label_len & 0xC0) == 0xC0)   // compression
417       {
418 	 if(len<=0)
419 	    break;
420 	 int offset=((label_len&0x3F)<<8) + *scan;
421 	 scan++;
422 	 len--;
423 
424 	 if(refs==0)
425 	    consumed=scan-start;
426 
427 	 if(answer+offset>=scan+len)
428 	    break; // error
429 
430 	 len=scan+len-answer+offset;
431 	 scan=answer+offset;
432 	 if(++refs > 256)
433 	    break;   // too many hops.
434 	 continue;
435       }
436 
437       if(label_len==0)
438 	 break;
439 
440       while(label_len>0)
441       {
442 	 if(len<=0)
443 	    break;
444 	 if(store && count<store_len)
445 	    *store++=*scan;
446 	 count++;
447 	 scan++;
448 	 len--;
449 	 label_len--;
450       }
451       if(store && count<store_len)
452 	 *store++='.';
453       count++;
454    }
455    if(store)
456       *store=0;
457    if(refs==0)
458       consumed=scan-start;
459    return consumed;
460 #endif // DN_EXPAND
461 }
462 
463 #ifndef NS_MAXDNAME
464 # define NS_MAXDNAME 1025
465 #endif
466 #ifndef NS_HFIXEDSZ
467 # define NS_HFIXEDSZ 12
468 #endif
469 
470 struct SRV
471 {
472    char domain[NS_MAXDNAME];
473    int port;
474    int priority;
475    int weight;
476    int order;
477 };
478 
479 static
SRV_compare(const SRV * sa,const SRV * sb)480 int SRV_compare(const SRV *sa,const SRV *sb)
481 {
482    if(sa->priority < sb->priority)
483       return -1;
484    if(sa->priority > sb->priority)
485       return 1;
486    if(sa->order < sb->order)
487       return -1;
488    if(sa->order > sb->order)
489       return 1;
490    if(sa->weight > sb->weight)
491       return -1;
492    if(sa->weight < sb->weight)
493       return 1;
494    return 0;
495 }
496 #endif // RES_SEARCH
497 
LookupSRV_RR()498 void Resolver::LookupSRV_RR()
499 {
500    if(!ResMgr::QueryBool("dns:SRV-query",hostname))
501       return;
502 #ifdef HAVE_RES_SEARCH
503    const char *tproto=proto?proto.get():"tcp";
504    time_t try_time;
505    unsigned char answer[0x1000];
506    const char *srv_name=xstring::format("_%s._%s.%s",service.get(),tproto,hostname.get());
507    srv_name=alloca_strdup(srv_name);
508 
509    int retries=0;
510    int max_retries=ResMgr::Query("dns:max-retries",hostname);
511    int len;
512    for(;;)
513    {
514       if(!use_fork)
515       {
516 	 Schedule();
517 	 if(Deleted())
518 	    return;
519       }
520       time(&try_time);
521 
522 #ifndef DNSSEC_LOCAL_VALIDATION
523       len=res_search(srv_name, C_IN, T_SRV, answer, sizeof(answer));
524       if(len>=0)
525 	 break;
526 #else
527       val_status_t val_status;
528       bool require_trust = ResMgr::QueryBool("dns:strict-dnssec",hostname);
529       len=val_res_search(NULL, srv_name, C_IN, T_SRV, answer, sizeof(answer), &val_status);
530       if(len>=0) {
531           if(require_trust && !val_istrusted(val_status))
532               return;
533           else
534               break;
535       }
536 #endif
537 #ifdef HAVE_H_ERRNO
538       if(h_errno!=TRY_AGAIN)
539 	 return;
540       if(++retries>=max_retries && max_retries)
541 	 return;
542       time_t t=time(0);
543       if(t-try_time<5)
544 	 sleep(5-(t-try_time));
545 #else // no h_errno
546       return;
547 #endif
548    }
549 
550    if(len>(int)sizeof(answer))
551       len=sizeof(answer);
552 
553    if(len<NS_HFIXEDSZ)
554       return;
555 
556    int question_count=(answer[4]<<8)+answer[5];
557    int answer_count  =(answer[6]<<8)+answer[7];
558 
559    // skip header
560    unsigned char *scan=answer+NS_HFIXEDSZ;
561    len-=NS_HFIXEDSZ;
562 
563    // skip questions section
564    for( ; question_count>0; question_count--)
565    {
566       int dom_len=extract_domain(answer,scan,len,0,0);
567       if(dom_len<0)
568 	 return;
569       scan+=dom_len;
570       len-=dom_len;
571       if(len<4)
572 	 return;
573       scan+=4;
574       len-=4;
575    }
576 
577    xarray<SRV> SRVs;
578 
579    // now process answers section
580    for( ; answer_count>0; answer_count--)
581    {
582       int dom_len=extract_domain(answer,scan,len,0,0);
583       if(dom_len<0)
584 	 return;
585       scan+=dom_len;
586       len-=dom_len;
587       if(len<8)
588 	 return;
589       scan+=8;
590       len-=8;  // skip type,class,ttl
591 
592       if(len<2)
593 	 return;
594 
595       int data_len=(scan[0]<<8)+scan[1];
596       scan+=2;
597       len-=2;
598 
599       if(len<data_len)
600 	 return;
601 
602       if(data_len<6)
603 	 return;
604 
605       struct SRV t;
606       t.priority=(scan[0]<<8)+scan[1];
607       t.weight  =(scan[2]<<8)+scan[3];
608       t.port    =(scan[4]<<8)+scan[5];
609       t.order=0;
610 
611       scan+=6;
612       len-=6;
613 
614       dom_len=extract_domain(answer,scan,len,t.domain,sizeof(t.domain));
615       if(dom_len<0)
616 	 return;
617 
618       scan+=dom_len;
619       len-=dom_len;
620 
621       // add unless the service is decidedly not available at this domain.
622       if(strcmp(t.domain,"."))
623 	 SRVs.append(t);
624    }
625 
626    // now sort and randomize the list.
627    SRVs.qsort(SRV_compare);
628 
629    srand(time(0));
630 
631    int SRVscan;
632    int base=0;
633    int curr_priority=-1;
634    int weight_sum=0;
635    for(SRVscan=0; ; SRVscan++)
636    {
637       if(SRVscan==SRVs.count() || SRVs[SRVscan].priority!=curr_priority)
638       {
639 	 if(base)
640 	 {
641 	    int o=1;
642 	    int s;
643 	    while(weight_sum>0)
644 	    {
645 	       int r=int(rand()/(RAND_MAX+1.0)*weight_sum);
646 	       if(r>=weight_sum)
647 		  r=weight_sum-1;
648 	       int w=0;
649 	       for(s=base; s<SRVscan; s++)
650 	       {
651 		  if(SRVs[s].order!=0)
652 		     continue;
653 		  w+=SRVs[s].weight;
654 		  if(r<w)
655 		  {
656 		     SRVs[s].order=o;
657 		     o++;
658 		     weight_sum-=SRVs[s].weight;
659 		     break;
660 		  }
661 	       }
662 	    }
663 	 }
664 	 if(SRVscan==SRVs.count())
665 	    break;
666 	 base=SRVscan;
667 	 curr_priority=SRVs[SRVscan].priority;
668 	 weight_sum=0;
669       }
670       weight_sum+=SRVs[SRVscan].weight;
671    }
672 
673    SRVs.qsort(SRV_compare);
674 
675    int oldport=port_number;
676    for(SRVscan=0; SRVscan<SRVs.count(); SRVscan++)
677    {
678       port_number=htons(SRVs[SRVscan].port);
679       LookupOne(SRVs[SRVscan].domain);
680    }
681    port_number=oldport;
682 
683 #endif // HAVE_RES_SEARCH
684 }
685 
LookupOne(const char * name)686 void Resolver::LookupOne(const char *name)
687 {
688    time_t try_time;
689    int af_index=0;
690    int af_order[16];
691 
692    const char *order=ResMgr::Query("dns:order",name);
693 
694    const char *proto_delim=strchr(name,',');
695    if(proto_delim)
696    {
697       char *o=string_alloca(proto_delim-name+1);
698       memcpy(o,name,proto_delim-name);
699       o[proto_delim-name]=0;
700       // check if the protocol name is valid.
701       if(FindAddressFamily(o)!=-1)
702 	 order=o;
703       name=proto_delim+1;
704    }
705 
706 #if LIBIDN2
707    xstring_c ascii_name;
708    int rc=idn2_lookup_ul(name,ascii_name.buf_ptr(),0);
709    if(rc!=IDN2_OK) {
710       error=idn2_strerror(rc);
711       return;
712    }
713    name=ascii_name;
714 #endif//LIBIDN2
715 
716    ParseOrder(order,af_order);
717 
718    int retries=0;
719    int max_retries=ResMgr::Query("dns:max-retries",name);
720    for(;;)
721    {
722       if(!use_fork)
723       {
724 	 Schedule();
725 	 if(Deleted())
726 	    return;
727       }
728 
729       time(&try_time);
730 
731 // Prefer getaddrinfo over gethostbyname2 and getipnodebyname, as
732 // approach with multiple lookups works badly when host name is in hosts file
733 // and no dns servers are reachable.
734 #if defined(HAVE_GETADDRINFO) && INET6
735 /* && !defined(HAVE_GETHOSTBYNAME2) \
736    && !defined(HAVE_GETIPNODEBYNAME) */
737 
738       // getaddrinfo support by Brandon Hume
739       struct addrinfo	    *ainfo=0,
740 			    *a_res,
741 			    a_hint;
742       int		    ainfo_res;
743       struct sockaddr	    *sockname;
744       struct sockaddr_in    *inet_addr;
745       struct sockaddr_in6   *inet6_addr;
746       const char	    *addr_data;
747       int		    addr_len;
748       unsigned int          addr_scope;
749 
750       memset(&a_hint, 0, sizeof(a_hint));
751       a_hint.ai_flags	    = AI_PASSIVE;
752       a_hint.ai_family	    = PF_UNSPEC;
753 
754 #ifndef DNSSEC_LOCAL_VALIDATION
755       ainfo_res	= getaddrinfo(name, NULL, &a_hint, &ainfo);
756 #else
757       val_status_t val_status;
758       bool require_trust=ResMgr::QueryBool("dns:strict-dnssec",name);
759       ainfo_res	= val_getaddrinfo(NULL, name, NULL, &a_hint, &ainfo,
760                                   &val_status);
761       if(VAL_GETADDRINFO_HAS_STATUS(ainfo_res) && !val_istrusted(val_status))
762       {
763           if(require_trust) {
764               // untrusted answer
765               error = _("DNS resolution not trusted.");
766               break;
767           } else {
768               fprintf(stderr,"\nWARNING: DNS lookup failed validation: %s\n",
769                       p_val_status(val_status));
770 	      fflush(stderr);
771           }
772       }
773 #endif
774 
775       if(ainfo_res == 0)
776       {
777         // by lav: add addresses in specified order.
778 	for(int af=af_order[af_index]; af!=-1; af=af_order[++af_index])
779 	{
780 	    for(a_res = ainfo; a_res != NULL; a_res = a_res->ai_next)
781 	    {
782 	       if(a_res->ai_family!=af)
783 		  continue;
784 
785 	       sockname	= a_res->ai_addr;
786 	       addr_scope = 0;
787 
788 	       switch(a_res->ai_family)
789 	       {
790 	       case AF_INET:
791 		  inet_addr   = (sockaddr_in *)sockname;
792 		  addr_data   = (const char *)&(inet_addr->sin_addr.s_addr);
793 		  addr_len    = sizeof(inet_addr->sin_addr.s_addr);
794 		  break;
795 	       case AF_INET6:
796 		  inet6_addr  = (sockaddr_in6 *)sockname;
797 		  addr_data   = (const char *)&(inet6_addr->sin6_addr.s6_addr);
798 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
799 		  addr_scope  = inet6_addr->sin6_scope_id;
800 #endif
801 		  addr_len    = sizeof(inet6_addr->sin6_addr.s6_addr);
802 		  break;
803 	       default:
804 		  continue;
805 	       }
806 	       AddAddress(a_res->ai_family, addr_data, addr_len, addr_scope);
807 	    }
808 	 }
809 
810 	 freeaddrinfo(ainfo);
811 	 break;
812       }
813 
814       if(ainfo_res != EAI_AGAIN
815       || (++retries>=max_retries && max_retries))
816       {
817 	 error = gai_strerror(ainfo_res);
818 	 break;
819       }
820 
821 #else // !HAVE_GETADDRINFO
822 
823       int af=af_order[af_index];
824       if(af==-1)
825 	 break;
826 
827       struct hostent *ha;
828 # if defined(HAVE_GETIPNODEBYNAME)
829 #  ifndef HAVE_H_ERRNO
830 #   define HAVE_H_ERRNO 1
831 #  endif
832 #  undef h_errno // it could be a macro, but we want it to be local variable.
833       int h_errno=0;
834       ha=getipnodebyname(name,af,0,&h_errno);
835 # elif defined(HAVE_GETHOSTBYNAME2)
836       ha=gethostbyname2(name,af);
837 # else
838       if(af==AF_INET)
839 	 ha=gethostbyname(name);
840       else
841       {
842 	 retries=0;
843 	 af_index++;
844 	 continue;
845       }
846 # endif
847 
848       if(ha)
849       {
850 	 const char * const *a;
851 	 for(a=ha->h_addr_list; *a; a++)
852 	    AddAddress(ha->h_addrtype, *a, ha->h_length, 0);
853 	 retries=0;
854 	 af_index++;
855 # if defined(HAVE_GETIPNODEBYNAME)
856 	 freehostent(ha);
857 # endif
858 	 continue;
859       }
860 
861 # ifdef HAVE_H_ERRNO
862       if(h_errno!=TRY_AGAIN
863       || (++retries>=max_retries && max_retries))
864 # endif
865       {
866 	 if(error==0)
867 	 {
868 # ifdef HAVE_H_ERRNO
869 	    error=hstrerror(h_errno);
870 # else
871 	    error=_("Host name lookup failure");
872 # endif
873 	 }
874 	 retries=0;
875 	 af_index++;
876 	 continue; // try other address families
877       }
878 #endif /* HAVE_GETADDRINFO */
879 
880       time_t t;
881       if((t=time(0))-try_time<5)
882 	 sleep(5-(t-try_time));
883    }
884 }
885 
DoGethostbyname()886 void Resolver::DoGethostbyname()
887 {
888    if(port_number==0)
889    {
890       const char *tproto=proto?proto.get():"tcp";
891       const char *tport=portname?portname.get():defport.get();
892 
893       if(isdigit((unsigned char)tport[0]))
894 	 port_number=htons(atoi(tport));
895       else
896       {
897 	 struct servent *se=getservbyname(tport,tproto);
898 	 if(se)
899 	    port_number=se->s_port;
900 	 else
901 	 {
902 	    buf->Put("P");
903 	    buf->Format(_("no such %s service"),tproto);
904 	    return;
905 	 }
906       }
907    }
908 
909    if(service && !portname && !isdigit((unsigned char)hostname[0]))
910       LookupSRV_RR();
911 
912    if(!use_fork && Deleted())
913       return;
914 
915    const char *h=ResMgr::Query("dns:name",hostname);
916    if(!h || !*h)
917       h=hostname;
918    char *hs=alloca_strdup(h);
919    char *tok;
920    for(hs=strtok_r(hs,",",&tok); hs; hs=strtok_r(NULL,",",&tok))
921       LookupOne(hs);
922 
923    if(!use_fork && Deleted())
924       return;
925 
926    if(addr.count()==0)
927    {
928       buf->Put("E");
929       if(error==0)
930 	 error=_("No address found");
931       buf->Put(error);
932       return;
933    }
934    buf->Put("O");
935    buf->Put((const char*)addr.get(),addr.count()*addr.get_element_size());
936    addr.unset();
937 }
938 
Reconfig(const char * name)939 void Resolver::Reconfig(const char *name)
940 {
941    if(!name || strncmp(name,"dns:",4))
942       return;
943 }
944 
945 
ResolverCache()946 ResolverCache::ResolverCache()
947    : Cache(ResMgr::FindRes("dns:cache-size"),ResMgr::FindRes("dns:cache-enable"))
948 {
949 }
Reconfig(const char * r)950 void ResolverCache::Reconfig(const char *r)
951 {
952    if(!xstrcmp(r,"dns:SRV-query")
953    || !xstrcmp(r,"dns:order"))
954       Flush();
955 }
Find(const char * h,const char * p,const char * defp,const char * ser,const char * pr)956 ResolverCacheEntry *ResolverCache::Find(const char *h,const char *p,const char *defp,const char *ser,const char *pr)
957 {
958    for(ResolverCacheEntry *c=IterateFirst(); c; c=IterateNext())
959    {
960       if(c->Matches(h,p,defp,ser,pr))
961 	 return c;
962    }
963    return 0;
964 }
Add(const char * h,const char * p,const char * defp,const char * ser,const char * pr,const sockaddr_u * a,int n)965 void ResolverCache::Add(const char *h,const char *p,const char *defp,
966 	 const char *ser,const char *pr,const sockaddr_u *a,int n)
967 {
968    Trim();
969    ResolverCacheEntry *c=Find(h,p,defp,ser,pr);
970    if(c)
971       c->SetData(a,n);
972    else
973    {
974       if(!IsEnabled(h))
975 	 return;
976       AddCacheEntry(new ResolverCacheEntry(h,p,defp,ser,pr,a,n));
977    }
978 }
Matches(const char * h,const char * p,const char * defp,const char * ser,const char * pr)979 bool ResolverCacheEntryLoc::Matches(const char *h,const char *p,
980 	 const char *defp,const char *ser,const char *pr)
981 {
982    return (!xstrcasecmp(hostname,h)
983       && !xstrcmp(portname,p)
984       && !xstrcmp(defport,defp)
985       && !xstrcmp(service,ser)
986       && !xstrcmp(proto,pr));
987 }
Find(const char * h,const char * p,const char * defp,const char * ser,const char * pr,const sockaddr_u ** a,int * n)988 void ResolverCache::Find(const char *h,const char *p,const char *defp,
989 	 const char *ser,const char *pr,const sockaddr_u **a,int *n)
990 {
991    *a=0;
992    *n=0;
993 
994    // if cache is disabled for this host, return nothing.
995    if(!IsEnabled(h))
996       return;
997 
998    ResolverCacheEntry *c=Find(h,p,defp,ser,pr);
999    if(c)
1000    {
1001       if(c->Stopped())
1002       {
1003 	 Trim();
1004 	 return;
1005       }
1006       c->GetData(a,n);
1007    }
1008 }
1009