alias_nbt.c revision 190841
1/*-
2 * Written by Atsushi Murai <amurai@spec.co.jp>
3 * Copyright (c) 1998, System Planning and Engineering Co.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *  TODO:
27 *       oClean up.
28 *       oConsidering for word alignment for other platform.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_nbt.c 190841 2009-04-08 11:56:49Z piso $");
33
34/*
35    alias_nbt.c performs special processing for NetBios over TCP/IP
36    sessions by UDP.
37
38    Initial version:  May, 1998  (Atsushi Murai <amurai@spec.co.jp>)
39
40    See HISTORY file for record of revisions.
41*/
42
43/* Includes */
44#ifdef _KERNEL
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/module.h>
49#else
50#include <errno.h>
51#include <sys/types.h>
52#include <stdio.h>
53#include <strings.h>
54#endif
55
56#include <netinet/in_systm.h>
57#include <netinet/in.h>
58#include <netinet/ip.h>
59#include <netinet/udp.h>
60
61#ifdef _KERNEL
62#include <netinet/libalias/alias_local.h>
63#include <netinet/libalias/alias_mod.h>
64#else
65#include "alias_local.h"
66#include "alias_mod.h"
67#endif
68
69#define NETBIOS_NS_PORT_NUMBER 137
70#define NETBIOS_DGM_PORT_NUMBER 138
71
72static int
73AliasHandleUdpNbt(struct libalias *, struct ip *, struct alias_link *,
74		  struct in_addr *, u_short);
75
76static int
77AliasHandleUdpNbtNS(struct libalias *, struct ip *, struct alias_link *,
78		    struct in_addr *, u_short *, struct in_addr *, u_short *);
79static int
80fingerprint1(struct libalias *la, struct alias_data *ah)
81{
82
83	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
84	    ah->aaddr == NULL || ah->aport == NULL)
85		return (-1);
86	if (ntohs(*ah->dport) == NETBIOS_DGM_PORT_NUMBER
87	    || ntohs(*ah->sport) == NETBIOS_DGM_PORT_NUMBER)
88		return (0);
89	return (-1);
90}
91
92static int
93protohandler1(struct libalias *la, struct ip *pip, struct alias_data *ah)
94{
95
96	AliasHandleUdpNbt(la, pip, ah->lnk, ah->aaddr, *ah->aport);
97	return (0);
98}
99
100static int
101fingerprint2(struct libalias *la, struct alias_data *ah)
102{
103
104	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
105	    ah->aaddr == NULL || ah->aport == NULL)
106		return (-1);
107	if (ntohs(*ah->dport) == NETBIOS_NS_PORT_NUMBER
108	    || ntohs(*ah->sport) == NETBIOS_NS_PORT_NUMBER)
109		return (0);
110	return (-1);
111}
112
113static int
114protohandler2in(struct libalias *la, struct ip *pip, struct alias_data *ah)
115{
116
117	AliasHandleUdpNbtNS(la, pip, ah->lnk, ah->aaddr, ah->aport,
118 			    ah->oaddr, ah->dport);
119	return (0);
120}
121
122static int
123protohandler2out(struct libalias *la, struct ip *pip, struct alias_data *ah)
124{
125
126	AliasHandleUdpNbtNS(la, pip, ah->lnk, &pip->ip_src, ah->sport,
127 			    ah->aaddr, ah->aport);
128	return (0);
129}
130
131/* Kernel module definition. */
132struct proto_handler handlers[] = {
133	{
134	  .pri = 130,
135	  .dir = IN|OUT,
136	  .proto = UDP,
137	  .fingerprint = &fingerprint1,
138	  .protohandler = &protohandler1
139	},
140	{
141	  .pri = 140,
142	  .dir = IN,
143	  .proto = UDP,
144	  .fingerprint = &fingerprint2,
145	  .protohandler = &protohandler2in
146	},
147	{
148	  .pri = 140,
149	  .dir = OUT,
150	  .proto = UDP,
151	  .fingerprint = &fingerprint2,
152	  .protohandler = &protohandler2out
153	},
154	{ EOH }
155};
156
157static int
158mod_handler(module_t mod, int type, void *data)
159{
160	int error;
161
162	switch (type) {
163	case MOD_LOAD:
164		error = 0;
165		LibAliasAttachHandlers(handlers);
166		break;
167	case MOD_UNLOAD:
168		error = 0;
169		LibAliasDetachHandlers(handlers);
170		break;
171	default:
172		error = EINVAL;
173	}
174	return (error);
175}
176
177#ifdef	_KERNEL
178static
179#endif
180moduledata_t alias_mod = {
181       "alias_nbt", mod_handler, NULL
182};
183
184#ifdef	_KERNEL
185DECLARE_MODULE(alias_nbt, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
186MODULE_VERSION(alias_nbt, 1);
187MODULE_DEPEND(alias_nbt, libalias, 1, 1, 1);
188#endif
189
190typedef struct {
191	struct in_addr	oldaddr;
192	u_short		oldport;
193	struct in_addr	newaddr;
194	u_short		newport;
195	u_short        *uh_sum;
196}		NBTArguments;
197
198typedef struct {
199	unsigned char	type;
200	unsigned char	flags;
201	u_short		id;
202	struct in_addr	source_ip;
203	u_short		source_port;
204	u_short		len;
205	u_short		offset;
206}		NbtDataHeader;
207
208#define OpQuery		0
209#define OpUnknown	4
210#define OpRegist	5
211#define OpRelease	6
212#define OpWACK		7
213#define OpRefresh	8
214typedef struct {
215	u_short		nametrid;
216	u_short		dir:	1, opcode:4, nmflags:7, rcode:4;
217	u_short		qdcount;
218	u_short		ancount;
219	u_short		nscount;
220	u_short		arcount;
221}		NbtNSHeader;
222
223#define FMT_ERR		0x1
224#define SRV_ERR		0x2
225#define IMP_ERR		0x4
226#define RFS_ERR		0x5
227#define ACT_ERR		0x6
228#define CFT_ERR		0x7
229
230
231#ifdef LIBALIAS_DEBUG
232static void
233PrintRcode(u_char rcode)
234{
235
236	switch (rcode) {
237		case FMT_ERR:
238		printf("\nFormat Error.");
239	case SRV_ERR:
240		printf("\nSever failure.");
241	case IMP_ERR:
242		printf("\nUnsupported request error.\n");
243	case RFS_ERR:
244		printf("\nRefused error.\n");
245	case ACT_ERR:
246		printf("\nActive error.\n");
247	case CFT_ERR:
248		printf("\nName in conflict error.\n");
249	default:
250		printf("\n?%c?=%0x\n", '?', rcode);
251
252	}
253}
254
255#endif
256
257
258/* Handling Name field */
259static u_char  *
260AliasHandleName(u_char * p, char *pmax)
261{
262
263	u_char *s;
264	u_char c;
265	int compress;
266
267	/* Following length field */
268
269	if (p == NULL || (char *)p >= pmax)
270		return (NULL);
271
272	if (*p & 0xc0) {
273		p = p + 2;
274		if ((char *)p > pmax)
275			return (NULL);
276		return ((u_char *) p);
277	}
278	while ((*p & 0x3f) != 0x00) {
279		s = p + 1;
280		if (*p == 0x20)
281			compress = 1;
282		else
283			compress = 0;
284
285		/* Get next length field */
286		p = (u_char *) (p + (*p & 0x3f) + 1);
287		if ((char *)p > pmax) {
288			p = NULL;
289			break;
290		}
291#ifdef LIBALIAS_DEBUG
292		printf(":");
293#endif
294		while (s < p) {
295			if (compress == 1) {
296				c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
297#ifdef LIBALIAS_DEBUG
298				if (isprint(c))
299					printf("%c", c);
300				else
301					printf("<0x%02x>", c);
302#endif
303				s += 2;
304			} else {
305#ifdef LIBALIAS_DEBUG
306				printf("%c", *s);
307#endif
308				s++;
309			}
310		}
311#ifdef LIBALIAS_DEBUG
312		printf(":");
313		fflush(stdout);
314#endif
315	}
316
317	/* Set up to out of Name field */
318	if (p == NULL || (char *)p >= pmax)
319		p = NULL;
320	else
321		p++;
322	return ((u_char *) p);
323}
324
325/*
326 * NetBios Datagram Handler (IP/UDP)
327 */
328#define DGM_DIRECT_UNIQ		0x10
329#define DGM_DIRECT_GROUP	0x11
330#define DGM_BROADCAST		0x12
331#define DGM_ERROR			0x13
332#define DGM_QUERY			0x14
333#define DGM_POSITIVE_RES	0x15
334#define DGM_NEGATIVE_RES	0x16
335
336static int
337AliasHandleUdpNbt(
338    struct libalias *la,
339    struct ip *pip,		/* IP packet to examine/patch */
340    struct alias_link *lnk,
341    struct in_addr *alias_address,
342    u_short alias_port
343)
344{
345	struct udphdr *uh;
346	NbtDataHeader *ndh;
347	u_char *p = NULL;
348	char *pmax;
349
350	(void)la;
351	(void)lnk;
352
353	/* Calculate data length of UDP packet */
354	uh = (struct udphdr *)ip_next(pip);
355	pmax = (char *)uh + ntohs(uh->uh_ulen);
356
357	ndh = (NbtDataHeader *)udp_next(uh);
358	if ((char *)(ndh + 1) > pmax)
359		return (-1);
360#ifdef LIBALIAS_DEBUG
361	printf("\nType=%02x,", ndh->type);
362#endif
363	switch (ndh->type) {
364	case DGM_DIRECT_UNIQ:
365	case DGM_DIRECT_GROUP:
366	case DGM_BROADCAST:
367		p = (u_char *) ndh + 14;
368		p = AliasHandleName(p, pmax);	/* Source Name */
369		p = AliasHandleName(p, pmax);	/* Destination Name */
370		break;
371	case DGM_ERROR:
372		p = (u_char *) ndh + 11;
373		break;
374	case DGM_QUERY:
375	case DGM_POSITIVE_RES:
376	case DGM_NEGATIVE_RES:
377		p = (u_char *) ndh + 10;
378		p = AliasHandleName(p, pmax);	/* Destination Name */
379		break;
380	}
381	if (p == NULL || (char *)p > pmax)
382		p = NULL;
383#ifdef LIBALIAS_DEBUG
384	printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
385#endif
386	/* Doing an IP address and Port number Translation */
387	if (uh->uh_sum != 0) {
388		int acc;
389		u_short *sptr;
390
391		acc = ndh->source_port;
392		acc -= alias_port;
393		sptr = (u_short *) & (ndh->source_ip);
394		acc += *sptr++;
395		acc += *sptr;
396		sptr = (u_short *) alias_address;
397		acc -= *sptr++;
398		acc -= *sptr;
399		ADJUST_CHECKSUM(acc, uh->uh_sum);
400	}
401	ndh->source_ip = *alias_address;
402	ndh->source_port = alias_port;
403#ifdef LIBALIAS_DEBUG
404	printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
405	fflush(stdout);
406#endif
407	return ((p == NULL) ? -1 : 0);
408}
409
410/* Question Section */
411#define QS_TYPE_NB		0x0020
412#define QS_TYPE_NBSTAT	0x0021
413#define QS_CLAS_IN		0x0001
414typedef struct {
415	u_short		type;	/* The type of Request */
416	u_short		class;	/* The class of Request */
417}		NBTNsQuestion;
418
419static u_char  *
420AliasHandleQuestion(
421    u_short count,
422    NBTNsQuestion * q,
423    char *pmax,
424    NBTArguments * nbtarg)
425{
426
427	(void)nbtarg;
428
429	while (count != 0) {
430		/* Name Filed */
431		q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax);
432
433		if (q == NULL || (char *)(q + 1) > pmax) {
434			q = NULL;
435			break;
436		}
437		/* Type and Class filed */
438		switch (ntohs(q->type)) {
439		case QS_TYPE_NB:
440		case QS_TYPE_NBSTAT:
441			q = q + 1;
442			break;
443		default:
444#ifdef LIBALIAS_DEBUG
445			printf("\nUnknown Type on Question %0x\n", ntohs(q->type));
446#endif
447			break;
448		}
449		count--;
450	}
451
452	/* Set up to out of Question Section */
453	return ((u_char *) q);
454}
455
456/* Resource Record */
457#define RR_TYPE_A		0x0001
458#define RR_TYPE_NS		0x0002
459#define RR_TYPE_NULL	0x000a
460#define RR_TYPE_NB		0x0020
461#define RR_TYPE_NBSTAT	0x0021
462#define RR_CLAS_IN		0x0001
463#define SizeOfNsResource	8
464typedef struct {
465	u_short		type;
466	u_short		class;
467	unsigned int	ttl;
468	u_short		rdlen;
469}		NBTNsResource;
470
471#define SizeOfNsRNB			6
472typedef struct {
473	u_short		g:	1  , ont:2, resv:13;
474	struct in_addr	addr;
475}		NBTNsRNB;
476
477static u_char  *
478AliasHandleResourceNB(
479    NBTNsResource * q,
480    char *pmax,
481    NBTArguments * nbtarg)
482{
483	NBTNsRNB *nb;
484	u_short bcount;
485
486	if (q == NULL || (char *)(q + 1) > pmax)
487		return (NULL);
488	/* Check out a length */
489	bcount = ntohs(q->rdlen);
490
491	/* Forward to Resource NB position */
492	nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource);
493
494	/* Processing all in_addr array */
495#ifdef LIBALIAS_DEBUG
496	printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
497	printf("->%s, %dbytes] ", inet_ntoa(nbtarg->newaddr), bcount);
498#endif
499	while (nb != NULL && bcount != 0) {
500		if ((char *)(nb + 1) > pmax) {
501			nb = NULL;
502			break;
503		}
504#ifdef LIBALIAS_DEBUG
505		printf("<%s>", inet_ntoa(nb->addr));
506#endif
507		if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
508			if (*nbtarg->uh_sum != 0) {
509				int acc;
510				u_short *sptr;
511
512				sptr = (u_short *) & (nb->addr);
513				acc = *sptr++;
514				acc += *sptr;
515				sptr = (u_short *) & (nbtarg->newaddr);
516				acc -= *sptr++;
517				acc -= *sptr;
518				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
519			}
520			nb->addr = nbtarg->newaddr;
521#ifdef LIBALIAS_DEBUG
522			printf("O");
523#endif
524		}
525#ifdef LIBALIAS_DEBUG
526		else {
527			printf(".");
528		}
529#endif
530		nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB);
531		bcount -= SizeOfNsRNB;
532	}
533	if (nb == NULL || (char *)(nb + 1) > pmax) {
534		nb = NULL;
535	}
536	return ((u_char *) nb);
537}
538
539#define SizeOfResourceA		6
540typedef struct {
541	struct in_addr	addr;
542}		NBTNsResourceA;
543
544static u_char  *
545AliasHandleResourceA(
546    NBTNsResource * q,
547    char *pmax,
548    NBTArguments * nbtarg)
549{
550	NBTNsResourceA *a;
551	u_short bcount;
552
553	if (q == NULL || (char *)(q + 1) > pmax)
554		return (NULL);
555
556	/* Forward to Resource A position */
557	a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource));
558
559	/* Check out of length */
560	bcount = ntohs(q->rdlen);
561
562	/* Processing all in_addr array */
563#ifdef LIBALIAS_DEBUG
564	printf("Arec [%s", inet_ntoa(nbtarg->oldaddr));
565	printf("->%s]", inet_ntoa(nbtarg->newaddr));
566#endif
567	while (bcount != 0) {
568		if (a == NULL || (char *)(a + 1) > pmax)
569			return (NULL);
570#ifdef LIBALIAS_DEBUG
571		printf("..%s", inet_ntoa(a->addr));
572#endif
573		if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
574			if (*nbtarg->uh_sum != 0) {
575				int acc;
576				u_short *sptr;
577
578				sptr = (u_short *) & (a->addr);	/* Old */
579				acc = *sptr++;
580				acc += *sptr;
581				sptr = (u_short *) & nbtarg->newaddr;	/* New */
582				acc -= *sptr++;
583				acc -= *sptr;
584				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
585			}
586			a->addr = nbtarg->newaddr;
587		}
588		a++;		/* XXXX */
589		bcount -= SizeOfResourceA;
590	}
591	if (a == NULL || (char *)(a + 1) > pmax)
592		a = NULL;
593	return ((u_char *) a);
594}
595
596typedef struct {
597	u_short		opcode:4, flags:8, resv:4;
598}		NBTNsResourceNULL;
599
600static u_char  *
601AliasHandleResourceNULL(
602    NBTNsResource * q,
603    char *pmax,
604    NBTArguments * nbtarg)
605{
606	NBTNsResourceNULL *n;
607	u_short bcount;
608
609	(void)nbtarg;
610
611	if (q == NULL || (char *)(q + 1) > pmax)
612		return (NULL);
613
614	/* Forward to Resource NULL position */
615	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
616
617	/* Check out of length */
618	bcount = ntohs(q->rdlen);
619
620	/* Processing all in_addr array */
621	while (bcount != 0) {
622		if ((char *)(n + 1) > pmax) {
623			n = NULL;
624			break;
625		}
626		n++;
627		bcount -= sizeof(NBTNsResourceNULL);
628	}
629	if ((char *)(n + 1) > pmax)
630		n = NULL;
631
632	return ((u_char *) n);
633}
634
635static u_char  *
636AliasHandleResourceNS(
637    NBTNsResource * q,
638    char *pmax,
639    NBTArguments * nbtarg)
640{
641	NBTNsResourceNULL *n;
642	u_short bcount;
643
644	(void)nbtarg;
645
646	if (q == NULL || (char *)(q + 1) > pmax)
647		return (NULL);
648
649	/* Forward to Resource NULL position */
650	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
651
652	/* Check out of length */
653	bcount = ntohs(q->rdlen);
654
655	/* Resource Record Name Filed */
656	q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax);	/* XXX */
657
658	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
659		return (NULL);
660	else
661		return ((u_char *) n + bcount);
662}
663
664typedef struct {
665	u_short		numnames;
666}		NBTNsResourceNBSTAT;
667
668static u_char  *
669AliasHandleResourceNBSTAT(
670    NBTNsResource * q,
671    char *pmax,
672    NBTArguments * nbtarg)
673{
674	NBTNsResourceNBSTAT *n;
675	u_short bcount;
676
677	(void)nbtarg;
678
679	if (q == NULL || (char *)(q + 1) > pmax)
680		return (NULL);
681
682	/* Forward to Resource NBSTAT position */
683	n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource));
684
685	/* Check out of length */
686	bcount = ntohs(q->rdlen);
687
688	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
689		return (NULL);
690	else
691		return ((u_char *) n + bcount);
692}
693
694static u_char  *
695AliasHandleResource(
696    u_short count,
697    NBTNsResource * q,
698    char *pmax,
699    NBTArguments
700    * nbtarg)
701{
702	while (count != 0) {
703		/* Resource Record Name Filed */
704		q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax);
705
706		if (q == NULL || (char *)(q + 1) > pmax)
707			break;
708#ifdef LIBALIAS_DEBUG
709		printf("type=%02x, count=%d\n", ntohs(q->type), count);
710#endif
711
712		/* Type and Class filed */
713		switch (ntohs(q->type)) {
714		case RR_TYPE_NB:
715			q = (NBTNsResource *) AliasHandleResourceNB(
716			    q,
717			    pmax,
718			    nbtarg
719			    );
720			break;
721		case RR_TYPE_A:
722			q = (NBTNsResource *) AliasHandleResourceA(
723			    q,
724			    pmax,
725			    nbtarg
726			    );
727			break;
728		case RR_TYPE_NS:
729			q = (NBTNsResource *) AliasHandleResourceNS(
730			    q,
731			    pmax,
732			    nbtarg
733			    );
734			break;
735		case RR_TYPE_NULL:
736			q = (NBTNsResource *) AliasHandleResourceNULL(
737			    q,
738			    pmax,
739			    nbtarg
740			    );
741			break;
742		case RR_TYPE_NBSTAT:
743			q = (NBTNsResource *) AliasHandleResourceNBSTAT(
744			    q,
745			    pmax,
746			    nbtarg
747			    );
748			break;
749		default:
750#ifdef LIBALIAS_DEBUG
751			printf(
752			    "\nUnknown Type of Resource %0x\n",
753			    ntohs(q->type)
754			    );
755			fflush(stdout);
756#endif
757			break;
758		}
759		count--;
760	}
761	return ((u_char *) q);
762}
763
764static int
765AliasHandleUdpNbtNS(
766    struct libalias *la,
767    struct ip *pip,		/* IP packet to examine/patch */
768    struct alias_link *lnk,
769    struct in_addr *alias_address,
770    u_short * alias_port,
771    struct in_addr *original_address,
772    u_short * original_port)
773{
774	struct udphdr *uh;
775	NbtNSHeader *nsh;
776	u_char *p;
777	char *pmax;
778	NBTArguments nbtarg;
779
780	(void)la;
781	(void)lnk;
782
783	/* Set up Common Parameter */
784	nbtarg.oldaddr = *alias_address;
785	nbtarg.oldport = *alias_port;
786	nbtarg.newaddr = *original_address;
787	nbtarg.newport = *original_port;
788
789	/* Calculate data length of UDP packet */
790	uh = (struct udphdr *)ip_next(pip);
791	nbtarg.uh_sum = &(uh->uh_sum);
792	nsh = (NbtNSHeader *)udp_next(uh);
793	p = (u_char *) (nsh + 1);
794	pmax = (char *)uh + ntohs(uh->uh_ulen);
795
796	if ((char *)(nsh + 1) > pmax)
797		return (-1);
798
799#ifdef LIBALIAS_DEBUG
800	printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
801	    ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
802	    nsh->dir ? "Response" : "Request",
803	    nsh->nametrid,
804	    nsh->opcode,
805	    nsh->nmflags,
806	    nsh->rcode,
807	    ntohs(nsh->qdcount),
808	    ntohs(nsh->ancount),
809	    ntohs(nsh->nscount),
810	    ntohs(nsh->arcount),
811	    (u_char *) p - (u_char *) nsh
812	    );
813#endif
814
815	/* Question Entries */
816	if (ntohs(nsh->qdcount) != 0) {
817		p = AliasHandleQuestion(
818		    ntohs(nsh->qdcount),
819		    (NBTNsQuestion *) p,
820		    pmax,
821		    &nbtarg
822		    );
823	}
824	/* Answer Resource Records */
825	if (ntohs(nsh->ancount) != 0) {
826		p = AliasHandleResource(
827		    ntohs(nsh->ancount),
828		    (NBTNsResource *) p,
829		    pmax,
830		    &nbtarg
831		    );
832	}
833	/* Authority Resource Recodrs */
834	if (ntohs(nsh->nscount) != 0) {
835		p = AliasHandleResource(
836		    ntohs(nsh->nscount),
837		    (NBTNsResource *) p,
838		    pmax,
839		    &nbtarg
840		    );
841	}
842	/* Additional Resource Recodrs */
843	if (ntohs(nsh->arcount) != 0) {
844		p = AliasHandleResource(
845		    ntohs(nsh->arcount),
846		    (NBTNsResource *) p,
847		    pmax,
848		    &nbtarg
849		    );
850	}
851#ifdef LIBALIAS_DEBUG
852	PrintRcode(nsh->rcode);
853#endif
854	return ((p == NULL) ? -1 : 0);
855}
856