pike.git / lib / modules / Protocols.pmod / DNS.pmod

version» Context lines:

pike.git/lib/modules/Protocols.pmod/DNS.pmod:1:   // Not yet finished -- Fredrik Hubinette       //inherit Stdio.UDP : udp;      //! Support for the Domain Name System protocol.   //! - //! RFC 1034, RFC 1035 and RFC 2308 + //! Implements @rfc{1034@}, @rfc{1035@} and @rfc{2308@}.      protected void send_reply(mapping r, mapping q, mapping m, Stdio.UDP udp);      #pike __REAL_VERSION__      // documentation taken from RFC 2136      //! No error condition.   final constant NOERROR=0;   
pike.git/lib/modules/Protocols.pmod/DNS.pmod:72:       //! Type - mail forwarder (Obsolete - use MX)    T_MF=4,       //! Type - canonical name for an alias    T_CNAME=5,       //! Type - start of a zone of authority    T_SOA=6,    -  //! Type - mailbox domain name (EXPERIMENTAL) +  //! Type - mailbox domain name (Obsolete)    T_MB=7,    -  //! Type - mail group member (EXPERIMENTAL) +  //! Type - mail group member (Obsolete)    T_MG=8,    -  //! Type - mail rename domain name (EXPERIMENTAL) +  //! Type - mail rename domain name (Obsolete)    T_MR=9,    -  //! Type - null RR (EXPERIMENTAL) +  //! Type - null RR (Obsolete @rfc{1035@})    T_NULL=10,    -  //! Type - well known service description +  //! Type - well known service description (Obsolete @rfc{1123@} and +  //! @rfc{1127@})    T_WKS=11,       //! Type - domain name pointer    T_PTR=12,       //! Type - host information    T_HINFO=13,    -  //! Type - mailbox or mail list information +  //! Type - mailbox or mail list information (Obsolete)    T_MINFO=14,       //! Type - mail exchange    T_MX=15,       //! Type - text strings    T_TXT=16,    -  //! Type - IPv6 address record (RFC 1886) +  //! Type - Responsible Person +  T_RP=17, +  +  //! Type - AFC database record (@rfc{1183@}) +  T_AFSDB=18, +  +  //! Type - X25 PSDN address (@rfc{1183@}) +  T_X25=19, +  +  //! Type - ISDN address (@rfc{1183@}) +  T_ISDN=20, +  +  //! Type - Route Through (@rfc{1183@}) +  T_RT=21, +  +  //! Type - OSI Network Service Access Protocol (@rfc{1348@}, +  //! @rfc{1637@} and @rfc{1706@}) +  T_NSAP=22, +  +  //! Type - OSI NSAP Pointer (@rfc{1348@} and Obsolete @rfc{1637@}) +  T_NSAP_PTR=23, +  +  //! Type - Signature (@rfc{2535@}) +  T_SIG=24, +  +  //! Type - Key record (@rfc{2535@} and @rfc{2930@}) +  T_KEY=25, +  +  //! Type - Pointer to X.400 mapping information (@rfc{1664@}) +  T_PX=26, +  +  //! Type - Global Position (@rfc{1712@} Obsolete use LOC). +  T_GPOS=27, +  +  //! Type - IPv6 address record (@rfc{1886@})    T_AAAA=28,    -  //! Type - Location Record (RFC 1876) +  //! Type - Location Record (@rfc{1876@})    T_LOC=29,    -  //! Type - Service location record (RFC 2782) +  //! Type - Next (@rfc{2065@} and Obsolete @rfc{3755@}) +  T_NXT=30, +  +  //! Type - Nimrod Endpoint IDentifier (draft) +  T_EID=31, +  +  //! Type - Nimrod Locator (draft) +  T_NIMLOC=32, +  +  //! Type - Service location record (@rfc{2782@})    T_SRV=33,    -  //! Type - NAPTR (RFC 3403) +  //! Type - ATM End System Address (af-saa-0069.000) +  T_ATMA=34, +  +  //! Type - NAPTR (@rfc{3403@})    T_NAPTR=35,    -  //! Type - IPv6 address record (RFC 2874, incomplete support) +  //! Type - Key eXchanger record (@rfc{2230@}) +  T_KX=36, +  +  //! Type - Certificate Record (@rfc{4398@}) +  T_CERT=37, +  +  //! Type - IPv6 address record (@rfc{2874@} and Obsolete @rfc{6563@})    T_A6=38,    -  //! Type - SPF - Sender Policy Framework (RFC 4408) +  //! Type - Delegation Name (@rfc{2672@}) +  T_DNAME=39, +  +  //! Type - Kitchen Sink (draft) +  T_SINK=40, +  +  //! Type - Option (@rfc{2671@}) +  T_OPT=41, +  +  //! Type - Address Prefix List (@rfc{3123@}) +  T_APL=42, +  +  //! Type - Delegation Signer (@rfc{4034@}) +  T_DS=43, +  +  //! Type - SSH Public Key Fingerprint (@rfc{4255@}) +  T_SSHFP=44, +  +  //! Type - IPsec Key (@rfc{4025@}) +  T_IPSECKEY=45, +  +  //! Type - DNSSEC signature (@rfc{4034@}) +  T_RRSIG=46, +  +  //! Type - Next-Secure record (@rfc{4034@}) +  T_NSEC=47, +  +  //! Type - DNS Key record (@rfc{4034@}) +  T_DNSKEY=48, +  +  //! Type - DHCP identifier (@rfc{4701@}) +  T_DHCID=49, +  +  //! Type - NSEC record version 3 (@rfc{5155@}) +  T_NSEC3=50, +  +  //! Type - NSEC3 parameters (@rfc{5155@}) +  T_NSEC3PARAM=51, +  +  //! Type - TLSA certificate association (@rfc{6698@}) +  T_TLSA=52, +  +  //! Type - Host Identity Protocol (@rfc{5205@}) +  T_HIP=55, +  +  //! Type - SPF - Sender Policy Framework (@rfc{4408@})    T_SPF=99,    -  +  // UserDB via DNS? +  T_UINFO=100, +  T_UID=101, +  T_GID=102, +  T_UNSPEC=103, +  +  //! Type - Secret key record (@rfc{2930@}) +  T_TKEY=249, +  +  //! Type - Transaction Signature (@rfc{2845@}) +  T_TSIG=250, +  +  //! Type - Incremental Zone Transfer (@rfc{1996@}) +  T_IXFR=251, +  +  //! Type - Authoritative Zone Transfer (@rfc{1035@}) +  T_AXFR=252, +  +  //! Type - Mail Box (MB, MG or MR) (Obsolete - use MX) +  T_MAILB=253, +  +  //! Type - Mail Agent (both MD and MF) (Obsolete - use MX) +  T_MAILA=254, +     //! Type - ANY - A request for all records    T_ANY=255, -  +  +  //! Type - Certificate Authority Authorization (@rfc{6844@}) +  T_CAA=257, +  +  //! Type - DNSSEC Trust Authorities (draft) +  T_TA=32768, +  +  //! Type - DNSSEC Lookaside Validation Record (@rfc{4431@}) +  T_DLV=32769,   };    -  + //! Flag bits used in @[T_DNSKEY] RRs. + enum DNSKEY_Flags { +  F_ZONEKEY = 0x0100, //! Zone Key. +  F_SECUREENTRYPOINT = 0x0001, //! Secure Entry Point. + }; +  + //! DNSSEC Protocol types. + //! + //! @note + //! @rfc{4034@} obsoleted all but @[DNSSEC_DNSSEC]. + enum DNSSEC_Protocol { +  DNSSEC_TLS = 1, //! Reserved for use by TLS. +  DNSSEC_EMAIL = 2, //! Reserved for use by SMTP et al. +  DNSSEC_DNSSEC = 3, //! Key for use by DNSSEC. @rfc{4034:2.1.2@}. +  DNSSEC_IPSEC = 4, //! Reserved for use by IPSEC. +  DNSSEC_ALL = 255, //! Any use. Discouraged. + }; +  + //! DNSSEC Algorithm types. + enum DNSSES_Algorithm { +  DNSSEC_RSAMD5 = 1, //! RSA/MD5 @rfc{2537@}. +  DNSSEC_DH = 2, //! Diffie-Hellman @rfc{2539@}. +  DNSSEC_DSA = 3, //! DSA/SHA1 @rfc{2536@}. +  DNSSEC_ECC = 4, +  DNSSEC_RSASHA1 = 5, //! RSA/SHA1 @rfc{3110@}. +  +  DNSSEC_INDIRECT = 252, +  DNSSEC_PRIVATEDNS = 253, //! Private algorithm DNS-based @rfc{4035:A.1.1@}. +  DNSSEC_PRIVATEOID = 254, //! Private algorithm OID-based @rfc{4035:A.1.1@}. + }; +  + //! DNSSEC Digest types. + enum DNSSEC_Digests { +  DNSSEC_SHA1 = 1, //! SHA1 digest @rfc{4035:A.2@}. + }; +    int safe_bind(Stdio.UDP udp, string|int port, string|void device)   {    mixed err = catch {    udp->bind(port, device, 1);    return 1;    };   #if constant(System.EADDRINUSE)    if (errno() == System.EADDRINUSE) return 0;   #endif -  werror("Protocols.DNS: Binding of UDP port failed with errno %d: %s\n", + #if constant(System.WSAEACCES) +  if (errno() == System.WSAEACCES) return 0; + #endif +  werror("Protocols.DNS: Binding of UDP port failed with errno %d: %s.\n",    errno(), strerror(errno()));    master()->handle_error(err);    return 0;   }      //! Low level DNS protocol   class protocol   {    string mklabel(string s)    {
pike.git/lib/modules/Protocols.pmod/DNS.pmod:238:    return map(stringp(entry->txt)? ({entry->txt}):(entry->txt||({})),    lambda(string t) {    return sprintf("%1H", t);    })*"";    case T_SPF:    return map(stringp(entry->spf)? ({entry->spf}):(entry->spf||({})),    lambda(string t) {    return sprintf("%1H", t);    })*"";    case T_LOC: -  // FIXME: Not implemented yet. +  int encode_T_LOC_tinyfloat(float|int subject) +  { +  int power = min((int)(log(subject*100.0)/log(10.0)), 9); +  int base = min((int)(subject*100.0/pow(10.0,power)), 9); +  return ((base&0xf)<<4)|(power&0xf); +  }; +  if ((entry->version? entry->version:1) != 1) +  error("Only T_LOC version 1 is supported"); +  return sprintf("%1c%1c%1c%1c%4c%4c%4c", +  0, // Only version that currently exists +  encode_T_LOC_tinyfloat(entry->size? entry->size:100.0), //Default is 1M +  encode_T_LOC_tinyfloat(entry->h_prec? entry->h_prec:1000*100.0), // Default is 10KM +  encode_T_LOC_tinyfloat(entry->v_prec? entry->v_prec:10*100.0), // Default is 10M +  entry->lat?(int)(entry->lat*3600000.0)+(2<<30):2<<30, // Default is 2<<30 which is 0.0 +  entry->long?(int)(entry->long*3600000.0)+(2<<30):2<<30, // Default is 2<<30 which is 0.0 +  entry->alt?(int)((entry->alt+100000)*100):100000, // Default to 0 WGS84 (which is 100000) +  ); +  case T_CAA: +  if (entry->tag == "" || !entry->tag) +  error("An empty tag is not permitted.\n"); +  return sprintf("%c%H%s", entry->flags | (!!entry->critical << 7), +  entry->tag, entry->value || "");    default:    return "";    }    }       protected private string encode_entries(array(mapping) entries, int pos,    mapping(string:int) comp)    {    string res="";    foreach(entries, mapping entry) {
pike.git/lib/modules/Protocols.pmod/DNS.pmod:432:    //! @mapping    //! @member int "preference"    //! @member string "mx"    //! @endmapping    //! @value T_HINFO    //! @mapping    //! @member string "cpu"    //! @member string "os"    //! @endmapping    //! @value T_SRV -  //! RFC 2052 and RFC 2782. +  //! @rfc{2052@} and @rfc{2782@}.    //! @mapping    //! @member int "priority"    //! @member int "weight"    //! @member int "port"    //! @member string "target"    //! @member string "service"    //! @member string "proto"    //! @member string "name"    //! @endmapping    //! @value T_A
pike.git/lib/modules/Protocols.pmod/DNS.pmod:457:    //! @value T_AAAA    //! @mapping    //! @member string "aaaa"    //! IPv6-address in colon-separated hexadecimal format.    //! @endmapping    //! @value T_LOC    //! @mapping    //! @member int "version"    //! Version, currently only version @expr{0@} (zero) is    //! supported. -  //! @member int "size" -  //! @member int "h_perc" -  //! @member int "v_perc" -  //! @member int "lat" -  //! @member int "long" -  //! @member int "alt" +  //! @member float "size" +  //! @member float "h_perc" +  //! @member float "v_perc" +  //! @member float "lat" +  //! @member float "long" +  //! @member float "alt"    //! @endmapping    //! @value T_SOA    //! @mapping    //! @member string "mname"    //! @member string "rname"    //! @member int "serial"    //! @member int "refresh"    //! @member int "retry"    //! @member int "expire"    //!    //! @member int "minimum"    //! Note: For historical reasons this entry is named    //! @expr{"minimum"@}, but it contains the TTL for -  //! negative answers (RFC 2308). +  //! negative answers (@rfc{2308@}).    //! @endmapping    //! @value T_NAPTR    //! @mapping    //! @member int "order"    //! @member int "preference"    //! @member string "flags"    //! @member string "service"    //! @member string "regexp"    //! @member string "replacement"    //! @endmapping
pike.git/lib/modules/Protocols.pmod/DNS.pmod:504:    //! When receiving decoded DNS data from a client, txta is    //! the array of all strings in the record. When sending    //! multiple strings in a TXT record in a server, please    //! supply an array as "txt" containing the strings, txta    //! will be ignored.    //! @endmapping    //! @value T_SPF    //! @mapping    //! @member string "spf"    //! @endmapping +  //! @value T_CAA +  //! @mapping +  //! @member int "critical" +  //! Sets the critical bit of the flag field. +  //! @member int "flags" +  //! +  //! @member string "tag" +  //! Cannot be empty. +  //! @member string "value" +  //! @endmapping    //! @endint    //! @endarray    array decode_entries(string s,int num, array(int) next)    {    array(string) ret=({});    for(int e=0;e<num && next[0]<sizeof(s);e++)    {    mapping m=([]);    m->name=decode_domain(s,next);    sscanf(s[next[0]..next[0]+10],
pike.git/lib/modules/Protocols.pmod/DNS.pmod:574:    case T_AAAA:    m->aaaa=sprintf("%{%02X%}",    (values(s[next[0]..next[0]+m->len-1])/2)[*])*":";    break;    case T_LOC:    m->version = decode_byte(s,next);    if (m->version == 0)    {    int aByte;    aByte = decode_byte(s,next); -  m->size = pow((aByte>>4)&0xf , aByte&0xf)/100.0; +  m->size = (((aByte>>4)&0xf)%10)*(pow(10,(aByte&0xf)%10)/100.0);    aByte = decode_byte(s,next); -  m->h_perc = pow((aByte>>4)&0xf , aByte&0xf)/100.0; +  m->h_perc = (((aByte>>4)&0xf)%10)*(pow(10,(aByte&0xf)%10)/100.0);    aByte = decode_byte(s,next); -  m->v_perc = pow((aByte>>4)&0xf , aByte&0xf)/100.0; +  m->v_perc = (((aByte>>4)&0xf)%10)*(pow(10,(aByte&0xf)%10)/100.0);    m->lat = ((decode_int(s,next)-(2<<30))/3600000.0);    m->long = ((decode_int(s,next)-(2<<30))/3600000.0);    m->alt = ((decode_int(s,next)/100.0)-100000.0);    }    break;    case T_SOA:    m->mname=decode_domain(s,next);    m->rname=decode_domain(s,next);    m->serial=decode_int(s,next);    m->refresh=decode_int(s,next);
pike.git/lib/modules/Protocols.pmod/DNS.pmod:616:    while (tlen < m->len) {    m->txta += ({ decode_string(s, next) });    tlen += sizeof(m->txta[-1]) + 1;    }    m->txt = m->txta[0];    }    break;    case T_SPF:    m->spf = decode_string(s, next);    break; +  case T_CAA: +  { +  string tag; +  +  m->critical = !!((m->flags = decode_byte(s, next)) & 0x80); +  tag = m->tag = decode_string(s, next); +  m->value = s[next[0]..next[0] + m->len - 3 - sizeof(tag)];    } -  +  break; +  }       next[0]=tmp+m->len;    ret+=({m});    }    return ret;    }       mapping decode_res(string s)    {    mapping m=([]);
pike.git/lib/modules/Protocols.pmod/DNS.pmod:693:    if (udp->bind(0, "::1") && udp->bind(0, "::") &&    (udp->send("127.0.0.1", 9, "/dev/null") == 9) &&    (udp->send("::1", 9, "/dev/null") == 9)) {    // Note: The above tests are apparently not sufficient, since    // WIN32 happily pretends to send stuff to ::ffff:0:0/96...    Stdio.UDP udp2 = Stdio.UDP();    if (udp2->bind(0, "127.0.0.1")) {    // IPv4 is present.    array(string) a = udp2->query_address()/" ";    int port = (int)a[1]; -  string key = Crypto.Random.random_string(16); +  string key = random_string(16);    udp2->set_nonblocking();       // We shouldn't get any lost packets, since we're on the loop-back,    // but for paranoia reasons we perform a couple of retries.    retry:    for (int i = 0; i < 16; i++) {    if (!udp->send("127.0.0.1", port, key)) continue;    // udp2->wait() throws errors on WIN32.    catch(udp2->wait(1));    mapping res;
pike.git/lib/modules/Protocols.pmod/DNS.pmod:837:    }       //! Handle a query response (stub).    //!    //! Overload this function to handle responses to possible recursive queries.    protected void handle_response(mapping r, mapping m, Stdio.UDP|object udp)    {    // This is a stub intended to simplify servers which allow recursion    }    +  //! Report a failure to decode a DNS request. +  //! +  //! The default implementation writes a backtrace to stderr. This +  //! method exists so that derived servers can replace it with more +  //! appropriate error handling for their environment. +  protected void report_decode_error(mixed err, mapping m, Stdio.UDP|object udp) +  { +  werror("DNS: Failed to read %s packet.\n%s\n", +  udp->tcp_connection ? "TCP" : "UDP", +  describe_backtrace(err)); +  } +  +  //! Respond to a query that cannot be decoded. +  //! +  //! This method exists so that servers can override the default behaviour. +  protected void handle_decode_error(mapping err, mapping m, +  Stdio.UDP|object udp) +  { +  if(m && m->data && sizeof(m->data)>=2) +  send_reply((["rcode":1]), +  mkmapping(({"id"}), array_sscanf(m->data, "%2c")), m, udp); +  } +     //! Low-level DNS-data receiver.    //!    //! This function receives the raw DNS-data from the @[Stdio.UDP] socket    //! or TCP connection object @[udp], decodes it, and dispatches the decoded    //! DNS request to @[handle_query()] and @[handle_response()].    protected void rec_data(mapping m, Stdio.UDP|object udp)    {    mixed err;    mapping q;    if (err = catch {    q=decode_res(m->data);    }) { -  werror("DNS: Failed to read %s packet.\n%s\n", -  udp->tcp_connection ? "TCP" : "UDP", -  describe_backtrace(err)); -  if(m && m->data && sizeof(m->data)>=2) -  send_reply((["rcode":1]), -  mkmapping(({"id"}), array_sscanf(m->data, "%2c")), m, udp); +  report_decode_error(err, m, udp); +  handle_decode_error(err, m, udp);    }    else if(q->qr)    handle_response(q, m, udp);    else    handle_query(q, m, udp);    }       protected void send_reply(mapping r, mapping q, mapping m,    Stdio.UDP|object con);    -  protected void destroy() +  protected void _destruct()    {    if(sizeof(ports))    {    foreach(ports;; object port)    destruct(port);    }    }   }      //! Base class for implementing a Domain Name Service (DNS) server operating
pike.git/lib/modules/Protocols.pmod/DNS.pmod:967:       protected class Connection {    constant tcp_connection = 1;       protected int(0..1) write_ready;    protected string read_buffer = "", out_buffer = "";    protected array c_id;    Stdio.File con;       protected void create(Stdio.File con) { -  this_program::con = con; +  this::con = con;    con->set_nonblocking(rcb, wcb, ccb);    c_id = call_out(destruct, 120, this);    }       protected void ccb(mixed id) {    destruct(con);    m_delete(connections, this);    }       protected void wcb(mixed id) {
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1027:    if (write_ready) {    int written = con->write(out_buffer);    out_buffer = out_buffer[written..];    write_ready = 0;    }       remove_call_out(c_id);    c_id = call_out(destruct, 120, this);    }    -  void destroy() { +  protected void _destruct() {    if (con) con->close();    destruct(con);    m_delete(connections, this);    }    }       protected int accept(Stdio.Port port) {    connections[Connection(port->accept())] = 1;    }   
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1093:    port = Stdio.Port(args[i+1], accept);    }       port->set_id(port);    // Port objects are stored for destruction when the server    // object is destroyed.    ports += ({ port });    }    }    -  protected void destroy() +  protected void _destruct()    {    foreach (connections; Connection con;) {    destruct(con);    }    -  ::destroy(); +  ::_destruct();    }   }      //! This is both a @[server] and @[tcp_server].   class dual_server {    inherit server : UDP;    inherit tcp_server : TCP;       protected void send_reply(mapping r, mapping q, mapping m,    Connection|Stdio.UDP con) {
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1129:    con->send(m->ip, m->port, rpl);    } else    con->send(rpl);    }       protected void create(int|string|void arg1, string|int ... args)    {    ::create(arg1, @args);    }    -  protected void destroy() +  protected void _destruct()    { -  ::destroy(); +  ::_destruct();    }   }         #define RETRIES 12   #define RETRY_DELAY 5      //! Synchronous DNS client.   class client   {
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1155: Inside #if defined(__NT__)
   array(string) get_tcpip_param(string val, void|string fallbackvalue)    {    array(string) res = ({});    foreach(({    "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",    "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters",    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"    }),string key)    {    catch { -  res += ({ RegGetValue(HKEY_LOCAL_MACHINE, key, val) }); +  res += ({ System.RegGetValue(HKEY_LOCAL_MACHINE, key, val) });    };    }    - #if constant(RegGetKeyNames) -  /* Catch if RegGetKeyNames() doesn't find the directory. */ + #if constant(System.RegGetKeyNames) +  /* Catch if System.RegGetKeyNames() doesn't find the directory. */    catch { -  foreach(RegGetKeyNames(HKEY_LOCAL_MACHINE, +  foreach(System.RegGetKeyNames(HKEY_LOCAL_MACHINE,    "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\"    "Parameters\\Interfaces"), string key)    {    catch { -  res += ({ RegGetValue(HKEY_LOCAL_MACHINE, +  res += ({ System.RegGetValue(HKEY_LOCAL_MACHINE,    "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\"    "Parameters\\Interfaces\\" + key, val) });    };    } -  foreach(RegGetKeyNames(HKEY_LOCAL_MACHINE, +  foreach(System.RegGetKeyNames(HKEY_LOCAL_MACHINE,    "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\"    "Parameters\\Interfaces"), string key)    {    catch { -  res += ({ RegGetValue(HKEY_LOCAL_MACHINE, +  res += ({ System.RegGetValue(HKEY_LOCAL_MACHINE,    "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\"    "Parameters\\Interfaces\\" + key, val) });    };    }    };   #endif    res -= ({ UNDEFINED });    return sizeof(res) ? res : ({ fallbackvalue });    }   
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1453:    // Restore blocking state for udp->send() on retry.    udp->set_blocking();    }    // Failure.    return 0;    }       protected mapping low_gethostbyname(string s, int type)    {    mapping m; -  if(sizeof(domains) && s[-1] != '.' && sizeof(s/".") < 3) { +  if(sizeof(domains) && sizeof(s) && s[-1] != '.' && sizeof(s/".") < 3) {    mapping m = do_sync_query(mkquery(s, C_IN, type));    if(!m || !m->an || !sizeof(m->an))    foreach(domains, string domain)    {    m = do_sync_query(mkquery(s+"."+domain, C_IN, type));    if(m && m->an && sizeof(m->an))    break;    }    return m;    } else {
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1527:    }    }       return ({    sizeof(names)?names[0]:0,    ips,    names,    });    }    -  //! Queries the service record (RFC 2782) from the default or given -  //! DNS server. The result is an array of arrays with the -  //! following six elements for each record. The array is -  //! sorted according to the priority of each record. +  //! Queries the service record (@rfc{2782@}) from the default or +  //! given DNS server. The result is an array of arrays with the +  //! following six elements for each record. The array is sorted +  //! according to the priority of each record.    //!    //! Each element of the array returned represents a service    //! record. Each service record contains the following:    //!    //! @returns    //! An array with the requested information about the specified    //! service.    //!    //! @array    //! @elem int priority
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1718:    }    if (!m) {    return 0;    }    array a = filter(m->an, `[], "mx");    array(string) b = column( a, "mx");    sort( column( a, "preference"), b);       return b;    } - } +     - #define REMOVE_DELAY 120 - #define GIVE_UP_DELAY (RETRIES * RETRY_DELAY + REMOVE_DELAY)*2 -  - // FIXME: Randomized source port! - //! Asynchronous DNS client. - class async_client +  //! +  class Request(string domain, string req, +  function(string,mapping,mixed...:void) callback, +  array(mixed) args)    { -  inherit client; -  inherit Stdio.UDP : udp; -  async_client next_client; +  int retries; +  int timestamp = time();    -  class Request +  //! Cancel the current request. +  void cancel()    { -  string req; -  string domain; -  function callback; -  int retries; -  int timestamp; -  array args; +  remove(this); +  } +  mixed retry_co;    };       mapping requests=([]);    -  protected private void remove(object(Request) r) +  protected void remove(object(Request) r)    {    if(!r) return;    sscanf(r->req,"%2c",int id);    m_delete(requests,id); -  r->callback(r->domain,0,@r->args); +  if (r->retry_co) remove_call_out(r->retry_co); +  r->retry_co = UNDEFINED; +  r->callback && r->callback(r->domain,0,@r->args);    destruct(r);    } -  + }    -  + #define REMOVE_DELAY 120 + #define GIVE_UP_DELAY (RETRIES * RETRY_DELAY + REMOVE_DELAY)*2 +  + // FIXME: Randomized source port! + //! Asynchronous DNS client. + class async_client + { +  inherit client; +  inherit Stdio.UDP : udp; +  async_client next_client; +     void retry(object(Request) r, void|int nsno)    {    if(!r) return;    if (nsno >= sizeof(nameservers)) {    if(r->retries++ > RETRIES)    { -  call_out(remove,REMOVE_DELAY,r); +  r->retry_co = call_out(remove, REMOVE_DELAY, r);    return;    } else {    nsno = 0;    }    }    -  send(nameservers[nsno],53,r->req); -  call_out(retry,RETRY_DELAY,r,nsno+1); +  r->retry_co = call_out(retry, RETRY_DELAY, r, nsno+1); +  udp::send(nameservers[nsno], 53, r->req);    }    -  +  //! Enqueue a new raw DNS request.    //! -  void do_query(string domain, int cl, int type, +  //! @returns +  //! Returns a @[Request] object. +  //! +  //! @note +  //! Pike versions prior to 8.0 did not return the @[Request] object. +  Request do_query(string domain, int cl, int type,    function(string,mapping,mixed...:void) callback,    mixed ... args)    {    for(int e=next_client ? 100 : 256;e>=0;e--)    {    int lid = random(65536);    if(!catch { requests[lid]++; })    {    string req=low_mkquery(lid,domain,cl,type);    -  object r=Request(); -  r->req=req; -  r->domain=domain; -  r->callback=callback; -  r->args=args; -  r->timestamp=time(); -  requests[lid]=r; -  udp::send(nameservers[0],53,r->req); -  call_out(retry,RETRY_DELAY,r,1); -  return; +  object r = Request(domain, req, callback, args); +  r->retry_co = call_out(retry, RETRY_DELAY, r, 1); +  requests[lid] = r; +  udp::send(nameservers[0], 53, req); +  return r;    }    }       /* We failed miserably to find a request id to use,    * so we create a second UDP port to be able to have more    * requests 'in the air'. /Hubbe    */    if(!next_client)    next_client=this_program(nameservers,domains);    -  next_client->do_query(domain, cl, type, callback, @args); +  return next_client->do_query(domain, cl, type, callback, @args);    }       protected private void rec_data(mapping m)    {    mixed err;    if (err = catch {    if(m->port != 53 || !has_value(nameservers, m->ip)) return;    sscanf(m->data,"%2c",int id);    object r=requests[id];    if(!r) {
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1825:    }    m_delete(requests,id);    r->callback(r->domain,decode_res(m->data),@r->args);    destruct(r);    }) {    werror("DNS: Failed to read UDP packet. Connection refused?\n%s\n",    describe_backtrace(err));    }    }    -  protected private void generic_get(string d, +  protected private Request generic_get(string d,    mapping answer,    int multi,    int all,    int type,    string field,    string domain,    function callback,    mixed ... args)    {    if(!answer || !answer->an || !sizeof(answer->an))    {    if(multi == -1 || multi >= sizeof(domains)) {    // Either a request without multi (ip, or FQDN) or we have tried all    // domains.    callback(domain,0,@args);    } else {    // Multiple domain request. Try the next one... -  do_query(domain+"."+domains[multi], C_IN, type, +  return do_query(domain+"."+domains[multi], C_IN, type,    generic_get, ++multi, all, type, field, domain,    callback, @args);    }    } else {    if (all) {    callback(domain, answer->an, @args);    } else {    foreach(answer->an, array an)    if(an[field])    {    callback(domain, an[field], @args); -  return; +  return UNDEFINED;    }    callback(domain,0,@args); -  return; +     }    } -  +  return UNDEFINED;    }       //! -  void host_to_ip(string host, function callback, mixed ... args) +  Request host_to_ip(string host, function callback, mixed ... args)    {    if(sizeof(domains) && host[-1] != '.' && sizeof(host/".") < 3) { -  do_query(host, C_IN, T_A, +  return do_query(host, C_IN, T_A,    generic_get, 0, 0, T_A, "a", host, callback, @args );    } else { -  do_query(host, C_IN, T_A, +  return do_query(host, C_IN, T_A,    generic_get, -1, 0, T_A, "a",    host, callback, @args);    }    }       //! -  void ip_to_host(string ip, function callback, mixed ... args) +  Request ip_to_host(string ip, function callback, mixed ... args)    { -  do_query(arpa_from_ip(ip), C_IN, T_PTR, +  return do_query(arpa_from_ip(ip), C_IN, T_PTR,    generic_get, -1, 0, T_PTR, "ptr",    ip, callback,    @args);    }       //! -  void get_mx_all(string host, function callback, mixed ... args) +  Request get_mx_all(string host, function callback, mixed ... args)    {    if(sizeof(domains) && host[-1] != '.' && sizeof(host/".") < 3) { -  do_query(host, C_IN, T_MX, +  return do_query(host, C_IN, T_MX,    generic_get, 0, 1, T_MX, "mx", host, callback, @args);    } else { -  do_query(host, C_IN, T_MX, +  return do_query(host, C_IN, T_MX,    generic_get, -1, 1, T_MX, "mx", host, callback, @args);    }    }       //! -  void get_mx(string host, function callback, mixed ... args) +  Request get_mx(string host, function callback, mixed ... args)    { -  get_mx_all(host, +  return get_mx_all(host,    lambda(string domain, array(mapping) mx,    function callback, mixed ... args) {    array a;    if (mx) {    a = column(mx, "mx");    sort(column(mx, "preference"), a);    }    callback(a, @args);    }, callback, @args);    }
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1993:    return 0;    }   }      // FIXME: Reuse sockets? Acknowledge RETRIES?   //! Asynchronous DNS client using TCP   class async_tcp_client   {    inherit async_client;    -  class Request(string domain, string req, +  //! +  class Request +  { +  inherit ::this_program; +  +  protected Stdio.File sock; +  protected string writebuf="",readbuf=""; +  +  protected void create(string domain, string req,    function(string,mapping,mixed...:void) callback,    array(mixed) args)    { -  Stdio.File sock; -  string writebuf="",readbuf=""; -  -  void create() -  { +  ::create(domain, req, callback, args);    sock=Stdio.File();    sock->async_connect(nameservers[0], 53, connectedcb);    }    -  void connectedcb(int ok) +  protected void close()    { -  +  sock && sock->close(); +  sock = UNDEFINED; +  } +  +  protected void connectedcb(int ok) +  {    if (!ok) {callback(domain, 0, @args); return;}    sock->set_nonblocking(readcb, writecb, closecb);    writebuf=sprintf("%2H",req);    writecb();    }    -  void readcb(mixed id,string data) +  protected void readcb(mixed id,string data)    {    readbuf+=data;    if (sscanf(readbuf,"%2H",string ret))    {    if (callback) callback(domain, decode_res(ret), @args);    callback=0; -  sock->close(); +  close();    }    }    -  void writecb() +  protected void writecb()    {    if (writebuf!="") writebuf=writebuf[sock->write(writebuf)..];    }    -  void closecb() +  protected void closecb()    { -  sock->close(); -  if (callback) callback(domain, 0, @args); -  callback=0; +  cancel();    } -  +  +  void cancel() +  { +  close(); +  ::cancel();    } -  +  }       //! -  void do_query(string domain, int cl, int type, +  Request do_query(string domain, int cl, int type,    function(string,mapping,mixed...:void) callback,    mixed ... args)    {    string req=low_mkquery(random(65536),domain,cl,type); -  Request(domain, req, callback, args); +  return Request(domain, req, callback, args);    }   }      //! Both a @[client] and a @[tcp_client].   class dual_client   {    inherit client : UDP;    inherit tcp_client : TCP;       //!
pike.git/lib/modules/Protocols.pmod/DNS.pmod:2080:       void check_truncation(string domain, mapping result, int cl, int type,    function(string,mapping,mixed...:void) callback,    mixed ... args)    {    if (!result || !result->tc) callback(domain,result,@args);    else TCP::do_query(domain,cl,type,callback,@args);    }       //! -  void do_query(string domain, int cl, int type, +  Request do_query(string domain, int cl, int type,    function(string,mapping,mixed...:void) callback,    mixed ... args)    { -  UDP::do_query(domain,cl,type,check_truncation,cl,type,callback,@args); +  return UDP::do_query(domain,cl,type,check_truncation, +  cl,type,callback,@args);    }       void create(mixed ... args) {::create(@args);}   }         async_client global_async_client;      #define GAC(X) \ - void async_##X( string host, function callback, mixed ... args ) \ + async_client.Request async_##X( string host, function callback, mixed ... args ) \   { \    if( !global_async_client ) \    global_async_client = async_client(); \ -  global_async_client->X(host,callback,@args); \ +  return global_async_client->X(host,callback,@args); \   }      //! @ignore   GAC(ip_to_host);   //! @endignore   //! @decl void async_ip_to_host(string ip, function cb, mixed ... cba)      //! @ignore   GAC(host_to_ip);   //! @endignore