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

version» Context lines:

pike.git/lib/modules/Protocols.pmod/DNS.pmod:99:    //! 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; +  }; +  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:617:    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;    }   };    - //! Implements a Domain Name Service (DNS) server. + protected string ANY; +  + protected void create() + { +  // Check if IPv6 support is available. +  catch { +  // Note: Attempt to open a port 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 opens ports on :: even +  // if no IPv6 interfaces are configured. +  // Try IPv6 any (::) too for paranoia reasons. +  Stdio.Port p = Stdio.Port(); +  if (p->bind(0, 0, "::1") && p->bind(0, 0, "::")) { +  ANY = "::"; +  } +  destruct(p); +  }; + } +  + //! 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;       array(Stdio.UDP) ports = ({});       protected void send_reply(mapping r, mapping q, mapping m, Stdio.UDP udp)
pike.git/lib/modules/Protocols.pmod/DNS.pmod:726:    if(m && m->data && sizeof(m->data)>=2)    send_reply((["rcode":1]),    mkmapping(({"id"}), array_sscanf(m->data, "%2c")), m, udp);    }    else if(q->qr)    handle_response(q, m, udp);    else    handle_query(q, m, udp);    }    +  //! @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{"::"@} 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.    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});    }       }       static void destory()
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1016:    nameservers = ({ server });       if(arrayp(domain))    domains = domain;    else    if(stringp(domain))    domains = ({ domain });    }    }    - //! perform a syncronous 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   //! // perform a hostname lookup, results stored in r->an   //! object d=Protocols.DNS.client();   //! mapping r=d->do_sync_query(d->mkquery("pike.ida.liu.se", C_IN, T_A));    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:1539:    }       void close()    {    udp::close();    udp::set_read_callback(0);    }       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);