Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/ndb/glean/nbns.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


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


Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.