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 -  +     protected void send_reply(mapping r, mapping q, mapping m, Stdio.UDP udp);      #pike __REAL_VERSION__      final constant NOERROR=0;   final constant FORMERR=1;   final constant SERVFAIL=2;   final constant NXDOMAIN=3;   final constant NOTIMPL=4;   final constant REFUSED=5;
pike.git/lib/modules/Protocols.pmod/DNS.pmod:98:    //! Type - NAPTR (RFC 3403)    T_NAPTR=35,       //! Type - IPv6 address record (RFC 2874, incomplete support)    T_A6=38,       //! Type - SPF - Sender Policy Framework (RFC 4408)    T_SPF=99,   };    + int safe_bind(Stdio.UDP udp, mixed ... args) + { +  mixed err = catch { +  udp->bind(@args); +  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", +  errno(), strerror(errno())); +  master()->handle_error(err); +  return 0; + } +    //! Low level DNS protocol   class protocol   {    string mklabel(string s)    {    if(sizeof(s)>63)    error("Too long component in domain name.\n");    return sprintf("%c%s",sizeof(s),s);    }   
pike.git/lib/modules/Protocols.pmod/DNS.pmod:605:    sscanf(s[next[0]..next[0]+3],"%2c%2c",m->qd[i]->type, m->qd[i]->cl);    next[0]+=4;    }    m->an=decode_entries(s,m->ancount,next);    m->ns=decode_entries(s,m->nscount,next);    m->ar=decode_entries(s,m->arcount,next);    return m;    }   };    + protected string ANY; +  + protected void create() + { +  // Check if IPv6 support is available, and that mapped IPv4 is enabled. +  catch { +  // Note: Attempt to bind on the IPv6 loopback (::1) +  // rather than on IPv6 any (::), to make sure some +  // IPv6 support is actually configured. This is needed +  // since eg Solaris happily binds on :: even +  // if no IPv6 interfaces are configured. +  // Try IPv6 any (::) too for paranoia reasons. +  // For even more paranoia, try sending some data +  // from :: to the drain services on 127.0.0.1 and ::1. +  // +  // If the tests fail, we regard the IPv6 support as broken, +  // and use just IPv4. +  Stdio.UDP udp = Stdio.UDP(); +  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)) { +  ANY = "::"; +  } +  destruct(udp); +  }; + } +    //! Base class for implementing a Domain Name Service (DNS) server.   //!   //! This class is typically used by inheriting it,   //! and overloading @[reply_query()] and @[handle_response()].   class server   {    //!    inherit protocol;       //inherit Stdio.UDP : udp;
pike.git/lib/modules/Protocols.pmod/DNS.pmod:743:       //! @decl void create()    //! @decl void create(int port)    //! @decl void create(string ip)    //! @decl void create(string ip, int port)    //! @decl void create(string ip, int port, string|int ... more)    //!    //! Open one or more new DNS server ports.    //!    //! @param ip -  //! The IP to bind to. Defaults to @expr{0@} (ie ANY). +  //! The IP to bind to. Defaults to @expr{"::"@} or @expr{0@} (ie ANY) +  //! depending on whether IPv6 support is present or not.    //!    //! @param port    //! The port number to bind to. Defaults to @expr{53@}.    //!    //! @param more    //! Optional further DNS server ports to open.    //! Must be a set of @[ip], @[port] argument pairs.    protected void create(int|string|void arg1, string|int ... args)    {    if(!arg1 && !sizeof(args))    arg1 = 53;    if(!sizeof(args))    {    if(stringp(arg1))    args = ({ arg1, 53 });    else -  args = ({ 0, arg1 }); +  args = ({ ANY, arg1 });    }    else    args = ({ arg1 }) + args;    if(sizeof(args)&1)    error("DNS: if you specify more than one argument, the number of "    "arguments needs to be even (server(ip1, port1, ip2, port2, "    "...)).\n");    for(int i;i<sizeof(args);i+=2) {    Stdio.UDP udp = Stdio.UDP();    if(args[i]) { -  if (!udp->bind(args[i+1],args[i])) +  if (!safe_bind(udp, args[i+1], args[i]))    error("DNS: failed to bind host:port %s:%d.\n", args[i],args[i+1]);    } else { -  if(!udp->bind(args[i+1])) +  if(!safe_bind(udp, args[i+1]))    error("DNS: failed to bind port %d.\n", args[i+1]);    }    udp->set_read_callback(rec_data, udp);    // port objects are stored for destruction when the server object is destroyed.    ports += ({udp});    }       }       protected void destory()
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1042:    nameservers = ({ server });       if(arrayp(domain))    domains = domain;    else    if(stringp(domain))    domains = ({ domain });    }    }    - //! Perform a syncronous DNS query. + //! Perform a synchronous DNS query.   //!   //! @param s   //! Result of @[Protocols.DNS.protocol.mkquery]   //! @returns   //! mapping containing query result or 0 on failure/timeout   //!   //! @example   //! @code   //! // Perform a hostname lookup, results stored in r->an   //! object d=Protocols.DNS.client();   //! mapping r=d->do_sync_query(d->mkquery("pike.lysator.liu.se", C_IN, T_A));   //! @endcode    mapping do_sync_query(string s)    {    int i;    object udp = Stdio.UDP();    // Attempt to randomize the source port.    for (i = 0; i < RETRIES; i++) { -  if (!catch { udp->bind(1024 + random(65536-1024)); }) continue; +  if (!safe_bind(udp, 1024 + random(65536-1024), ANY)) continue;    } -  if (i >= RETRIES) udp->bind(0); +  if (i >= RETRIES) safe_bind(udp, 0, ANY) || udp->bind(0);   #if 0    werror("Protocols.DNS.client()->do_sync_query(%O)\n"    "UDP Address: %s\n"    "%s\n", s, udp->query_address(), describe_backtrace(backtrace()));   #endif /* 0 */    mapping m;    for (i=0; i < RETRIES; i++) {    udp->send(nameservers[i % sizeof(nameservers)], 53, s);       // upd->wait() can throw an error sometimes.
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1382:    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   {    inherit client;    inherit Stdio.UDP : udp;    async_client next_client;       class Request    {    string req;    string domain;
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1520:    {    callback(domain, an[field], @args);    return;    }    callback(domain,0,@args);    return;    }    }    }    +  //!    void host_to_ip(string host, function callback, mixed ... args)    {    if(sizeof(domains) && host[-1] != '.' && sizeof(host/".") < 3) {    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,    generic_get, -1, 0, T_A, "a",    host, callback, @args);    }    }    -  +  //!    void ip_to_host(string ip, function callback, mixed ... args)    {    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)    {    if(sizeof(domains) && host[-1] != '.' && sizeof(host/".") < 3) {    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,    generic_get, -1, 1, T_MX, "mx", host, callback, @args);    }    }    -  +  //!    void get_mx(string host, function callback, mixed ... args)    {    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);    }    -  +  //! Close the client. +  //! +  //! @note +  //! All active requests are aborted.    void close()    { -  +  foreach(requests; ; Request r) { +  remove(r); +  }    udp::close();    udp::set_read_callback(0);    }       //!    protected void create(void|string|array(string) server,    void|string|array(string) domain)    { -  if(!udp::bind(0)) +  int i; +  // Attempt to randomize the source port. +  for (i = 0; i < RETRIES; i++) { +  if (safe_bind(udp::this, 1024 + random(65536-1024), ANY)) break; +  } +  if((i >= RETRIES) && +  !safe_bind(udp::this, 0, ANY) && +  !safe_bind(udp::this, 0))    error( "DNS: failed to bind a port.\n" );   #if 0    werror("Protocols.DNS.async_client(%O, %O)\n"    "UDP Address: %s\n"    "%s\n", server, domain, udp::query_address(),    describe_backtrace(backtrace()));   #endif /* 0 */       udp::set_read_callback(rec_data);    ::create(server,domain);