bb02cc | 1997-09-15 | Fredrik Hübinette (Hubbe) | |
constant NOERROR=0;
constant FORMERR=1;
constant SERVFAIL=2;
constant NXDOMAIN=3;
constant NOTIMPL=4;
constant NXRRSET=8;
constant QUERY=0;
constant C_IN=1;
constant C_ANY=255;
constant T_A=1;
constant T_NS=2;
constant T_MD=3;
constant T_MF=4;
constant T_CNAME=5;
constant T_SOA=6;
constant T_MB=7;
constant T_PTR=12;
constant T_HINFO=13;
constant T_MINFO=14;
constant T_MX=15;
constant T_TXT=16;
constant T_AAAA=28;
class protocol
{
string mklabel(string s)
{
if(strlen(s)>63)
throw(({"Too long component in domain name",backtrace()}));
return sprintf("%c%s",strlen(s),s);
}
|
3d3ed7 | 1997-09-15 | Fredrik Hübinette (Hubbe) | | string low_mkquery(int id,
string dname,
int cl,
int type)
|
bb02cc | 1997-09-15 | Fredrik Hübinette (Hubbe) | | {
return sprintf("%2c%c%c%2c%2c%2c%2c%s\000%2c%2c",
id,
1,0,
1,
0,
0,
0,
Array.map(dname/".",mklabel)*"",
type,cl);
}
|
3d3ed7 | 1997-09-15 | Fredrik Hübinette (Hubbe) | |
string mkquery(string dname,
int cl,
int type)
{
return low_mkquery(random(65536),dname,cl,type);
}
|
bb02cc | 1997-09-15 | Fredrik Hübinette (Hubbe) | | string decode_domain(string msg, int *n)
{
string *domains=({});
int pos=n[0];
int next=-1;
string *ret=({});
while(1)
{
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:
if(next==-1) next=pos+2;
pos=((len&63)<<8) + msg[pos+1];
continue;
}
break;
}
}
string decode_string(string s, int *next)
{
int len=s[next[0]];
next[0]+=len+1;
return s[next[0]-len..next[0]-1];
}
int decode_short(string s, int *next)
{
sscanf(s[next[0]..next[0]+1],"%2c",int ret);
next[0]+=2;
return ret;
}
int decode_int(string s, int *next)
{
sscanf(s[next[0]..next[0]+1],"%2c",int ret);
next[0]+=2;
return ret;
}
mixed *decode_entries(string s,int num, int *next)
{
string *ret=({});
for(int e=0;e<num;e++)
{
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;
case T_A:
case T_AAAA:
m->a=sprintf("%{.%d%}",values(s[next[0]..next[0]+m->len-1]))[1..];
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);
m->retry=decode_int(s,next);
m->expire=decode_int(s,next);
m->minimum=decode_int(s,next);
break;
}
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);
m->rd=(m->c1>>7)&1;
m->tc=(m->c1>>6)&1;
m->tc=(m->c1>>5)&1;
m->opcode=(m->c1>>1)&15;
m->qr=m->c1&1;
m->rcode=(m->c2>>4)&15;
m->cd=(m->c2>>3)&1;
m->ad=(m->c2>>2)&1;
m->ra=(m->c2)&1;
m->length=strlen(s);
string *tmp=({});
int e;
if(m->qdcount!=1)
return m;
int *next=({12});
m->qd=decode_domain(s,next);
sscanf(s[next[0]..next[0]+3],"%2c%2c",m->type, m->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;
}
};
class client {
inherit protocol;
string nameserver;
void create(void|string server)
{
if(!server)
{
foreach(Stdio.read_file("/etc/resolv.conf")/"\n", string line)
{
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":
case "search":
break;
case "nameserver":
nameserver=rest;
break;
}
}
}else{
nameserver=server;
}
}
mapping do_sync_query(string s)
{
object udp=spider.dumUDP();
udp->bind(0);
udp->send(nameserver,53,s);
mapping m;
do {
m=udp->read();
} while (m->port != 53 ||
m->ip != nameserver ||
m->data[0..1]!=s[0..1]);
return decode_res(m->data);
}
mixed *gethostbyname(string s)
{
mapping m=do_sync_query(mkquery(s, C_IN, T_A));
string *names=({});
string *ips=({});
foreach(m->an, mapping x)
{
if(x->name)
names+=({x->name});
if(x->a)
ips+=({x->a});
}
return ({
sizeof(names)?names[0]:0,
ips,
names,
});
}
mixed *gethostbyaddr(string s)
{
mapping m=do_sync_query(mkquery(reverse(s/".")*"."+".IN-ADDR.ARPA",
C_IN,
T_PTR));
string *names=({});
string *ips=({});
foreach(m->an, mapping x)
{
if(x->ptr)
names+=({x->ptr});
if(x->name)
{
ips+=({reverse(x->name/".")[2..]*"."});
}
}
return ({
sizeof(names)?names[0]:0,
ips,
names,
});
}
string get_primary_mx(string host)
{
mapping m=do_sync_query(mkquery(host,C_IN,T_MX));
int minpref=29372974;
string ret;
foreach(m->an, mapping m2)
{
if(m2->preference<minpref)
{
ret=m2->mx;
minpref=m2->preference;
}
}
return ret;
}
}
class async_client
{
inherit client;
|
3d3ed7 | 1997-09-15 | Fredrik Hübinette (Hubbe) | | inherit spider.dumUDP;
int id;
|
bb02cc | 1997-09-15 | Fredrik Hübinette (Hubbe) | |
|
3d3ed7 | 1997-09-15 | Fredrik Hübinette (Hubbe) | | class Request
|
bb02cc | 1997-09-15 | Fredrik Hübinette (Hubbe) | | {
|
3d3ed7 | 1997-09-15 | Fredrik Hübinette (Hubbe) | | string req;
function success;
function fail;
int retries;
mixed *args;
|
bb02cc | 1997-09-15 | Fredrik Hübinette (Hubbe) | | };
|
3d3ed7 | 1997-09-15 | Fredrik Hübinette (Hubbe) | |
static private mapping requests=([]);
static private void remove(object(Request) r)
{
if(!r) return;
sscanf(r->req,"%2c",int id);
function f=r->fail;
mixed *args=r->args;
m_delete(requests,id);
destruct(r);
f(@args);
}
void retry(object(Request) r)
{
if(!r) return;
if(r->retries > 6)
{
call_out(remove,120,r);
}else{
send(nameserver,53,r->req);
}
}
void do_query(string domain, int cl, int type,
function callback,
function fail_callback,
mixed ... args)
{
id++;
id&=65535;
string req=low_mkquery(id,domain,cl,type);
if(requests[id])
throw(({"Cannot find an empty request slot.\n",backtrace()}));
object r=Request();
r->req=req;
r->success=callback;
r->fail=fail_callback;
requests[id]=r;
call_out(retry,5,r);
send(nameserver,53,r->req);
}
static private void rec_data()
{
mapping m=read();
if(m->port != 53 || m->ip != nameserver) return;
sscanf(m->data,"%2c",int id);
object r=requests[id];
if(!r) return;
function f=r->success;
mixed *args=r->args;
m_delete(requests,id);
destruct(r);
f(decode_res(m->data),@args);
}
void creat(string server)
{
bind(0);
set_read_callback(rec_data);
::create(server);
}
|
bb02cc | 1997-09-15 | Fredrik Hübinette (Hubbe) | | };
|