#include <u.h>
#include <libc.h>
#include <ip.h>
#include <bio.h>
#include <ndb.h>
#include "nbcache.h"
/*
* Name query requests are somewhat suspicious in a modern
* Active directory setup, they usually relate to laptops that
* are trying to mount drives available in a previous location.
*
* More worrying some viruses use broadcast name requests to
* access their botnet masters
*/
static void
name_query_request(Pkt *p)
{
Attr *a;
Udphdr *u;
Node *n1, *n2;
uchar srcip[IPv4addrlen], ip[IPv4addrlen];
int i, class, srv, type, que;
char *s, *t, question[20], from[32], requestor[32];
que = rb16(p); /* questions */
rb16(p); /* answers */
rb16(p); /* authoritave answers */
rb16(p); /* additional answers */
for(i = 0; i < que; i++){
rnbname(p, question, sizeof(question)); /* question name */
srv = question[15];
question[15] = 0;
type = rb16(p);
class = rb16(p);
if(type != 0x20 || class != 1) /* must be a netbios, internet request */
continue;
trim(question, ' ');
strlwr(question);
if(strcmp(question, "unknown-host") == 0)
continue;
u = (Udphdr *)p->buf;
v6tov4(srcip, u->raddr);
/*
* who asked the question
*/
snprint(from, sizeof(from), "%V", srcip);
s = csgetvalue(Netdir, "ip", from, "sys", nil);
if(s == nil)
s = csgetvalue(Netdir, "ip", from, "dom", nil);
if(s != nil){
strlwr(s);
if((t = strchr(s, '.')) != nil)
*t = 0;
snprint(requestor, sizeof(requestor), "%s", s);
free(s);
}
else
snprint(requestor, sizeof(requestor), "unknown-%V", srcip);
n1 = getnode(Thost, -1, "%s", requestor);
a = setval(n1, "ip", "%V", srcip);
if(Debug)
addval(a, "src", "nbnq srv=0x%x", srv);
/*
* what they asked for
*/
switch(srv){
case 0x1b: /* domain master browser */
case 0x1c: /* domain controller */
case 0x1d: /* local master browser */
case 0x1e: /* browser election service */
n2 = getnode(Tdomain, -1, "%s", question);
setval(n2, "member", "%s", requestor);
break;
default:
s = csgetvalue(Netdir, "sys", question, "ip", nil);
if(s == nil)
s = csgetvalue(Netdir, "dom", question, "ip", nil);
if(s){
n2 = getnode(Thost, -1, "%s", question);
a = setval(n2, "ip", "%s", s);
v4parseip(ip, s);
adapter_status(a, -1, ip);
free(s);
if(Debug)
addval(a, "src", "nbnq srv=0x%x", srv);
}
else
setval(n1, "failed", "%s <0x%02x>", question, srv);
break;
}
}
}
static void
name_query_response(Pkt *p)
{
Node *n;
Attr *a;
long ttl;
char name[20];
uchar ip[IPv4addrlen];
int i, j, num, que, ans;
que = rb16(p); /* questions */
ans = rb16(p); /* answers */
rb16(p); /* authoritave answers */
rb16(p); /* additional answers */
skip(p, que * (16 + 2 + 2));
for(i = 0; i < ans; i++){
rnbname(p, name, sizeof(name)); /* question name */
rb16(p); /* question type */
rb16(p); /* class */
ttl = rb32(p); /* time to live */
name[15] = 0;
strlwr(name);
trim(name, ' ');
n = getnode(Thost, ttl, "%s", name);
rb16(p); /* data length */
num = r8(p); /* number of names */
for(j = 0; j < num; j++){
rb16(p); /* flags */
rmem(p, ip, IPv4addrlen); /* IP address */
a = setval(n, "ip", "%V", ip);
adapter_status(a, ttl, ip);
if(Debug)
addval(a, "src", "nb-nq-resp");
}
}
}
static void
name_registration_response(Pkt *p)
{
Node *n;
Attr *a;
long ttl;
char name[20];
uchar ip[IPv4addrlen];
int i, j, srv, num, que, ans, aut, add;
que = rb16(p); /* questions */
ans = rb16(p); /* answers */
aut = rb16(p); /* authoritave answers */
add = rb16(p); /* additional answers */
srv = -1;
for(i = 0; i < que; i++){
rnbname(p, name, sizeof(name)); /* name */
srv = name[15];
name[15] = 0;
rb16(p); /* type */
rb16(p); /* class */
}
if(srv != 0 && srv != 0x20) /* not workstation && not server */
return;
skip(p, ans * (16 + 2 + 2));
skip(p, aut * (16 + 2 + 2));
for(i = 0; i < add; i++){
rb16(p); /* name pointer */
rb16(p); /* type */
rb16(p); /* class */
ttl = rb32(p); /* flags */
num = rb16(p);
strlwr(name);
trim(name, ' ');
if(ttl < 60)
ttl = 60*12*3;
n = getnode(Thost, ttl, "%s", name);
for(j = 0; j < num; j += 6){
rb16(p); /* flags */
rmem(p, ip, IPv4addrlen); /* IP address */
a = setval(n, "ip", "%V", ip);
adapter_status(a, ttl, ip);
if(Debug)
addval(a, "src", "nb-reg-resp");
}
}
}
void
nbns(Pkt *p)
{
int flags;
rb16(p); /* Transaction ID */
flags = rb16(p); /* flags */
switch(flags){
case 0x0110:
name_query_request(p);
break;
case 0x8500:
case 0x8580:
name_query_response(p);
break;
case 0x2910:
name_registration_response(p);
break;
}
}
|