#include #include #include #include #include #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; } }