b910e42011-01-21Martin Jonsson // $Id$
bb02cc1997-09-15Fredrik Hübinette (Hubbe) // Not yet finished -- Fredrik Hubinette
2253ed2002-12-01Martin Nilsson 
f7616f2010-01-05H. William Welliver III  //inherit Stdio.UDP : udp;
4b995e2012-01-31Henrik Grubbström (Grubba)  //! Support for the Domain Name System protocol. //!
8630372008-07-23Henrik Grubbström (Grubba) //! RFC 1034, RFC 1035 and RFC 2308
4b995e2012-01-31Henrik Grubbström (Grubba) 
f7616f2010-01-05H. William Welliver III  protected void send_reply(mapping r, mapping q, mapping m, Stdio.UDP udp);
a20af62000-09-26Fredrik Hübinette (Hubbe) 
a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
189c792000-09-11Leif Stensson 
f53d9c2008-07-13Marcus Comstedt final constant NOERROR=0; final constant FORMERR=1; final constant SERVFAIL=2; final constant NXDOMAIN=3; final constant NOTIMPL=4;
8630372008-07-23Henrik Grubbström (Grubba) final constant REFUSED=5;
f53d9c2008-07-13Marcus Comstedt final constant NXRRSET=8;
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
f53d9c2008-07-13Marcus Comstedt final constant QUERY=0;
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
c534f62002-12-23Henrik Grubbström (Grubba) //! Resource classes enum ResourceClass { //! Class Internet C_IN=1,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Class CSNET (Obsolete) C_CS=2,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Class CHAOS C_CH=3,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Class Hesiod C_HS=4,
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Class ANY C_ANY=255, };
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba) //! Entry types enum EntryType { //! Type - host address T_A=1,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - authoritative name server T_NS=2,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - mail destination (Obsolete - use MX) T_MD=3,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - mail forwarder (Obsolete - use MX) T_MF=4,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - canonical name for an alias T_CNAME=5,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - start of a zone of authority T_SOA=6,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - mailbox domain name (EXPERIMENTAL) T_MB=7,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - mail group member (EXPERIMENTAL) T_MG=8,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - mail rename domain name (EXPERIMENTAL) T_MR=9,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - null RR (EXPERIMENTAL) T_NULL=10,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - well known service description T_WKS=11,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - domain name pointer T_PTR=12,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - host information T_HINFO=13,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - mailbox or mail list information T_MINFO=14,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - mail exchange T_MX=15,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - text strings T_TXT=16,
27e9f92002-12-01H. William Welliver III 
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - IPv6 address record (RFC 1886, deprecated) T_AAAA=28,
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
79d3032004-04-13Jeff Hungerford  //! Type - Location Record (RFC 1876) T_LOC=29,
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - Service location record (RFC 2782) T_SRV=33,
ddcaf02007-03-19Ignasi Cavero  //! Type - NAPTR (RFC 3403) T_NAPTR=35,
c534f62002-12-23Henrik Grubbström (Grubba)  //! Type - IPv6 address record (RFC 2874, incomplete support) T_A6=38,
5241a02008-07-24Henrik Grubbström (Grubba)  //! Type - SPF - Sender Policy Framework (RFC 4408) T_SPF=99,
c534f62002-12-23Henrik Grubbström (Grubba) };
27e9f92002-12-01H. William Welliver III 
4f4a5c2012-01-25Henrik Grubbström (Grubba) int safe_bind(Stdio.UDP udp, mixed ... args) { mixed err = catch { udp->bind(@args); return 1; };
0cf5e52012-01-30Henrik Grubbström (Grubba) #if constant(System.EADDRINUSE) if (errno() == System.EADDRINUSE) return 0; #endif
8ca0422014-11-17Pontus Rodling #if constant(System.WSAEACCES) if (errno() == System.WSAEACCES) return 0; #endif
0cf5e52012-01-30Henrik Grubbström (Grubba)  werror("Protocols.DNS: Binding of UDP port failed with errno %d: %s\n", errno(), strerror(errno()));
4f4a5c2012-01-25Henrik Grubbström (Grubba)  master()->handle_error(err); return 0; }
27e9f92002-12-01H. William Welliver III //! Low level DNS protocol
bb02cc1997-09-15Fredrik Hübinette (Hubbe) class protocol { string mklabel(string s) {
ead9722003-01-20Martin Nilsson  if(sizeof(s)>63)
484a742002-03-09Martin Nilsson  error("Too long component in domain name.\n");
ead9722003-01-20Martin Nilsson  return sprintf("%c%s",sizeof(s),s);
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  }
9eaf1d2008-06-28Martin Nilsson  protected private string mkname(string|array(string) labels, int pos,
8be18a2000-04-12Marcus Comstedt  mapping(string:int) comp) { if(stringp(labels)) labels = labels/"."-({""}); if(!labels || !sizeof(labels)) return "\0"; string n = labels*"."; if(comp[n]) return sprintf("%2c", comp[n]|0xc000); else { if(pos<0x4000) comp[n]=pos; string l = mklabel(labels[0]);
ead9722003-01-20Martin Nilsson  return l + mkname(labels[1..], pos+sizeof(l), comp);
8be18a2000-04-12Marcus Comstedt  } }
9eaf1d2008-06-28Martin Nilsson  protected string make_raw_addr6(string addr6)
e94d1a2003-04-23Marcus Comstedt  { if(!addr6) return "\0"*16; if(has_value(addr6, "::")) { int parts = sizeof((addr6/":")-({""})); if(has_value(addr6, ".")) parts++; addr6 = replace(addr6, "::", ":"+"0:"*(8-parts)); sscanf(addr6, ":%s", addr6); } if(has_value(addr6, "."))
c9d5e12007-04-07Henrik Grubbström (Grubba)  return sprintf("%2c%2c%2c%2c%2c%2c%1c%1c%1c%1c", @array_sscanf(addr6, "%x:%x:%x:%x:%x:%x:%x.%x.%x.%x"));
e94d1a2003-04-23Marcus Comstedt  else return sprintf("%@2c", array_sscanf(addr6, "%x:%x:%x:%x:%x:%x:%x:%x")); }
9eaf1d2008-06-28Martin Nilsson  protected private string mkrdata(mapping entry, int pos, mapping(string:int) c)
8be18a2000-04-12Marcus Comstedt  { switch(entry->type) { case T_CNAME: return mkname(entry->cname, pos, c); case T_PTR: return mkname(entry->ptr, pos, c); case T_NS: return mkname(entry->ns, pos, c); case T_MD: return mkname(entry->md, pos, c); case T_MF: return mkname(entry->mf, pos, c); case T_MB: return mkname(entry->mb, pos, c); case T_MG: return mkname(entry->mg, pos, c); case T_MR: return mkname(entry->mr, pos, c); case T_MX: return sprintf("%2c", entry->preference)+mkname(entry->mx, pos+2, c); case T_HINFO:
ead9722003-01-20Martin Nilsson  return sprintf("%1c%s%1c%s", sizeof(entry->cpu||""), entry->cpu||"", sizeof(entry->os||""), entry->os||"");
8be18a2000-04-12Marcus Comstedt  case T_MINFO: string rmailbx = mkname(entry->rmailbx, pos, c);
ead9722003-01-20Martin Nilsson  return rmailbx + mkname(entry->emailbx, pos+sizeof(rmailbx), c);
b6e3442002-11-26H. William Welliver III  case T_SRV: return sprintf("%2c%2c%2c", entry->priority, entry->weight, entry->port) + mkname(entry->target||"", pos+6, c);
8be18a2000-04-12Marcus Comstedt  case T_A: return sprintf("%@1c", (array(int))((entry->a||"0.0.0.0")/".")[0..3]);
d004002003-04-22Martin Nilsson  case T_AAAA:
e94d1a2003-04-23Marcus Comstedt  return make_raw_addr6(entry->aaaa);
cd00f82011-12-09Per Hedbor  case T_A6: if( stringp( entry->a6 ) || !entry->a6 ) return "\0"+make_raw_addr6(entry->a6); return sprintf( "%c%s%s", entry->a6->prefixlen, make_raw_addr6(entry->a6->address)[entry->a6->prefixlen/8..], entry->a6->prefixname||"");
8be18a2000-04-12Marcus Comstedt  case T_SOA: string mname = mkname(entry->mname, pos, c);
ead9722003-01-20Martin Nilsson  return mname + mkname(entry->rname, pos+sizeof(mname), c) +
8be18a2000-04-12Marcus Comstedt  sprintf("%4c%4c%4c%4c%4c", entry->serial, entry->refresh, entry->retry, entry->expire, entry->minimum);
ddcaf02007-03-19Ignasi Cavero  case T_NAPTR: string rnaptr = sprintf("%2c%2c", entry->order, entry->preference); rnaptr += sprintf("%1c%s%1c%s%1c%s%s", sizeof(entry->flags || ""), entry->flags || "", sizeof(entry->service || ""), entry->service || "", sizeof(entry->regexp || ""), entry->regexp || "", mkname(entry->replacement, pos, c)); return rnaptr;
8be18a2000-04-12Marcus Comstedt  case T_TXT: return Array.map(stringp(entry->txt)? ({entry->txt}):(entry->txt||({})), lambda(string t) {
ead9722003-01-20Martin Nilsson  return sprintf("%1c%s", sizeof(t), t);
8be18a2000-04-12Marcus Comstedt  })*"";
5241a02008-07-24Henrik Grubbström (Grubba)  case T_SPF: return Array.map(stringp(entry->spf)? ({entry->spf}):(entry->spf||({})), lambda(string t) { return sprintf("%1c%s", sizeof(t), t); })*"";
79d3032004-04-13Jeff Hungerford  case T_LOC: // FIXME: Not implemented yet.
8be18a2000-04-12Marcus Comstedt  default: return ""; } }
9eaf1d2008-06-28Martin Nilsson  protected private string encode_entries(array(mapping) entries, int pos,
8be18a2000-04-12Marcus Comstedt  mapping(string:int) comp) { string res=""; foreach(entries, mapping entry) { string e = mkname(entry->name, pos, comp)+ sprintf("%2c%2c%4c", entry->type, entry->cl, entry->ttl);
ead9722003-01-20Martin Nilsson  pos += sizeof(e)+2;
8be18a2000-04-12Marcus Comstedt  string rd = entry->rdata || mkrdata(entry, pos, comp);
ead9722003-01-20Martin Nilsson  res += e + sprintf("%2c", sizeof(rd)) + rd; pos += sizeof(rd);
8be18a2000-04-12Marcus Comstedt  } return res; } string low_low_mkquery(mapping q) { array qd = q->qd && (arrayp(q->qd)? q->qd : ({q->qd})); array an = q->an && (arrayp(q->an)? q->an : ({q->an})); array ns = q->ns && (arrayp(q->ns)? q->ns : ({q->ns})); array ar = q->ar && (arrayp(q->ar)? q->ar : ({q->ar})); string r = sprintf("%2c%c%c%2c%2c%2c%2c", q->id, ((q->rd)&1)|(((q->tc)&1)<<1)|(((q->aa)&1)<<2)| (((q->opcode)&15)<<3)|(((q->qr)&1)<<7), ((q->rcode)&15)|(((q->cd)&1)<<4)|(((q->ad)&1)<<5)| (((q->ra)&1)<<7), qd && sizeof(qd), an && sizeof(an), ns && sizeof(ns), ar && sizeof(ar)); mapping(string:int) c = ([]); if(qd) foreach(qd, mapping _qd)
ead9722003-01-20Martin Nilsson  r += mkname(_qd->name, sizeof(r), c) +
8be18a2000-04-12Marcus Comstedt  sprintf("%2c%2c", _qd->type, _qd->cl); if(an)
ead9722003-01-20Martin Nilsson  r+=encode_entries(an, sizeof(r), c);
8be18a2000-04-12Marcus Comstedt  if(ns)
ead9722003-01-20Martin Nilsson  r+=encode_entries(ns, sizeof(r), c);
8be18a2000-04-12Marcus Comstedt  if(ar)
ead9722003-01-20Martin Nilsson  r+=encode_entries(ar, sizeof(r), c);
8be18a2000-04-12Marcus Comstedt  return r; }
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  string low_mkquery(int id, string dname, int cl, int type)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  {
8be18a2000-04-12Marcus Comstedt  return low_low_mkquery((["id":id, "rd":1, "qd":(["name":dname, "cl":cl, "type":type])]));
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  }
27e9f92002-12-01H. William Welliver III //! create a DNS query PDU //! //! @param dnameorquery //! @param cl //! record class such as Protocols.DNS.C_IN //! @param type //! query type such Protocols.DNS.T_A //! //! @returns //! data suitable for use with //! @[Protocols.DNS.client.do_sync_query]
2789992002-12-01H. William Welliver III //! //! @example //! // generate a query PDU for a address lookup on the hostname pike.ida.liu.se //! string q=Protocols.DNS.protocol()->mkquery("pike.ida.liu.se", Protocols.DNS.C_IN, Protocols.DNS.T_A);
8be18a2000-04-12Marcus Comstedt  string mkquery(string|mapping dnameorquery, int|void cl, int|void type)
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  {
8be18a2000-04-12Marcus Comstedt  if(mappingp(dnameorquery)) return low_low_mkquery(dnameorquery); else return low_mkquery(random(65536),dnameorquery,cl,type);
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  }
4755b72000-02-18Henrik Grubbström (Grubba)  string decode_domain(string msg, array(int) n)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  {
4755b72000-02-18Henrik Grubbström (Grubba)  array(string) domains=({});
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  int pos=n[0]; int next=-1;
4755b72000-02-18Henrik Grubbström (Grubba)  array(string) ret=({});
b956561998-05-20Henrik Grubbström (Grubba)  while(pos < sizeof(msg))
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  { switch(int len=msg[pos]) { case 0: if(next==-1) next=pos+1; n[0]=next; return ret*"."; case 1..63: pos+=len+1; ret+=({msg[pos-len..pos-1]}); continue; default:
5b31d62000-04-11Marcus Comstedt  if((~len)&0xc0)
484a742002-03-09Martin Nilsson  error("Invalid message compression mode.\n");
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  if(next==-1) next=pos+2; pos=((len&63)<<8) + msg[pos+1]; continue; } break; } }
4755b72000-02-18Henrik Grubbström (Grubba)  string decode_string(string s, array(int) next)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  { int len=s[next[0]]; next[0]+=len+1; return s[next[0]-len..next[0]-1]; }
79d3032004-04-13Jeff Hungerford  int decode_byte(string s, array(int) next) { return s[next[0]++]; }
4755b72000-02-18Henrik Grubbström (Grubba)  int decode_short(string s, array(int) next)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  { sscanf(s[next[0]..next[0]+1],"%2c",int ret); next[0]+=2; return ret; }
4755b72000-02-18Henrik Grubbström (Grubba)  int decode_int(string s, array(int) next)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  {
a8c3f22002-01-13Marcus Comstedt  sscanf(s[next[0]..next[0]+3],"%4c",int ret); next[0]+=4;
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  return ret; }
8630372008-07-23Henrik Grubbström (Grubba)  //! Decode a set of entries from an answer. //! //! @param s //! Encoded entries. //! //! @param num //! Number of entires in @[s]. //! //! @param next //! Array with a single element containing the start position in @[s] //! on entry and the continuation position on return. //! //! @returns //! Returns an array of mappings describing the decoded entires: //! @array //! @elem mapping 0.. //! Mapping describing a single entry: //! @mapping //! @member string "name" //! Name the entry concerns. //! @member EntryType "type" //! Type of entry. //! @member ResourceClass "cl" //! Resource class. Typically @[C_IN]. //! @member int "ttl" //! Time to live for the entry in seconds. //! @member int "len" //! Length in bytes of the encoded data section. //! @endmapping //! Depending on the type of entry the mapping may contain //! different additional fields: //! @int //! @value T_CNAME //! @mapping //! @member string "cname" //! @endmapping //! @value T_PTR //! @mapping //! @member string "ptr" //! @endmapping //! @value T_NS //! @mapping //! @member string "ns" //! @endmapping //! @value T_MX //! @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. //! @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 //! @mapping //! @member string "a" //! IPv4-address in dotted-decimal format. //! @endmapping //! @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" //! @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). //! @endmapping //! @value T_NAPTR //! @mapping //! @member int "order" //! @member int "preference" //! @member string "flags" //! @member string "service" //! @member string "regexp" //! @member string "replacement" //! @endmapping //! @value T_TXT //! @mapping //! @member string "txt"
8be58e2013-01-08Tobias S. Josefowitz  //! Note: For historical reasons, when receiving decoded //! DNS entries from a client, this will be the first string //! in the TXT record only. //! @member string "txta" //! 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.
8630372008-07-23Henrik Grubbström (Grubba)  //! @endmapping
5241a02008-07-24Henrik Grubbström (Grubba)  //! @value T_SPF //! @mapping //! @member string "spf" //! @endmapping
8630372008-07-23Henrik Grubbström (Grubba)  //! @endint //! @endarray
4755b72000-02-18Henrik Grubbström (Grubba)  array decode_entries(string s,int num, array(int) next)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  {
4755b72000-02-18Henrik Grubbström (Grubba)  array(string) ret=({});
ead9722003-01-20Martin Nilsson  for(int e=0;e<num && next[0]<sizeof(s);e++)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  { mapping m=([]); m->name=decode_domain(s,next); sscanf(s[next[0]..next[0]+10], "%2c%2c%4c%2c", m->type,m->cl,m->ttl,m->len); next[0]+=10; int tmp=next[0]; switch(m->type) { case T_CNAME: m->cname=decode_domain(s,next); break; case T_PTR: m->ptr=decode_domain(s,next); break; case T_NS: m->ns=decode_domain(s,next); break; case T_MX: m->preference=decode_short(s,next); m->mx=decode_domain(s,next); break; case T_HINFO: m->cpu=decode_string(s,next); m->os=decode_string(s,next); break;
b6e3442002-11-26H. William Welliver III  case T_SRV:
8630372008-07-23Henrik Grubbström (Grubba)  // RFC 2052 and RFC 2782.
b6e3442002-11-26H. William Welliver III  m->priority=decode_short(s,next); m->weight=decode_short(s,next); m->port=decode_short(s,next); m->target=decode_domain(s,next); array x=m->name/".";
8630372008-07-23Henrik Grubbström (Grubba)  if(x[0][0..0]=="_") m->service=x[0][1..]; else m->service=x[0]; if(sizeof(x) > 1)
b6e3442002-11-26H. William Welliver III  { if(x[1][0..0]=="_") m->proto=x[1][1..]; else m->proto=x[1]; }
8630372008-07-23Henrik Grubbström (Grubba)  m->name=x[2..]*".";
b6e3442002-11-26H. William Welliver III  break;
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  case T_A: m->a=sprintf("%{.%d%}",values(s[next[0]..next[0]+m->len-1]))[1..]; break;
d004002003-04-22Martin Nilsson  case T_AAAA:
e94d1a2003-04-23Marcus Comstedt  m->aaaa=sprintf("%{:%02X%02X%}",
29dd3e2003-04-22Martin Nilsson  values(s[next[0]..next[0]+m->len-1])/2)[1..];
d004002003-04-22Martin Nilsson  break;
79d3032004-04-13Jeff Hungerford  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; aByte = decode_byte(s,next); m->h_perc = pow((aByte>>4)&0xf , aByte&0xf)/100.0; aByte = decode_byte(s,next); m->v_perc = pow((aByte>>4)&0xf , aByte&0xf)/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;
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  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); m->retry=decode_int(s,next); m->expire=decode_int(s,next); m->minimum=decode_int(s,next); break;
ddcaf02007-03-19Ignasi Cavero  case T_NAPTR: m->order = decode_short (s, next); m->preference = decode_short (s, next); m->flags = decode_string (s, next); m->service = decode_string (s, next); m->regexp = decode_string (s, next); m->replacement = decode_domain (s, next); break;
f96a6f2005-01-03Jeff Hungerford  case T_TXT:
8be58e2013-01-08Tobias S. Josefowitz  { int tlen; m->txta = ({ }); while (tlen < m->len) { m->txta += ({ decode_string(s, next) }); tlen += sizeof(m->txta[-1]) + 1; } m->txt = m->txta[0]; }
5241a02008-07-24Henrik Grubbström (Grubba)  break; case T_SPF: m->spf = decode_string(s, next);
f96a6f2005-01-03Jeff Hungerford  break;
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  } next[0]=tmp+m->len; ret+=({m}); } return ret; } mapping decode_res(string s) { mapping m=([]); sscanf(s,"%2c%c%c%2c%2c%2c%2c", m->id, m->c1, m->c2, m->qdcount, m->ancount, m->nscount, m->arcount);
5b31d62000-04-11Marcus Comstedt  m->rd=m->c1&1; m->tc=(m->c1>>1)&1; m->aa=(m->c1>>2)&1; m->opcode=(m->c1>>3)&15; m->qr=(m->c1>>7)&1;
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
5b31d62000-04-11Marcus Comstedt  m->rcode=m->c2&15; m->cd=(m->c2>>4)&1; m->ad=(m->c2>>5)&1; m->ra=(m->c2>>7)&1;
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
ead9722003-01-20Martin Nilsson  m->length=sizeof(s);
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
4755b72000-02-18Henrik Grubbström (Grubba)  array(string) tmp=({});
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
4755b72000-02-18Henrik Grubbström (Grubba)  array(int) next=({12});
5b31d62000-04-11Marcus Comstedt  m->qd = allocate(m->qdcount); for(int i=0; i<m->qdcount; i++) { m->qd[i]=(["name":decode_domain(s,next)]); sscanf(s[next[0]..next[0]+3],"%2c%2c",m->qd[i]->type, m->qd[i]->cl); next[0]+=4; }
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  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; } };
4f4a5c2012-01-25Henrik Grubbström (Grubba) protected string ANY; protected void create() {
4b995e2012-01-31Henrik Grubbström (Grubba)  // Check if IPv6 support is available, and that mapped IPv4 is enabled.
4f4a5c2012-01-25Henrik Grubbström (Grubba)  catch {
4b995e2012-01-31Henrik Grubbström (Grubba)  // Note: Attempt to bind on the IPv6 loopback (::1)
4f4a5c2012-01-25Henrik Grubbström (Grubba)  // rather than on IPv6 any (::), to make sure some // IPv6 support is actually configured. This is needed
4b995e2012-01-31Henrik Grubbström (Grubba)  // since eg Solaris happily binds on :: even
4f4a5c2012-01-25Henrik Grubbström (Grubba)  // if no IPv6 interfaces are configured. // Try IPv6 any (::) too for paranoia reasons.
4b995e2012-01-31Henrik Grubbström (Grubba)  // 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)) {
720fe42012-04-02Henrik Grubbström (Grubba)  // 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); 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; while ((res = udp2->read())) { if (res->data == key) { // Mapped IPv4 seems to work. ANY = "::"; break retry; } } } destruct(udp2); }
4f4a5c2012-01-25Henrik Grubbström (Grubba)  }
4b995e2012-01-31Henrik Grubbström (Grubba)  destruct(udp);
4f4a5c2012-01-25Henrik Grubbström (Grubba)  }; } //! 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()].
8be18a2000-04-12Marcus Comstedt class server {
8630372008-07-23Henrik Grubbström (Grubba)  //!
8be18a2000-04-12Marcus Comstedt  inherit protocol;
8630372008-07-23Henrik Grubbström (Grubba) 
f7616f2010-01-05H. William Welliver III  //inherit Stdio.UDP : udp; array(Stdio.UDP) ports = ({});
8be18a2000-04-12Marcus Comstedt 
f7616f2010-01-05H. William Welliver III  protected void send_reply(mapping r, mapping q, mapping m, Stdio.UDP udp)
8be18a2000-04-12Marcus Comstedt  { // FIXME: Needs to handle truncation somehow. if(!r) r = (["rcode":4]); r->id = q->id; r->qr = 1; r->opcode = q->opcode; r->rd = q->rd; r->qd = r->qd || q->qd; string s = mkquery(r);
f7616f2010-01-05H. William Welliver III  udp->send(m->ip, m->port, s);
8be18a2000-04-12Marcus Comstedt  }
c534f62002-12-23Henrik Grubbström (Grubba)  //! Reply to a query (stub). //! //! @param query //! Parsed query. //! //! @param udp_data //! Raw UDP data. //!
f7616f2010-01-05H. William Welliver III  //! @param cb //! Callback you can call with the result instead of returning it. //! In that case, return @expr{0@} (zero). //! //!
c534f62002-12-23Henrik Grubbström (Grubba)  //! Overload this function to implement the proper lookup. //! //! @returns
cbe8c92003-04-07Martin Nilsson  //! Returns @expr{0@} (zero) on failure, or a result mapping on success:
c534f62002-12-23Henrik Grubbström (Grubba)  //! @mapping //! @member int "rcode"
8630372008-07-23Henrik Grubbström (Grubba)  //! @member array(mapping(string:string|int))|void "an"
c534f62002-12-23Henrik Grubbström (Grubba)  //! @array //! @elem mapping(string:string|int) entry //! @mapping //! @member string|array(string) "name" //! @member int "type" //! @member int "cl" //! @endmapping //! @endarray
8630372008-07-23Henrik Grubbström (Grubba)  //! @member array|void "qd"
c534f62002-12-23Henrik Grubbström (Grubba)  //! @member array|void "ns" //! @member array|void "ar" //! @endmapping
f7616f2010-01-05H. William Welliver III  protected mapping reply_query(mapping query, mapping udp_data, function(mapping:void) cb)
8be18a2000-04-12Marcus Comstedt  { // Override this function. // // Return mapping may contain: // aa, ra, {ad, cd,} rcode, an, ns, ar return 0; }
f7616f2010-01-05H. William Welliver III  protected void handle_query(mapping q, mapping m, Stdio.UDP udp)
8be18a2000-04-12Marcus Comstedt  {
f7616f2010-01-05H. William Welliver III  int(0..1) result_available = 0; void _cb(mapping r) { if(result_available) error("DNS: you can either use the callback OR return the reply, not both.\n"); result_available = 1; send_reply(r, q, m, udp); }; mapping r = reply_query(q, m, _cb); if(r && result_available) error("DNS: you can either use the callback OR return the reply, not both.\n"); if(r) { result_available = 1; send_reply(r, q, m, udp); }
8be18a2000-04-12Marcus Comstedt  }
f7616f2010-01-05H. William Welliver III  protected void handle_response(mapping r, mapping m, Stdio.UDP udp)
8be18a2000-04-12Marcus Comstedt  { // This is a stub intended to simplify servers which allow recursion }
f7616f2010-01-05H. William Welliver III  protected private void rec_data(mapping m, Stdio.UDP udp)
8be18a2000-04-12Marcus Comstedt  { mixed err; mapping q; if (err = catch { q=decode_res(m->data); }) {
0bd6f52003-10-21Martin Nilsson  werror("DNS: Failed to read UDP packet.\n%s\n", describe_backtrace(err));
8be18a2000-04-12Marcus Comstedt  if(m && m->data && sizeof(m->data)>=2) send_reply((["rcode":1]),
f7616f2010-01-05H. William Welliver III  mkmapping(({"id"}), array_sscanf(m->data, "%2c")), m, udp);
8be18a2000-04-12Marcus Comstedt  } else if(q->qr)
f7616f2010-01-05H. William Welliver III  handle_response(q, m, udp);
8be18a2000-04-12Marcus Comstedt  else
f7616f2010-01-05H. William Welliver III  handle_query(q, m, udp);
8be18a2000-04-12Marcus Comstedt  }
4f4a5c2012-01-25Henrik Grubbström (Grubba)  //! @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.
f7616f2010-01-05H. William Welliver III  void create(int|string|void arg1, string|int ... args)
8be18a2000-04-12Marcus Comstedt  {
f7616f2010-01-05H. William Welliver III  if(!arg1 && !sizeof(args)) arg1 = 53; if(!sizeof(args)) { if(stringp(arg1)) args = ({ arg1, 53 }); else
4f4a5c2012-01-25Henrik Grubbström (Grubba)  args = ({ ANY, arg1 });
f7616f2010-01-05H. William Welliver III  } 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]) {
4f4a5c2012-01-25Henrik Grubbström (Grubba)  if (!safe_bind(udp, args[i+1], args[i]))
f7616f2010-01-05H. William Welliver III  error("DNS: failed to bind host:port %s:%d.\n", args[i],args[i+1]); } else {
4f4a5c2012-01-25Henrik Grubbström (Grubba)  if(!safe_bind(udp, args[i+1]))
f7616f2010-01-05H. William Welliver III  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}); } }
6e37522012-12-03Tobias S. Josefowitz  static void destroy()
f7616f2010-01-05H. William Welliver III  { if(sizeof(ports)) { foreach(ports;; Stdio.UDP port) destruct(port); }
8be18a2000-04-12Marcus Comstedt  } }
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
eabcd51999-07-25Henrik Grubbström (Grubba) #define RETRIES 12 #define RETRY_DELAY 5
7dc3162001-04-27Henrik Grubbström (Grubba) //! Synchronous DNS client.
a7c1441999-10-30Mirar (Pontus Hagland) class client {
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  inherit protocol;
37ffea1998-04-06Fredrik Hübinette (Hubbe) #ifdef __NT__
e177732000-12-07Henrik Grubbström (Grubba)  array(string) get_tcpip_param(string val, void|string fallbackvalue)
a7c1441999-10-30Mirar (Pontus Hagland)  {
e177732000-12-07Henrik Grubbström (Grubba)  array(string) res = ({});
a7c1441999-10-30Mirar (Pontus Hagland)  foreach(({ "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
720fe42012-04-02Henrik Grubbström (Grubba)  "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters",
a7c1441999-10-30Mirar (Pontus Hagland)  "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP" }),string key)
37ffea1998-04-06Fredrik Hübinette (Hubbe)  {
a7c1441999-10-30Mirar (Pontus Hagland)  catch {
e177732000-12-07Henrik Grubbström (Grubba)  res += ({ RegGetValue(HKEY_LOCAL_MACHINE, key, val) });
a7c1441999-10-30Mirar (Pontus Hagland)  };
37ffea1998-04-06Fredrik Hübinette (Hubbe)  }
63ecf62000-06-28Fredrik Hübinette (Hubbe)  #if constant(RegGetKeyNames)
b3e4402001-03-14Henrik Grubbström (Grubba)  /* Catch if RegGetKeyNames() doesn't find the directory. */ catch { foreach(RegGetKeyNames(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\" "Parameters\\Interfaces"), string key)
63ecf62000-06-28Fredrik Hübinette (Hubbe)  { catch {
e177732000-12-07Henrik Grubbström (Grubba)  res += ({ RegGetValue(HKEY_LOCAL_MACHINE,
3097d92001-02-05Tomas Nilsson  "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\"
e177732000-12-07Henrik Grubbström (Grubba)  "Parameters\\Interfaces\\" + key, val) });
63ecf62000-06-28Fredrik Hübinette (Hubbe)  }; }
720fe42012-04-02Henrik Grubbström (Grubba)  foreach(RegGetKeyNames(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\" "Parameters\\Interfaces"), string key) { catch { res += ({ RegGetValue(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\" "Parameters\\Interfaces\\" + key, val) }); }; }
b3e4402001-03-14Henrik Grubbström (Grubba)  };
83e1902000-06-28Fredrik Hübinette (Hubbe) #endif
7f55912009-03-16Henrik Grubbström (Grubba)  res -= ({ UNDEFINED });
e177732000-12-07Henrik Grubbström (Grubba)  return sizeof(res) ? res : ({ fallbackvalue });
a7c1441999-10-30Mirar (Pontus Hagland)  }
2880382008-01-31Henrik Grubbström (Grubba)  #else /* !__NT__ */
df6e592005-03-01Henrik Grubbström (Grubba) 
9eaf1d2008-06-28Martin Nilsson  protected private mapping(string:string) etc_hosts;
df6e592005-03-01Henrik Grubbström (Grubba) 
9eaf1d2008-06-28Martin Nilsson  protected private int is_ip(string ip)
2880382008-01-31Henrik Grubbström (Grubba)  {
25eb152011-02-10Per Hedbor  if( has_value( ip, ":") ) return (replace(ip, "0123456789abcdefABCDEF:"/1, allocate(23,"")) == "");
2880382008-01-31Henrik Grubbström (Grubba)  return (replace(ip, "0123456789."/1, allocate(11,"")) == ""); }
9eaf1d2008-06-28Martin Nilsson  protected private string read_etc_file(string fname)
a7c1441999-10-30Mirar (Pontus Hagland)  {
df6e592005-03-01Henrik Grubbström (Grubba)  array(string) paths; string res;
9f6f4d1998-02-27Fredrik Hübinette (Hubbe) #ifdef __NT__
df6e592005-03-01Henrik Grubbström (Grubba)  paths = get_tcpip_param("DataBasePath");
9f6f4d1998-02-27Fredrik Hübinette (Hubbe) #else
df6e592005-03-01Henrik Grubbström (Grubba)  paths = ({ "/etc", "/amitcp/db" });
9f6f4d1998-02-27Fredrik Hübinette (Hubbe) #endif
df6e592005-03-01Henrik Grubbström (Grubba)  foreach(paths, string path) { string raw = Stdio.read_file(path + "/" + fname); if (raw && sizeof(raw = replace(raw, "\r", "\n"))) { if (res) { if (sizeof(res) && (res[-1] != '\n')) { // Avoid confusion... res += "\n"; } res += raw; } else { res = raw; } } } return res; }
e177732000-12-07Henrik Grubbström (Grubba) 
9eaf1d2008-06-28Martin Nilsson  protected private string match_etc_hosts(string host)
df6e592005-03-01Henrik Grubbström (Grubba)  { if (!etc_hosts) {
a7c1441999-10-30Mirar (Pontus Hagland)  etc_hosts = ([ "localhost":"127.0.0.1" ]);
37ffea1998-04-06Fredrik Hübinette (Hubbe) 
df6e592005-03-01Henrik Grubbström (Grubba)  string raw = read_etc_file("hosts");
e177732000-12-07Henrik Grubbström (Grubba) 
df6e592005-03-01Henrik Grubbström (Grubba)  if (raw && sizeof(raw)) { foreach(raw/"\n"-({""}), string line) { // Handle comments, and split the line on white-space line = lower_case(replace((line/"#")[0], "\t", " ")); array arr = (line/" ") - ({ "" });
37ffea1998-04-06Fredrik Hübinette (Hubbe) 
df6e592005-03-01Henrik Grubbström (Grubba)  if (sizeof(arr) > 1) { if (is_ip(arr[0])) { foreach(arr[1..], string name) { etc_hosts[name] = arr[0];
a7c1441999-10-30Mirar (Pontus Hagland)  }
df6e592005-03-01Henrik Grubbström (Grubba)  } else { // Bad /etc/hosts entry ignored.
6676441998-01-25Henrik Grubbström (Grubba)  } } }
df6e592005-03-01Henrik Grubbström (Grubba)  } else { // Couldn't read or no /etc/hosts.
6676441998-01-25Henrik Grubbström (Grubba)  } }
18096f2003-08-22Martin Nilsson  return etc_hosts[lower_case(host)];
a7c1441999-10-30Mirar (Pontus Hagland)  }
2863542008-01-31Henrik Grubbström (Grubba) #endif /* !__NT__ */
a7c1441999-10-30Mirar (Pontus Hagland) 
df6e592005-03-01Henrik Grubbström (Grubba)  // FIXME: Read hosts entry in /etc/nswitch.conf?
7dc3162001-04-27Henrik Grubbström (Grubba)  //! @decl void create() //! @decl void create(void|string|array server, void|int|array domain)
6676441998-01-25Henrik Grubbström (Grubba) 
6256271998-01-11Henrik Grubbström (Grubba)  array(string) nameservers = ({});
7f82921997-12-10David Hedbor  array domains = ({});
cd6ed01998-07-17Fredrik Hübinette (Hubbe)  void create(void|string|array(string) server, void|int|array(string) domain)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  { if(!server) {
d357791999-04-14Henrik Grubbström (Grubba) #if __NT__
e177732000-12-07Henrik Grubbström (Grubba)  domains = get_tcpip_param("Domain", "") + get_tcpip_param("DhcpDomain", "") +
3c287a2000-12-08Henrik Grubbström (Grubba)  map(get_tcpip_param("SearchList", ""), lambda(string s) { return replace(s, " ", ",")/","; }) * ({});
89249d2000-08-22Johan Schön 
e177732000-12-07Henrik Grubbström (Grubba)  nameservers = map(get_tcpip_param("NameServer", "") +
3c287a2000-12-08Henrik Grubbström (Grubba)  get_tcpip_param("DhcpNameServer", ""), lambda(string s) { return replace(s, " ", ",")/","; }) * ({});
9f6f4d1998-02-27Fredrik Hübinette (Hubbe) #else
e177732000-12-07Henrik Grubbström (Grubba)  string domain;
9f70401998-11-13Marcus Comstedt  string resolv_conf;
8fe0142000-10-17Henrik Grubbström (Grubba)  foreach(({"/etc/resolv.conf", "/amitcp/db/resolv.conf"}), string resolv_loc)
9f70401998-11-13Marcus Comstedt  if ((resolv_conf = Stdio.read_file(resolv_loc))) break;
6256271998-01-11Henrik Grubbström (Grubba)  if (!resolv_conf) {
7b80842002-09-17Martin Nilsson  if (System->get_netinfo_property) {
d334772001-04-09Jonas Wallden  // Mac OS X / Darwin (and possibly other systems) that use // NetInfo may have these values in the database. if (nameservers =
7b80842002-09-17Martin Nilsson  System->get_netinfo_property(".",
d334772001-04-09Jonas Wallden  "/locations/resolver", "nameserver")) {
6241d62001-09-17Henrik Grubbström (Grubba)  nameservers = map(nameservers, `-, "\n");
eb04632004-09-15 Marian  } else { nameservers = ({});
d334772001-04-09Jonas Wallden  }
7b80842002-09-17Martin Nilsson  if (domains = System->get_netinfo_property(".",
d334772001-04-09Jonas Wallden  "/locations/resolver", "domain")) {
6241d62001-09-17Henrik Grubbström (Grubba)  domains = map(domains, `-, "\n");
eb04632004-09-15 Marian  } else { domains = ({});
d334772001-04-09Jonas Wallden  } } else { /* FIXME: Is this a good idea? * Why not just try the fallback? * /grubba 1999-04-14 * * Now uses 127.0.0.1 as fallback. * /grubba 2000-10-17 */ resolv_conf = "nameserver 127.0.0.1"; }
8fe0142000-10-17Henrik Grubbström (Grubba) #if 0
484a742002-03-09Martin Nilsson  error( "Protocols.DNS.client(): No /etc/resolv.conf!\n" );
8fe0142000-10-17Henrik Grubbström (Grubba) #endif /* 0 */
6256271998-01-11Henrik Grubbström (Grubba)  }
d334772001-04-09Jonas Wallden  if (resolv_conf) foreach(resolv_conf/"\n", string line)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  {
d334772001-04-09Jonas Wallden  string rest; sscanf(line,"%s#",line); sscanf(line,"%*[\r \t]%s",line); line=reverse(line); sscanf(line,"%*[\r \t]%s",line); line=reverse(line); sscanf(line,"%s%*[ \t]%s",line,rest); switch(line) { case "domain": // Save domain for later. domain = sizeof(rest) && rest; break; case "search": rest = replace(rest, "\t", " "); domains += ((rest/" ") - ({""})); break;
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
d334772001-04-09Jonas Wallden  case "nameserver": if (!is_ip(rest)) { // Not an IP-number! string host = rest; if (!(rest = match_etc_hosts(host))) {
0bd6f52003-10-21Martin Nilsson  werror("Protocols.DNS.client(): " "Can't resolv nameserver \"%s\"\n", host);
d334772001-04-09Jonas Wallden  break; }
a7c1441999-10-30Mirar (Pontus Hagland)  }
d334772001-04-09Jonas Wallden  if (sizeof(rest)) { nameservers += ({ rest }); } break; }
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  }
9381ae2001-04-09Marcus Comstedt 
e177732000-12-07Henrik Grubbström (Grubba)  if(domain) domains = ({ domain }) + domains;
9f6f4d1998-02-27Fredrik Hübinette (Hubbe) #endif
e177732000-12-07Henrik Grubbström (Grubba)  nameservers -= ({ "" });
6256271998-01-11Henrik Grubbström (Grubba)  if (!sizeof(nameservers)) {
d357791999-04-14Henrik Grubbström (Grubba)  /* Try localhost... */
6256271998-01-11Henrik Grubbström (Grubba)  nameservers = ({ "127.0.0.1" }); }
dc01b51999-06-01Henrik Grubbström (Grubba)  domains -= ({ "" });
b9b6ec1998-01-25Henrik Grubbström (Grubba)  domains = Array.map(domains, lambda(string d) { if (d[-1] == '.') {
8a531a2006-11-04Martin Nilsson  return d[..<1];
b9b6ec1998-01-25Henrik Grubbström (Grubba)  } return d; });
a7c1441999-10-30Mirar (Pontus Hagland)  } else {
cd6ed01998-07-17Fredrik Hübinette (Hubbe)  if(arrayp(server))
940cb71998-07-17Henrik Grubbström (Grubba)  nameservers = server;
cd6ed01998-07-17Fredrik Hübinette (Hubbe)  else
940cb71998-07-17Henrik Grubbström (Grubba)  nameservers = ({ server });
cd6ed01998-07-17Fredrik Hübinette (Hubbe)  if(arrayp(domain)) domains = domain; else
522de11998-07-17Fredrik Hübinette (Hubbe)  if(stringp(domain))
4f3ea41998-07-17Fredrik Hübinette (Hubbe)  domains = ({ domain });
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  } }
4f4a5c2012-01-25Henrik Grubbström (Grubba) //! Perform a synchronous DNS query.
27e9f92002-12-01H. William Welliver III //! //! @param s //! result of @[Protocols.DNS.protocol.mkquery] //! @returns //! mapping containing query result or 0 on failure/timeout
2789992002-12-01H. William Welliver III //! //! @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));
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  mapping do_sync_query(string s) {
3347a82008-07-22Henrik Grubbström (Grubba)  int i;
eabcd51999-07-25Henrik Grubbström (Grubba)  object udp = Stdio.UDP();
3347a82008-07-22Henrik Grubbström (Grubba)  // Attempt to randomize the source port. for (i = 0; i < RETRIES; i++) {
4f4a5c2012-01-25Henrik Grubbström (Grubba)  if (!safe_bind(udp, 1024 + random(65536-1024), ANY)) continue;
3347a82008-07-22Henrik Grubbström (Grubba)  }
4f4a5c2012-01-25Henrik Grubbström (Grubba)  if (i >= RETRIES) safe_bind(udp, 0, ANY) || udp->bind(0);
355bbe2005-01-03Henrik Grubbström (Grubba) #if 0
f96a6f2005-01-03Jeff Hungerford  werror("Protocols.DNS.client()->do_sync_query(%O)\n" "UDP Address: %s\n" "%s\n", s, udp->query_address(), describe_backtrace(backtrace()));
355bbe2005-01-03Henrik Grubbström (Grubba) #endif /* 0 */
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  mapping m;
eabcd51999-07-25Henrik Grubbström (Grubba)  for (i=0; i < RETRIES; i++) { udp->send(nameservers[i % sizeof(nameservers)], 53, s);
d692ea2000-09-07Leif Stensson  // upd->wait() can throw an error sometimes.
720fe42012-04-02Henrik Grubbström (Grubba)  // // One common case is on WIN32 where select complains // about it not being a socket. catch { udp->wait(RETRY_DELAY); }; // Make sure that udp->read() doesn't block. udp->set_nonblocking(); // udp->read() can throw an error on connection refused. catch { m = udp->read(); if (m && (m->port == 53) && (m->data[0..1] == s[0..1]) && has_value(nameservers, m->ip)) { // Success. return decode_res(m->data); }
d692ea2000-09-07Leif Stensson  };
720fe42012-04-02Henrik Grubbström (Grubba)  // Restore blocking state for udp->send() on retry. udp->set_blocking();
eabcd51999-07-25Henrik Grubbström (Grubba)  } // Failure. return 0;
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  }
df6e592005-03-01Henrik Grubbström (Grubba) 
9eaf1d2008-06-28Martin Nilsson  protected mapping low_gethostbyname(string s, int type)
df6e592005-03-01Henrik Grubbström (Grubba)  { mapping m; if(sizeof(domains) && 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 { return do_sync_query(mkquery(s, C_IN, type)); } }
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
7dc3162001-04-27Henrik Grubbström (Grubba)  //! @decl array gethostbyname(string hostname)
bf895c2002-11-27Marek Habersack  //! Queries the host name from the default or given
7dc3162001-04-27Henrik Grubbström (Grubba)  //! DNS server. The result is an array with three elements,
bf895c2002-11-27Marek Habersack  //! //! @returns //! An array with the requested information about the specified //! host. //!
7dc3162001-04-27Henrik Grubbström (Grubba)  //! @array //! @elem string hostname //! Hostname. //! @elem array(string) ip //! IP number(s). //! @elem array(string) aliases //! DNS name(s). //! @endarray
a7c1441999-10-30Mirar (Pontus Hagland)  //!
df6e592005-03-01Henrik Grubbström (Grubba)  //! @note //! Prior to Pike 7.7 this function only returned IPv4 addresses. //!
4755b72000-02-18Henrik Grubbström (Grubba)  array gethostbyname(string s)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  {
df6e592005-03-01Henrik Grubbström (Grubba)  mapping a_records = low_gethostbyname(s, T_A); mapping a6_records = low_gethostbyname(s, T_A6); mapping aaaa_records = low_gethostbyname(s, T_AAAA);
24e8852005-03-01Martin Nilsson #if 0
df6e592005-03-01Henrik Grubbström (Grubba)  werror("a_records: %O\n" "a6_records: %O\n" "aaaa_records: %O\n", a_records, a6_records, aaaa_records); #endif /* 0 */
eabcd51999-07-25Henrik Grubbström (Grubba) 
4755b72000-02-18Henrik Grubbström (Grubba)  array(string) names=({}); array(string) ips=({});
df6e592005-03-01Henrik Grubbström (Grubba)  if (a_records) { foreach(a_records->an, mapping x) { if(x->name) names+=({x->name}); if(x->a) ips+=({x->a}); }
27c6851997-12-10David Hedbor  }
df6e592005-03-01Henrik Grubbström (Grubba)  // Prefer a6 to aaaa. if (a6_records) { foreach(a6_records->an, mapping x) { if(x->name) names+=({x->name}); if(x->a6) ips+=({x->a6}); } } if (aaaa_records) { foreach(aaaa_records->an, mapping x) { if(x->name) names+=({x->name}); if(x->aaaa) ips+=({x->aaaa}); } }
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  return ({ sizeof(names)?names[0]:0,
eabcd51999-07-25Henrik Grubbström (Grubba)  ips, names, });
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  }
f971bd1997-09-15Fredrik Hübinette (Hubbe) 
27e9f92002-12-01H. William Welliver III  //! Queries the service record (RFC 2782) from the default or given
b6e3442002-11-26H. William Welliver III  //! 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:
bf895c2002-11-27Marek Habersack  //! //! @returns //! An array with the requested information about the specified //! service. //!
b6e3442002-11-26H. William Welliver III  //! @array //! @elem int priority //! Priority //! @elem int weight //! Weight in event of multiple records with same priority. //! @elem int port //! port number //! @elem string target //! target dns name //! @endarray //! array getsrvbyname(string service, string protocol, string|void name) { mapping m; if(!service) error("no service name specified."); if(!protocol) error("no service name specified."); if(sizeof(domains) && !name) { // we haven't provided a target domain to search on. // we probably shouldn't do a searchdomains search, // as it might return ambiguous results. m = do_sync_query( mkquery("_" + service +"._"+ protocol + "." + name, C_IN, T_SRV)); if(!m || !m->an || !sizeof(m->an)) foreach(domains, string domain) { m = do_sync_query( mkquery("_" + service +"._"+ protocol + "." + domain, C_IN, T_SRV)); if(m && m->an && sizeof(m->an)) break; } } else { m = do_sync_query( mkquery("_" + service +"._"+ protocol + "." + name, C_IN, T_SRV)); } if (!m) { // no entries. return ({}); } array res=({}); foreach(m->an, mapping x) { res+=({({x->priority, x->weight, x->port, x->target})}); } // now we sort the array by priority as a convenience array y=({}); foreach(res, array t) y+=({t[0]}); sort(y, res); return res; }
f971bd1997-09-15Fredrik Hübinette (Hubbe)  string arpa_from_ip(string ip) {
e94d1a2003-04-23Marcus Comstedt  if(has_value(ip,':')) { string raw_ipv6 = make_raw_addr6(ip); return reverse(sprintf("%@02X", values(raw_ipv6)))/1*"."+".IP6.ARPA"; } else return reverse(ip/".")*"."+".IN-ADDR.ARPA";
f971bd1997-09-15Fredrik Hübinette (Hubbe)  } string ip_from_arpa(string arpa) {
e94d1a2003-04-23Marcus Comstedt  array(string) parts = reverse(arpa/"."); if(sizeof(parts)<2) return ""; if(lower_case(parts[1]) == "ip6") return map(parts[2..]/4, `*, "")*":"; else return parts[2..]*".";
f971bd1997-09-15Fredrik Hübinette (Hubbe)  }
a7c1441999-10-30Mirar (Pontus Hagland) 
bf895c2002-11-27Marek Habersack  //! @decl array gethostbyaddr(string hostip) //! Queries the host name or ip from the default or given //! DNS server. The result is an array with three elements, //! //! @returns //! The requested data about the specified host. //! //! @array //! @elem string hostip //! The host IP. //! @elem array(string) ip //! IP number(s). //! @elem array(string) aliases //! DNS name(s). //! @endarray //!
1f9e122002-11-27Marek Habersack  array gethostbyaddr(string s)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  {
f971bd1997-09-15Fredrik Hübinette (Hubbe)  mapping m=do_sync_query(mkquery(arpa_from_ip(s), C_IN, T_PTR));
eabcd51999-07-25Henrik Grubbström (Grubba)  if (m) {
4755b72000-02-18Henrik Grubbström (Grubba)  array(string) names=({}); array(string) ips=({});
eabcd51999-07-25Henrik Grubbström (Grubba)  foreach(m->an, mapping x)
27c6851997-12-10David Hedbor  {
eabcd51999-07-25Henrik Grubbström (Grubba)  if(x->ptr) names+=({x->ptr}); if(x->name) { ips+=({ip_from_arpa(x->name)}); }
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  }
eabcd51999-07-25Henrik Grubbström (Grubba)  return ({ sizeof(names)?names[0]:0,
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  ips, names,
eabcd51999-07-25Henrik Grubbström (Grubba)  }); } else { // Lookup failed.
18096f2003-08-22Martin Nilsson  return ({ 0, ({}), ({}) });
eabcd51999-07-25Henrik Grubbström (Grubba)  }
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  }
7dc3162001-04-27Henrik Grubbström (Grubba)  //! @decl string get_primary_mx(string hostname)
bf895c2002-11-27Marek Habersack  //! Queries the primary mx for the host.
7dc3162001-04-27Henrik Grubbström (Grubba)  //! @returns //! Returns the hostname of the primary mail exchanger.
a7c1441999-10-30Mirar (Pontus Hagland)  //!
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  string get_primary_mx(string host) {
27c6851997-12-10David Hedbor  mapping m;
7f82921997-12-10David Hedbor  if(sizeof(domains) && host[-1] != '.' && sizeof(host/".") < 3) {
27c6851997-12-10David Hedbor  m=do_sync_query(mkquery(host, C_IN, T_MX)); if(!m || !m->an || !sizeof(m->an))
7f82921997-12-10David Hedbor  foreach(domains, string domain)
27c6851997-12-10David Hedbor  { m=do_sync_query(mkquery(host+"."+domain, C_IN, T_MX)); if(m && m->an && sizeof(m->an)) break; } } else { m=do_sync_query(mkquery(host, C_IN, T_MX)); }
eabcd51999-07-25Henrik Grubbström (Grubba)  if (!m) { return 0; }
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  int minpref=29372974; string ret; foreach(m->an, mapping m2)
27c6851997-12-10David Hedbor  {
b031b92008-03-10Henrik Grubbström (Grubba)  if(m2->mx && m2->preference<minpref)
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  {
27c6851997-12-10David Hedbor  ret=m2->mx; minpref=m2->preference;
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  }
27c6851997-12-10David Hedbor  }
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  return ret; }
3833921999-12-22Henrik Grubbström (Grubba) 
4755b72000-02-18Henrik Grubbström (Grubba)  array(string) get_mx(string host)
3833921999-12-22Henrik Grubbström (Grubba)  { mapping m; if(sizeof(domains) && host[-1] != '.' && sizeof(host/".") < 3) { m = do_sync_query(mkquery(host, C_IN, T_MX)); if(!m || !m->an || !sizeof(m->an)) { foreach(domains, string domain) { m = do_sync_query(mkquery(host+"."+domain, C_IN, T_MX)); if(m && m->an && sizeof(m->an)) break; } } } else { m = do_sync_query(mkquery(host, C_IN, T_MX)); } if (!m) { return 0; }
b031b92008-03-10Henrik Grubbström (Grubba)  array a = filter(m->an, `[], "mx");
3833921999-12-22Henrik Grubbström (Grubba)  array(string) b = column( a, "mx"); sort( column( a, "preference"), b); return b; }
bb02cc1997-09-15Fredrik Hübinette (Hubbe) }
cd6ed01998-07-17Fredrik Hübinette (Hubbe) #define REMOVE_DELAY 120 #define GIVE_UP_DELAY (RETRIES * RETRY_DELAY + REMOVE_DELAY)*2
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
3347a82008-07-22Henrik Grubbström (Grubba) // FIXME: Randomized source port!
a323352012-02-29Henrik Grubbström (Grubba) //! Asynchronous DNS client.
bb02cc1997-09-15Fredrik Hübinette (Hubbe) class async_client { inherit client;
8540911999-07-21David Hedbor  inherit Stdio.UDP : udp;
cd6ed01998-07-17Fredrik Hübinette (Hubbe)  async_client next_client;
bb02cc1997-09-15Fredrik Hübinette (Hubbe) 
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  class Request
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  {
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  string req;
f971bd1997-09-15Fredrik Hübinette (Hubbe)  string domain; function callback;
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  int retries;
cd6ed01998-07-17Fredrik Hübinette (Hubbe)  int timestamp;
4755b72000-02-18Henrik Grubbström (Grubba)  array args;
6314ba2015-03-31Henrik Grubbström (Grubba)  mixed retry_co;
bb02cc1997-09-15Fredrik Hübinette (Hubbe)  };
3d3ed71997-09-15Fredrik Hübinette (Hubbe) 
f971bd1997-09-15Fredrik Hübinette (Hubbe)  mapping requests=([]);
3d3ed71997-09-15Fredrik Hübinette (Hubbe) 
9eaf1d2008-06-28Martin Nilsson  protected private void remove(object(Request) r)
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  { if(!r) return; sscanf(r->req,"%2c",int id); m_delete(requests,id);
6314ba2015-03-31Henrik Grubbström (Grubba)  if (r->retry_co) remove_call_out(r->retry_co); r->retry_co = UNDEFINED;
f971bd1997-09-15Fredrik Hübinette (Hubbe)  r->callback(r->domain,0,@r->args);
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  destruct(r); }
6256271998-01-11Henrik Grubbström (Grubba)  void retry(object(Request) r, void|int nsno)
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  { if(!r) return;
6256271998-01-11Henrik Grubbström (Grubba)  if (nsno >= sizeof(nameservers)) {
cd6ed01998-07-17Fredrik Hübinette (Hubbe)  if(r->retries++ > RETRIES)
6256271998-01-11Henrik Grubbström (Grubba)  {
6314ba2015-03-31Henrik Grubbström (Grubba)  r->retry_co = call_out(remove, REMOVE_DELAY, r);
6256271998-01-11Henrik Grubbström (Grubba)  return; } else { nsno = 0; }
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  }
f93b6f2015-09-24Henrik Grubbström (Grubba) 
6314ba2015-03-31Henrik Grubbström (Grubba)  r->retry_co = call_out(retry, RETRY_DELAY, r, nsno+1);
f93b6f2015-09-24Henrik Grubbström (Grubba)  udp::send(nameservers[nsno], 53, r->req);
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  } void do_query(string domain, int cl, int type,
f971bd1997-09-15Fredrik Hübinette (Hubbe)  function(string,mapping,mixed...:void) callback,
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  mixed ... args) {
8ba41f2003-07-30Anders Johansson  for(int e=next_client ? 100 : 256;e>=0;e--)
cd6ed01998-07-17Fredrik Hübinette (Hubbe)  {
75c66d1998-07-17Fredrik Hübinette (Hubbe)  int lid = random(65536); if(!catch { requests[lid]++; })
cd6ed01998-07-17Fredrik Hübinette (Hubbe)  {
75c66d1998-07-17Fredrik Hübinette (Hubbe)  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();
6314ba2015-03-31Henrik Grubbström (Grubba)  r->retry_co = call_out(retry, RETRY_DELAY, r, 1);
f93b6f2015-09-24Henrik Grubbström (Grubba)  requests[lid] = r; udp::send(nameservers[0], 53, req);
75c66d1998-07-17Fredrik Hübinette (Hubbe)  return;
cd6ed01998-07-17Fredrik Hübinette (Hubbe)  } }
75c66d1998-07-17Fredrik Hübinette (Hubbe)  /* 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=async_client(nameservers,domains); next_client->do_query(domain, cl, type, callback, @args);
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  }
9eaf1d2008-06-28Martin Nilsson  protected private void rec_data(mapping m)
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  {
6aa4b71998-06-13Henrik Grubbström (Grubba)  mixed err; if (err = catch {
7b69642003-08-07Martin Nilsson  if(m->port != 53 || !has_value(nameservers, m->ip)) return;
6aa4b71998-06-13Henrik Grubbström (Grubba)  sscanf(m->data,"%2c",int id); object r=requests[id]; if(!r) return; m_delete(requests,id); r->callback(r->domain,decode_res(m->data),@r->args); destruct(r); }) {
0bd6f52003-10-21Martin Nilsson  werror("DNS: Failed to read UDP packet. Connection refused?\n%s\n", describe_backtrace(err));
6aa4b71998-06-13Henrik Grubbström (Grubba)  }
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  }
f971bd1997-09-15Fredrik Hübinette (Hubbe) 
9eaf1d2008-06-28Martin Nilsson  protected private void generic_get(string d,
f971bd1997-09-15Fredrik Hübinette (Hubbe)  mapping answer,
27c6851997-12-10David Hedbor  int multi,
901dde1998-09-13Henrik Grubbström (Grubba)  int all, int type,
f971bd1997-09-15Fredrik Hübinette (Hubbe)  string field, string domain, function callback, mixed ... args) { if(!answer || !answer->an || !sizeof(answer->an)) {
7f82921997-12-10David Hedbor  if(multi == -1 || multi >= sizeof(domains)) {
27c6851997-12-10David Hedbor  // 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...
901dde1998-09-13Henrik Grubbström (Grubba)  do_query(domain+"."+domains[multi], C_IN, type, generic_get, ++multi, all, type, field, domain, callback, @args);
27c6851997-12-10David Hedbor  } } else {
901dde1998-09-13Henrik Grubbström (Grubba)  if (all) { callback(domain, answer->an, @args); } else { foreach(answer->an, array an) if(an[field]) { callback(domain, an[field], @args); return; } callback(domain,0,@args); return; }
f971bd1997-09-15Fredrik Hübinette (Hubbe)  } }
a323352012-02-29Henrik Grubbström (Grubba)  //!
f971bd1997-09-15Fredrik Hübinette (Hubbe)  void host_to_ip(string host, function callback, mixed ... args) {
7f82921997-12-10David Hedbor  if(sizeof(domains) && host[-1] != '.' && sizeof(host/".") < 3) {
27c6851997-12-10David Hedbor  do_query(host, C_IN, T_A,
901dde1998-09-13Henrik Grubbström (Grubba)  generic_get, 0, 0, T_A, "a", host, callback, @args );
27c6851997-12-10David Hedbor  } else { do_query(host, C_IN, T_A,
c9d48d1998-09-13Henrik Grubbström (Grubba)  generic_get, -1, 0, T_A, "a",
27c6851997-12-10David Hedbor  host, callback, @args); }
f971bd1997-09-15Fredrik Hübinette (Hubbe)  }
a323352012-02-29Henrik Grubbström (Grubba)  //!
f971bd1997-09-15Fredrik Hübinette (Hubbe)  void ip_to_host(string ip, function callback, mixed ... args)
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  {
f971bd1997-09-15Fredrik Hübinette (Hubbe)  do_query(arpa_from_ip(ip), C_IN, T_PTR,
901dde1998-09-13Henrik Grubbström (Grubba)  generic_get, -1, 0, T_PTR, "ptr",
f971bd1997-09-15Fredrik Hübinette (Hubbe)  ip, callback, @args); }
a323352012-02-29Henrik Grubbström (Grubba)  //!
901dde1998-09-13Henrik Grubbström (Grubba)  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); } }
a323352012-02-29Henrik Grubbström (Grubba)  //!
901dde1998-09-13Henrik Grubbström (Grubba)  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);
79ee221998-09-18Henrik Grubbström (Grubba)  }, callback, @args);
901dde1998-09-13Henrik Grubbström (Grubba)  }
d768da2012-02-29Henrik Grubbström (Grubba)  //! Close the client. //! //! @note //! All active requests are aborted.
b910e42011-01-21Martin Jonsson  void close() {
d768da2012-02-29Henrik Grubbström (Grubba)  foreach(requests; ; Request r) { remove(r); }
b910e42011-01-21Martin Jonsson  udp::close(); udp::set_read_callback(0); }
cd6ed01998-07-17Fredrik Hübinette (Hubbe)  void create(void|string|array(string) server, void|string|array(string) domain)
f971bd1997-09-15Fredrik Hübinette (Hubbe)  {
4f4a5c2012-01-25Henrik Grubbström (Grubba)  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))
484a742002-03-09Martin Nilsson  error( "DNS: failed to bind a port.\n" );
355bbe2005-01-03Henrik Grubbström (Grubba) #if 0
f96a6f2005-01-03Jeff Hungerford  werror("Protocols.DNS.async_client(%O, %O)\n" "UDP Address: %s\n" "%s\n", server, domain, udp::query_address(), describe_backtrace(backtrace()));
355bbe2005-01-03Henrik Grubbström (Grubba) #endif /* 0 */
f971bd1997-09-15Fredrik Hübinette (Hubbe)  udp::set_read_callback(rec_data);
cd6ed01998-07-17Fredrik Hübinette (Hubbe)  ::create(server,domain);
3d3ed71997-09-15Fredrik Hübinette (Hubbe)  }
bb02cc1997-09-15Fredrik Hübinette (Hubbe) };
b6e3442002-11-26H. William Welliver III 
8ba41f2003-07-30Anders Johansson  async_client global_async_client; #define GAC(X) \ void async_##X( string host, function callback, mixed ... args ) \ { \ if( !global_async_client ) \ global_async_client = async_client(); \ global_async_client->X(host,callback,@args); \ }
f3b89c2003-08-05Martin Nilsson //! @ignore
8ba41f2003-07-30Anders Johansson GAC(ip_to_host);
f3b89c2003-08-05Martin Nilsson //! @endignore //! @decl void async_ip_to_host(string ip, function cb, mixed ... cba)
8ba41f2003-07-30Anders Johansson 
f3b89c2003-08-05Martin Nilsson //! @ignore
8ba41f2003-07-30Anders Johansson GAC(host_to_ip);
f3b89c2003-08-05Martin Nilsson //! @endignore //! @decl void async_host_to_ip(string host, function cb, mixed ... cba)
8ba41f2003-07-30Anders Johansson 
f3b89c2003-08-05Martin Nilsson //! @ignore
8ba41f2003-07-30Anders Johansson GAC(get_mx_all);
f3b89c2003-08-05Martin Nilsson //! @endignore //! @decl void async_get_mx_all(string host, function cb, mixed ... cba)
8ba41f2003-07-30Anders Johansson 
f3b89c2003-08-05Martin Nilsson //! @ignore
8ba41f2003-07-30Anders Johansson GAC(get_mx);
f3b89c2003-08-05Martin Nilsson //! @endignore //! @decl void async_get_mx(string host, function cb, mixed ... cba)
8ba41f2003-07-30Anders Johansson  client global_client; #define GC(X) \ mixed X( string host ) \ { \ if( !global_client ) \ global_client = client(); \ return global_client->X(host); \ }
f3b89c2003-08-05Martin Nilsson //! @ignore
8ba41f2003-07-30Anders Johansson GC(gethostbyname);
f3b89c2003-08-05Martin Nilsson //! @endignore //! @decl array gethostbyname(string host)
8ba41f2003-07-30Anders Johansson 
f3b89c2003-08-05Martin Nilsson //! @ignore
8ba41f2003-07-30Anders Johansson GC(gethostbyaddr);
f3b89c2003-08-05Martin Nilsson //! @endignore //! @decl array gethostbyaddr(string host)
8ba41f2003-07-30Anders Johansson 
f3b89c2003-08-05Martin Nilsson //! @ignore
8ba41f2003-07-30Anders Johansson GC(get_mx);
f3b89c2003-08-05Martin Nilsson //! @endignore //! @decl string get_mx(string host)
8ba41f2003-07-30Anders Johansson 
f3b89c2003-08-05Martin Nilsson //! @ignore
8ba41f2003-07-30Anders Johansson GC(get_primary_mx);
f3b89c2003-08-05Martin Nilsson //! @endignore //! @decl string get_primary_mx(string host)