177696Sbrian/*-
236321Samurai * Written by Atsushi Murai <amurai@spec.co.jp>
377696Sbrian * Copyright (c) 1998, System Planning and Engineering Co.
477696Sbrian * All rights reserved.
536321Samurai *
677696Sbrian * Redistribution and use in source and binary forms, with or without
777696Sbrian * modification, are permitted provided that the following conditions
877696Sbrian * are met:
977696Sbrian * 1. Redistributions of source code must retain the above copyright
1077696Sbrian *    notice, this list of conditions and the following disclaimer.
1177696Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1277696Sbrian *    notice, this list of conditions and the following disclaimer in the
1377696Sbrian *    documentation and/or other materials provided with the distribution.
1436321Samurai *
1577696Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1677696Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1777696Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1877696Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1977696Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2077696Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2177696Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2277696Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2377696Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2477696Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2577696Sbrian * SUCH DAMAGE.
2636321Samurai *  TODO:
2799207Sbrian *       oClean up.
2836321Samurai *       oConsidering for word alignment for other platform.
2936321Samurai */
3084195Sdillon
3184195Sdillon#include <sys/cdefs.h>
3284195Sdillon__FBSDID("$FreeBSD: stable/11/sys/netinet/libalias/alias_nbt.c 315456 2017-03-17 14:54:10Z vangyzen $");
3384195Sdillon
3436321Samurai/*
3536321Samurai    alias_nbt.c performs special processing for NetBios over TCP/IP
3636321Samurai    sessions by UDP.
3736321Samurai
3836321Samurai    Initial version:  May, 1998  (Atsushi Murai <amurai@spec.co.jp>)
3936321Samurai
4036321Samurai    See HISTORY file for record of revisions.
4136321Samurai*/
4236321Samurai
4336321Samurai/* Includes */
44145921Sglebius#ifdef _KERNEL
45145921Sglebius#include <sys/param.h>
46162674Spiso#include <sys/systm.h>
47162674Spiso#include <sys/kernel.h>
48162674Spiso#include <sys/module.h>
49145921Sglebius#else
50162674Spiso#include <errno.h>
51145921Sglebius#include <sys/types.h>
5299207Sbrian#include <stdio.h>
53187304Spiso#include <strings.h>
54145921Sglebius#endif
55145921Sglebius
5636321Samurai#include <netinet/in_systm.h>
5736321Samurai#include <netinet/in.h>
5836321Samurai#include <netinet/ip.h>
5936321Samurai#include <netinet/udp.h>
6036321Samurai
61145921Sglebius#ifdef _KERNEL
62145921Sglebius#include <netinet/libalias/alias_local.h>
63162674Spiso#include <netinet/libalias/alias_mod.h>
64145921Sglebius#else
6536321Samurai#include "alias_local.h"
66162674Spiso#include "alias_mod.h"
67145921Sglebius#endif
6836321Samurai
69162674Spiso#define NETBIOS_NS_PORT_NUMBER 137
70162674Spiso#define NETBIOS_DGM_PORT_NUMBER 138
71162674Spiso
72162674Spisostatic int
73259858SglebiusAliasHandleUdpNbt(struct libalias *, struct ip *, struct alias_link *,
74162674Spiso		  struct in_addr *, u_short);
75162674Spiso
76162674Spisostatic int
77162674SpisoAliasHandleUdpNbtNS(struct libalias *, struct ip *, struct alias_link *,
78162674Spiso		    struct in_addr *, u_short *, struct in_addr *, u_short *);
79259858Sglebiusstatic int
80190841Spisofingerprint1(struct libalias *la, struct alias_data *ah)
81162674Spiso{
82162674Spiso
83259858Sglebius	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
84162674Spiso	    ah->aaddr == NULL || ah->aport == NULL)
85162674Spiso		return (-1);
86162674Spiso	if (ntohs(*ah->dport) == NETBIOS_DGM_PORT_NUMBER
87162674Spiso	    || ntohs(*ah->sport) == NETBIOS_DGM_PORT_NUMBER)
88162674Spiso		return (0);
89162674Spiso	return (-1);
90162674Spiso}
91162674Spiso
92259858Sglebiusstatic int
93162674Spisoprotohandler1(struct libalias *la, struct ip *pip, struct alias_data *ah)
94162674Spiso{
95162674Spiso
96190938Spiso	return (AliasHandleUdpNbt(la, pip, ah->lnk, ah->aaddr, *ah->aport));
97162674Spiso}
98162674Spiso
99259858Sglebiusstatic int
100190841Spisofingerprint2(struct libalias *la, struct alias_data *ah)
101162674Spiso{
102162674Spiso
103259858Sglebius	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
104162674Spiso	    ah->aaddr == NULL || ah->aport == NULL)
105162674Spiso		return (-1);
106162674Spiso	if (ntohs(*ah->dport) == NETBIOS_NS_PORT_NUMBER
107162674Spiso	    || ntohs(*ah->sport) == NETBIOS_NS_PORT_NUMBER)
108162674Spiso		return (0);
109162674Spiso	return (-1);
110162674Spiso}
111162674Spiso
112259858Sglebiusstatic int
113162674Spisoprotohandler2in(struct libalias *la, struct ip *pip, struct alias_data *ah)
114162674Spiso{
115162674Spiso
116162674Spiso	AliasHandleUdpNbtNS(la, pip, ah->lnk, ah->aaddr, ah->aport,
117162674Spiso 			    ah->oaddr, ah->dport);
118162674Spiso	return (0);
119162674Spiso}
120162674Spiso
121259858Sglebiusstatic int
122162674Spisoprotohandler2out(struct libalias *la, struct ip *pip, struct alias_data *ah)
123162674Spiso{
124162674Spiso
125190938Spiso	return (AliasHandleUdpNbtNS(la, pip, ah->lnk, &pip->ip_src, ah->sport,
126190938Spiso 	    ah->aaddr, ah->aport));
127162674Spiso}
128162674Spiso
129162674Spiso/* Kernel module definition. */
130162674Spisostruct proto_handler handlers[] = {
131259858Sglebius	{
132259858Sglebius	  .pri = 130,
133259858Sglebius	  .dir = IN|OUT,
134259858Sglebius	  .proto = UDP,
135259858Sglebius	  .fingerprint = &fingerprint1,
136162674Spiso	  .protohandler = &protohandler1
137259858Sglebius	},
138259858Sglebius	{
139259858Sglebius	  .pri = 140,
140259858Sglebius	  .dir = IN,
141259858Sglebius	  .proto = UDP,
142259858Sglebius	  .fingerprint = &fingerprint2,
143162674Spiso	  .protohandler = &protohandler2in
144259858Sglebius	},
145259858Sglebius	{
146259858Sglebius	  .pri = 140,
147259858Sglebius	  .dir = OUT,
148259858Sglebius	  .proto = UDP,
149259858Sglebius	  .fingerprint = &fingerprint2,
150162674Spiso	  .protohandler = &protohandler2out
151259858Sglebius	},
152162674Spiso	{ EOH }
153162674Spiso};
154162674Spiso
155162674Spisostatic int
156162674Spisomod_handler(module_t mod, int type, void *data)
157162674Spiso{
158162674Spiso	int error;
159162674Spiso
160162674Spiso	switch (type) {
161162674Spiso	case MOD_LOAD:
162162674Spiso		error = 0;
163162674Spiso		LibAliasAttachHandlers(handlers);
164162674Spiso		break;
165162674Spiso	case MOD_UNLOAD:
166162674Spiso		error = 0;
167162674Spiso		LibAliasDetachHandlers(handlers);
168162674Spiso		break;
169162674Spiso	default:
170162674Spiso		error = EINVAL;
171162674Spiso	}
172162674Spiso	return (error);
173162674Spiso}
174162674Spiso
175162674Spiso#ifdef	_KERNEL
176259858Sglebiusstatic
177162674Spiso#endif
178162674Spisomoduledata_t alias_mod = {
179162674Spiso       "alias_nbt", mod_handler, NULL
180162674Spiso};
181162674Spiso
182162674Spiso#ifdef	_KERNEL
183162674SpisoDECLARE_MODULE(alias_nbt, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
184162674SpisoMODULE_VERSION(alias_nbt, 1);
185162674SpisoMODULE_DEPEND(alias_nbt, libalias, 1, 1, 1);
186162674Spiso#endif
187162674Spiso
18836321Samuraitypedef struct {
189127094Sdes	struct in_addr	oldaddr;
190127094Sdes	u_short		oldport;
191127094Sdes	struct in_addr	newaddr;
192127094Sdes	u_short		newport;
193127094Sdes	u_short        *uh_sum;
194127094Sdes}		NBTArguments;
19536321Samurai
19636321Samuraitypedef struct {
197127094Sdes	unsigned char	type;
198127094Sdes	unsigned char	flags;
199127094Sdes	u_short		id;
200127094Sdes	struct in_addr	source_ip;
201127094Sdes	u_short		source_port;
202127094Sdes	u_short		len;
203127094Sdes	u_short		offset;
204127094Sdes}		NbtDataHeader;
20536321Samurai
20636321Samurai#define OpQuery		0
20736321Samurai#define OpUnknown	4
20836321Samurai#define OpRegist	5
20936321Samurai#define OpRelease	6
21036321Samurai#define OpWACK		7
21136321Samurai#define OpRefresh	8
21236321Samuraitypedef struct {
213127094Sdes	u_short		nametrid;
214127094Sdes	u_short		dir:	1, opcode:4, nmflags:7, rcode:4;
215127094Sdes	u_short		qdcount;
216127094Sdes	u_short		ancount;
217127094Sdes	u_short		nscount;
218127094Sdes	u_short		arcount;
219127094Sdes}		NbtNSHeader;
22036321Samurai
22136321Samurai#define FMT_ERR		0x1
22236321Samurai#define SRV_ERR		0x2
22336321Samurai#define IMP_ERR		0x4
22436321Samurai#define RFS_ERR		0x5
22536321Samurai#define ACT_ERR		0x6
22636321Samurai#define CFT_ERR		0x7
22736321Samurai
22836321Samurai
229145961Sglebius#ifdef LIBALIAS_DEBUG
230127094Sdesstatic void
231127094SdesPrintRcode(u_char rcode)
232127094Sdes{
23336321Samurai
23436321Samurai	switch (rcode) {
23536321Samurai		case FMT_ERR:
236127094Sdes		printf("\nFormat Error.");
237127094Sdes	case SRV_ERR:
238127094Sdes		printf("\nSever failure.");
239127094Sdes	case IMP_ERR:
240127094Sdes		printf("\nUnsupported request error.\n");
241127094Sdes	case RFS_ERR:
242127094Sdes		printf("\nRefused error.\n");
243127094Sdes	case ACT_ERR:
244127094Sdes		printf("\nActive error.\n");
245127094Sdes	case CFT_ERR:
246127094Sdes		printf("\nName in conflict error.\n");
247127094Sdes	default:
248127094Sdes		printf("\n?%c?=%0x\n", '?', rcode);
24936321Samurai
25099207Sbrian	}
25136321Samurai}
252127094Sdes
25344616Sbrian#endif
25436321Samurai
25536321Samurai
25636321Samurai/* Handling Name field */
257127094Sdesstatic u_char  *
258127094SdesAliasHandleName(u_char * p, char *pmax)
259127094Sdes{
26036321Samurai
26136321Samurai	u_char *s;
26236321Samurai	u_char c;
263127094Sdes	int compress;
26436321Samurai
26536321Samurai	/* Following length field */
26641759Sdillon
26741759Sdillon	if (p == NULL || (char *)p >= pmax)
268127094Sdes		return (NULL);
26941759Sdillon
270127094Sdes	if (*p & 0xc0) {
27136321Samurai		p = p + 2;
27241759Sdillon		if ((char *)p > pmax)
273127094Sdes			return (NULL);
274127094Sdes		return ((u_char *) p);
27536321Samurai	}
276127094Sdes	while ((*p & 0x3f) != 0x00) {
27736321Samurai		s = p + 1;
278127094Sdes		if (*p == 0x20)
27936321Samurai			compress = 1;
28036321Samurai		else
28136321Samurai			compress = 0;
28299207Sbrian
283127094Sdes		/* Get next length field */
284127094Sdes		p = (u_char *) (p + (*p & 0x3f) + 1);
28541759Sdillon		if ((char *)p > pmax) {
28641759Sdillon			p = NULL;
28741759Sdillon			break;
28841759Sdillon		}
289145961Sglebius#ifdef LIBALIAS_DEBUG
29036321Samurai		printf(":");
29136321Samurai#endif
29236321Samurai		while (s < p) {
293127094Sdes			if (compress == 1) {
294127094Sdes				c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
295145961Sglebius#ifdef LIBALIAS_DEBUG
296127094Sdes				if (isprint(c))
297127094Sdes					printf("%c", c);
29836321Samurai				else
299127094Sdes					printf("<0x%02x>", c);
30036321Samurai#endif
301127094Sdes				s += 2;
30236321Samurai			} else {
303145961Sglebius#ifdef LIBALIAS_DEBUG
30436321Samurai				printf("%c", *s);
30536321Samurai#endif
30636321Samurai				s++;
30736321Samurai			}
30836321Samurai		}
309145961Sglebius#ifdef LIBALIAS_DEBUG
31036321Samurai		printf(":");
311145928Sglebius		fflush(stdout);
31236321Samurai#endif
313127094Sdes	}
31436321Samurai
31536321Samurai	/* Set up to out of Name field */
31641759Sdillon	if (p == NULL || (char *)p >= pmax)
317127094Sdes		p = NULL;
31841759Sdillon	else
319127094Sdes		p++;
320127094Sdes	return ((u_char *) p);
32136321Samurai}
32236321Samurai
32399207Sbrian/*
32436321Samurai * NetBios Datagram Handler (IP/UDP)
32536321Samurai */
32636321Samurai#define DGM_DIRECT_UNIQ		0x10
32736321Samurai#define DGM_DIRECT_GROUP	0x11
32836321Samurai#define DGM_BROADCAST		0x12
32936321Samurai#define DGM_ERROR			0x13
33036321Samurai#define DGM_QUERY			0x14
33136321Samurai#define DGM_POSITIVE_RES	0x15
33236321Samurai#define DGM_NEGATIVE_RES	0x16
33336321Samurai
334162674Spisostatic int
335127094SdesAliasHandleUdpNbt(
336127094Sdes    struct libalias *la,
337127094Sdes    struct ip *pip,		/* IP packet to examine/patch */
338131614Sdes    struct alias_link *lnk,
339127094Sdes    struct in_addr *alias_address,
340127094Sdes    u_short alias_port
341127094Sdes)
342127094Sdes{
343127094Sdes	struct udphdr *uh;
344127094Sdes	NbtDataHeader *ndh;
345127094Sdes	u_char *p = NULL;
346127094Sdes	char *pmax;
347315456Svangyzen#ifdef LIBALIAS_DEBUG
348315456Svangyzen	char addrbuf[INET_ADDRSTRLEN];
349315456Svangyzen#endif
35099207Sbrian
351131614Sdes	(void)la;
352131614Sdes	(void)lnk;
353131614Sdes
354127094Sdes	/* Calculate data length of UDP packet */
355131699Sdes	uh = (struct udphdr *)ip_next(pip);
356127094Sdes	pmax = (char *)uh + ntohs(uh->uh_ulen);
35741759Sdillon
358131699Sdes	ndh = (NbtDataHeader *)udp_next(uh);
359127094Sdes	if ((char *)(ndh + 1) > pmax)
360127094Sdes		return (-1);
361145961Sglebius#ifdef LIBALIAS_DEBUG
362127094Sdes	printf("\nType=%02x,", ndh->type);
36336321Samurai#endif
364127094Sdes	switch (ndh->type) {
365127094Sdes	case DGM_DIRECT_UNIQ:
366127094Sdes	case DGM_DIRECT_GROUP:
367127094Sdes	case DGM_BROADCAST:
368127094Sdes		p = (u_char *) ndh + 14;
369127094Sdes		p = AliasHandleName(p, pmax);	/* Source Name */
370127094Sdes		p = AliasHandleName(p, pmax);	/* Destination Name */
371127094Sdes		break;
372127094Sdes	case DGM_ERROR:
373127094Sdes		p = (u_char *) ndh + 11;
374127094Sdes		break;
375127094Sdes	case DGM_QUERY:
376127094Sdes	case DGM_POSITIVE_RES:
377127094Sdes	case DGM_NEGATIVE_RES:
378127094Sdes		p = (u_char *) ndh + 10;
379127094Sdes		p = AliasHandleName(p, pmax);	/* Destination Name */
380127094Sdes		break;
38136321Samurai	}
382127094Sdes	if (p == NULL || (char *)p > pmax)
383127094Sdes		p = NULL;
384145961Sglebius#ifdef LIBALIAS_DEBUG
385315456Svangyzen	printf("%s:%d-->", inet_ntoa_r(ndh->source_ip, INET_NTOA_BUF(addrbuf)),
386315456Svangyzen	    ntohs(ndh->source_port));
38736321Samurai#endif
388108533Sschweikh	/* Doing an IP address and Port number Translation */
389127094Sdes	if (uh->uh_sum != 0) {
390127094Sdes		int acc;
391127094Sdes		u_short *sptr;
392127094Sdes
393127094Sdes		acc = ndh->source_port;
39436321Samurai		acc -= alias_port;
395127094Sdes		sptr = (u_short *) & (ndh->source_ip);
39636321Samurai		acc += *sptr++;
39736321Samurai		acc += *sptr;
39836321Samurai		sptr = (u_short *) alias_address;
39936321Samurai		acc -= *sptr++;
40036321Samurai		acc -= *sptr;
40174778Sbrian		ADJUST_CHECKSUM(acc, uh->uh_sum);
40236321Samurai	}
403127094Sdes	ndh->source_ip = *alias_address;
404127094Sdes	ndh->source_port = alias_port;
405145961Sglebius#ifdef LIBALIAS_DEBUG
406315456Svangyzen	printf("%s:%d\n", inet_ntoa_r(ndh->source_ip, INET_NTOA_BUF(addrbuf)),
407315456Svangyzen	    ntohs(ndh->source_port));
40836321Samurai	fflush(stdout);
40936321Samurai#endif
410127094Sdes	return ((p == NULL) ? -1 : 0);
41136321Samurai}
412127094Sdes
41336321Samurai/* Question Section */
41436321Samurai#define QS_TYPE_NB		0x0020
41536321Samurai#define QS_TYPE_NBSTAT	0x0021
41636321Samurai#define QS_CLAS_IN		0x0001
41736321Samuraitypedef struct {
418127094Sdes	u_short		type;	/* The type of Request */
419127094Sdes	u_short		class;	/* The class of Request */
420127094Sdes}		NBTNsQuestion;
42136321Samurai
422127094Sdesstatic u_char  *
42341759SdillonAliasHandleQuestion(
42441759Sdillon    u_short count,
425127094Sdes    NBTNsQuestion * q,
42641759Sdillon    char *pmax,
427127094Sdes    NBTArguments * nbtarg)
42836321Samurai{
42936321Samurai
430131614Sdes	(void)nbtarg;
431131614Sdes
432127094Sdes	while (count != 0) {
43336321Samurai		/* Name Filed */
434127094Sdes		q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax);
43536321Samurai
43641759Sdillon		if (q == NULL || (char *)(q + 1) > pmax) {
43741759Sdillon			q = NULL;
43841759Sdillon			break;
43941759Sdillon		}
44036321Samurai		/* Type and Class filed */
441127094Sdes		switch (ntohs(q->type)) {
442127094Sdes		case QS_TYPE_NB:
443127094Sdes		case QS_TYPE_NBSTAT:
444127094Sdes			q = q + 1;
44536321Samurai			break;
446127094Sdes		default:
447145961Sglebius#ifdef LIBALIAS_DEBUG
448127094Sdes			printf("\nUnknown Type on Question %0x\n", ntohs(q->type));
44944616Sbrian#endif
45036321Samurai			break;
45136321Samurai		}
45236321Samurai		count--;
45336321Samurai	}
45436321Samurai
45536321Samurai	/* Set up to out of Question Section */
456127094Sdes	return ((u_char *) q);
45736321Samurai}
45836321Samurai
45936321Samurai/* Resource Record */
46036321Samurai#define RR_TYPE_A		0x0001
46136321Samurai#define RR_TYPE_NS		0x0002
46236321Samurai#define RR_TYPE_NULL	0x000a
46336321Samurai#define RR_TYPE_NB		0x0020
46436321Samurai#define RR_TYPE_NBSTAT	0x0021
46536321Samurai#define RR_CLAS_IN		0x0001
46636321Samurai#define SizeOfNsResource	8
46736321Samuraitypedef struct {
468127094Sdes	u_short		type;
469127094Sdes	u_short		class;
470127094Sdes	unsigned int	ttl;
471127094Sdes	u_short		rdlen;
472127094Sdes}		NBTNsResource;
47336321Samurai
47436321Samurai#define SizeOfNsRNB			6
47536321Samuraitypedef struct {
476127094Sdes	u_short		g:	1  , ont:2, resv:13;
477127094Sdes	struct in_addr	addr;
478127094Sdes}		NBTNsRNB;
47936321Samurai
480127094Sdesstatic u_char  *
48199207SbrianAliasHandleResourceNB(
482127094Sdes    NBTNsResource * q,
48399207Sbrian    char *pmax,
484127094Sdes    NBTArguments * nbtarg)
48536321Samurai{
486127094Sdes	NBTNsRNB *nb;
48736321Samurai	u_short bcount;
488315456Svangyzen#ifdef LIBALIAS_DEBUG
489315456Svangyzen	char oldbuf[INET_ADDRSTRLEN];
490315456Svangyzen	char newbuf[INET_ADDRSTRLEN];
491315456Svangyzen#endif
49236321Samurai
49341759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
494127094Sdes		return (NULL);
49536321Samurai	/* Check out a length */
49636321Samurai	bcount = ntohs(q->rdlen);
49736321Samurai
49836321Samurai	/* Forward to Resource NB position */
499127094Sdes	nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource);
50036321Samurai
50136321Samurai	/* Processing all in_addr array */
502145961Sglebius#ifdef LIBALIAS_DEBUG
503315456Svangyzen	printf("NB rec[%s->%s, %dbytes] ",
504315456Svangyzen	    inet_ntoa_r(nbtarg->oldaddr, INET_NTOA_BUF(oldbuf)),
505315456Svangyzen	    inet_ntoa_r(nbtarg->newaddr, INET_NTOA_BUF(newbuf)),
506315456Svangyzen	    bcount);
50736321Samurai#endif
508127094Sdes	while (nb != NULL && bcount != 0) {
50941759Sdillon		if ((char *)(nb + 1) > pmax) {
51041759Sdillon			nb = NULL;
51141759Sdillon			break;
51241759Sdillon		}
513145961Sglebius#ifdef LIBALIAS_DEBUG
514315456Svangyzen		printf("<%s>", inet_ntoa_r(nb->addr, INET_NTOA_BUF(newbuf)));
51536321Samurai#endif
516127094Sdes		if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
517127094Sdes			if (*nbtarg->uh_sum != 0) {
518127094Sdes				int acc;
519127094Sdes				u_short *sptr;
52036321Samurai
521127094Sdes				sptr = (u_short *) & (nb->addr);
522127094Sdes				acc = *sptr++;
523127094Sdes				acc += *sptr;
524127094Sdes				sptr = (u_short *) & (nbtarg->newaddr);
525127094Sdes				acc -= *sptr++;
526127094Sdes				acc -= *sptr;
527127094Sdes				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
52836321Samurai			}
52936321Samurai			nb->addr = nbtarg->newaddr;
530145961Sglebius#ifdef LIBALIAS_DEBUG
53136321Samurai			printf("O");
53236321Samurai#endif
53336321Samurai		}
534145961Sglebius#ifdef LIBALIAS_DEBUG
535127094Sdes		else {
53636321Samurai			printf(".");
53736321Samurai		}
53836321Samurai#endif
539127094Sdes		nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB);
540127094Sdes		bcount -= SizeOfNsRNB;
54136321Samurai	}
54241759Sdillon	if (nb == NULL || (char *)(nb + 1) > pmax) {
54341759Sdillon		nb = NULL;
54441759Sdillon	}
545127094Sdes	return ((u_char *) nb);
54636321Samurai}
54736321Samurai
54836321Samurai#define SizeOfResourceA		6
54936321Samuraitypedef struct {
550127094Sdes	struct in_addr	addr;
551127094Sdes}		NBTNsResourceA;
55236321Samurai
553127094Sdesstatic u_char  *
55499207SbrianAliasHandleResourceA(
555127094Sdes    NBTNsResource * q,
55641759Sdillon    char *pmax,
557127094Sdes    NBTArguments * nbtarg)
55836321Samurai{
559127094Sdes	NBTNsResourceA *a;
56036321Samurai	u_short bcount;
561315456Svangyzen#ifdef LIBALIAS_DEBUG
562315456Svangyzen	char oldbuf[INET_ADDRSTRLEN];
563315456Svangyzen	char newbuf[INET_ADDRSTRLEN];
564315456Svangyzen#endif
56536321Samurai
56641759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
567127094Sdes		return (NULL);
56841759Sdillon
56936321Samurai	/* Forward to Resource A position */
570127094Sdes	a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource));
57136321Samurai
57236321Samurai	/* Check out of length */
57336321Samurai	bcount = ntohs(q->rdlen);
57436321Samurai
57536321Samurai	/* Processing all in_addr array */
576145961Sglebius#ifdef LIBALIAS_DEBUG
577315456Svangyzen	printf("Arec [%s->%s]",
578315456Svangyzen	    inet_ntoa_r(nbtarg->oldaddr, INET_NTOA_BUF(oldbuf)),
579315456Svangyzen	    inet_ntoa_r(nbtarg->newaddr, INET_NTOA_BUF(newbuf)));
58036321Samurai#endif
581127094Sdes	while (bcount != 0) {
58241759Sdillon		if (a == NULL || (char *)(a + 1) > pmax)
583127094Sdes			return (NULL);
584145961Sglebius#ifdef LIBALIAS_DEBUG
585315456Svangyzen		printf("..%s", inet_ntoa_r(a->addr, INET_NTOA_BUF(newbuf)));
58636321Samurai#endif
587127094Sdes		if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
588127094Sdes			if (*nbtarg->uh_sum != 0) {
589127094Sdes				int acc;
590127094Sdes				u_short *sptr;
59136321Samurai
592127094Sdes				sptr = (u_short *) & (a->addr);	/* Old */
593127094Sdes				acc = *sptr++;
594127094Sdes				acc += *sptr;
595127094Sdes				sptr = (u_short *) & nbtarg->newaddr;	/* New */
596127094Sdes				acc -= *sptr++;
597127094Sdes				acc -= *sptr;
598127094Sdes				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
59936321Samurai			}
60036321Samurai			a->addr = nbtarg->newaddr;
60136321Samurai		}
602127094Sdes		a++;		/* XXXX */
60336321Samurai		bcount -= SizeOfResourceA;
60436321Samurai	}
60541759Sdillon	if (a == NULL || (char *)(a + 1) > pmax)
606127094Sdes		a = NULL;
607127094Sdes	return ((u_char *) a);
60836321Samurai}
60936321Samurai
61036321Samuraitypedef struct {
611127094Sdes	u_short		opcode:4, flags:8, resv:4;
612127094Sdes}		NBTNsResourceNULL;
61336321Samurai
614127094Sdesstatic u_char  *
61599207SbrianAliasHandleResourceNULL(
616127094Sdes    NBTNsResource * q,
61741759Sdillon    char *pmax,
618127094Sdes    NBTArguments * nbtarg)
61936321Samurai{
620127094Sdes	NBTNsResourceNULL *n;
62136321Samurai	u_short bcount;
62236321Samurai
623131614Sdes	(void)nbtarg;
624131614Sdes
62541759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
626127094Sdes		return (NULL);
62741759Sdillon
62836321Samurai	/* Forward to Resource NULL position */
629127094Sdes	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
63036321Samurai
63136321Samurai	/* Check out of length */
63236321Samurai	bcount = ntohs(q->rdlen);
63336321Samurai
63436321Samurai	/* Processing all in_addr array */
635127094Sdes	while (bcount != 0) {
63641759Sdillon		if ((char *)(n + 1) > pmax) {
63741759Sdillon			n = NULL;
63841759Sdillon			break;
63941759Sdillon		}
64036321Samurai		n++;
64136321Samurai		bcount -= sizeof(NBTNsResourceNULL);
64236321Samurai	}
64341759Sdillon	if ((char *)(n + 1) > pmax)
64441759Sdillon		n = NULL;
64536321Samurai
646127094Sdes	return ((u_char *) n);
64736321Samurai}
64836321Samurai
649127094Sdesstatic u_char  *
65099207SbrianAliasHandleResourceNS(
651127094Sdes    NBTNsResource * q,
65241759Sdillon    char *pmax,
653127094Sdes    NBTArguments * nbtarg)
65436321Samurai{
655127094Sdes	NBTNsResourceNULL *n;
65636321Samurai	u_short bcount;
65736321Samurai
658131614Sdes	(void)nbtarg;
659131614Sdes
66041759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
661127094Sdes		return (NULL);
66241759Sdillon
66336321Samurai	/* Forward to Resource NULL position */
664127094Sdes	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
66536321Samurai
66636321Samurai	/* Check out of length */
66736321Samurai	bcount = ntohs(q->rdlen);
66836321Samurai
66936321Samurai	/* Resource Record Name Filed */
670127094Sdes	q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax);	/* XXX */
67136321Samurai
672127094Sdes	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
673127094Sdes		return (NULL);
67441759Sdillon	else
675127094Sdes		return ((u_char *) n + bcount);
67636321Samurai}
67736321Samurai
67836321Samuraitypedef struct {
679127094Sdes	u_short		numnames;
680127094Sdes}		NBTNsResourceNBSTAT;
68136321Samurai
682127094Sdesstatic u_char  *
68341759SdillonAliasHandleResourceNBSTAT(
684127094Sdes    NBTNsResource * q,
68541759Sdillon    char *pmax,
686127094Sdes    NBTArguments * nbtarg)
68736321Samurai{
688127094Sdes	NBTNsResourceNBSTAT *n;
68936321Samurai	u_short bcount;
69036321Samurai
691131614Sdes	(void)nbtarg;
692131614Sdes
69341759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
694127094Sdes		return (NULL);
69541759Sdillon
69636321Samurai	/* Forward to Resource NBSTAT position */
697127094Sdes	n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource));
69836321Samurai
69936321Samurai	/* Check out of length */
70036321Samurai	bcount = ntohs(q->rdlen);
70136321Samurai
702127094Sdes	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
703127094Sdes		return (NULL);
70441759Sdillon	else
705127094Sdes		return ((u_char *) n + bcount);
70636321Samurai}
70736321Samurai
708127094Sdesstatic u_char  *
70941759SdillonAliasHandleResource(
71099207Sbrian    u_short count,
711127094Sdes    NBTNsResource * q,
71241759Sdillon    char *pmax,
71399207Sbrian    NBTArguments
714127094Sdes    * nbtarg)
71536321Samurai{
716127094Sdes	while (count != 0) {
71736321Samurai		/* Resource Record Name Filed */
718127094Sdes		q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax);
71941759Sdillon
72041759Sdillon		if (q == NULL || (char *)(q + 1) > pmax)
72141759Sdillon			break;
722145961Sglebius#ifdef LIBALIAS_DEBUG
723127094Sdes		printf("type=%02x, count=%d\n", ntohs(q->type), count);
72436321Samurai#endif
72536321Samurai
72636321Samurai		/* Type and Class filed */
727127094Sdes		switch (ntohs(q->type)) {
728127094Sdes		case RR_TYPE_NB:
729127094Sdes			q = (NBTNsResource *) AliasHandleResourceNB(
730127094Sdes			    q,
731127094Sdes			    pmax,
732127094Sdes			    nbtarg
733127094Sdes			    );
734127094Sdes			break;
735127094Sdes		case RR_TYPE_A:
736127094Sdes			q = (NBTNsResource *) AliasHandleResourceA(
737127094Sdes			    q,
738127094Sdes			    pmax,
739127094Sdes			    nbtarg
740127094Sdes			    );
741127094Sdes			break;
742127094Sdes		case RR_TYPE_NS:
743127094Sdes			q = (NBTNsResource *) AliasHandleResourceNS(
744127094Sdes			    q,
745127094Sdes			    pmax,
746127094Sdes			    nbtarg
747127094Sdes			    );
748127094Sdes			break;
749127094Sdes		case RR_TYPE_NULL:
750127094Sdes			q = (NBTNsResource *) AliasHandleResourceNULL(
751127094Sdes			    q,
752127094Sdes			    pmax,
753127094Sdes			    nbtarg
754127094Sdes			    );
755127094Sdes			break;
756127094Sdes		case RR_TYPE_NBSTAT:
757127094Sdes			q = (NBTNsResource *) AliasHandleResourceNBSTAT(
758127094Sdes			    q,
759127094Sdes			    pmax,
760127094Sdes			    nbtarg
761127094Sdes			    );
762127094Sdes			break;
763127094Sdes		default:
764145961Sglebius#ifdef LIBALIAS_DEBUG
765127094Sdes			printf(
766127094Sdes			    "\nUnknown Type of Resource %0x\n",
767127094Sdes			    ntohs(q->type)
768127094Sdes			    );
769145928Sglebius			fflush(stdout);
77044616Sbrian#endif
771127094Sdes			break;
77236321Samurai		}
77336321Samurai		count--;
77436321Samurai	}
775127094Sdes	return ((u_char *) q);
77636321Samurai}
77736321Samurai
778162674Spisostatic int
779127094SdesAliasHandleUdpNbtNS(
780127094Sdes    struct libalias *la,
781127094Sdes    struct ip *pip,		/* IP packet to examine/patch */
782131614Sdes    struct alias_link *lnk,
783127094Sdes    struct in_addr *alias_address,
784127094Sdes    u_short * alias_port,
785127094Sdes    struct in_addr *original_address,
786127094Sdes    u_short * original_port)
78736321Samurai{
788127094Sdes	struct udphdr *uh;
789127094Sdes	NbtNSHeader *nsh;
790127094Sdes	u_char *p;
791127094Sdes	char *pmax;
792127094Sdes	NBTArguments nbtarg;
79336321Samurai
794131614Sdes	(void)la;
795131614Sdes	(void)lnk;
796131614Sdes
79799207Sbrian	/* Set up Common Parameter */
798127094Sdes	nbtarg.oldaddr = *alias_address;
799127094Sdes	nbtarg.oldport = *alias_port;
800127094Sdes	nbtarg.newaddr = *original_address;
801127094Sdes	nbtarg.newport = *original_port;
80236321Samurai
803127094Sdes	/* Calculate data length of UDP packet */
804131699Sdes	uh = (struct udphdr *)ip_next(pip);
805127094Sdes	nbtarg.uh_sum = &(uh->uh_sum);
806131699Sdes	nsh = (NbtNSHeader *)udp_next(uh);
807127094Sdes	p = (u_char *) (nsh + 1);
808127094Sdes	pmax = (char *)uh + ntohs(uh->uh_ulen);
80936321Samurai
810127094Sdes	if ((char *)(nsh + 1) > pmax)
811127094Sdes		return (-1);
81241759Sdillon
813145961Sglebius#ifdef LIBALIAS_DEBUG
814127094Sdes	printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
815127094Sdes	    ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
816127094Sdes	    nsh->dir ? "Response" : "Request",
817127094Sdes	    nsh->nametrid,
818127094Sdes	    nsh->opcode,
819127094Sdes	    nsh->nmflags,
820127094Sdes	    nsh->rcode,
821127094Sdes	    ntohs(nsh->qdcount),
822127094Sdes	    ntohs(nsh->ancount),
823127094Sdes	    ntohs(nsh->nscount),
824127094Sdes	    ntohs(nsh->arcount),
825127094Sdes	    (u_char *) p - (u_char *) nsh
826127094Sdes	    );
82736321Samurai#endif
82836321Samurai
82936321Samurai	/* Question Entries */
830127094Sdes	if (ntohs(nsh->qdcount) != 0) {
831127094Sdes		p = AliasHandleQuestion(
832127094Sdes		    ntohs(nsh->qdcount),
833127094Sdes		    (NBTNsQuestion *) p,
834127094Sdes		    pmax,
835127094Sdes		    &nbtarg
836127094Sdes		    );
83736321Samurai	}
83836321Samurai	/* Answer Resource Records */
839127094Sdes	if (ntohs(nsh->ancount) != 0) {
840127094Sdes		p = AliasHandleResource(
841127094Sdes		    ntohs(nsh->ancount),
842127094Sdes		    (NBTNsResource *) p,
843127094Sdes		    pmax,
844127094Sdes		    &nbtarg
845127094Sdes		    );
84636321Samurai	}
84736321Samurai	/* Authority Resource Recodrs */
848127094Sdes	if (ntohs(nsh->nscount) != 0) {
849127094Sdes		p = AliasHandleResource(
850127094Sdes		    ntohs(nsh->nscount),
851127094Sdes		    (NBTNsResource *) p,
852127094Sdes		    pmax,
853127094Sdes		    &nbtarg
854127094Sdes		    );
85536321Samurai	}
85636321Samurai	/* Additional Resource Recodrs */
857127094Sdes	if (ntohs(nsh->arcount) != 0) {
858127094Sdes		p = AliasHandleResource(
859127094Sdes		    ntohs(nsh->arcount),
860127094Sdes		    (NBTNsResource *) p,
861127094Sdes		    pmax,
862127094Sdes		    &nbtarg
863127094Sdes		    );
86436321Samurai	}
865145961Sglebius#ifdef LIBALIAS_DEBUG
866127094Sdes	PrintRcode(nsh->rcode);
86736321Samurai#endif
868127094Sdes	return ((p == NULL) ? -1 : 0);
86936321Samurai}
870