1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright (c) 1998,2000 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27#include <stdio.h>
28#include <arpa/inet.h>
29#include <stdlib.h>
30#include <string.h>
31#include <sys/time.h>
32#include <iconv.h>
33#include "snoop.h"
34#include "slp.h"
35
36#define	MAXSUMLEN 30
37
38/* define VERIFYSLP to enable full message checking in summary mode */
39#define	VERIFYSLP
40
41/* Globals -- ugly, yes, but fast and easy in macros */
42static int msglength;
43static int retlength;
44static char *msgend;	/* the end of the summary message buffer */
45static char *p;		/* current position in the packet */
46static char *msgbuf;	/* message buffer for summary mode */
47static boolean_t url_auth	= B_FALSE;
48static boolean_t attr_auth	= B_FALSE;
49static boolean_t fresh		= B_FALSE;
50static boolean_t overflow	= B_FALSE;
51static int v1_charset		= 0;	/* character set; only in V1 */
52
53/* Entry points for parsing the protocol */
54static int interpret_slp_v1(int, struct slpv1_hdr *, int);
55static int interpret_slp_v2(int, struct slpv2_hdr *, int);
56
57/* header parsing */
58static int v1_header(int, struct slpv1_hdr *, int);
59static int v2_header(int, struct slpv2_hdr *, int *, int);
60static int v2_finish(struct slpv2_hdr *, int);
61
62/* V2 auth blocks */
63static int slpv2_authblock(int);
64
65/*
66 * Functions for parsing each protocol message
67 * Each function takes the interpreter's flags argument as its input
68 * parameter, and returns 1 on success, or 0 on message corruption.
69 * retlength is set as a side-effect in summary mode.
70 */
71static int v2_srv_rqst(int);
72static int v2_srv_rply(int);
73static int v2_srv_reg(int);
74static int v2_srv_dereg(int);
75static int v2_srv_ack(int);
76static int v2_attr_rqst(int);
77static int v2_attr_rply(int);
78static int v2_daadvert(int);
79static int v2_srv_type_rqst(int);
80static int v2_srv_type_rply(int);
81static int v2_saadvert(int);
82
83static int v1_srv_rqst(int);
84static int v1_srv_rply(int);
85static int v1_srv_reg(int);
86static int v1_srv_dereg(int);
87static int v1_srv_ack(int);
88static int v1_attr_rqst(int);
89static int v1_attr_rply(int);
90static int v1_daadvert(int);
91static int v1_srv_type_rqst(int);
92static int v1_srv_type_rply(int);
93
94/*
95 * The dispatch tables for handling individual messages, keyed by
96 * function number.
97 */
98typedef int function_handler();
99
100#define	V2_MAX_FUNCTION	11
101
102static function_handler *v2_functions[V2_MAX_FUNCTION + 1] = {
103	(function_handler *) NULL,
104	(function_handler *) v2_srv_rqst,
105	(function_handler *) v2_srv_rply,
106	(function_handler *) v2_srv_reg,
107	(function_handler *) v2_srv_dereg,
108	(function_handler *) v2_srv_ack,
109	(function_handler *) v2_attr_rqst,
110	(function_handler *) v2_attr_rply,
111	(function_handler *) v2_daadvert,
112	(function_handler *) v2_srv_type_rqst,
113	(function_handler *) v2_srv_type_rply,
114	(function_handler *) v2_saadvert };
115
116#define	V1_MAX_FUNCTION	10
117
118static function_handler *v1_functions[V1_MAX_FUNCTION + 1] = {
119	(function_handler *) NULL,
120	(function_handler *) v1_srv_rqst,
121	(function_handler *) v1_srv_rply,
122	(function_handler *) v1_srv_reg,
123	(function_handler *) v1_srv_dereg,
124	(function_handler *) v1_srv_ack,
125	(function_handler *) v1_attr_rqst,
126	(function_handler *) v1_attr_rply,
127	(function_handler *) v1_daadvert,
128	(function_handler *) v1_srv_type_rqst,
129	(function_handler *) v1_srv_type_rply };
130
131/* TCP continuation handling */
132static boolean_t tcp_continuation = B_FALSE;
133
134#define	MAX_TCPCONT	16
135
136static struct tcp_cont {
137	int dst_port;
138	char *msg;
139	int totallen;
140	int curr_offset;
141} *tcp_cont[MAX_TCPCONT];
142
143static int current_tcp_cont;
144
145static void reg_tcp_cont(char *, int, int, int);
146static int add_tcp_cont(struct tcp_cont *, char *, int);
147static struct tcp_cont *find_tcp_cont(int);
148static void remove_tcp_cont(int);
149
150/* Conversions from numbers to strings */
151static char *slpv2_func(int, boolean_t);
152static char *slpv2_error(unsigned short);
153static char *slpv1_func(int, boolean_t);
154static char *slpv1_error(unsigned short);
155static char *slpv1_charset(unsigned short);
156
157/*
158 * The only external entry point to the SLP interpreter. This function
159 * simply dispatches the packet based on the version.
160 */
161int
162interpret_slp(int flags, void *slp, int fraglen)
163{
164	extern int dst_port, curr_proto;
165	struct tcp_cont *tce = NULL;
166	char *s;
167
168	msglength = fraglen;
169	retlength = 0;
170	p = slp;
171
172	/* check if this is a TCP continuation */
173	if (flags & F_DTAIL && curr_proto == IPPROTO_TCP) {
174		tce = find_tcp_cont(dst_port);
175		if (tce) {
176			if (add_tcp_cont(tce, slp, fraglen)) {
177				slp = tce->msg;
178				fraglen = tce->curr_offset;
179				tcp_continuation = B_TRUE;
180			}
181		}
182	}
183	if (*(char *)slp == 2 || tce)
184		interpret_slp_v2(flags, slp, fraglen);
185	else
186		interpret_slp_v1(flags, slp, fraglen);
187
188	tcp_continuation = B_FALSE;
189	return (0);
190}
191
192/*
193 * Primitives. These are implemented as much as possible as macros for
194 * speed.
195 */
196
197#define	FIELD_DEFAULT	0
198#define	FIELD_PREVRESP	1
199#define	FIELD_TYPENA	2
200
201static long long netval = 0;	/* need signed 64 bit quantity */
202
203/* gets two bytes from p and leaves the result in netval */
204#define	nbtohs() \
205	netval = ((int)(p[0] & 0xff)) << 8; \
206	netval += ((int)(p[1] & 0xff))
207
208/* gets four bytes from p and leaves the result in netval */
209#define	nbtohl() \
210	netval = ((int)(p[0] & 0xff)) << 24; \
211	netval += ((int)(p[1] & 0xff)) << 16; \
212	netval += ((int)(p[2] & 0xff)) << 8; \
213	netval += ((int)(p[3] & 0xff))
214
215#define	get_byte() \
216	if (msglength >= 1) { \
217		netval = *p; \
218		p++; \
219		msglength--; \
220	} else \
221		netval = -1
222
223#define	GETBYTE(x) \
224	get_byte(); \
225	if ((retlength = netval) < 0) \
226		return (0); \
227	x = netval
228
229#define	SKIPBYTE \
230	get_byte(); \
231	if ((retlength = netval) < 0) \
232		return (0); \
233
234/*
235 * gets two bytes from p, leaves the result in netval, and updates
236 * msglength and p.
237 */
238#define	get_short() \
239	if (msglength >= sizeof (unsigned short)) { \
240		nbtohs(); \
241		p += sizeof (unsigned short); \
242		msglength -= sizeof (unsigned short); \
243	} else \
244		netval = -1
245
246#define	GETSHORT(x) \
247	get_short(); \
248	if ((retlength = netval) < 0) \
249		return (0); \
250	x = netval
251
252#define	SKIPSHORT \
253	get_short(); \
254	if ((retlength = netval) < 0) \
255		return (0)
256
257#define	get_int24(pp) \
258	netval = ((int)((pp)[0] & 0xff)) << 16; \
259	netval += ((int)((pp)[1] & 0xff)) << 8; \
260	netval += ((int)((pp)[2] & 0xff))
261
262static void slp_prevresp(char *p) {
263	char *p2;
264
265	/* cycle through all entries */
266	for (; p != NULL; p = p2) {
267	    p2 = strchr(p, ',');
268	    if (p2 != NULL)
269		*p2++ = '\0';
270
271	    /* print entry at p */
272	    sprintf(get_line(0, 0), "  \"%s\"", p);
273	}
274}
275
276static int skip_field(int type) {
277	unsigned short stringlen;
278
279	get_short();
280	if (netval < 0) {
281	    return (-1);
282	}
283	stringlen = netval;
284
285	/* special case for NA field in SrvTypeRqst */
286	if (type == FIELD_TYPENA && stringlen == 0xffff) {
287	    stringlen = 0;
288	}
289
290	if (stringlen > msglength) {
291	    return (-1);
292	}
293
294	msglength -= stringlen;
295	p += stringlen;
296
297	return (stringlen);
298}
299
300#define	SKIPFIELD(type) \
301	if ((retlength = skip_field(type)) < 0) \
302		return (0)
303
304#define	GETFIELD \
305	get_short(); \
306	if ((retlength = netval) < 0) \
307		return (0); \
308	strncat(msgbuf, p, (retlength > MAXSUMLEN ? MAXSUMLEN : retlength)); \
309	p += retlength; \
310	msglength -= retlength
311
312/*
313 * Determines from the first five bytes of a potential SLP header
314 * if the following message is really an SLP message. Returns 1 if
315 * it is a real SLP message, 0 if not.
316 */
317int valid_slp(unsigned char *slphdr, int len) {
318	struct slpv1_hdr slp1;
319	struct slpv2_hdr slp2;
320
321	len -= (8 /* udp */ + 20 /* IP */ + 14 /* ether */);
322	/* a valid version will be 1 or 2 */
323	switch (*slphdr) {
324	case 1:
325	    memcpy(&slp1, slphdr, 5);
326	    /* valid function? */
327	    if (slp1.function > V1_MAX_FUNCTION) {
328		return (0);
329	    }
330	    /* valid length heuristic */
331	    if (slp1.length > len) {
332		return (0);
333	    }
334	    return (1);
335	case 2:
336	    memcpy(&slp2, slphdr, 5);
337	    /* valid function? */
338	    if (slp2.function > V2_MAX_FUNCTION) {
339		return (0);
340	    }
341	    /* valid length heuristic */
342	    get_int24(&(slp2.l1));
343	    if (netval > len) {
344		return (0);
345	    }
346	    return (1);
347	default:
348	    return (0);
349	}
350}
351
352/*
353 * Converts a V1 char encoding to UTF8. If this fails, returns 0,
354 * otherwise, 1. This function is the union of iconv UTF-8
355 * modules and character sets registered with IANA.
356 */
357static int make_utf8(char *outbuf, size_t outlen,
358			const char *inbuf, size_t inlen) {
359	iconv_t cd;
360	size_t converted;
361
362	switch (v1_charset) {
363	case 4:
364	case 1004:
365	    cd = iconv_open("UTF-8", "8859-1");
366	    break;
367	case 5:
368	    cd = iconv_open("UTF-8", "8859-2");
369	    break;
370	case 6:
371	    cd = iconv_open("UTF-8", "8859-3");
372	    break;
373	case 7:
374	    cd = iconv_open("UTF-8", "8859-4");
375	    break;
376	case 8:
377	    cd = iconv_open("UTF-8", "8859-5");
378	    break;
379	case 9:
380	    cd = iconv_open("UTF-8", "8859-6");
381	    break;
382	case 10:
383	    cd = iconv_open("UTF-8", "8859-7");
384	    break;
385	case 11:
386	    cd = iconv_open("UTF-8", "8859-8");
387	    break;
388	case 12:
389	    cd = iconv_open("UTF-8", "8859-9");
390	    break;
391	case 13:
392	    cd = iconv_open("UTF-8", "8859-10");
393	    break;
394	case 37:
395	    cd = iconv_open("UTF-8", "ko_KR-iso2022-7");
396	    break;
397	case 104:
398	    cd = iconv_open("UTF-8", "iso2022");
399	    break;
400	case 1000:
401	    cd = iconv_open("UTF-8", "UCS-2");
402	    break;
403	case 1001:
404	    cd = iconv_open("UTF-8", "UCS-4");
405	    break;
406	default:
407		/*
408		 * charset not set, or reserved, or not supported, so
409		 * just copy it and hope for the best.
410		 */
411	    converted = outlen < inlen ? outlen : inlen;
412	    memcpy(outbuf, inbuf, converted);
413	    outbuf[converted] = 0;
414	    return (1);
415	}
416
417	if (cd == (iconv_t)-1) {
418	    return (0);
419	}
420
421	if ((converted = iconv(cd, &inbuf, &inlen, &outbuf, &outlen))
422	    == (size_t)-1) {
423	    return (0);
424	}
425
426	outbuf[converted] = 0;
427	iconv_close(cd);
428
429	return (1);
430}
431
432static int slp_field(char *tag, int type) {
433	int length;
434
435	get_short();
436	if (netval < 0) {
437	    return (-1);
438	}
439	length = netval;
440
441	/* special case for NA field in SrvTypeRqst */
442	if (type == FIELD_TYPENA && length == 0xffff) {
443	    sprintf(get_line(0, 0), "%s: length = -1: Use all NAs", tag);
444	    return (0);
445	}
446
447	sprintf(get_line(0, 0), "%s: length = %d", tag, length);
448	if (length > msglength) {
449	    /* framing error: message is not long enough to contain data */
450	    sprintf(get_line(0, 0),
451		    "  [Framing error: remaining pkt length = %u]",
452		    msglength);
453	    return (-1);
454	}
455
456	if (length > 0) {
457	    char *buf = malloc(length + 1);
458	    if (buf != NULL) {
459		if (v1_charset) {
460		    if (!make_utf8(buf, length, p, length)) {
461			strcpy(buf, "[Invalid Character Encoding]");
462		    }
463		} else {
464		    memcpy(buf, p, length);
465		    buf[length] = '\0';		/* ensure null-terminated */
466		}
467
468		switch (type) {
469		    case FIELD_PREVRESP:
470			slp_prevresp(buf);
471			break;
472
473		    default:
474			sprintf(get_line(0, 0), "  \"%s\"", buf);
475			break;
476		}
477		free(buf);
478	    }
479
480	    p += length;
481	    msglength -= length;
482	}
483
484	/* return ok */
485	return (0);
486}
487
488static int slpv2_url(int cnt) {
489	time_t exp;
490	int lifetime, length, n;
491
492	/* reserved */
493	get_byte();
494	if (netval < 0)
495	    return (-1);
496
497	/* lifetime */
498	get_short();
499	if ((lifetime = netval) < 0)
500	    return (-1);
501
502	/* length */
503	get_short();
504	if ((length = netval) < 0)
505	    return (-1);
506
507	/* time */
508	exp = time(0) + lifetime;
509	if (cnt == -1)
510	    sprintf(get_line(0, 0),
511		    "URL: length = %u, lifetime = %d (%24.24s)",
512		    length, lifetime, ctime(&exp));
513	else
514	    /* number the URLs to make it easier to parse them */
515	    sprintf(get_line(0, 0),
516		    "URL %d: length = %u, lifetime = %d (%24.24s)",
517		    cnt, length, lifetime, ctime(&exp));
518
519	if (length > msglength) {
520	    if (!tcp_continuation)
521		/* framing error: message is not long enough to contain data */
522		sprintf(get_line(0, 0),
523			"  [Framing error: remaining pkt length = %u]",
524			msglength);
525	    return (-1);
526	}
527
528	if (length > 0) {
529	    char *buf = malloc(length + 1);
530	    if (buf != NULL) {
531		memcpy(buf, p, length);
532		buf[length] = '\0';		/* ensure null-terminated */
533		sprintf(get_line(0, 0), "  \"%s\"", buf);
534		free(buf);
535	    }
536	}
537	msglength -= length;
538	p += length;
539
540	get_byte();
541	if ((n = netval) < 0)
542	    return (-1);
543
544	if (n > 0) {
545	    int i;
546	    sprintf(get_line(0, 0), "%d Authentication Blocks", n);
547	    for (i = 0; i < n; i++)
548		if ((length = slpv2_authblock(i)) < 0)
549		    return (-1);
550	}
551	return (0);
552}
553
554#define	DOFIELD(tag, type) \
555	if (slp_field(tag, type) < 0) \
556		return (0)
557
558#define	V2_DOURL(x) \
559	if (slpv2_url(x) < 0) \
560		return (0)
561
562#define	V2_DOERRCODE \
563	if (msglength < sizeof (unsigned short)) \
564		return (0); \
565	nbtohs(); \
566	errcode = netval; \
567	sprintf(get_line(0, 0), "Error code = %d, %s", \
568				errcode, slpv2_error(errcode)); \
569	p += sizeof (unsigned short); \
570	msglength -= sizeof (unsigned short); \
571	if (errcode != OK) \
572		msglength = 0;	/* skip rest of message */ \
573	if (errcode != OK) \
574		return (0)
575
576#define	V2_DOAUTH(cnt) \
577	if (slpv2_authblock(cnt) < 0) \
578		return (0)
579
580#define	V2_DOTIMESTAMP \
581	if (msglength < 4) \
582		return (0); \
583	nbtohl(); \
584	timestamp = netval; \
585	sprintf(get_line(0, 0), "Timestamp = %u, %s", \
586		timestamp, (timestamp ? convert_ts(timestamp) : "0")); \
587	p += 4; \
588	msglength -= 4
589
590/* some V1 macros */
591#define	SKIPAUTH(auth) \
592	if (auth && ((retlength = skip_v1authblock()) < 0)) \
593		return (0)
594
595#define	DOERRCODE \
596	if (msglength < sizeof (unsigned short)) \
597		return (0); \
598	nbtohs(); \
599	errcode = netval; \
600	sprintf(get_line(0, 0), "Error code = %d, %s", errcode, \
601				slpv1_error(errcode)); \
602	p += sizeof (unsigned short); \
603	msglength -= sizeof (unsigned short); \
604	if (errcode != OK) \
605		return (0)
606
607#define	DOURL \
608	if (slpv1_url(url_auth) < 0) \
609		return (0)
610
611#define	DOAUTH(auth) \
612	if (auth && slpv1_authblock() < 0) \
613		return (0)
614
615/*
616 * TCP Continuation handling
617 * We keep track of continuations in a fixed size cache, so as to prevent
618 * memory leaks if some continuations are never finished. The continuations
619 * are indexed by their destination ports.
620 */
621static void reg_tcp_cont(char *msg, int totallen,
622			    int fraglen, int dst_port) {
623	struct tcp_cont *tce = malloc(sizeof (*tce));
624
625	/* always overwrite the entry at current_tcp_cont */
626	if (tcp_cont[current_tcp_cont]) {
627	    free(tcp_cont[current_tcp_cont]->msg);
628	    free(tcp_cont[current_tcp_cont]);
629	}
630
631	tce->dst_port = dst_port;
632	tce->msg = malloc(totallen);
633	memcpy(tce->msg, msg, fraglen);
634	tce->totallen = totallen;
635	tce->curr_offset = fraglen;
636
637	tcp_cont[current_tcp_cont++] = tce;
638	if (current_tcp_cont == MAX_TCPCONT)
639	    current_tcp_cont = 0;
640}
641
642/* returns 0 if there is a mismatch error, 1 on success */
643static int add_tcp_cont(struct tcp_cont *tce, char *msg, int fraglen) {
644	if ((fraglen + tce->curr_offset) > tce->totallen)
645	    return (0);
646
647	memcpy(tce->msg + tce->curr_offset, msg, fraglen);
648	tce->curr_offset += fraglen;
649	return (1);
650}
651
652static struct tcp_cont *find_tcp_cont(int dst_port) {
653	int i;
654	for (i = current_tcp_cont; i >= 0; i--)
655	    if (tcp_cont[i] && tcp_cont[i]->dst_port == dst_port)
656		return (tcp_cont[i]);
657
658	for (i = MAX_TCPCONT -1; i > current_tcp_cont; i--)
659	    if (tcp_cont[i] && tcp_cont[i]->dst_port == dst_port)
660		return (tcp_cont[i]);
661
662	return (NULL);
663}
664
665static void remove_tcp_cont(int dst_port) {
666	int i;
667	for (i = current_tcp_cont; i >= 0; i--)
668	    if (tcp_cont[i] && tcp_cont[i]->dst_port == dst_port) {
669		free(tcp_cont[i]->msg);
670		free(tcp_cont[i]);
671		tcp_cont[i] = NULL;
672		return;
673	    }
674
675	for (i = MAX_TCPCONT -1; i > current_tcp_cont; i--)
676	    if (tcp_cont[i] && tcp_cont[i]->dst_port == dst_port) {
677		free(tcp_cont[i]->msg);
678		free(tcp_cont[i]);
679		tcp_cont[i] = NULL;
680		return;
681	    }
682}
683
684/*
685 * V2 interpreter
686 */
687
688static int interpret_slp_v2(int flags, struct slpv2_hdr *slp, int fraglen) {
689	extern int src_port, dst_port, curr_proto;
690	char msgbuf_real[256];
691	int totallen = 0;
692
693	msgbuf = msgbuf_real;
694
695	/*
696	 * Somewhat of a hack to decode traffic from a server that does
697	 * not send udp replies from its SLP src port.
698	 */
699
700	if (curr_proto == IPPROTO_UDP &&
701	    dst_port == 427 &&
702	    src_port != 427) {
703	    add_transient(src_port, interpret_slp);
704	}
705
706	/* parse the header */
707	if (v2_header(flags, slp, &totallen, fraglen)) {
708
709	    if (slp->function <= V2_MAX_FUNCTION && slp->function > 0) {
710
711		/* Parse the message body */
712		if ((v2_functions[slp->function])(flags)) {
713
714		    /* finish any remaining tasks */
715		    v2_finish(slp, flags);
716
717		}
718
719	    }
720
721	}
722
723	/* summary error check */
724	if (flags & F_SUM) {
725	    if (retlength < 0) {
726		if (curr_proto == IPPROTO_TCP)
727		    sprintf(get_sum_line(),
728			    "%s [partial TCP message]", msgbuf);
729		else if (overflow)
730		    sprintf(get_sum_line(), "%s [OVERFLOW]", msgbuf);
731		else
732		    sprintf(get_sum_line(), "%s [CORRUPTED MESSAGE]", msgbuf);
733	    }
734#ifdef VERIFYSLP
735	    else if (msglength > 0)
736		sprintf(get_sum_line(), "%s +%d", msgbuf, msglength);
737#endif
738	    else
739		sprintf(get_sum_line(), "%s", msgbuf);
740	} else if (flags & F_DTAIL) {
741	    /* detailed error check */
742	    if (msglength > 0) {
743		if (tcp_continuation) {
744		    sprintf(get_line(0, 0),
745			    "[TCP Continuation, %d bytes remaining]",
746			    totallen - fraglen);
747		} else
748		    sprintf(get_line(0, 0),
749			"[%d extra bytes at end of SLP message]", msglength);
750	    }
751
752	    show_trailer();
753
754	    if (tcp_continuation && msglength == 0)
755		remove_tcp_cont(dst_port);
756	}
757
758	return (0);
759}
760
761static int v2_header(int flags,
762			struct slpv2_hdr *slp,
763			int *totallen,
764			int fraglen) {
765	extern int curr_proto, dst_port;
766	char *prototag = (curr_proto == IPPROTO_TCP ? "/tcp" : "");
767
768	if ((slp->flags & V2_OVERFLOW) == V2_OVERFLOW)
769	    overflow = B_TRUE;
770
771	/* summary mode header parsing */
772	if (flags & F_SUM) {
773
774	    /* make sure we have at least a header */
775	    if (msglength < sizeof (*slp)) {
776		sprintf(get_sum_line(), "SLP V2 [Incomplete Header]");
777		return (0);
778	    }
779
780	    sprintf(msgbuf, "SLP V2 %s [%d%s] ",
781		    slpv2_func(slp->function, B_TRUE),
782		    ntohs(slp->xid), prototag);
783
784	    /* skip to end of header */
785	    msgend = msgbuf + strlen(msgbuf);
786	    msglength -= sizeof (*slp);
787	    p += sizeof (*slp);
788
789	    /* skip language tag */
790	    SKIPFIELD(FIELD_DEFAULT);
791	} else if (flags & F_DTAIL) {
792	    char *lang;
793	    int len;
794
795	    /* detailed mode header parsing */
796	    show_header("SLP:  ", "Service Location Protocol (v2)", fraglen);
797	    show_space();
798
799	    if (msglength < sizeof (*slp)) {
800		sprintf(get_line(0, 0), "==> Incomplete SLP header");
801		return (0);
802	    }
803
804	    sprintf(get_line(0, 0), "Version = %d", slp->vers);
805	    sprintf(get_line(0, 0), "Function = %d, %s",
806		    slp->function, slpv2_func(slp->function, B_FALSE));
807	    get_int24(&(slp->l1));
808	    *totallen = netval;
809	    sprintf(get_line(0, 0), "Message length = %u", *totallen);
810	    /* check for TCP continuation */
811	    if (curr_proto == IPPROTO_TCP &&
812		*totallen > msglength &&
813		!tcp_continuation) {
814		tcp_continuation = B_TRUE;
815		reg_tcp_cont((char *)slp, *totallen, msglength, dst_port);
816	    }
817
818	    if (!tcp_continuation && *totallen != msglength) {
819		sprintf(get_line(0, 0),
820			"  (Stated and on-the-wire lengths differ)");
821	    }
822	    /* flags */
823	    sprintf(get_line(0, 0), "Flags = 0x%02x", slp->flags);
824	    sprintf(get_line(0, 0), "      %s",
825		    getflag(slp->flags, V2_OVERFLOW,
826			    "overflow", "no overflow"));
827	    sprintf(get_line(0, 0), "      %s",
828		    getflag(slp->flags, V2_FRESH,
829			    "fresh registration", "no fresh registration"));
830	    sprintf(get_line(0, 0), "      %s",
831		    getflag(slp->flags, V2_MCAST,
832			    "request multicast / broadcast", "unicast"));
833	    /* check reserved flags that must be zero */
834	    if ((slp->flags & 7) != 0) {
835		sprintf(get_line(0, 0),
836			"      .... .xxx = %d (reserved flags nonzero)",
837			slp->flags & 7);
838	    }
839	    /* end of flags */
840
841	    /* language tag */
842	    p = (char *)slp + sizeof (*slp);
843	    msglength -= sizeof (*slp);
844	    GETSHORT(len);
845	    if (len > msglength) {
846		sprintf(get_line(0, 0),
847			"Language Tag Length = %u [CORRUPT MESSAGE]",
848			len);
849		return (0);
850	    }
851
852	    lang = get_line(0, 0);
853	    strcpy(lang, "Language Tag = ");
854	    strncat(lang,  p, len);
855	    sprintf(get_line(0, 0), "XID = %u", ntohs(slp->xid));
856
857	    /* set msglength to remaining length of SLP message */
858	    p += len;
859	    msglength -= len;
860	}
861
862	return (1);
863}
864
865static int v2_finish(struct slpv2_hdr *slp, int flags) {
866	unsigned int firstop;
867
868	if (!(flags & F_DTAIL))
869	    return (1);
870
871	/* check for options */
872	get_int24(&(slp->o1));
873	firstop = netval;
874
875	if (firstop) {
876	    unsigned short op_id;
877	    unsigned short nextop;
878	    char *op_class;
879
880	    for (;;) {
881		unsigned short real_oplen;
882
883		if (msglength < 4) {
884		    sprintf(get_line(0, 0),
885			    "Option expected but not present");
886		    return (0);
887		}
888
889		nbtohs();
890		op_id = netval;
891		p += sizeof (unsigned short);
892		msglength -= sizeof (unsigned short);
893		nbtohs();
894		nextop = netval;
895		p += sizeof (unsigned short);
896		msglength -= sizeof (unsigned short);
897
898		real_oplen = nextop ? nextop : msglength;
899
900		/* known options */
901		switch (op_id) {
902		case 1:
903		    sprintf(get_line(0, 0),
904			    "Option: Required Attribute Missing");
905		    DOFIELD("Template IDVer", FIELD_DEFAULT);
906		    DOFIELD("Required Attrs", FIELD_DEFAULT);
907		    break;
908		default:
909		    sprintf(get_line(0, 0), "Option: Unknown");
910		    p += (real_oplen - 4);
911		    msglength -= (real_oplen - 4);
912		    break;
913		}
914
915		if (op_id < 0x3fff)
916		    op_class = "Standardized, optional";
917		else if (op_id < 0x7fff)
918		    op_class = "Standardized, mandatory";
919		else if (op_id < 0x8fff)
920		    op_class = "Not standardized, private";
921		else if (op_id < 0xffff)
922		    op_class = "Reserved";
923		sprintf(get_line(0, 0), "Option ID = 0x%04x, %s",
924			op_id, op_class);
925		if (nextop &&
926		    ((nextop - 4) > msglength) &&
927		    !tcp_continuation) {
928		    sprintf(get_line(0, 0),
929			    "[Framing error: remaining pkt length = %u]",
930			    msglength);
931		    return (0);
932		}
933
934		sprintf(get_line(0, 0), "Option Length = %u", real_oplen);
935
936		if (!nextop)
937		    break;
938	    }
939	}
940
941	return (1);
942}
943
944#ifdef VERIFYSLP
945static int skip_v2authblock() {
946	unsigned short length, slen;
947
948	/* auth header */
949	if (msglength < 10)
950	    return (-1);
951
952	/* block descriptor: 2 bytes */
953	p += sizeof (unsigned short);
954	/* length */
955	nbtohs();
956	length = netval;
957	p += sizeof (unsigned short);
958	/* timestamp */
959	p += 4;
960	/* SPI String length */
961	nbtohs();
962	slen = netval;
963	p += sizeof (unsigned short);
964
965	msglength -= 10;
966	if (slen > msglength || length > (msglength + 10))
967	    return (-1);
968
969	p += slen;
970	msglength -= slen;
971
972	/* structured auth block */
973	p += (length - 10 - slen);
974	msglength -= (length - 10 - slen);
975	return (0);
976}
977#endif
978
979static char *display_bsd(unsigned short bsd) {
980	switch (bsd) {
981	case 1: return ("MD5 with RSA");
982	case 2: return ("DSA with SHA-1");
983	case 3: return ("Keyed HMAC with MD5");
984	default: return ("Unknown BSD");
985	}
986}
987
988static char *slpv2_func(int t, boolean_t s) {
989	static char buf[128];
990
991	switch (t) {
992	case V2_SRVRQST:	return s? "SrvRqst"  : "Service Request";
993	case V2_SRVRPLY:	return s? "SrvRply"  : "Service Reply";
994	case V2_SRVREG:		return s? "SrvReg"   : "Service Registration";
995	case V2_SRVDEREG:
996	    return (s ? "SrvDereg" : "Service Deregistration");
997	case V2_SRVACK:		return s? "SrvAck"   : "Service Acknowledge";
998	case V2_ATTRRQST:	return s? "AttrRqst" : "Attribute Request";
999	case V2_ATTRRPLY:	return s? "AttrRply" : "Attribute Reply";
1000	case V2_DAADVERT:	return s? "DAAdvert" : "DA advertisement";
1001	case V2_SRVTYPERQST:
1002	    return (s ? "SrvTypeRqst" : "Service Type Request");
1003	case V2_SRVTYPERPLY:
1004	    return (s ? "SrvTypeRply" : "Service Type Reply");
1005	case V2_SAADVERT:	return s? "SAAdvert" : "SA advertisement";
1006	}
1007	sprintf(buf, "(func %d)", t);
1008	return (s ? buf : "unknown function");
1009}
1010
1011static char *slpv2_error(unsigned short code) {
1012	static char buf[128];
1013
1014	switch (code) {
1015	case OK:			return "ok";
1016	case LANG_NOT_SUPPORTED:	return "language not supported";
1017	case PROTOCOL_PARSE_ERR:	return "protocol parse error";
1018	case INVALID_REGISTRATION:	return "invalid registration";
1019	case SCOPE_NOT_SUPPORTED:	return "scope not supported";
1020	case AUTHENTICATION_UNKNOWN:	return "authentication unknown";
1021	case V2_AUTHENTICATION_ABSENT:	return "authentication absent";
1022	case V2_AUTHENTICATION_FAILED:	return "authentication failed";
1023	case V2_VER_NOT_SUPPORTED:	return "version not supported";
1024	case V2_INTERNAL_ERROR:		return "internal error";
1025	case V2_DA_BUSY_NOW:		return "DA busy";
1026	case V2_OPTION_NOT_UNDERSTOOD:	return "option not understood";
1027	case V2_INVALID_UPDATE:		return "invalid update";
1028	case V2_RQST_NOT_SUPPORTED:	return "request not supported";
1029	case INVALID_LIFETIME:		return "invalid lifetime";
1030	}
1031	sprintf(buf, "error %d", code);
1032	return (buf);
1033}
1034
1035static char *convert_ts(unsigned int timestamp) {
1036	/* timestamp is in UNIX time */
1037	static char buff[128];
1038
1039	strcpy(buff, ctime((time_t *)&timestamp));
1040	buff[strlen(buff) - 1] = '\0';
1041	return (buff);
1042}
1043
1044static int slpv2_authblock(int cnt) {
1045	unsigned short bsd, length, slen;
1046	char *pp, *scopes;
1047	unsigned int timestamp;
1048
1049	if (msglength < 10) {
1050	    sprintf(get_line(0, 0),
1051		"  [no room for auth block header: remaining msg length = %u]",
1052		    msglength);
1053	    return (-1);
1054	}
1055
1056	/* bsd */
1057	nbtohs();
1058	bsd = netval;
1059	p += sizeof (unsigned short);
1060
1061	/* length */
1062	nbtohs();
1063	length = netval;
1064	p += sizeof (unsigned short);
1065
1066	/* timestamp */
1067	nbtohl();
1068	timestamp = netval;
1069	p += 4;
1070
1071	/* SPI String length */
1072	nbtohs();
1073	slen = netval;
1074	p += sizeof (unsigned short);
1075
1076	msglength -= 10;
1077	if (slen > msglength) {
1078	    sprintf(get_line(0, 0),
1079		"  [no room for auth block scopes: remaining msg length = %u]",
1080		    msglength);
1081	    return (-1);
1082	}
1083
1084	if (length > (msglength + 10)) {
1085	    if (!tcp_continuation)
1086		/* framing error: message is not long enough to contain data */
1087		sprintf(get_line(0, 0),
1088			"  [Framing error: remaining pkt length = %u]",
1089			msglength);
1090	    return (-1);
1091	}
1092
1093	scopes = p;
1094	p += slen;
1095	msglength -= slen;
1096
1097	sprintf(get_line(0, 0),
1098	    "Auth block %d: timestamp = %s", cnt,
1099	    (timestamp) ? convert_ts(timestamp) : "0");
1100
1101	pp = get_line(0, 0);
1102	strcpy(pp, "              SPI = ");
1103	strncat(pp, scopes, slen);
1104
1105	sprintf(get_line(0, 0),
1106	    "              block desc = 0x%04x: %s", bsd, display_bsd(bsd));
1107
1108	sprintf(get_line(0, 0), "              length = %u", length);
1109
1110	p += (length - 10 - slen);
1111	msglength -= (length - 10 - slen);
1112	return (0);
1113}
1114
1115static int v2_srv_rqst(int flags) {
1116	if (flags & F_SUM) {
1117		SKIPFIELD(FIELD_DEFAULT);	/* PR list */
1118		GETFIELD;			/* service type */
1119		SKIPFIELD(FIELD_DEFAULT);	/* scopes */
1120		strcat(msgend, " [");
1121		GETFIELD;			/* predicate */
1122		strcat(msgend, "]");
1123		SKIPFIELD(FIELD_DEFAULT);	/* SPI */
1124	} else if (flags & F_DTAIL) {
1125		DOFIELD("Previous responders", FIELD_DEFAULT);
1126		DOFIELD("Service type",  FIELD_DEFAULT);
1127		DOFIELD("Scopes",  FIELD_DEFAULT);
1128		DOFIELD("Predicate string",  FIELD_DEFAULT);
1129		DOFIELD("Requested SPI", FIELD_DEFAULT);
1130	}
1131
1132	return (1);
1133}
1134
1135static int v2_srv_rply(int flags) {
1136	unsigned short itemcnt, errcode;
1137	int n;
1138
1139	if (flags & F_SUM) {
1140	    int i, auth_cnt;
1141
1142	    GETSHORT(errcode);
1143	    if (errcode != OK) {
1144		strcat(msgbuf, slpv2_error(errcode));
1145		msglength = 0;	/* skip rest of message */
1146		return (0);
1147	    } else {
1148		GETSHORT(itemcnt);
1149		sprintf(msgend, "%d URL entries", itemcnt);
1150#ifdef VERIFYSLP
1151		for (n = 0; n < itemcnt; n++) {
1152		    SKIPBYTE;			/* reserved */
1153		    SKIPSHORT;			/* lifetime */
1154		    SKIPFIELD(FIELD_DEFAULT);	/* URL */
1155		    GETBYTE(auth_cnt);
1156		    for (i = 0; i < auth_cnt; auth_cnt++)
1157			if (skip_v2authblock() < 0)
1158			    return (0);
1159		}
1160#endif
1161	    }
1162	} else if (flags & F_DTAIL) {
1163	    V2_DOERRCODE;
1164	    GETSHORT(itemcnt);
1165	    sprintf(get_line(0, 0), "URL entry count = %d", itemcnt);
1166	    for (n = 0; n < itemcnt; n++) {
1167		V2_DOURL(n);
1168	    }
1169	}
1170
1171	return (1);
1172}
1173
1174static int v2_srv_reg(int flags) {
1175	int i, auth_cnt;
1176
1177	if (flags & F_SUM) {
1178	    SKIPBYTE;			/* reserved */
1179	    SKIPSHORT;			/* lifetime */
1180	    GETFIELD;			/* URL */
1181#ifdef VERIFYSLP
1182	    GETBYTE(auth_cnt);
1183	    for (i = 0; i < auth_cnt; i++)
1184		if (skip_v2authblock() < 0)
1185		    return (0);
1186	    SKIPFIELD(FIELD_DEFAULT);	/* type */
1187	    SKIPFIELD(FIELD_DEFAULT);	/* scopes */
1188	    SKIPFIELD(FIELD_DEFAULT);	/* attrs */
1189	    GETBYTE(auth_cnt);
1190	    for (i = 0; i < auth_cnt; i++)
1191		if (skip_v2authblock() < 0)
1192		    return (0);
1193#endif
1194	} if (flags & F_DTAIL) {
1195	    V2_DOURL(-1);
1196	    DOFIELD("Service type", FIELD_DEFAULT);
1197	    DOFIELD("Scopes", FIELD_DEFAULT);
1198	    DOFIELD("Attribute list", FIELD_DEFAULT);
1199	    /* auth */
1200	    GETBYTE(auth_cnt);
1201	    for (i = 0; i < auth_cnt; i++)
1202		V2_DOAUTH(i);
1203	}
1204
1205	return (1);
1206}
1207
1208static int v2_srv_dereg(int flags) {
1209	if (flags & F_SUM) {
1210	    int i, auth_cnt;
1211
1212	    SKIPFIELD(FIELD_DEFAULT);	/* scopes */
1213	    SKIPBYTE;			/* reserved */
1214	    SKIPSHORT;			/* lifetime */
1215	    GETFIELD;			/* URL */
1216
1217#ifdef VERIFYSLP
1218	    GETBYTE(auth_cnt);
1219	    for (i = 0; i < auth_cnt; i++)
1220		if (skip_v2authblock() < 0)
1221		    return (0);
1222	    SKIPFIELD(FIELD_DEFAULT);	/* attrs */
1223#endif
1224	} else if (flags & F_DTAIL) {
1225	    DOFIELD("Scopes", FIELD_DEFAULT);
1226	    V2_DOURL(-1);
1227	    DOFIELD("Tag list",  FIELD_DEFAULT);
1228	}
1229
1230	return (1);
1231}
1232
1233static int v2_srv_ack(int flags) {
1234	unsigned short errcode;
1235	if (flags & F_SUM) {
1236	    GETSHORT(errcode);
1237	    strcat(msgbuf, slpv2_error(errcode));
1238	} else if (flags & F_DTAIL) {
1239	    V2_DOERRCODE;
1240	}
1241
1242	return (1);
1243}
1244
1245static int v2_attr_rqst(int flags) {
1246	if (flags  & F_SUM) {
1247	    SKIPFIELD(FIELD_DEFAULT);	/* PR list */
1248	    GETFIELD;			/* URL */
1249	    SKIPFIELD(FIELD_DEFAULT);	/* scopes */
1250	    strcat(msgend, " [");
1251	    GETFIELD;			/* attrs */
1252	    strcat(msgend, "]");
1253
1254#ifdef VERIFYSLP
1255	    SKIPFIELD(FIELD_DEFAULT);	/* SPI */
1256#endif
1257	} else if (flags & F_DTAIL) {
1258	    DOFIELD("Previous responders", FIELD_DEFAULT);
1259	    DOFIELD("URL",  FIELD_DEFAULT);
1260	    DOFIELD("Scopes",  FIELD_DEFAULT);
1261	    DOFIELD("Tag list",  FIELD_DEFAULT);
1262	    DOFIELD("Requested SPI", FIELD_DEFAULT);
1263	}
1264
1265	return (1);
1266}
1267
1268static int v2_attr_rply(int flags) {
1269	int auth_cnt, i;
1270	unsigned short errcode;
1271
1272	if (flags & F_SUM) {
1273	    GETSHORT(errcode);
1274	    if (errcode != OK) {
1275		strcat(msgbuf, slpv2_error(errcode));
1276		msglength = 0;	/* skip rest of message */
1277		return (0);
1278	    } else {
1279		GETFIELD;			/* attr list */
1280
1281#ifdef VERIFYSLP
1282		GETBYTE(auth_cnt);
1283		for (i = 0; i < auth_cnt; i++)
1284		    if (skip_v2authblock() < 0)
1285			return (0);
1286#endif
1287	    }
1288	} else if (flags & F_DTAIL) {
1289	    V2_DOERRCODE;
1290	    DOFIELD("Attribute list", FIELD_DEFAULT);
1291	    /* auth */
1292	    GETBYTE(auth_cnt);
1293	    for (i = 0; i < auth_cnt; i++)
1294		V2_DOAUTH(i);
1295	}
1296
1297	return (1);
1298}
1299
1300static int v2_daadvert(int flags) {
1301	int auth_cnt, i;
1302	unsigned short errcode;
1303	unsigned int timestamp;
1304
1305	if (flags & F_SUM) {
1306	    SKIPSHORT;			/* error code */
1307	    SKIPSHORT; SKIPSHORT;	/* timestamp */
1308	    GETFIELD;			/* URL */
1309
1310#ifdef VERIFYSLP
1311	    SKIPFIELD(FIELD_DEFAULT);	/* scopes */
1312	    SKIPFIELD(FIELD_DEFAULT);	/* attrs */
1313	    SKIPFIELD(FIELD_DEFAULT);	/* SPIs */
1314
1315	    GETBYTE(auth_cnt);
1316	    for (i = 0; i < auth_cnt; i++)
1317		if (skip_v2authblock() < 0)
1318		    return (0);
1319#endif
1320	} else if (flags & F_DTAIL) {
1321	    V2_DOERRCODE;
1322	    V2_DOTIMESTAMP;
1323	    DOFIELD("URL", FIELD_DEFAULT);
1324	    DOFIELD("Scope list", FIELD_DEFAULT);
1325	    DOFIELD("Attribute list", FIELD_DEFAULT);
1326	    DOFIELD("Configured SPIs", FIELD_DEFAULT);
1327	    /* auth */
1328	    GETBYTE(auth_cnt);
1329	    for (i = 0; i < auth_cnt; i++)
1330		V2_DOAUTH(i);
1331	}
1332
1333	return (1);
1334}
1335
1336static int v2_srv_type_rqst(int flags) {
1337	if (flags & F_SUM) {
1338	    SKIPFIELD(FIELD_DEFAULT);	/* prev responders */
1339	    SKIPFIELD(FIELD_TYPENA);	/* naming authority */
1340	    GETFIELD;			/* scope */
1341	} else if (flags & F_DTAIL) {
1342	    DOFIELD("Previous responders", FIELD_DEFAULT);
1343	    DOFIELD("Naming authority", FIELD_TYPENA);
1344	    DOFIELD("Scopes",  FIELD_DEFAULT);
1345	}
1346
1347	return (1);
1348}
1349
1350static int v2_srv_type_rply(int flags) {
1351	unsigned short errcode;
1352
1353	if (flags & F_SUM) {
1354	    GETSHORT(errcode);
1355	    if (errcode != OK)
1356		strcat(msgbuf, slpv2_error(errcode));
1357	    else
1358		GETFIELD;
1359	} else if (flags & F_DTAIL) {
1360		V2_DOERRCODE;
1361		DOFIELD("Service types", FIELD_DEFAULT);
1362	}
1363
1364	return (1);
1365}
1366
1367static int v2_saadvert(int flags) {
1368	int auth_cnt, i;
1369
1370	if (flags & F_SUM) {
1371	    GETFIELD;			/* URL */
1372
1373#ifdef VERIFYSLP
1374	    SKIPFIELD(FIELD_DEFAULT);	/* scopes */
1375	    SKIPFIELD(FIELD_DEFAULT);	/* attrs */
1376
1377	    GETBYTE(auth_cnt);
1378	    for (i = 0; i < auth_cnt; i++)
1379		if (skip_v2authblock() < 0)
1380		    return (0);
1381#endif
1382	} else if (flags & F_DTAIL) {
1383	    DOFIELD("URL", FIELD_DEFAULT);
1384	    DOFIELD("Scopes",  FIELD_DEFAULT);
1385	    DOFIELD("Attribute list", FIELD_DEFAULT);
1386	    /* auth */
1387	    GETBYTE(auth_cnt);
1388	    for (i = 0; i < auth_cnt; i++)
1389		V2_DOAUTH(i);
1390	}
1391
1392	return (1);
1393}
1394
1395/*
1396 * V1 Interpreter
1397 */
1398
1399static int interpret_slp_v1(int flags, struct slpv1_hdr *slp, int fraglen) {
1400	char msgbuf_real[256];
1401	extern int src_port, dst_port, curr_proto;
1402	boolean_t overflow	= B_FALSE;
1403
1404	msgbuf = msgbuf_real;
1405
1406	if (msglength >= sizeof (*slp)) {
1407	    if ((slp->flags & V1_URL_AUTH) == V1_URL_AUTH)
1408		url_auth = B_TRUE;
1409	    if ((slp->flags & V1_ATTR_AUTH) == V1_ATTR_AUTH)
1410		attr_auth = B_TRUE;
1411	    if ((slp->flags & V1_FRESH_REG) == V1_FRESH_REG)
1412		fresh = B_TRUE;
1413	    if ((slp->flags & V1_OVERFLOW) == V1_OVERFLOW)
1414		overflow = B_TRUE;
1415	}
1416
1417	/*
1418	 * Somewhat of a hack to decode traffic from a server that does
1419	 * not send udp replies from its SLP src port.
1420	 */
1421	if (curr_proto == IPPROTO_UDP &&
1422	    dst_port == 427 &&
1423	    src_port != 427)
1424		add_transient(src_port, interpret_slp);
1425
1426	/* parse the header */
1427	if (v1_header(flags, slp, fraglen)) {
1428
1429	    if (slp->function <= V1_MAX_FUNCTION && slp->function > 0) {
1430
1431		/* Parse the message body */
1432		(v1_functions[slp->function])(flags);
1433
1434	    }
1435
1436	}
1437
1438	/* summary error check */
1439	if (flags & F_SUM) {
1440	    if (retlength < 0) {
1441		if (curr_proto == IPPROTO_TCP)
1442		    sprintf(get_sum_line(),
1443			    "%s [partial TCP message]",
1444			    msgbuf);
1445		else if (overflow)
1446		    sprintf(get_sum_line(), "%s [OVERFLOW]", msgbuf);
1447		else
1448		    sprintf(get_sum_line(), "%s [CORRUPTED MESSAGE]", msgbuf);
1449	    }
1450#ifdef VERIFYSLP
1451	    else if (msglength > 0)
1452		sprintf(get_sum_line(), "%s +%d", msgbuf, msglength);
1453#endif
1454	    else
1455		sprintf(get_sum_line(), "%s", msgbuf);
1456	} else if (flags & F_DTAIL) {
1457	    /* detail error check */
1458	    if (msglength > 0) {
1459		sprintf(get_line(0, 0),
1460			"[%d extra bytes at end of SLP message]", msglength);
1461	    }
1462
1463	    show_trailer();
1464
1465	}
1466
1467	v1_charset = 0;
1468
1469	return (0);
1470}
1471
1472static int v1_header(int flags,
1473			struct slpv1_hdr *slp,
1474			int fraglen) {
1475	extern int src_port, dst_port, curr_proto;
1476	char *prototag = (curr_proto == IPPROTO_TCP? "/tcp" : "");
1477
1478	if (flags & F_SUM) {
1479	    char portflag = ' ';
1480
1481	    if (msglength < sizeof (*slp)) {
1482		sprintf(msgbuf, "SLP V1 [incomplete header]");
1483		return (0);
1484	    }
1485
1486	    if (slp->vers != 1) {
1487		if (curr_proto == IPPROTO_TCP)
1488		    sprintf(msgbuf, "SLP [TCP Continuation]");
1489		else
1490		    sprintf(msgbuf, "SLP [unknown version %d]", slp->vers);
1491		return (0);
1492	    }
1493
1494	    if (src_port != 427 && dst_port != 427)
1495		portflag = '-';
1496
1497	    sprintf(msgbuf, "SLP V1%c%s [%d%s] ", portflag,
1498		    slpv1_func(slp->function, B_TRUE),
1499		    ntohs(slp->xid), prototag);
1500	    msgend = msgbuf + strlen(msgbuf);
1501	    msglength -= sizeof (*slp);
1502	    p += sizeof (*slp);
1503	} else if (flags & F_DTAIL) {
1504	    show_header("SLP:  ", "Service Location Protocol (v1)", fraglen);
1505	    show_space();
1506
1507	    if (msglength < sizeof (*slp)) {
1508		sprintf(get_line(0, 0), "==> Incomplete SLP header");
1509		return (0);
1510	    }
1511
1512	    sprintf(get_line(0, 0), "Version = %d", slp->vers);
1513	    if (slp->vers != 1) {
1514		if (curr_proto == IPPROTO_TCP)
1515		    sprintf(get_line(0, 0), "==> TCP continuation");
1516		else
1517		    sprintf(get_line(0, 0), "==> Unexpected version number");
1518		return (0);
1519	    }
1520	    sprintf(get_line(0, 0), "Function = %d, %s",
1521		slp->function, slpv1_func(slp->function, B_FALSE));
1522	    sprintf(get_line(0, 0), "Message length = %u", ntohs(slp->length));
1523
1524	    /* flags */
1525	    sprintf(get_line(0, 0), "Flags = 0x%02x", slp->flags);
1526	    sprintf(get_line(0, 0), "      %s",
1527		    getflag(slp->flags, V1_OVERFLOW,
1528			    "overflow", "no overflow"));
1529	    sprintf(get_line(0, 0), "      %s",
1530		    getflag(slp->flags, V1_MONOLINGUAL,
1531			    "monolingual", "not monolingual"));
1532	    sprintf(get_line(0, 0), "      %s",
1533		    getflag(slp->flags, V1_URL_AUTH,
1534			    "url authentication", "no url authentication"));
1535	    sprintf(get_line(0, 0), "      %s",
1536		    getflag(slp->flags, V1_ATTR_AUTH,
1537		"attribute authentication", "no attribute authentication"));
1538	    sprintf(get_line(0, 0), "      %s",
1539		    getflag(slp->flags, V1_FRESH_REG,
1540			    "fresh registration", "no fresh registration"));
1541	    /* check reserved flags that must be zero */
1542	    if ((slp->flags & 7) != 0) {
1543		sprintf(get_line(0, 0),
1544			"      .... .xxx = %d (reserved flags nonzero)",
1545			slp->flags & 7);
1546	    }
1547	    /* end of flags */
1548
1549	    sprintf(get_line(0, 0), "Dialect = %u", slp->dialect);
1550	    sprintf(get_line(0, 0), "Language = 0x%02x%02x, %c%c",
1551		    slp->language[0], slp->language[1],
1552		    slp->language[0], slp->language[1]);
1553	    v1_charset = ntohs(slp->charset);
1554	    sprintf(get_line(0, 0), "Character encoding = %u, %s",
1555		    v1_charset,
1556		    slpv1_charset(v1_charset));
1557	    sprintf(get_line(0, 0), "XID = %u", ntohs(slp->xid));
1558
1559	    /* set msglength to remaining length of SLP message */
1560	    msglength -= sizeof (*slp);
1561	    p += sizeof (*slp);
1562	}
1563
1564	return (1);
1565}
1566
1567static char *slpv1_func(int t, boolean_t s) {
1568	static char buf[128];
1569	switch (t) {
1570	case V1_SRVREQ:	return s? "SrvRqst"  : "Service Request";
1571	case V1_SRVRPLY:	return s? "SrvRply"  : "Service Reply";
1572	case V1_SRVREG:	return s? "SrvReg"   : "Service Registration";
1573	case V1_SRVDEREG:	return s?
1574					"SrvDereg" : "Service Deregistration";
1575	case V1_SRVACK:	return s? "SrvAck"   : "Service Acknowledge";
1576	case V1_ATTRRQST:	return s? "AttrRqst" : "Attribute Request";
1577	case V1_ATTRRPLY:	return s? "AttrRply" : "Attribute Reply";
1578	case V1_DAADVERT:	return s? "DAAdvert" : "DA advertisement";
1579	case V1_SRVTYPERQST:return s? "SrvTypeRqst" : "Service Type Request";
1580	case V1_SRVTYPERPLY:return s? "SrvTypeRply" : "Service Type Reply";
1581	}
1582	sprintf(buf, "(func %d)", t);
1583	return (s ? buf : "unknown function");
1584}
1585
1586static char *slpv1_error(unsigned short code) {
1587	static char buf[128];
1588
1589	switch (code) {
1590	    case OK:			return "ok";
1591	    case LANG_NOT_SUPPORTED:	return "language not supported";
1592	    case PROTOCOL_PARSE_ERR:	return "protocol parse error";
1593	    case INVALID_REGISTRATION:	return "invalid registration";
1594	    case SCOPE_NOT_SUPPORTED:	return "scope not supported";
1595	    case CHARSET_NOT_UNDERSTOOD:return "character set not understood";
1596	    case AUTHENTICATION_INVALID:return "invalid authentication";
1597	    case NOT_SUPPORTED_YET:	return "not yet supported";
1598	    case REQUEST_TIMED_OUT:	return "request timed out";
1599	    case COULD_NOT_INIT_NET_RESOURCES:
1600				return ("could not initialize net resources");
1601	    case COULD_NOT_ALLOCATE_MEMORY:
1602					return ("could not allocate memory");
1603	    case PARAMETER_BAD:		return "bad parameter";
1604	    case INTERNAL_NET_ERROR:	return "internal network error";
1605	    case INTERNAL_SYSTEM_ERROR:	return "internal system error";
1606	}
1607	sprintf(buf, "error %d", code);
1608	return (buf);
1609}
1610
1611/*
1612 *  Character set info from
1613 *    www.isi.edu/in-notes/iana/assignments/character-sets
1614 *
1615 *	Assigned MIB enum Numbers
1616 *	-------------------------
1617 *	0               Reserved
1618 *	1               Reserved
1619 *	3-106           Set By Standards Organizations
1620 *	1000-1010       Unicode / 10646
1621 *	2000-2087       Vendor
1622 *	2250-2258       Vendor
1623 *
1624 *	MIBenum: 3
1625 *	Alias: US-ASCII (preferred MIME name)
1626 *	Source: ECMA registry [RFC1345]
1627 *
1628 *	MIBenum: 106
1629 *	Name: UTF-8
1630 *	Source: RFC 2044
1631 */
1632
1633static char *slpv1_charset(unsigned short code) {
1634	if (code <= 1)
1635	    return ("Reserved");
1636	if (code == 3)
1637	    return ("US-ASCII");
1638	if (code == 4)
1639	    return ("latin1");
1640	if (code == 106)
1641	    return ("UTF-8");
1642	if (code >= 3 && code <= 106)
1643	    return ("set by standards organization");
1644	if (code >= 1000 && code <= 1010)
1645	    return ("Unicode variant");
1646	if ((code >= 2000 && code <= 2087) ||
1647	    (code >= 2250 && code <= 2258))
1648	    return ("Vendor assigned");
1649
1650	return ("unknown");
1651}
1652
1653#ifdef VERIFYSLP
1654static int skip_v1authblock() {
1655	unsigned short length;
1656
1657	/* auth header: 12 bytes total */
1658	if (msglength < 12)
1659	    return (-1);
1660
1661	/* timestamp: 8 bytes */
1662	p += 8;			/* timestamp: 8 bytes */
1663	p += sizeof (short);		/* block descriptor: 2 bytes */
1664	nbtohs();
1665	length = netval;
1666	p += sizeof (short);
1667	msglength -= 12;
1668
1669	if (length > msglength) {
1670	    /* framing error: message is not long enough to contain data */
1671	    return (-1);
1672	}
1673
1674	p += length;
1675	msglength -= length;
1676	return (0);
1677}
1678#endif
1679
1680static int slpv1_authblock() {
1681	unsigned short bsd, length;
1682	char msgbuf[128];
1683	int n;
1684
1685	if (msglength < 12) {
1686	    sprintf(get_line(0, 0),
1687		    "  [no room for auth block: remaining msg length = %u]",
1688		    msglength);
1689	    return (-1);
1690	}
1691
1692	/* timestamp: 8 bytes */
1693	*msgbuf = '\0';
1694	for (n = 0; n < 8; n++, p += 1) {
1695	    char tmp[16];
1696	    sprintf(tmp, "%02x", (unsigned char)(*p));
1697	    strcat(msgbuf, tmp);
1698	}
1699
1700	nbtohs();
1701	bsd = netval;
1702	p += sizeof (short);
1703	nbtohs();
1704	length = netval;
1705	p += sizeof (short);
1706	msglength -= 12;
1707
1708	sprintf(get_line(0, 0),
1709		"  Auth block: timestamp = %s",
1710		msgbuf);
1711	sprintf(get_line(0, 0),
1712		"              block desc = 0x%04x, length = %u",
1713		bsd, length);
1714	if (length > msglength) {
1715	    /* framing error: message is not long enough to contain data */
1716	    sprintf(get_line(0, 0),
1717		"  [Framing error: remaining pkt length = %u]",  msglength);
1718	    return (-1);
1719	}
1720
1721	p += length;
1722	msglength -= length;
1723	return (0);
1724}
1725
1726static int slpv1_url(boolean_t auth_present) {
1727	time_t exp;
1728	int lifetime, length;
1729
1730	get_short();
1731	if ((lifetime = netval) < 0)
1732	    return (-1);
1733	get_short();
1734	if ((length = netval) < 0)
1735	    return (-1);
1736
1737	exp = time(0) + lifetime;
1738	sprintf(get_line(0, 0), "URL: length = %u, lifetime = %d (%24.24s)",
1739		length, lifetime, ctime(&exp));
1740	if (length > msglength) {
1741	    /* framing error: message is not long enough to contain data */
1742	    sprintf(get_line(0, 0),
1743		"  [Framing error: remaining pkt length = %u]",  msglength);
1744	    return (-1);
1745	}
1746
1747	if (length > 0) {
1748	    char *buf = malloc(length + 1);
1749	    if (buf != NULL) {
1750		if (!make_utf8(buf, length, p, length)) {
1751			strcpy(buf, "[Invalid Character Encoding]");
1752		}
1753		sprintf(get_line(0, 0), "  \"%s\"", buf);
1754		free(buf);
1755	    }
1756	}
1757	msglength -= length;
1758	p += length;
1759
1760	if (auth_present)
1761	    return (slpv1_authblock());
1762
1763	return (0);
1764}
1765
1766static int v1_srv_rqst(int flags) {
1767	if (flags & F_SUM) {
1768	    SKIPFIELD(FIELD_PREVRESP);	/* prev responders */
1769	    GETFIELD;			/* predicate */
1770	} else if (flags & F_DTAIL) {
1771	    DOFIELD("Previous responders", FIELD_PREVRESP);
1772	    DOFIELD("predicate string", FIELD_DEFAULT);
1773	}
1774
1775	return (1);
1776}
1777
1778static int v1_srv_rply(int flags) {
1779	unsigned short errcode, itemcnt;
1780	int n;
1781
1782	if (flags & F_SUM) {
1783	    GETSHORT(errcode);
1784	    if (errcode != OK) {
1785		strcat(msgbuf, slpv1_error(errcode));
1786	    } else {
1787		GETSHORT(itemcnt);
1788		sprintf(msgend, "%d URL entries", itemcnt);
1789#ifdef VERIFYSLP
1790		for (n = 0; n < itemcnt; n++) {
1791		    SKIPSHORT;		/* lifetime */
1792		    SKIPFIELD(FIELD_DEFAULT);	/* URL */
1793		    SKIPAUTH(url_auth);		/* URL auth */
1794		}
1795#endif
1796	    }
1797	} else if (flags & F_DTAIL) {
1798	    DOERRCODE;
1799	    GETSHORT(itemcnt);
1800	    sprintf(get_line(0, 0), "URL entry count = %d", itemcnt);
1801	    for (n = 0; n < itemcnt; n++) {
1802		DOURL;
1803	    }
1804	}
1805
1806	return (1);
1807}
1808
1809static int v1_srv_reg(int flags) {
1810	if (flags & F_SUM) {
1811	    SKIPSHORT;			/* lifetime */
1812	    GETFIELD;			/* URL */
1813#ifdef VERIFYSLP
1814	    SKIPAUTH(url_auth);		/* URL auth */
1815	    SKIPFIELD(FIELD_DEFAULT);	/* attribute list */
1816	    SKIPAUTH(attr_auth);		/* attr auth */
1817#endif
1818	} else if (flags & F_DTAIL) {
1819	    DOURL;
1820	    DOFIELD("Attribute list", FIELD_DEFAULT);
1821	    DOAUTH(attr_auth);
1822	}
1823
1824	return (1);
1825}
1826
1827static int v1_srv_ack(int flags) {
1828	unsigned short errcode;
1829
1830	if (flags & F_SUM) {
1831	    GETSHORT(errcode);
1832	    strcat(msgbuf, slpv1_error(errcode));
1833	    if (errcode == OK && fresh) {
1834		strcat(msgbuf, " [Fresh]");
1835	    }
1836	} else if (flags & F_DTAIL) {
1837	    DOERRCODE;
1838	}
1839
1840	return (1);
1841}
1842
1843static int v1_srv_dereg(int flags) {
1844	if (flags & F_SUM) {
1845	    GETFIELD;			/* URL */
1846#ifdef VERIFYSLP
1847	    SKIPAUTH(url_auth);
1848	    SKIPFIELD(FIELD_DEFAULT);	/* tag spec */
1849#endif
1850	} else if (flags & F_DTAIL) {
1851	    DOFIELD("URL", FIELD_DEFAULT);
1852	    DOAUTH(url_auth);
1853	    DOFIELD("Tag spec", FIELD_DEFAULT);
1854	}
1855
1856	return (1);
1857}
1858
1859static int v1_attr_rqst(int flags) {
1860	if (flags & F_SUM) {
1861	    SKIPFIELD(FIELD_PREVRESP);	/* prev responders */
1862	    GETFIELD;			/* URL */
1863#ifdef VERIFYSLP
1864	    SKIPFIELD(FIELD_DEFAULT);	/* scope */
1865	    SKIPFIELD(FIELD_DEFAULT);	/* select list */
1866#endif
1867	} else if (flags & F_DTAIL) {
1868	    DOFIELD("Previous responders", FIELD_PREVRESP);
1869	    DOFIELD("URL", FIELD_DEFAULT);
1870	    DOFIELD("Scope", FIELD_DEFAULT);
1871	    DOFIELD("Select list", FIELD_DEFAULT);
1872	}
1873
1874	return (1);
1875}
1876
1877static int v1_attr_rply(int flags) {
1878	unsigned short errcode;
1879
1880	if (flags & F_SUM) {
1881	    GETSHORT(errcode);
1882	    if (errcode != OK) {
1883		strcat(msgbuf, slpv1_error(errcode));
1884	    } else {
1885		GETFIELD;			/* attr list */
1886#ifdef VERIFYSLP
1887		SKIPAUTH(attr_auth);
1888#endif
1889	    }
1890	} else if (flags & F_DTAIL) {
1891	    DOERRCODE;
1892	    DOFIELD("Attribute list", FIELD_DEFAULT);
1893	    DOAUTH(attr_auth);
1894	}
1895
1896	return (1);
1897}
1898
1899static int v1_daadvert(int flags) {
1900	unsigned short errcode;
1901
1902	if (flags & F_SUM) {
1903	    GETSHORT(errcode);
1904	    if (errcode != OK) {
1905		strcat(msgbuf, slpv1_error(errcode));
1906	    } else {
1907		    GETFIELD;			/* URL */
1908#ifdef VERIFYSLP
1909		    SKIPFIELD(FIELD_DEFAULT);	/* scope list */
1910#endif
1911	    }
1912	} else if (flags & F_DTAIL) {
1913	    DOERRCODE;
1914	    DOFIELD("URL", FIELD_DEFAULT);
1915	    DOFIELD("Scope list", FIELD_DEFAULT);
1916	}
1917
1918	return (1);
1919}
1920
1921static int v1_srv_type_rqst(int flags) {
1922	if (flags & F_SUM) {
1923	    SKIPFIELD(FIELD_PREVRESP);	/* prev responders */
1924	    SKIPFIELD(FIELD_TYPENA);	/* naming authority */
1925	    GETFIELD;			/* scope */
1926	} else if (flags & F_DTAIL) {
1927	    DOFIELD("Previous responders", FIELD_PREVRESP);
1928	    DOFIELD("Naming authority", FIELD_TYPENA);
1929	    DOFIELD("Scope string", FIELD_DEFAULT);
1930	}
1931
1932	return (1);
1933}
1934
1935static int v1_srv_type_rply(int flags) {
1936	unsigned short errcode, itemcnt;
1937	int n;
1938
1939	if (flags & F_SUM) {
1940	    GETSHORT(errcode);
1941	    if (errcode != OK) {
1942		strcat(msgbuf, slpv1_error(errcode));
1943	    } else {
1944		GETSHORT(itemcnt);
1945		sprintf(msgend, "%d type entries", itemcnt);
1946#ifdef VERIFYSLP
1947		for (n = 0; n < itemcnt; n++) {
1948		    SKIPFIELD(FIELD_DEFAULT);  /* Service type item */
1949		}
1950#endif
1951	    }
1952	} else if (flags & F_DTAIL) {
1953	    DOERRCODE;
1954	    GETSHORT(itemcnt);
1955	    sprintf(get_line(0, 0), "Service type count = %d", itemcnt);
1956	    for (n = 0; n < itemcnt; n++) {
1957		DOFIELD("  Service type item", FIELD_DEFAULT);
1958	    }
1959	}
1960
1961	return (1);
1962}
1963