NCBI C++ ToolKit
ncbi_lbdns.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbi_lbdns.c 100535 2023-08-10 14:52:24Z lavr $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Anton Lavrentiev
27  *
28  * File Description:
29  * Low-level API to resolve an NCBI service name to server meta-addresses
30  * with the use of DNS.
31  *
32  */
33 
34 #include "ncbi_ansi_ext.h"
35 #include "ncbi_lbdns.h"
36 #include "ncbi_once.h"
37 
38 #ifdef NCBI_OS_UNIX
39 
40 #include "ncbi_lb.h"
41 #include <connect/ncbi_ipv6.h>
42 #include <ctype.h>
43 #include <errno.h>
44 #include <math.h>
45 #include <netdb.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include <arpa/inet.h>
51 #ifdef NCBI_OS_DARWIN
52 # define BIND_8_COMPAT 1
53 #endif /*NCBI_OS_DARWIN*/
54 #include <arpa/nameser.h>
55 #include <netinet/in.h>
56 #include <resolv.h>
57 
58 #define NCBI_USE_ERRCODE_X Connect_LBSM /* errors: 32 and up */
59 
60 
61 #define SizeOf(a) (sizeof(a) / sizeof((a)[0]))
62 #ifdef max
63 #undef max
64 #endif/*max*/
65 #define max(a, b) ((a) > (b) ? (a) : (b))
66 
67 #define SERVNSD_TXT_RR_PORT_LEN (sizeof(SERVNSD_TXT_RR_PORT)-1)
68 
69 #define LBDNS_INITIAL_ALLOC 32
70 
71 
72 #if defined(HAVE_SOCKLEN_T) || defined(_SOCKLEN_T)
74 #else
75 typedef int TSOCK_socklen_t;
76 #endif /*HAVE_SOCKLEN_T || _SOCKLEN_T*/
77 
78 
79 #ifdef __cplusplus
80 extern "C" {
81 #endif /*__cplusplus*/
82 
84 static void s_Reset (SERV_ITER);
85 static void s_Close (SERV_ITER);
86 
87 static const SSERV_VTable kLbdnsOp = {
88  s_GetNextInfo, 0/*Feedback*/, 0/*Update*/, s_Reset, s_Close, "LBDNS"
89 };
90 
91 #ifdef __cplusplus
92 } /* extern "C" */
93 #endif /*__cplusplus*/
94 
95 
96 struct SLBDNS_Data {
97  unsigned int host; /* LB DNS server host */
98  unsigned short port; /* LB DNS server port */
99  unsigned debug:1; /* Debug output */
100  unsigned check:1; /* Private check mode */
101  unsigned empty:1; /* No more data */
102  unsigned :13; /* Reserved */
103  const char* domain; /* Domain name to use:
104  no lead/trail '.' */
105  size_t domlen; /* Domain name length */
106  size_t a_cand; /* Allocated elements */
107  size_t n_cand; /* Used elements */
108  SLB_Candidate cand[1]; /* "a_cand" elements */
109 };
110 
111 
112 static const char* x_TypeStr(ns_type atype, char* buf)
113 {
114  switch (atype) {
115  case ns_t_a:
116  return "A";
117  case ns_t_ns:
118  return "NS";
119  case ns_t_cname:
120  return "CNAME";
121  case ns_t_soa:
122  return "SOA";
123  case ns_t_null:
124  return "NULL";
125  case ns_t_ptr:
126  return "PTR";
127  case ns_t_hinfo:
128  return "HINFO";
129  case ns_t_mx:
130  return "MX";
131  case ns_t_txt:
132  return "TXT";
133  case ns_t_rp:
134  return "RP";
135  case ns_t_aaaa:
136  return "AAAA";
137  case ns_t_srv:
138  return "SRV";
139  case ns_t_a6:
140  return "A6";
141  case ns_t_opt:
142  return "OPT";
143  case ns_t_any:
144  return "ANY";
145 #ifdef T_URI
146  case ns_t_uri:
147  return "URI";
148 #endif /*T_URI*/
149  default:
150  break;
151  }
152  sprintf(buf, "TYPE(%hu)", (unsigned short) atype);
153  return buf;
154 }
155 
156 
157 static const char* x_ClassStr(ns_class aclass, char* buf)
158 {
159  switch (aclass) {
160  case ns_c_in:
161  return "IN";
162  case ns_c_any:
163  return "ANY";
164  default:
165  break;
166  }
167  sprintf(buf, "CLASS(%hu)", (unsigned short) aclass);
168  return buf;
169 }
170 
171 
172 static const char* x_RcodeStr(unsigned short rcode, char* buf)
173 {
174  switch (rcode) {
175  case ns_r_noerror:
176  return "NOERROR";
177  case ns_r_formerr:
178  return "FORMERR";
179  case ns_r_servfail:
180  return "SERVFAIL";
181  case ns_r_nxdomain:
182  return "NXDOMAIN";
183  case ns_r_notimpl:
184  return "NOTIMPL";
185  case ns_r_refused:
186  return "REFUSED";
187  default:
188  break;
189  }
190  sprintf(buf, "RCODE(%hu)", rcode);
191  return buf;
192 }
193 
194 
195 static const char* x_OpcodeStr(unsigned short opcode, char* buf)
196 {
197  switch (opcode) {
198  case ns_o_query:
199  return "QUERY";
200  case ns_o_iquery:
201  return "IQUERY";
202  case ns_o_status:
203  return "STATUS";
204  case ns_o_notify:
205  return "NOTIFY";
206  case ns_o_update:
207  return "UPDATE";
208  default:
209  break;
210  }
211  sprintf(buf, "OPCODE(%hu)", opcode);
212  return buf;
213 }
214 
215 
216 static const char* strherror(int err)
217 {
218  switch (err) {
219 #ifdef NETDB_INTERNAL
220  case NETDB_INTERNAL:
221  return "Internal error";
222 #endif /*NETDB_INTERNAL*/
223 #ifdef HOST_NOT_FOUND
224  case HOST_NOT_FOUND:
225  return "Host not found";
226 #endif /*HOST_NOT_FOUND*/
227 #ifdef TRY_AGAIN
228  case TRY_AGAIN:
229  return "Server failure";
230 #endif /*TRY_AGAIN*/
231 #ifdef NO_RECOVERY
232  case NO_RECOVERY:
233  return "Unrecoverable error";
234 #endif /*NO_RECOVERY*/
235 #ifdef NO_ADDRESS
236 # if !defined(NO_DATA) || NO_DATA != NO_ADDRESS
237  case NO_ADDRESS:
238  return "No address record found";
239 # endif /*!NO_DATA || NO_DATA!=NO_ADDRESS*/
240 #endif /*NO_ADDRESS*/
241 #ifdef NO_DATA
242  case NO_DATA:
243  return "No data of requested type";
244 #endif /*NO_DATA*/
245  default:
246  break;
247  }
248  return hstrerror(err);
249 }
250 
251 
252 static const char* x_FlagsStr(const HEADER* hdr, char* buf)
253 {
254  char rcode[40];
255  char* ptr = (char*) x_OpcodeStr(hdr->opcode, buf);
256  size_t len = strlen(ptr);
257  if (ptr != buf) {
258  memcpy(buf, ptr, len);
259  ptr = buf;
260  }
261  ptr += len;
262  if (hdr->aa)
263  ptr += sprintf(ptr, ", AA");
264  if (hdr->tc)
265  ptr += sprintf(ptr, ", TC");
266  if (hdr->rd)
267  ptr += sprintf(ptr, ", RD");
268  if (hdr->ra)
269  ptr += sprintf(ptr, ", RA");
270  if (hdr->unused)
271  ptr += sprintf(ptr, ", Z?");
272  if (hdr->ad)
273  ptr += sprintf(ptr, ", AD");
274  if (hdr->cd)
275  ptr += sprintf(ptr, ", CD");
276  sprintf(ptr, ", %s", x_RcodeStr(hdr->rcode, rcode));
277  return buf;
278 }
279 
280 
281 static void x_DumpHdr(const HEADER* hdr, const unsigned short count[4])
282 {
283  char buf[128];
285  ("DNS %s (ID=%hu, 0x%04hX):\n"
286  "\t%s\n"
287  "\tQD: %hu, AN: %hu, NS: %hu, AR: %hu",
288  hdr->qr ? "REPLY" : "QUERY",
289  ntohs(hdr->id),
290  ntohs(((const unsigned short*) hdr)[1]),
291  x_FlagsStr(hdr, buf),
292  count[0], count[1], count[2], count[3]));
293 }
294 
295 
296 static void x_DumpRR(const ns_rr* rr, const char* part, unsigned short n)
297 {
298  char clbuf[40], tybuf[40], ttlbuf[40], szbuf[40];
299  if (part) {
300  sprintf(ttlbuf, " %lu", (unsigned long) ns_rr_ttl(*rr));
301  sprintf(szbuf, " (%u)", ns_rr_rdlen(*rr));
302  } else
303  *ttlbuf = *szbuf = '\0';
305  ("%s%s %2hu: %s%s %s %s%s",
306  part ? part : "QD",
307  part ? " RR" : " ", n,
308  ns_rr_name(*rr), ttlbuf,
309  x_ClassStr(ns_rr_class(*rr), clbuf),
310  x_TypeStr(ns_rr_type(*rr), tybuf), szbuf));
311 }
312 
313 
314 static int unpack_rr(const unsigned char* msg, const unsigned char* eom,
315  const unsigned char* ptr, ns_rr* rr, int/*bool*/ qd,
316  ELOG_Level level)
317 {
318  const char* what = qd ? "QD" : "RR";
319  int len, size;
320 
321  memset(rr, 0, sizeof(*rr));
322  if ((len = dn_expand(msg, eom, ptr, rr->name, sizeof(rr->name))) <= 0) {
323  CORE_LOGF(level, ("DNS %s cannot expand name", what));
324  return -1;
325  }
326  ptr += len;
327  size = qd ? NS_QFIXEDSZ : NS_RRFIXEDSZ;
328  if (ptr + size > eom) {
329  CORE_LOGF(level, ("DNS %s overrun", what));
330  return -1;
331  }
332  assert(NS_QFIXEDSZ == NS_INT16SZ*2);
333  assert(NS_RRFIXEDSZ == NS_INT16SZ*2 + NS_INT32SZ + NS_INT16SZ);
334  NS_GET16(rr->type, ptr);
335  NS_GET16(rr->rr_class, ptr);
336  if (!qd) {
337  char buf[40];
338  NS_GET32(rr->ttl, ptr);
339  NS_GET16(rr->rdlength, ptr);
340  if (!rr->rdlength) {
342  ("DNS RR %s RDATA empty",
343  x_TypeStr(ns_rr_type(*rr), buf)));
344  } else if (ptr + rr->rdlength > eom) {
345  CORE_LOGF(level,
346  ("DNS RR %s RDATA overrun",
347  x_TypeStr(ns_rr_type(*rr), buf)));
348  return -1;
349  }
350  size += rr->rdlength;
351  rr->rdata = ptr;
352  }
353  return len + size;
354 }
355 
356 
357 static int skip_rr(const unsigned char* ptr, const unsigned char* eom,
358  int/*bool*/ qd)
359 {
360  const char* what = qd ? "QD" : "RR";
361  int len, size;
362 
363  if ((len = dn_skipname(ptr, eom)) <= 0) {
364  CORE_LOGF(eLOG_Error, ("DNS %s cannot skip name", what));
365  return -1;
366  }
367  ptr += len;
368  size = qd ? NS_QFIXEDSZ : NS_RRFIXEDSZ;
369  if (ptr + size > eom) {
370  CORE_LOGF(eLOG_Error, ("DNS %s overrun", what));
371  return -1;
372  }
373  if (!qd) {
374  unsigned short rdlen;
375  ptr += NS_INT16SZ*2 + NS_INT32SZ;
376  NS_GET16(rdlen, ptr);
377  if (ptr + rdlen > eom) {
378  CORE_LOG(eLOG_Error, "DNS RR RDATA overrun");
379  return -1;
380  }
381  size += rdlen;
382  }
383  return len + size;
384 }
385 
386 
387 static const unsigned char* x_DumpMsg(const unsigned char* msg,
388  const unsigned char* eom)
389 {
390  static const char* kPart[] = { 0/*QD*/, "AN", "NS", "AR" };
391  const unsigned char* ptr = msg + NS_HFIXEDSZ;
392  const HEADER* hdr = (const HEADER*) msg;
393  unsigned short count[SizeOf(kPart)];
394  size_t n;
395 
396  assert(sizeof(*hdr) == NS_HFIXEDSZ);
397  count[0] = ntohs(hdr->qdcount);
398  count[1] = ntohs(hdr->ancount);
399  count[2] = ntohs(hdr->nscount);
400  count[3] = ntohs(hdr->arcount);
401  x_DumpHdr(hdr, count);
402 
403  if (ptr >= eom)
404  return ptr;
405  for (n = 0; n < SizeOf(count); ++n) {
406  unsigned short c = 0;
407  while (c < count[n]) {
408  ns_rr rr;
409  int rv = unpack_rr(msg, eom, ptr, &rr, !n, eLOG_Trace);
410  if (rv < 0)
411  return ptr;
412  x_DumpRR(&rr, kPart[n], ++c);
413  ptr += rv;
414  }
415  }
416  return ptr;
417 }
418 
419 
420 static int/*bool*/ x_AddInfo(SERV_ITER iter, SSERV_Info* info)
421 {
422  const char* name = SERV_NameOfInfo(info); /*name==NULL iff info==NULL*/
423  struct SLBDNS_Data* data = (struct SLBDNS_Data*) iter->data;
424  size_t n;
425 
426  if (!name) {
427  assert(!info);
429  ("LBDNS cannot create entry for \"%s\"", iter->name));
430  return 0/*failure(NULL info)*/;
431  }
432  assert(info);
433  assert(info->port || info->type == fSERV_Dns);
434  assert(info->host || info->type == fSERV_Standalone);
435  assert(info->type == fSERV_Dns || info->type == fSERV_Standalone);
436  for (n = 0; n < data->n_cand; ++n) {
437  if (SERV_EqualInfo(info, data->cand[n].info)
438  && strcasecmp(name, SERV_NameOfInfo(data->cand[n].info)) == 0) {
439  char* infostr = SERV_WriteInfo(info);
441  ("LBDNS ignoring duplicate entry: \"%s\" %s", name,
442  infostr ? infostr : "<NULL>"));
443  if (infostr)
444  free(infostr);
445  free(info);
446  return 1/*fake success*/;
447  }
448  }
449  if (data->n_cand == data->a_cand) {
450  n = data->a_cand << 1;
451  data = (struct SLBDNS_Data*) realloc(iter->data, sizeof(*data)
452  + (n - 1) * sizeof(data->cand));
453  if (!data) {
455  ("LBDNS cannot add entry for \"%s\"", iter->name));
456  free(info);
457  return 0/*failure*/;
458  }
459  iter->data = data;
460  data->a_cand = n;
461  }
462  assert(data->n_cand < data->a_cand);
463  data->cand[data->n_cand++].info = info;
464  if (data->debug) {
465  char* infostr = SERV_WriteInfo(info);
467  ("LBDNS adding \"%s\" @%p %s", name, info,
468  infostr ? infostr : "NULL"));
469  if (infostr)
470  free(infostr);
471  }
472  return 1/*success*/;
473 }
474 
475 
476 static int/*bool*/ x_UpdateHost(SERV_ITER iter, const char* fqdn,
477  const TNCBI_IPv6Addr* addr)
478 {
479  struct SLBDNS_Data* data = (struct SLBDNS_Data*) iter->data;
480  int/*bool*/ done = 0/*false*/;
481  unsigned int host;
482  size_t n;
483 
484  assert(!NcbiIsEmptyIPv6(addr));
485  host = NcbiIPv6ToIPv4(addr, 0);
486  for (n = 0; n < data->n_cand; ++n) {
487  SSERV_Info* x_info, *info = (SSERV_Info*) data->cand[n].info;
488  const char* name = SERV_NameOfInfo(info);
489  char buf[INET6_ADDRSTRLEN];
490  if (strcasecmp(fqdn, name) != 0)
491  continue;
492  if (!info->host) {
493  assert(NcbiIsEmptyIPv6(&info->addr));
494  info->host = host ? host : (unsigned int)(-1);
495  info->addr = *addr;
496  x_info = info;
497  } else if (!host && info->host == NcbiIPv6ToIPv4(&info->addr, 0)) {
498  if ((x_info = SERV_CopyInfoEx(info, name)) != 0) {
499  x_info->host = (unsigned int)(-1);
500  x_info->addr = *addr;
501  }
502  } else if ( host && info->host == (unsigned int)(-1)) {
503  if ((x_info = SERV_CopyInfoEx(info, name)) != 0) {
504  x_info->host = host;
505  NcbiIPv4ToIPv6(&x_info->addr, host, 0);
506  }
507  } else {
508  /* NB: "buf" is always '\0'-terminated, even on error */
509  NcbiAddrToString(buf, sizeof(buf), addr);
511  ("LBDNS cannot re-update entry \"%s\" @%p with host"
512  " \"%s\": %s", SERV_NameOfInfo(info), info, fqdn, buf));
513  continue;
514  }
515  if (x_info != info) {
516  if (!x_AddInfo(iter, x_info))
517  x_info = 0;
518  } else if (data->debug) {
519  NcbiAddrToString(buf, sizeof(buf), addr);
521  ("LBDNS updating entry \"%s\" @%p with host \"%s\": %s",
522  SERV_NameOfInfo(info), info, fqdn, buf));
523  }
524  if (x_info) {
525  if (done) {
526  NcbiAddrToString(buf, sizeof(buf), addr);
528  ("LBDNS multiple entries updated with host \"%s\":"
529  " %s", fqdn, buf));
530  } else
531  done = 1/*true*/;
532  }
533  }
534  return done;
535 }
536 
537 
538 static void x_UpdatePort(SERV_ITER iter, unsigned short port)
539 {
540  struct SLBDNS_Data* data = (struct SLBDNS_Data*) iter->data;
541  size_t n;
542  assert(port);
543  for (n = 0; n < data->n_cand; ++n) {
544  SSERV_Info* info = (SSERV_Info*) data->cand[n].info;
545  if (!info->port) {
546  assert(info->host && info->type == fSERV_Dns);
547  info->port = port;
548  if (data->debug) {
550  ("LBDNS updating entry \"%s\" @%p with port: %hu",
552  }
553  }
554  }
555 }
556 
557 
559 {
561  memset(info, 0, sizeof(*info));
562  info->type = type;
563  info->site = fSERV_Local;
564  info->time = LBSM_DEFAULT_TIME;
565  info->mime_t = eMIME_T_Undefined;
566  info->mime_s = eMIME_Undefined;
567  info->mime_e = eENCOD_None;
568  info->algo = SERV_DEFAULT_ALGO;
569 }
570 
571 
572 static double x_RoundUp(double rate)
573 {
574  double tens = floor(rate / 10.0);
575  return (tens + (rate - tens * 10.0 < 10.0 ? 1.0 : 0.0)) * 10.0;
576 }
577 
578 
579 struct ns_rr_srv_ {
580  unsigned short priority;
581  unsigned short weight;
582  unsigned short port;
583 }
584 #ifdef __GNUC__
585 __attribute__((packed))
586 #endif /*__GNUC__*/
587 ;
588 typedef struct ns_rr_srv_ ns_rr_srv;
589 
590 
591 static int/*bool*/ dns_srv(SERV_ITER iter, const unsigned char* msg,
592  const unsigned char* eom, const char* fqdn,
593  unsigned short rdlen, const unsigned char* rdata)
594 {
595  const unsigned char* start = rdata;
596  char target[NS_MAXDNAME];
597  SSERV_Info x_info;
598  ns_rr_srv srv;
599  int rv;
600 
601  if (rdlen <= sizeof(srv)) {
603  ("DNS SRV RR RDATA too short: %hu", rdlen));
604  return 0/*false*/;
605  }
606  memset(&srv, 0, sizeof(srv));
607  NS_GET16(srv.priority, rdata);
608  NS_GET16(srv.weight, rdata);
609  NS_GET16(srv.port, rdata);
610  if ((rv = dn_expand(msg, eom, rdata, target, sizeof(target))) <= 0) {
611  CORE_LOG(eLOG_Error, "DNS SRV RR cannot expand target");
612  return 0/*false*/;
613  }
614  if (&rdata[rv] > &start[rdlen]) {
615  CORE_LOG(eLOG_Error, "DNS SRV RR target overrun");
616  return 0/*false*/;
617  }
618  if (((const struct SLBDNS_Data*) iter->data)->debug) {
620  ("DNS SRV RR %s -> %s:%hu %hu %hu", fqdn,
621  *target ? target : ".",
622  srv.port, srv.priority, srv.weight));
623  }
624  if (&rdata[rv] != &start[rdlen]) {
625  assert(&rdata[rv] < &start[rdlen]);
627  ("DNS SRV RR %lu/%hu byte(s) remain unparsed",
628  (unsigned long)(&start[rdlen] - &rdata[rv]), rdlen));
629  }
630  if (!target[0] || (target[0] == '.' && !target[1])) {
631  /* service down */
632  if (srv.port | srv.priority | srv.weight)
633  CORE_LOG(eLOG_Warning, "DNS SRV RR blank target dirty");
634  return -1/*true, special*/;
635  } else if (!srv.port) {
636  CORE_LOG(eLOG_Error, "DNS SRV RR zero port");
637  return 0/*false*/;
638  }
639  x_BlankInfo(&x_info, fSERV_Standalone);
640  x_info.time += iter->time;
641  x_info.port = srv.port;
642  x_info.rate = srv.priority
643  ? (11.0 - max(srv.priority, 10)) / LBSM_DEFAULT_RATE : srv.weight
644  ? x_RoundUp((srv.weight * SERV_MAXIMAL_RATE) / 0xFFFF) : 1.0;
645  return x_AddInfo(iter, SERV_CopyInfoEx(&x_info, target));
646 }
647 
648 
649 static void dns_txt(SERV_ITER iter, const char* fqdn,
650  unsigned short rdlen, const unsigned char* rdata)
651 {
652  unsigned int len = 0;
653  while (len < rdlen) {
654  char buf[40];
655  unsigned short slen = *rdata++;
656  if ((len += 1 + slen) > rdlen) {
657  CORE_LOG(eLOG_Error, "DNS TXT RR RDATA overrun");
658  return;
659  }
660  if (slen > SERVNSD_TXT_RR_PORT_LEN
661  && slen - SERVNSD_TXT_RR_PORT_LEN < sizeof(buf)
663  && strncasecmp((const char*) rdata, SERVNSD_TXT_RR_PORT,
664  SERVNSD_TXT_RR_PORT_LEN) == 0) {
665  unsigned short port;
666  int n;
667  if (((const struct SLBDNS_Data*) iter->data)->debug) {
669  ("DNS TXT RR %s: \"%.*s\"", fqdn,
670  (int) slen, (const char*) rdata));
671  }
672  rdata += SERVNSD_TXT_RR_PORT_LEN;
673  slen -= SERVNSD_TXT_RR_PORT_LEN;
674  memcpy(buf, rdata, slen);
675  buf[slen] = '\0';
676  assert(strlen(buf) < sizeof(buf));
677  if (sscanf(buf, "%hu%n", &port, &n) > 0 && n == (int) slen && port)
678  x_UpdatePort(iter, port);
679  }
680  rdata += slen;
681  }
682 }
683 
684 
685 static int/*bool*/ dns_a(SERV_ITER iter, ns_type qtype, ns_type rtype,
686  const char* fqdn,
687  unsigned short rdlen, const unsigned char* rdata)
688 {
689  const struct SLBDNS_Data* data = (const struct SLBDNS_Data*) iter->data;
690  char buf[INET6_ADDRSTRLEN];
691  TNCBI_IPv6Addr ipv6;
692  unsigned short len;
693  unsigned int ipv4;
694  SSERV_Info x_info;
695 
696  assert(sizeof(ipv4) == NS_INADDRSZ);
697  assert(sizeof(ipv6) == NS_IN6ADDRSZ);
698  if (rtype == ns_t_a && NS_INADDRSZ <= rdlen) {
699  memcpy(&ipv4, rdata, sizeof(ipv4));
700  if (data->debug) {
702  ("DNS A RR %s @ %s", fqdn,
703  inet_ntop(AF_INET, &ipv4,
704  buf, (TSOCK_socklen_t) sizeof(buf))));
705  }
706  if (!ipv4 || ipv4 == (unsigned int)(-1)) {
707  SOCK_ntoa(ipv4, buf, sizeof(buf));
709  ("DNS A RR bad IPv4 ignored: %s", buf));
710  return 0/*failure*/;
711  }
712  verify(NcbiIPv4ToIPv6(&ipv6, ipv4, 0));
713  len = NS_INADDRSZ;
714  } else if (rtype == ns_t_aaaa && NS_IN6ADDRSZ <= rdlen) {
715  memcpy(&ipv6, rdata, sizeof(ipv6));
716  if (data->debug) {
718  ("DNS AAAA RR %s @ %s", fqdn,
719  inet_ntop(AF_INET6, &ipv6,
720  buf, (TSOCK_socklen_t) sizeof(buf))));
721  }
722  if (NcbiIsEmptyIPv6(&ipv6)
723  || NcbiIPv6ToIPv4(&ipv6, 0) == (unsigned int)(-1)) {
724  NcbiIPv6ToString(buf, sizeof(buf), &ipv6);
726  ("DNS AAAA RR bad IPv6 ignored: %s", buf));
727  return 0/*failure*/;
728  }
729  len = NS_IN6ADDRSZ;
730  } else {
732  ("DNS %s RR RDATA bad size: %hu",
733  x_TypeStr(rtype, buf), rdlen));
734  return 0/*failure*/;
735  }
736  if (len < rdlen) {
738  ("DNS %s RR %u/%hu byte(s) remain unparsed",
739  x_TypeStr(rtype, buf), rdlen - len, rdlen));
740  }
741  if (qtype == ns_t_srv)
742  return x_UpdateHost(iter, fqdn, &ipv6);
743  x_BlankInfo(&x_info, fSERV_Dns);
744  x_info.time += iter->time;
745  x_info.rate = LBSM_DEFAULT_RATE;
746  x_info.addr = ipv6;
747  if (!(x_info.host = NcbiIPv6ToIPv4(&ipv6, 0)))
748  x_info.host = (unsigned int)(-1);
749  return x_AddInfo(iter, SERV_CopyInfoEx(&x_info, fqdn));
750 }
751 
752 
753 static const char* dns_cname(unsigned int/*bool*/ debug,
754  const unsigned char* msg,
755  const unsigned char* eom,
756  const char* fqdn,
757  unsigned short rdlen,
758  const unsigned char* rdata)
759 {
760  char cname[NS_MAXDNAME];
761  const char* retval;
762  int rv;
763  if ((rv = dn_expand(msg, eom, rdata, cname, sizeof(cname))) <= 0) {
764  CORE_LOG(eLOG_Error, "DNS CNAME RR cannot expand cname");
765  return 0/*failure*/;
766  }
767  if (rv > (int) rdlen) {
768  CORE_LOG(eLOG_Error, "DNS CNAME RR cname overrun");
769  return 0/*failure*/;
770  }
771  if (debug) {
773  ("DNS CNAME RR %s -> %s",
774  fqdn, cname));
775  }
776  if (rv != (int) rdlen) {
777  assert(rv < (int) rdlen);
779  ("DNS CNAME RR %d/%hu byte(s) remain unparsed",
780  (int) rdlen - rv, rdlen));
781  }
782  if (!(retval = strdup(strlwr(cname)))) {
784  ("DNS CNAME RR cannot store cname \"%s\" for \"%s\"",
785  cname, fqdn));
786  return 0/*failure*/;
787  }
788  return retval;
789 }
790 
791 
792 static int/*bool*/ same_domain(const char* a, const char* b)
793 {
794  size_t lena = strlen(a);
795  size_t lenb = strlen(b);
796  if (lena && a[lena - 1] == '.')
797  lena--;
798  if (lenb && b[lenb - 1] == '.')
799  lenb--;
800  return lena == lenb && strncasecmp(a, b, lena) == 0 ? 1/*T*/ : 0/*F*/;
801 }
802 
803 
804 static const unsigned char* x_ProcessReply(SERV_ITER iter,
805  const struct SLBDNS_Data* data,
806  const char* fqdn, ns_type type,
807  const unsigned char* msg,
808  const unsigned char* eom,
809  const unsigned char* ptr,
810  unsigned short count[3])
811 {
812  /* NB: we do not "check" authority section altogether, and cut corners on
813  * doing thorough checks in other sections of the reply, for efficiency. */
814  int/*bool*/ done = 0/*false*/;
815  const char* cname = 0;
816  int n;
817 
818  assert(iter->data == data);
819  assert(count[0]/*ans*/ && (type == ns_t_srv || type == ns_t_any));
820  for (n = 0; n < 3; ++n) {
821  unsigned short c;
822  for (c = 0; c < count[n]; ++c) {
823  ns_rr rr;
824  int skip = n && ((n & 1)/*auth*/ || type != ns_t_srv/*adtl*/);
825  int rv = (skip
826  ? skip_rr(ptr, eom, 0)
827  : unpack_rr(msg, eom, ptr, &rr, 0/*RR*/, eLOG_Error));
828  if (rv < 0)
829  goto out;
830  ptr += rv;
831  if (skip)
832  continue;
833  if (ns_rr_class(rr) != ns_c_in || !ns_rr_rdlen(rr))
834  continue;
835  if (!n && type == ns_t_srv &&
836  ns_rr_type(rr) != ns_t_srv && ns_rr_type(rr) != ns_t_cname) {
837  continue;
838  }
839  if (!n && !same_domain(fqdn, ns_rr_name(rr))) {
841  ("DNS reply AN %u \"%s\" mismatch FQDN \"%s\"",
842  c + 1, ns_rr_name(rr), fqdn));
843  continue;
844  }
845  if (ns_rr_type(rr) == ns_t_cname) {
846  /* special CNAME processing: replace fqdn */
847  if (!(n | c)) {
848  cname = dns_cname(data->debug, msg, eom, ns_rr_name(rr),
849  ns_rr_rdlen(rr), ns_rr_rdata(rr));
850  if (!cname) {
851  assert(!done);
852  return 0/*failed*/;
853  }
854  fqdn = cname;
855  done = 1/*true*/;
856  } else {
858  ("DNS CNAME RR misplaced @A%c %u",
859  "RN"[!n], c + 1));
860  }
861  continue;
862  }
863  if (!n && type == ns_t_srv) {
864  /*NB: FQDN match*/
865  assert(ns_rr_type(rr) == ns_t_srv);
866  rv = dns_srv(iter, msg, eom,
867  ns_rr_name(rr), ns_rr_rdlen(rr), ns_rr_rdata(rr));
868  if (rv) {
869  if (rv < 0 && data->n_cand) {
871  "DNS SRV RR blank target misplaced");
872  } else
873  done = 1/*true*/;
874  }
875  continue;
876  }
877  if (!n && type != ns_t_srv && ns_rr_type(rr) == ns_t_txt) {
878  /*NB: FQDN match*/
879  dns_txt(iter,
880  ns_rr_name(rr), ns_rr_rdlen(rr), ns_rr_rdata(rr));
881  continue;
882  }
883  if (ns_rr_type(rr) != ns_t_a && ns_rr_type(rr) != ns_t_aaaa)
884  continue;
885  assert(!n/*AN for ANY, so FQDN match*/
886  || type == ns_t_srv/*AR for SRV*/);
887  rv = dns_a(iter, type, ns_rr_type(rr),
888  ns_rr_name(rr), ns_rr_rdlen(rr), ns_rr_rdata(rr));
889  if (rv)
890  done = 1/*true*/;
891  }
892  }
893 
894  out:
895  if (cname)
896  free((void*) cname);
897  assert(ptr && ptr <= eom);
898  return done ? ptr : 0/*failed*/;
899 }
900 
901 
902 /* This also advances the pointer to the beginning of the answer section */
903 static const unsigned char* x_VerifyReply(const char* fqdn,
904  const unsigned char* msg,
905  const unsigned char* eom,
906  unsigned short count[3])
907 {
908  const HEADER* hdr = (const HEADER*) msg;
909  const unsigned char* ptr;
910  char buf[40];
911  ns_rr qd;
912  int rv;
913 
914  assert(eom - msg >= NS_HFIXEDSZ);
915  if (hdr->rcode/*!=ns_r_noerror*/) {
917  ("DNS reply indicates an error: %s",
918  x_RcodeStr(hdr->rcode, buf)));
919  return 0/*failed*/;
920  }
921  if (!hdr->qr) {
923  ("DNS reply is a query, not a reply"));
924  return 0/*failed*/;
925  }
926  if (hdr->opcode != ns_o_query) {
928  ("DNS reply has unexpected opcode: %s",
929  x_OpcodeStr(hdr->opcode, buf)));
930  return 0/*failed*/;
931  }
932  if ((count[0] = ntohs(hdr->qdcount)) != 1) {
934  ("DNS reply has bad number of questions: %hu",
935  count[0]));
936  return 0/*failed*/;
937  }
938  if (!(count[0] = ntohs(hdr->ancount))) {
939  CORE_LOG(eLOG_Error, "DNS reply has no answers");
940  return 0/*failed*/;
941  }
942  ptr = msg + NS_HFIXEDSZ;
943  if (ptr == eom) {
944  CORE_LOG(eLOG_Error, "DNS reply has no records");
945  return 0/*failed*/;
946  }
947  rv = unpack_rr(msg, eom, ptr, &qd, 1/*QD*/, eLOG_Error);
948  if (rv < 0)
949  return 0/*failed*/;
950  if (ns_rr_class(qd) != ns_c_in) {
952  ("DNS reply for unsupported class: %s",
953  x_ClassStr(ns_rr_class(qd), buf)));
954  return 0/*failed*/;
955  }
956  if (ns_rr_type(qd) != ns_t_any) {
958  ("DNS reply for unmatching type: %s vs. ANY queried",
959  x_TypeStr(ns_rr_type(qd), buf)));
960  return 0/*failed*/;
961  }
962  if (!same_domain(ns_rr_name(qd), fqdn)) {
964  ("DNS reply for unmatching name: \"%s\" vs. \"%s\" queried",
965  ns_rr_name(qd), fqdn));
966  return 0/*failed*/;
967  }
968  ptr += rv;
969  assert(ptr <= eom);
970  if (ptr == eom) {
971  CORE_LOG(eLOG_Error, "DNS reply too short to include any RR(s)");
972  return 0/*failed*/;
973  }
974  count[1] = ntohs(hdr->nscount);
975  count[2] = ntohs(hdr->arcount);
976  return ptr/*succeeded*/;
977 }
978 
979 
980 static int/*bool*/ x_NoDataReply(const char* fqdn, ns_type type,
981  const unsigned char* msg,
982  const unsigned char* eom)
983 {
984  int rv;
985  ns_rr rr;
986  const unsigned char* ptr;
987  const HEADER* hdr = (const HEADER*) msg;
988  /* Check header */
989  if (hdr->rcode || !(hdr->qr & hdr->aa) || hdr->opcode != ns_o_query)
990  return 0/*false*/;
991  if (ntohs(hdr->qdcount) != 1 || hdr->ancount || !hdr->nscount)
992  return 0/*false*/;
993  /* Check question */
994  ptr = msg + NS_HFIXEDSZ;
995  if ((rv = unpack_rr(msg, eom, ptr, &rr, 1/*QD*/, eLOG_Trace)) < 0)
996  return 0/*false*/;
997  if (ns_rr_class(rr) != ns_c_in || ns_rr_type(rr) != type)
998  return 0/*false*/;
999  if (!same_domain(ns_rr_name(rr), fqdn))
1000  return 0/*false*/;
1001  /* Check NS record */
1002  if (unpack_rr(msg, eom, ptr + rv, &rr, 0/*RR*/, eLOG_Trace) < 0)
1003  return 0/*false*/;
1004  if (!same_domain(ns_rr_name(rr), strchr(fqdn, '.') + 1))
1005  return 0/*false*/;
1006  return ns_rr_class(rr) != ns_c_in || ns_rr_type(rr) != ns_t_soa
1007  ? 0/*false*/ : 1/*true*/;
1008 }
1009 
1010 
1011 static const char* x_FormFQDN(char fqdn[NS_MAXCDNAME + 1],
1012  const char* prefix,
1013  size_t pfxlen,
1014  ns_type type,
1015  const char* domain,
1016  size_t domlen)
1017 {
1018  size_t xlen, zlen;
1019  const char* zone;
1020  char* ptr = fqdn;
1021 
1022  assert(type == ns_t_srv || type == ns_t_any);
1023  assert(pfxlen && domlen);
1024  if (type == ns_t_srv) {
1025  *ptr++ = '_';
1026  zone = "._tcp.lb.";
1027  zlen = 9;
1028  xlen = 11;
1029  } else {
1030  zone = ".lb.";
1031  zlen = 4;
1032  xlen = 5;
1033  }
1034  if (pfxlen + xlen + domlen > NS_MAXCDNAME)
1035  return 0/*failure*/;
1036  memcpy(ptr, prefix, pfxlen);
1037  ptr += pfxlen;
1038  memcpy(ptr, zone, zlen);
1039  ptr += zlen;
1040  memcpy(ptr, domain, domlen);
1041  ptr += domlen;
1042  *ptr++ = '.';
1043  *ptr = '\0';
1044  assert(ptr - fqdn <= NS_MAXCDNAME);
1045  return strlwr(fqdn);
1046 }
1047 
1048 
1049 static int/*bool*/ x_ResolveType(SERV_ITER iter, ns_type type)
1050 {
1051  const struct SLBDNS_Data* data = (const struct SLBDNS_Data*) iter->data;
1052  size_t len = strlen(iter->name);
1053  const unsigned char* ptr, *eom;
1054  char fqdn[NS_MAXCDNAME + 1];
1055  unsigned short count[3];
1056  unsigned char msg[2048];
1057  int rv, err, x_error;
1058  const char* errstr;
1059  char errbuf[40];
1060 
1061  assert(sizeof(msg) > NS_HFIXEDSZ);
1062  assert(type == ns_t_srv || type == ns_t_any);
1063 
1064  if (!data->check) {
1065  if (type != ns_t_srv
1066  && (len < 4 || strcasecmp(&iter->name[len -= 3], "_lb") != 0)) {
1067  return 0/*failure*/;
1068  }
1069  }
1070  if (!x_FormFQDN(fqdn, iter->name, len, type, data->domain, data->domlen)) {
1072  ("LBDNS FQDN for \"%s\" %s in \"%s\": Name too long",
1073  iter->name, x_TypeStr(type, errbuf), data->domain));
1074  return 0/*failure*/;
1075  }
1076  CORE_TRACEF(("LBDNS query \"%s\" %s", fqdn, x_TypeStr(type, errbuf)));
1077 
1078  h_errno = errno = 0;
1079  memset(msg, 0, NS_HFIXEDSZ);
1080  rv = res_query(fqdn, ns_c_in, ns_t_any, msg, sizeof(msg));
1081  if (rv < 0) {
1082  int/*bool*/ nodata = 0/*false*/;
1083  x_error = errno;
1084  errstr = strherror(err = h_errno);
1085  rv = memcchr(msg, 0, NS_HFIXEDSZ) ? (int) sizeof(msg) : 0;
1086  eom = msg + rv;
1087 #ifdef NO_DATA
1088  if (err == NO_DATA
1089 # if defined(NO_ADDRESS) && NO_ADDRESS != NO_DATA
1090  || err == NO_ADDRESS
1091 # endif /*NO_ADDRESS && NO_ADDRESS!=NO_DATA*/
1092  )
1093 #endif /*NO_DATA*/
1094  {
1095  nodata = rv
1096  && x_NoDataReply(fqdn, type, msg, eom) ? 1/*T*/ : 0/*F*/;
1097  }
1098  if (!errstr || !*errstr) {
1099  sprintf(errbuf, "Error %d", err);
1100  errstr = errbuf;
1101  }
1102  err = nodata ? 1 : -1;
1103  } else {
1104  CORE_TRACEF(("LBDNS reply \"%s\": %d byte(s)", fqdn, rv));
1105  if (rv < NS_HFIXEDSZ) {
1107  ("DNS reply for \"%s\" too short: %d", fqdn, rv));
1108  return 0/*failure*/;
1109  }
1110  if (rv >= (int) sizeof(msg)) {
1111  CORE_LOGF(rv > (int) sizeof(msg) ? eLOG_Error : eLOG_Warning,
1112  ("DNS reply overflow: %d", rv));
1113  rv = (int) sizeof(msg);
1114  }
1115  eom = msg + rv;
1116  err = 0;
1117  }
1118  assert((size_t)(eom - msg) <= sizeof(msg));
1119 
1120  if (data->debug && rv)
1121  x_DumpMsg(msg, eom);
1122  if (err) {
1123  if (err > 0)
1124  err = 0/*false*/;
1125  CORE_LOGF_ERRNO(rv ? eLOG_Trace : eLOG_Error, err ? x_error : 0,
1126  ("DNS lookup failure \"%s\": %s", fqdn, errstr));
1127  return !err/*failure/success(but nodata)*/;
1128  }
1129  assert(NS_HFIXEDSZ <= (size_t)(eom - msg));
1130 
1131  if (!(ptr = x_VerifyReply(fqdn, msg, eom, count)))
1132  return 0/*failure*/;
1133  assert(msg < ptr);
1134 
1135  CORE_TRACE("LBDNS processing DNS reply");
1136  if (!(ptr = x_ProcessReply(iter, data, fqdn, type, msg, eom, ptr, count)))
1137  return 0/*failure*/;
1138  if (ptr < eom) {
1139  assert(msg < ptr);
1141  ("DNS reply %lu/%d byte(s) remain unparsed",
1142  (unsigned long)(eom - ptr), rv));
1143  }
1144  return 1/*success*/;
1145 }
1146 
1147 
1148 static void x_Finalize(SERV_ITER iter)
1149 {
1150  struct SLBDNS_Data* data = (struct SLBDNS_Data*) iter->data;
1151  size_t n = 0;
1152 
1153  CORE_TRACEF(("LBDNS finalizing result-set for \"%s\"", iter->name));
1154  while (n < data->n_cand) {
1155  SSERV_Info* info = (SSERV_Info*) data->cand[n].info;
1156  const char* drop = 0/*reason*/;
1157  if (info->host) {
1158  size_t s;
1159  const char* name = SERV_NameOfInfo(info);
1160  assert(name && *name);
1161  if (iter->reverse_dns) {
1162  char* ptr;
1163  if ((ptr = (char*) strchr(name, '.')) != 0)
1164  *ptr = '\0';
1165  strupr((char*) name);
1166  if (info->type == fSERV_Standalone) {
1167  info->type = fSERV_Dns;
1168  info->u.dns.name = 1/*true*/;
1169  assert(info->port);
1170  } else for (s = 0; s < data->n_cand; ++s) {
1171  const SSERV_Info* skip = data->cand[s].info;
1172  assert(skip->type == fSERV_Dns);
1173  if (SERV_EqualInfo(skip, info)) {
1174  drop = "duplicate";
1175  break;
1176  }
1177  }
1178  assert(*name);
1179  } else
1180  *((char*) name) = '\0';
1181  if (!drop) {
1182  for (s = 0; s < iter->n_skip; ++s) {
1183  const SSERV_Info* skip = iter->skip[s];
1184  if (*name) {
1185  assert(iter->reverse_dns && SERV_NameOfInfo(skip));
1186  if (strcasecmp(SERV_NameOfInfo(skip), name) == 0
1187  && ((skip->type == fSERV_Dns && !skip->host)
1188  || SERV_EqualInfo(skip, info))) {
1189  break;
1190  }
1191  } else if (SERV_EqualInfo(skip, info))
1192  break;
1193  if (iter->reverse_dns && skip->type == fSERV_Dns
1194  && skip->host == info->host
1195  && (!skip->port || skip->port == info->port)) {
1196  break;
1197  }
1198  }
1199  if (s >= iter->n_skip) {
1200  data->cand[n++].status = info->rate; /*FIXME, temp*/
1201  continue;
1202  }
1203  drop = "excluded";
1204  }
1205  } else {
1206  assert(info->type == fSERV_Standalone);
1207  drop = "incomplete";
1208  }
1209  verify(drop);
1210  CORE_TRACEF(("LBDNS dropping \"%s\" @%p: %s",
1211  SERV_NameOfInfo(info), info, drop));
1212  if (n < --data->n_cand) {
1213  memmove(data->cand + n, data->cand + n + 1,
1214  (data->n_cand - n) * sizeof(data->cand));
1215  }
1216  free(info);
1217  }
1218 
1219  if (!data->n_cand && (iter->types & fSERV_Dns)
1220  && !iter->last && !iter->n_skip) {
1221  SSERV_Info x_info;
1222  x_BlankInfo(&x_info, fSERV_Dns);
1223  x_info.time += iter->time;
1224  if (!(data->cand[0].info = SERV_CopyInfoEx(&x_info, iter->reverse_dns
1225  ? iter->name : ""))) {
1227  ("LBDNS cannot create dummy entry for \"%s\"",
1228  iter->name));
1229  } else {
1230  data->cand[0].status = 0.0;
1231  if (data->debug) {
1232  char* infostr = SERV_WriteInfo(data->cand[0].info);
1234  ("LBDNS adding dummy entry \"%s\" @%p %s",
1235  SERV_NameOfInfo(data->cand[0].info),
1236  data->cand[0].info,
1237  infostr ? infostr : "<NULL>"));
1238  if (infostr)
1239  free(infostr);
1240  }
1241  data->n_cand = 1;
1242  }
1243  }
1244  CORE_TRACEF(("LBDNS made ready result-set for \"%s\": %lu",
1245  iter->name, (unsigned long) data->n_cand));
1246 }
1247 
1248 
1249 static int/*bool*/ x_Resolve(SERV_ITER iter)
1250 {
1251  int/*bool*/ rv = 0/*false*/;
1252  CORE_TRACEF(("LBDNS resolving \"%s\"", iter->name));
1253  if (!(iter->types & ~fSERV_Stateless) || (iter->types & fSERV_Standalone))
1254  rv |= x_ResolveType(iter, ns_t_srv);
1255  if (iter->types & fSERV_Dns)
1256  rv |= x_ResolveType(iter, ns_t_any);
1257  CORE_TRACEF(("LBDNS returning \"%s\": %s", iter->name,
1258  rv ? "located" : "unknown"));
1259  if (rv)
1260  x_Finalize(iter);
1261  else
1262  assert(!((const struct SLBDNS_Data*) iter->data)->n_cand);
1263  return rv;
1264 }
1265 
1266 
1267 static int/*bool*/ s_Resolve(SERV_ITER iter)
1268 {
1269  const struct SLBDNS_Data* data = (const struct SLBDNS_Data*) iter->data;
1270  struct sockaddr_in ns_save;
1271  int ns_count, ns_retry, rv;
1272  u_long ns_options;
1273  res_state r;
1274 
1275  assert(!data->n_cand && !data->empty);
1276 
1277  if (data->host | data->port) {
1278  static void* /*bool*/ s_Init = 0/*false*/;
1279  struct sockaddr_in ns_addr;
1280  if (CORE_Once(&s_Init))
1281  res_init();
1282  memset(&ns_addr, 0, sizeof(ns_addr));
1283 #ifdef HAVE_SIN_LEN
1284  ns_addr.sin_len = sizeof(ns_addr);
1285 #endif /*HAVE_SIN_LEN*/
1286  ns_addr.sin_family = AF_INET;
1287  ns_addr.sin_addr.s_addr = data->host;
1288  ns_addr.sin_port = htons(data->port);
1290  r = &_res;
1291  assert(r);
1292  ns_retry = r->retry;
1293  ns_options = r->options;
1294  ns_count = r->nscount;
1295  ns_save = r->nsaddr;
1296 #ifdef RES_IGNTC
1297  r->options |= RES_IGNTC;
1298 #endif /*RES_IGNTC*/
1299 #ifdef RES_USE_EDNS0
1300  /* This option, in general, should allow sending max payload size (our
1301  * provided answer size) to the server -- that's a good thing! But the
1302  * current glibc behavior for this option is to always override with
1303  * 1200 -- and that's bad! -- because servnsd would comply. If nothing
1304  * is specified, servnsd uses 2048 (per RFC3226, 3) by default, so...*/
1305 # if 0
1306  r->options |= RES_USE_EDNS0;
1307 # endif /*0*/
1308 #endif /*RES_USE_EDNS0*/
1309 #ifdef RES_DEBUG
1310  if (data->debug)
1311  r->options |= RES_DEBUG; /* will most likely be a NOOP, though */
1312 #endif /*RES_DEBUG*/
1313  r->nsaddr = ns_addr;
1314  r->nscount = 1;
1315  r->retry = 1/*# of tries*/;
1316  } else
1317  r = 0;
1318 
1319  rv = x_Resolve(iter);
1320 
1321  if (r) {
1322  r->options = ns_options;
1323  r->nsaddr = ns_save;
1324  r->nscount = ns_count;
1325  r->retry = ns_retry;
1326  CORE_UNLOCK;
1327  }
1328 
1329  if (!data->n_cand)
1330  ((struct SLBDNS_Data*) data)->empty = 1/*true*/;
1331  return rv;
1332 }
1333 
1334 
1335 static SSERV_Info* s_GetNextInfo(SERV_ITER iter, HOST_INFO* host_info)
1336 {
1337  struct SLBDNS_Data* data = (struct SLBDNS_Data*) iter->data;
1338  SSERV_Info* info;
1339 
1340  CORE_TRACEF(("LBDNS getnextinfo(\"%s\"): %lu%s", iter->name,
1341  (unsigned long) data->n_cand, data->empty ? ", EOF" : ""));
1342  assert(!data->empty || !data->n_cand);
1343  if (!data->n_cand) {
1344  if (!data->empty)
1345  s_Resolve(iter);
1346  if ( data->empty) {
1347  CORE_TRACEF(("LBDNS getnextinfo(\"%s\"): EOF", iter->name));
1348  assert(!data->n_cand);
1349  return 0/*EOF*/;
1350  }
1351  }
1352  info = (SSERV_Info*) data->cand[0].info;
1353  info->rate = data->cand[0].status;
1354  if (--data->n_cand) {
1355  memmove(data->cand, data->cand + 1,
1356  data->n_cand * sizeof(data->cand));
1357  } else
1358  data->empty = 1/*true*/;
1359  if (host_info)
1360  *host_info = 0;
1361  CORE_TRACEF(("LBDNS getnextinfo(\"%s\"): \"%s\" @%p", iter->name,
1363  return info;
1364 }
1365 
1366 
1367 static void s_Reset(SERV_ITER iter)
1368 {
1369  struct SLBDNS_Data* data = (struct SLBDNS_Data*) iter->data;
1370  CORE_TRACEF(("LBDNS reset(\"%s\"): %lu", iter->name,
1371  (unsigned long) data->n_cand));
1372  assert(data);
1373  if (data->n_cand) {
1374  size_t n;
1375  for (n = 0; n < data->n_cand; ++n) {
1376  assert(data->cand[n].info);
1377  free((void*) data->cand[n].info);
1378  }
1379  data->n_cand = 0;
1380  }
1381  data->empty = 0/*false*/;
1382 }
1383 
1384 
1385 static void s_Close(SERV_ITER iter)
1386 {
1387  struct SLBDNS_Data* data = (struct SLBDNS_Data*) iter->data;
1388  CORE_TRACEF(("LBDNS close(\"%s\")", iter->name));
1389  iter->data = 0;
1390  assert(data && !data->n_cand); /*s_Reset() had to be called before*/
1391  if (data->domain)
1392  free((void*) data->domain);
1393  free(data);
1394 }
1395 
1396 
1397 static const char* s_SysGetDomainName(char* domain, size_t domainsize)
1398 {
1399  char* p;
1400  assert(domain && domainsize);
1401 
1402 #if defined(NCBI_OS_CYGWIN) || defined(NCBI_OS_IRIX)
1403  if (getdomainname(domain, domainsize) == 0
1404  && domain[0] && domain[1]
1405  && strcasecmp(domain, "(none)") != 0) {
1406  return domain;
1407  }
1408 #endif /*NCBI_OS_CYGWIN || NCBI_OS_IRIX*/
1409 
1410  if (SOCK_gethostbyaddr(0, domain, domainsize)
1411  && (p = strchr(domain, '.')) != 0 && p[1]) {
1412  return p;
1413  }
1414 
1416  if ((p = getenv("LOCALDOMAIN")) != 0) {
1417  size_t n = strlen(p);
1418  if (1 < n && n < domainsize)
1419  memcpy(domain, p, n + 1);
1420  else
1421  domain = 0;
1422  } else
1423  domain = 0;
1424  CORE_UNLOCK;
1425 
1426  return domain;
1427 }
1428 
1429 
1430 #define isdash(s) ((s) == '-' || (s) == '_')
1431 
1432 static int/*bool*/ x_CheckDomain(const char* domain)
1433 {
1434  int/*bool*/ dot = *domain == '.' ? 1/*true*/ : 0/*false*/;
1435  const char* ptr = dot ? ++domain : domain;
1436  int/*bool*/ alpha = 0/*false*/;
1437  size_t len;
1438 
1439  if (!*ptr)
1440  return 0/*false: just dot(root) or empty*/;
1441  for ( ; *ptr; ++ptr) {
1442  if (*ptr == '.') {
1443  if (dot || (alpha && isdash(ptr[-1])))
1444  return 0/*false: double dot or trailing dash*/;
1445  dot = 1/*true*/;
1446  continue;
1447  }
1448  if ((dot || ptr == domain) && isdash(*ptr))
1449  return 0/*false: leading dash */;
1450  dot = 0/*false*/;
1451  if (isdigit((unsigned char)(*ptr)))
1452  continue;
1453  if (!isalpha((unsigned char)(*ptr)) && !isdash(*ptr))
1454  return 0/*false: bad character*/;
1455  /* at least one regular "letter" seen */
1456  alpha = 1/*true*/;
1457  }
1458  len = (size_t)(ptr - domain);
1459  assert(len);
1460  if (domain[len - 1] == '.')
1461  verify(--len);
1462  if (!alpha) {
1463  unsigned int temp;
1464  ptr = NcbiStringToIPv4(&temp, domain, len);
1465  assert(!ptr || ptr > domain);
1466  if (ptr == domain + len)
1467  return 0/*false: IPv4 instead of domain*/;
1468  } else if (isdash(ptr[-1]))
1469  return 0/*false: trailing dash*/;
1470  return 1 < len && len <= NS_MAXCDNAME ? 1/*true*/ : 0/*false: bad size*/;
1471 }
1472 
1473 
1474 /* Assumes domain has been verified. Skips the initial "[.]lb." (if any).
1475  * Return a copy of "domain" stripped of any leading and trailing dot(s). */
1476 static const char* x_CopyDomain(const char* domain)
1477 {
1478  size_t len;
1479  assert(*domain);
1480  if (*domain == '.')
1481  ++domain;
1482  len = strlen(domain);
1483  if (len > 1 && strncasecmp(domain, "lb", 2) == 0
1484  && (!domain[2] || domain[2] == '.')) {
1485  if (!domain[2] || !(len -= 3)) {
1486  errno = EINVAL;
1487  return 0/*failure*/;
1488  }
1489  domain += 3;
1490  } else
1491  assert(len);
1492  assert(*domain);
1493  if (domain[len - 1] == '.')
1494  --len;
1495  assert(len && domain[0] != '.' && domain[len - 1] != '.');
1496  return strndup(domain, len);
1497 }
1498 
1499 
1500 
1501 /***********************************************************************
1502  * EXTERNAL
1503  ***********************************************************************/
1504 
1506 {
1507  char val[CONN_HOST_LEN + 1];
1508  struct SLBDNS_Data* data;
1510  const char* domain;
1511  unsigned long port;
1512 
1513  assert(iter && !iter->data && !iter->op);
1514  /* No wildcard or external processing */
1515  if (iter->ismask)
1516  return 0;
1517  assert(iter->name && *iter->name);
1518  if (iter->external)
1519  return 0;
1520  /* Can process fSERV_Any (basically meaning fSERV_Standalone), and explicit
1521  * fSERV_Standalone and/or fSERV_Dns only */
1522  types = iter->types & ~fSERV_Stateless;
1523  if (types != fSERV_Any/*0*/ && !(types & (fSERV_Standalone | fSERV_Dns)))
1524  return 0;
1525  if (types == fSERV_Dns) {
1526  /* DNS-only lookups are for the *_lb services */
1527  size_t len = strlen(iter->name);
1528  if (len < 4 || strcasecmp(&iter->name[len - 3], "_lb") != 0)
1529  return 0;
1530  }
1531 
1532  CORE_TRACEF(("LBDNS open(\"%s\")", iter->name));
1533  if (iter->arg) {
1534  assert(iter->arglen);
1536  ("[%s] Argument affinity lookup not supported by LBDNS:"
1537  " %s%s%s%s%s", iter->name, iter->arg, &"="[!iter->val],
1538  &"\""[!iter->val], iter->val ? iter->val : "",
1539  &"\""[!iter->val]));
1540  goto err;
1541  }
1542  if (!(data = (struct SLBDNS_Data*) calloc(1, sizeof(*data)
1543  + (LBDNS_INITIAL_ALLOC - 1)
1544  * sizeof(data->cand)))) {
1545  CORE_LOG_ERRNO(eLOG_Error, errno,
1546  "LBDNS failed to create private data structure");
1547  goto err;
1548  }
1551  val, sizeof(val), 0));
1553  (0, "CONN_LBDNS_CHECK", /*private*/
1554  val, sizeof(val), 0));
1555  data->a_cand = LBDNS_INITIAL_ALLOC;
1556  iter->data = data;
1557 
1559  val, sizeof(val), 0)) {
1560  goto out;
1561  }
1562  if (!*val) {
1563  domain = s_SysGetDomainName(val, sizeof(val));
1564  if (!domain || !x_CheckDomain(domain)) {
1566  "LBDNS cannot figure out system domain name");
1567  goto out;
1568  }
1569  CORE_TRACEF(("LBDNS found system domain \"%s\"", domain));
1570  } else if (!x_CheckDomain(val)) {
1571  CORE_LOGF(eLOG_Error, ("LBDNS bad domain name \"%s\"", val));
1572  goto out;
1573  } else
1574  domain = val;
1575  if (!(data->domain = x_CopyDomain(domain))) {
1576  CORE_LOGF_ERRNO(eLOG_Error, errno,
1577  ("LBDNS failed to store domain name \"%s\"", domain));
1578  goto out;
1579  }
1580  data->domlen = strlen(data->domain);
1581  assert(1 < data->domlen && data->domlen <= NS_MAXCDNAME);
1582  assert(data->domain[0] != '.' && data->domain[data->domlen - 1] != '.');
1583 
1585  val, sizeof(val), 0)) {
1586  goto out;
1587  }
1588  if (!*val)
1589  port = 0;
1590  else if (!isdigit((unsigned char)(*val)))
1591  goto out;
1592  else {
1593  char* end;
1594  errno = 0;
1595  port = strtoul(val, &end, 0);
1596  if (errno || *end || port > 0xFFFF)
1597  goto out;
1598  if (!port)
1599  port = NS_DEFAULTPORT;
1600  }
1601  if (port) {
1603  val, sizeof(val), 0)) {
1604  goto out;
1605  }
1606  if (!*val)
1607  port = 0;
1608  else if (!(data->host = SOCK_gethostbyname(val)))
1609  goto out;
1610  else {
1611  SOCK_HostPortToString(data->host, (unsigned short) port,
1612  val, sizeof(val));
1613  CORE_LOGF(data->debug ? eLOG_Note : eLOG_Trace,
1614  ("LBDNS using server @ %s", val));
1615  }
1616  data->port = (unsigned short) port;
1617  }
1618  assert(!data->host == !data->port);
1619  CORE_LOGF(data->debug ? eLOG_Note : eLOG_Trace,
1620  ("LBDNS using domain = \"%s\"", data->domain));
1621 
1622  if (s_Resolve(iter)) {
1623  /* call GetNextInfo subsequently if info is actually needed */
1624  if (info)
1625  *info = 0;
1626  CORE_TRACEF(("LBDNS open(\"%s\"): okay", iter->name));
1627  return &kLbdnsOp;
1628  }
1629 
1630  out:
1631  s_Reset(iter);
1632  s_Close(iter);
1633  err:
1634  CORE_TRACEF(("LBDNS open(\"%s\"): fail", iter->name));
1635  return 0/*failure*/;
1636 }
1637 
1638 
1639 #else
1640 
1641 
1642 /*ARGSUSED*/
1644 {
1645  /* NB: This should never be called on a non-UNIX platform */
1646  static void* /*bool*/ s_Once = 0/*false*/;
1647  if (CORE_Once(&s_Once))
1648  CORE_LOG(eLOG_Critical, "LBDNS only available on UNIX platform(s)");
1649  return 0;
1650 }
1651 
1652 
1653 #endif /*NCBI_OS_UNIX*/
std::ofstream out("events_result.xml")
main entry point for tests
static int type
Definition: getdata.c:31
static const struct type types[]
Definition: type.c:22
char data[12]
Definition: iconv.c:80
void debug()
ESERV_Type
TNCBI_Time time
TNCBI_IPv6Addr addr
#define SERV_MAXIMAL_RATE
#define SERV_DEFAULT_ALGO
char * SERV_WriteInfo(const SSERV_Info *info)
unsigned short TSERV_TypeOnly
Server type only, w/o specials.
Definition: ncbi_service.h:95
unsigned int host
unsigned short port
int SERV_EqualInfo(const SSERV_Info *info1, const SSERV_Info *info2)
ESERV_Type type
@ fSERV_Standalone
@ fSERV_Dns
@ fSERV_Stateless
Stateless servers only.
Definition: ncbi_service.h:81
@ fSERV_Any
Definition: ncbi_service.h:79
@ fSERV_Local
size_t SOCK_HostPortToString(unsigned int host, unsigned short port, char *buf, size_t bufsize)
Print numeric string "host:port" into a buffer provided, not to exceed 'bufsize' bytes (including the...
Definition: ncbi_socket.c:8945
unsigned int SOCK_gethostbyname(const char *hostname)
Same as SOCK_gethostbynameEx(,<current API data logging>)
Definition: ncbi_socket.c:8790
int SOCK_ntoa(unsigned int addr, char *buf, size_t bufsize)
Convert IP address to a string in dotted notation.
Definition: ncbi_socket.c:8661
const char * SOCK_gethostbyaddr(unsigned int addr, char *name, size_t namelen)
Same as SOCK_gethostbyaddrEx(,,<current API data logging>)
Definition: ncbi_socket.c:8813
ELOG_Level
Log severity level.
Definition: ncbi_core.h:292
#define REG_CONN_LBDNS_DEBUG
#define REG_CONN_LBDNS_PORT
#define REG_CONN_LBDNS_DOMAIN
#define REG_CONN_LBDNS_HOST
int ConnNetInfo_Boolean(const char *str)
@ eLOG_Critical
Definition: ncbi_core.h:298
@ eLOG_Error
Definition: ncbi_core.h:297
@ eLOG_Note
Definition: ncbi_core.h:294
@ eLOG_Warning
Definition: ncbi_core.h:296
@ eLOG_Trace
Definition: ncbi_core.h:293
@ eMIME_T_Undefined
@ eMIME_Undefined
@ eENCOD_None
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
int socklen_t
Definition: config.h:95
char * buf
if(yy_accept[yy_current_state])
yy_size_t n
int len
static MDB_envinfo info
Definition: mdb_load.c:37
const struct ncbi::grid::netcache::search::fields::SIZE size
#define strdup
Definition: ncbi_ansi_ext.h:70
#define strlwr
#define strncasecmp
#define strcasecmp
#define strndup
Definition: ncbi_ansi_ext.h:89
#define strupr
#define memcchr
#define verify(expr)
Definition: ncbi_assert.h:51
#define LBSM_DEFAULT_RATE
Definition: ncbi_comm.h:46
#define SERVNSD_TXT_RR_PORT
Definition: ncbi_comm.h:58
#define LBSM_DEFAULT_TIME
Definition: ncbi_comm.h:45
const char * ConnNetInfo_GetValueInternal(const char *service, const char *param, char *value, size_t value_size, const char *def_value)
#define CONN_HOST_LEN
int NcbiIsEmptyIPv6(const TNCBI_IPv6Addr *addr)
Return non-zero if the address is empty (either as IPv6 or IPv4); return zero otherwise.
Definition: ncbi_ipv6.c:80
unsigned int NcbiIPv6ToIPv4(const TNCBI_IPv6Addr *addr, size_t pfxlen)
Extract and return a network byte order IPv4 embedded address from an IPv6 address,...
Definition: ncbi_ipv6.c:101
char * NcbiAddrToString(char *buf, size_t bufsize, const TNCBI_IPv6Addr *addr)
Convert an IPv6 address into either a full-quad text IPv4 (for IPv4-mapped IPv6 addresses) or a hex c...
Definition: ncbi_ipv6.c:490
char * NcbiIPv6ToString(char *buf, size_t bufsize, const TNCBI_IPv6Addr *addr)
Convert an IPv6 address into a hex colon-separated text form and store the result in the "buf" of siz...
Definition: ncbi_ipv6.c:476
const char * NcbiStringToIPv4(unsigned int *addr, const char *str, size_t len)
Convert into a network byte order IPv4 address, the first "len" (or "strlen(str)" if "len" is 0) byte...
Definition: ncbi_ipv6.c:346
int NcbiIPv4ToIPv6(TNCBI_IPv6Addr *addr, unsigned int ipv4, size_t pfxlen)
Embed a passed network byte order IPv4 address into an IPv6 address using the specified prefix length...
Definition: ncbi_ipv6.c:142
int TSOCK_socklen_t
Definition: ncbi_lbdns.c:75
static int dns_srv(SERV_ITER iter, const unsigned char *msg, const unsigned char *eom, const char *fqdn, unsigned short rdlen, const unsigned char *rdata)
Definition: ncbi_lbdns.c:591
static const unsigned char * x_VerifyReply(const char *fqdn, const unsigned char *msg, const unsigned char *eom, unsigned short count[3])
Definition: ncbi_lbdns.c:903
static const char * x_RcodeStr(unsigned short rcode, char *buf)
Definition: ncbi_lbdns.c:172
static const char * s_SysGetDomainName(char *domain, size_t domainsize)
Definition: ncbi_lbdns.c:1397
static const char * x_ClassStr(ns_class aclass, char *buf)
Definition: ncbi_lbdns.c:157
static int x_UpdateHost(SERV_ITER iter, const char *fqdn, const TNCBI_IPv6Addr *addr)
Definition: ncbi_lbdns.c:476
static const SSERV_VTable kLbdnsOp
Definition: ncbi_lbdns.c:87
static int x_AddInfo(SERV_ITER iter, SSERV_Info *info)
Definition: ncbi_lbdns.c:420
#define LBDNS_INITIAL_ALLOC
Definition: ncbi_lbdns.c:69
static int unpack_rr(const unsigned char *msg, const unsigned char *eom, const unsigned char *ptr, ns_rr *rr, int qd, ELOG_Level level)
Definition: ncbi_lbdns.c:314
static const unsigned char * x_DumpMsg(const unsigned char *msg, const unsigned char *eom)
Definition: ncbi_lbdns.c:387
static void s_Close(SERV_ITER)
Definition: ncbi_lbdns.c:1385
static int x_Resolve(SERV_ITER iter)
Definition: ncbi_lbdns.c:1249
static const char * strherror(int err)
Definition: ncbi_lbdns.c:216
static int x_ResolveType(SERV_ITER iter, ns_type type)
Definition: ncbi_lbdns.c:1049
static const char * x_OpcodeStr(unsigned short opcode, char *buf)
Definition: ncbi_lbdns.c:195
#define SERVNSD_TXT_RR_PORT_LEN
Definition: ncbi_lbdns.c:67
static const unsigned char * x_ProcessReply(SERV_ITER iter, const struct SLBDNS_Data *data, const char *fqdn, ns_type type, const unsigned char *msg, const unsigned char *eom, const unsigned char *ptr, unsigned short count[3])
Definition: ncbi_lbdns.c:804
static double x_RoundUp(double rate)
Definition: ncbi_lbdns.c:572
static const char * x_FlagsStr(const HEADER *hdr, char *buf)
Definition: ncbi_lbdns.c:252
static void s_Reset(SERV_ITER)
Definition: ncbi_lbdns.c:1367
const SSERV_VTable * SERV_LBDNS_Open(SERV_ITER iter, SSERV_Info **info)
Definition: ncbi_lbdns.c:1505
static const char * x_TypeStr(ns_type atype, char *buf)
Definition: ncbi_lbdns.c:112
static const char * x_CopyDomain(const char *domain)
Definition: ncbi_lbdns.c:1476
#define isdash(s)
Definition: ncbi_lbdns.c:1430
static int x_NoDataReply(const char *fqdn, ns_type type, const unsigned char *msg, const unsigned char *eom)
Definition: ncbi_lbdns.c:980
static const char * dns_cname(unsigned int debug, const unsigned char *msg, const unsigned char *eom, const char *fqdn, unsigned short rdlen, const unsigned char *rdata)
Definition: ncbi_lbdns.c:753
static void x_UpdatePort(SERV_ITER iter, unsigned short port)
Definition: ncbi_lbdns.c:538
static const char * x_FormFQDN(char fqdn[NS_MAXCDNAME+1], const char *prefix, size_t pfxlen, ns_type type, const char *domain, size_t domlen)
Definition: ncbi_lbdns.c:1011
static int s_Resolve(SERV_ITER iter)
Definition: ncbi_lbdns.c:1267
static void x_Finalize(SERV_ITER iter)
Definition: ncbi_lbdns.c:1148
static void x_DumpRR(const ns_rr *rr, const char *part, unsigned short n)
Definition: ncbi_lbdns.c:296
static void x_BlankInfo(SSERV_Info *info, ESERV_Type type)
Definition: ncbi_lbdns.c:558
static SSERV_Info * s_GetNextInfo(SERV_ITER, HOST_INFO *)
Definition: ncbi_lbdns.c:1335
static void x_DumpHdr(const HEADER *hdr, const unsigned short count[4])
Definition: ncbi_lbdns.c:281
static int x_CheckDomain(const char *domain)
Definition: ncbi_lbdns.c:1432
static int same_domain(const char *a, const char *b)
Definition: ncbi_lbdns.c:792
static int skip_rr(const unsigned char *ptr, const unsigned char *eom, int qd)
Definition: ncbi_lbdns.c:357
#define SizeOf(a)
Definition: ncbi_lbdns.c:61
static void dns_txt(SERV_ITER iter, const char *fqdn, unsigned short rdlen, const unsigned char *rdata)
Definition: ncbi_lbdns.c:649
static int dns_a(SERV_ITER iter, ns_type qtype, ns_type rtype, const char *fqdn, unsigned short rdlen, const unsigned char *rdata)
Definition: ncbi_lbdns.c:685
#define max(a, b)
Definition: ncbi_lbdns.c:65
unsigned int a
Definition: ncbi_localip.c:102
#define CORE_Once(once)
Return non-zero (true) if "*once" had a value of NULL, and set the value to non-NULL regardless (best...
Definition: ncbi_once.h:47
#define CORE_LOGF_ERRNO(level, error, fmt_args)
Definition: ncbi_priv.h:174
#define CORE_LOG_ERRNO(level, error, message)
Definition: ncbi_priv.h:170
#define CORE_LOCK_WRITE
Definition: ncbi_priv.h:269
#define CORE_TRACEF(fmt_args)
Definition: ncbi_priv.h:138
#define CORE_TRACE(message)
Definition: ncbi_priv.h:137
#define CORE_UNLOCK
Definition: ncbi_priv.h:273
#define CORE_LOGF(level, fmt_args)
Definition: ncbi_priv.h:158
#define CORE_LOCK_READ
Definition: ncbi_priv.h:271
#define CORE_LOG(level, message)
Definition: ncbi_priv.h:154
SSERV_Info * SERV_CopyInfoEx(const SSERV_Info *orig, const char *name)
const char * SERV_NameOfInfo(const SSERV_Info *info)
int isalpha(Uchar c)
Definition: ncbictype.hpp:61
int isdigit(Uchar c)
Definition: ncbictype.hpp:64
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
#define memmove(a, b, c)
static const char * prefix[]
Definition: pcregrep.c:405
#define assert(x)
Definition: srv_diag.hpp:58
CCompressionStreamProcessor * s_Init(EInitType type, CCompressStream::EMethod method, ICompression::TFlags flags, ICompression::ELevel level)
size_t n_cand
Definition: ncbi_lbdns.c:107
size_t a_cand
Definition: ncbi_lbdns.c:106
unsigned debug
Definition: ncbi_lbdns.c:99
SLB_Candidate cand[1]
Definition: ncbi_lbdns.c:108
const char * domain
Definition: ncbi_lbdns.c:103
unsigned empty
Definition: ncbi_lbdns.c:101
unsigned int host
Definition: ncbi_lbdns.c:97
size_t domlen
Definition: ncbi_lbdns.c:105
unsigned check
Definition: ncbi_lbdns.c:100
unsigned short port
Definition: ncbi_lbdns.c:98
unsigned external
const char * arg
const char * name
Definition: ncbi_servicep.h:89
SSERV_InfoCPtr * skip
unsigned ismask
Definition: ncbi_servicep.h:95
const char * val
const SSERV_VTable * op
SSERV_InfoCPtr last
unsigned reverse_dns
TSERV_TypeOnly types
Definition: ncbi_servicep.h:94
TNCBI_Time time
Definition: ncbi_servicep.h:91
unsigned short weight
Definition: ncbi_lbdns.c:581
unsigned short port
Definition: ncbi_lbdns.c:582
unsigned short priority
Definition: ncbi_lbdns.c:580
Definition: type.c:6
done
Definition: token1.c:1
void free(voidpf ptr)
voidp calloc(uInt items, uInt size)
Modified on Tue May 21 10:53:56 2024 by modify_doxy.py rev. 669887