pike.git
/
lib
/
modules
/
Protocols.pmod
/
DNS.pmod
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/lib/modules/Protocols.pmod/DNS.pmod:1:
+
// Not yet finished -- Fredrik Hubinette
-
+
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);
+
}
+
+
// This will have to be generalized for
+
// the server part...
+
string mkquery(string dname,
+
int cl,
+
int type)
+
{
+
int id=random(65536); // make spoofing harder
+
+
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);
+
+
}
+
+
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; // Not yet implemented
+
+
case "nameserver":
+
nameserver=rest;
+
break;
+
}
+
}
+
}else{
+
nameserver=server;
+
}
+
}
+
+
+
// Warning: NO TIMEOUT
+
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);
+
}
+
+
+
// Warning: NO TIMEOUT
+
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,
+
});
+
}
+
+
// Warning: NO TIMEOUT
+
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;
+
+
mapping requests=([]);
+
class request
+
{
+
};
+
};
Newline at end of file added.