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 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SunOS */
29 
30 #include <ctype.h>
31 #include <sys/sysmacros.h>
32 #include <sys/types.h>
33 #include <sys/errno.h>
34 #include <setjmp.h>
35 #include <sys/socket.h>
36 #include <net/if.h>
37 #include <netinet/in_systm.h>
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
40 #include <netinet/if_ether.h>
41 #include "snoop.h"
42 
43 #define	NULL 0
44 
45 extern void interpret_mip_cntrlmsg(int, uchar_t *, int);
46 
47 struct porttable {
48 	int	pt_num;
49 	char	*pt_short;
50 	char	*pt_long;
51 };
52 
53 struct porttable pt_udp[] = {
54 	7,	"ECHO",		"Echo",
55 	9,	"DISCARD",	"Discard",
56 	13,	"DAYTIME",	"Daytime",
57 	19,	"CHARGEN",	"Character generator",
58 	37,	"TIME",		"Time",
59 	42,	"NAME",		"Host name server",
60 	53,	"DNS",		"Domain Name Server",
61 	67,	"BOOTPS",	"Bootstrap Protocol Server",
62 	68,	"BOOTPC",	"Boostrap Protocol Client",
63 	69,	"TFTP",		"Trivial File Transfer Protocol",
64 	79,	"FINGER",	"Finger",
65 /*	111,	"PORTMAP",	"Portmapper", Just Sun RPC */
66 	123,	"NTP",		"Network Time Protocol",
67 	137,	"NBNS",		"Netbios name service",
68 	138,	"NBDG",		"Netbios datagram service",
69 	389,	"LDAP",		"Lightweight Directory Access Protocol",
70 	427,	"SLP",		"Service Location Protocol",
71 /* Mobile IP defines a set of new control messages sent over UDP port 434 */
72 	434,	"Mobile IP",	"Mobile IP Control Messages",
73 	512,	"BIFF",		"BIFF",
74 	513,	"WHO",		"WHO",
75 	514,	"SYSLOG",	"SYSLOG",
76 	517,	"TALK",		"TALK",
77 	520,	"RIP",		"Routing Information Protocol",
78 	550,	"NEW-RWHO",	"NEW-RWHO",
79 	560,	"RMONITOR",	"RMONITOR",
80 	561,	"MONITOR",	"MONITOR",
81 	521,	"RIPng",	"Routing Information Protocol for IPv6",
82 	1080,	"SOCKS",	"SOCKS Gateway",
83 	0,	NULL,		"",
84 };
85 
86 struct porttable pt_tcp[] = {
87 	1,	"TCPMUX",	"TCPMUX",
88 	7,	"ECHO",		"Echo",
89 	9,	"DISCARD",	"Discard",
90 	11,	"SYSTAT",	"Active users",
91 	13,	"DAYTIME",	"Daytime",
92 	15,	"NETSTAT",	"Who is up",
93 	19,	"CHARGEN",	"Character generator",
94 	20,	"FTP-DATA",	"File Transfer Protocol (data)",
95 	21,	"FTP",		"File Transfer Protocol",
96 	23,	"TELNET",	"Terminal connection",
97 	25,	"SMTP",		"Simple Mail Transport Protocol",
98 	37,	"TIME",		"Time",
99 	39,	"RLP",		"Resource Location Protocol",
100 	42,	"NAMESERVER",	"Host Name Server",
101 	43,	"NICNAME",	"Who is",
102 	53,	"DNS",		"Domain Name Server",
103 	67,	"BOOTPS",	"Bootstrap Protocol Server",
104 	68,	"BOOTPC",	"Bootstrap Protocol Client",
105 	69,	"TFTP",		"Trivial File Transfer Protocol",
106 	70,	"GOPHER",	"Internet Gopher Protocol",
107 	77,	"RJE",		"RJE service (private)",
108 	79,	"FINGER",	"Finger",
109 	80,	"HTTP",		"HyperText Transfer Protocol",
110 	87,	"LINK",		"Link",
111 	95,	"SUPDUP",	"SUPDUP Protocol",
112 	101,	"HOSTNAME",	"NIC Host Name Server",
113 	102,	"ISO-TSAP",	"ISO-TSAP",
114 	103,	"X400",		"X400 Mail service",
115 	104,	"X400-SND",	"X400 Mail service",
116 	105,	"CSNET-NS",	"CSNET-NS",
117 	109,	"POP-2",	"POP-2",
118 /*	111,	"PORTMAP",	"Portmapper", Just Sun RPC */
119 	113,	"AUTH",		"Authentication Service",
120 	117,	"UUCP-PATH",	"UUCP Path Service",
121 	119,	"NNTP",		"Network News Transfer Protocol",
122 	123,	"NTP",		"Network Time Protocol",
123 	139,	"NBT",		"Netbios over TCP",
124 	143,	"IMAP",		"Internet Message Access Protocol",
125 	144,	"NeWS",		"Network extensible Window System",
126 	389,	"LDAP",		"Lightweight Directory Access Protocol",
127 	427,	"SLP",		"Service Location Protocol",
128 	443,	"HTTPS",	"HTTP over SSL",
129 	445,    "SMB",          "Direct Hosted Server Message Block",
130 	512,	"EXEC",		"EXEC",
131 	513,	"RLOGIN",	"RLOGIN",
132 	514,	"RSHELL",	"RSHELL",
133 	515,	"PRINTER",	"PRINTER",
134 	530,	"COURIER",	"COURIER",
135 	540,	"UUCP",		"UUCP",
136 	600,	"PCSERVER",	"PCSERVER",
137 	1524,	"INGRESLOCK",	"INGRESLOCK",
138 	1080,	"SOCKS",	"SOCKS Gateway",
139 	2904,	"M2UA",		"SS7 MTP2 User Adaption Layer",
140 	2905,	"M3UA",		"SS7 MTP3 User Adaption Layer",
141 	6000,	"XWIN",		"X Window System",
142 	8080,	"HTTP (proxy)",	"HyperText Transfer Protocol (proxy)",
143 	9900,	"IUA",		"ISDN Q.921 User Adaption Layer",
144 	0,	NULL,		"",
145 };
146 
147 char *
148 getportname(int proto, in_port_t port)
149 {
150 	struct porttable *p, *pt;
151 
152 	switch (proto) {
153 	case IPPROTO_SCTP: /* fallthru */
154 	case IPPROTO_TCP: pt = pt_tcp; break;
155 	case IPPROTO_UDP: pt = pt_udp; break;
156 	default: return (NULL);
157 	}
158 
159 	for (p = pt; p->pt_num; p++) {
160 		if (port == p->pt_num)
161 			return (p->pt_short);
162 	}
163 	return (NULL);
164 }
165 
166 int
167 reservedport(int proto, int port)
168 {
169 	struct porttable *p, *pt;
170 
171 	switch (proto) {
172 	case IPPROTO_TCP: pt = pt_tcp; break;
173 	case IPPROTO_UDP: pt = pt_udp; break;
174 	default: return (NULL);
175 	}
176 	for (p = pt; p->pt_num; p++) {
177 		if (port == p->pt_num)
178 			return (1);
179 	}
180 	return (0);
181 }
182 
183 /*
184  * Need to be able to register an
185  * interpreter for transient ports.
186  * See TFTP interpreter.
187  */
188 #define	MAXTRANS 64
189 struct ttable {
190 	int t_port;
191 	int (*t_proc)();
192 } transients [MAXTRANS];
193 
194 int
195 add_transient(int port, int (*proc)())
196 {
197 	static struct ttable *next = transients;
198 
199 	next->t_port = port;
200 	next->t_proc = proc;
201 
202 	if (++next >= &transients[MAXTRANS])
203 		next = transients;
204 
205 	return (1);
206 }
207 
208 static struct ttable *
209 is_transient(int port)
210 {
211 	struct ttable *p;
212 
213 	for (p = transients; p->t_port && p < &transients[MAXTRANS]; p++) {
214 		if (port == p->t_port)
215 			return (p);
216 	}
217 
218 	return (NULL);
219 }
220 
221 void
222 del_transient(int port)
223 {
224 	struct ttable *p;
225 
226 	for (p = transients; p->t_port && p < &transients[MAXTRANS]; p++) {
227 		if (port == p->t_port)
228 			p->t_port = -1;
229 	}
230 }
231 
232 static void
233 interpret_syslog(int flags, char dir, int port, const char *syslogstr,
234     int dlen)
235 {
236 	static const char *pris[] = {
237 	    "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug"
238 	};
239 	static const char *facs[] = {
240 	    "kern", "user", "mail", "daemon", "auth", "syslog", "lpr", "news",
241 	    "uucp", NULL, NULL, NULL, NULL, "audit", NULL, "cron", "local0",
242 	    "local1", "local2", "local3", "local4", "local5", "local6", "local7"
243 	};
244 
245 	int composit;
246 	int pri = -1;
247 	int facil = -1;
248 	boolean_t bogus = B_TRUE;
249 	int priostrlen = 0;
250 	int datalen = dlen;
251 	char unknown[4];	/* for unrecognized ones */
252 	const char *facilstr = "BAD";
253 	const char *pristr = "FMT";
254 	const char *data = syslogstr;
255 
256 	/*
257 	 * Is there enough data to interpret (left bracket + at least 3 chars
258 	 * which could be digits, right bracket, or space)?
259 	 */
260 	if (datalen >= 4 && data != NULL) {
261 		if (*data == '<') {
262 			const int FACS_LEN = sizeof (facs) / sizeof (facs[0]);
263 			char buffer[4];
264 			char *end;
265 
266 			data++;
267 			datalen--;
268 
269 			strlcpy(buffer, data, sizeof (buffer));
270 			composit = strtoul(buffer, &end, 0);
271 			data += end - buffer;
272 			if (*data == '>') {
273 				data++;
274 				datalen -= end - buffer + 1;
275 
276 				pri = composit & 0x7;
277 				facil = (composit & 0xF8) >> 3;
278 
279 				if ((facil >= FACS_LEN) ||
280 				    (facs[facil] == NULL)) {
281 					snprintf(unknown, sizeof (unknown),
282 					    "%d", facil);
283 					facilstr = unknown;
284 				} else {
285 					facilstr = facs[facil];
286 				}
287 				pristr = pris[pri];
288 				priostrlen = dlen - datalen;
289 				bogus = B_FALSE;
290 			} else {
291 				data = syslogstr;
292 				datalen = dlen;
293 			}
294 		}
295 	}
296 
297 	if (flags & F_SUM) {
298 		(void) snprintf(get_sum_line(), MAXLINE,
299 		    "SYSLOG %c port=%d %s.%s: %s",
300 		    dir, port, facilstr, pristr,
301 		    show_string(syslogstr, dlen, 20));
302 
303 	}
304 
305 	if (flags & F_DTAIL) {
306 		static char syslog[] = "SYSLOG:  ";
307 		show_header(syslog, syslog, dlen);
308 		show_space();
309 		(void) sprintf(get_detail_line(0, 80),
310 		    "%s%sPriority: %.*s%s(%s.%s)", prot_nest_prefix, syslog,
311 		    priostrlen, syslogstr, bogus ? "" : " ",
312 		    facilstr, pristr);
313 		(void) sprintf(get_line(0, 0),
314 			"\"%s\"",
315 			show_string(syslogstr, dlen, 60));
316 		show_trailer();
317 	}
318 }
319 
320 int src_port, dst_port, curr_proto;
321 
322 int
323 interpret_reserved(int flags, int proto, in_port_t src, in_port_t dst,
324     char *data, int dlen)
325 {
326 	char *pn;
327 	int dir, port, which;
328 	char pbuff[16], hbuff[32];
329 	struct ttable *ttabp;
330 
331 	src_port = src;
332 	dst_port = dst;
333 	curr_proto = proto;
334 
335 	pn = getportname(proto, src);
336 	if (pn != NULL) {
337 		dir = 'R';
338 		port = dst;
339 		which = src;
340 	} else {
341 		pn = getportname(proto, dst);
342 		if (pn == NULL) {
343 			ttabp = is_transient(src);
344 			if (ttabp) {
345 				(ttabp->t_proc)(flags, data, dlen);
346 				return (1);
347 			}
348 			ttabp = is_transient(dst);
349 			if (ttabp) {
350 				(ttabp->t_proc)(flags, data, dlen);
351 				return (1);
352 			}
353 			return (0);
354 		}
355 
356 		dir = 'C';
357 		port = src;
358 		which = dst;
359 	}
360 
361 	if ((dst == 53 || src == 53) && proto != IPPROTO_TCP) {
362 		interpret_dns(flags, proto, (uchar_t *)data, dlen);
363 		return (1);
364 	}
365 
366 	if (dst == 514 && proto != IPPROTO_TCP) {
367 		/*
368 		 * TCP port 514 is rshell.  UDP port 514 is syslog.
369 		 */
370 		interpret_syslog(flags, dir, port, (const char *)data, dlen);
371 		return (1);
372 	}
373 
374 	if (dlen > 0) {
375 		switch (which) {
376 		case  67:
377 		case  68:
378 			interpret_dhcp(flags, data, dlen);
379 			return (1);
380 		case  69:
381 			interpret_tftp(flags, data, dlen);
382 			return (1);
383 		case  80:
384 		case  8080:
385 			interpret_http(flags, data, dlen);
386 			return (1);
387 		case 123:
388 			interpret_ntp(flags, data, dlen);
389 			return (1);
390 		case 137:
391 			interpret_netbios_ns(flags, data, dlen);
392 			return (1);
393 		case 138:
394 			interpret_netbios_datagram(flags, data, dlen);
395 			return (1);
396 		case 139:
397 		case 445:
398 			/*
399 			 * SMB on port 445 is a subset of NetBIOS SMB
400 			 * on port 139.  The same interpreter can be used
401 			 * for both.
402 			 */
403 			interpret_netbios_ses(flags, data, dlen);
404 			return (1);
405 		case 389:
406 			interpret_ldap(flags, data, dlen, src, dst);
407 			return (1);
408 		case 427:
409 			interpret_slp(flags, data, dlen);
410 			return (1);
411 		case 434:
412 			interpret_mip_cntrlmsg(flags, (uchar_t *)data, dlen);
413 			return (1);
414 		case 520:
415 			interpret_rip(flags, data, dlen);
416 			return (1);
417 		case 521:
418 			interpret_rip6(flags, data, dlen);
419 			return (1);
420 		case 1080:
421 			if (dir == 'C')
422 				interpret_socks_call(flags, data, dlen);
423 			else
424 				interpret_socks_reply(flags, data, dlen);
425 			return (1);
426 		}
427 	}
428 
429 	if (flags & F_SUM) {
430 		(void) sprintf(get_sum_line(),
431 			"%s %c port=%d %s",
432 			pn, dir, port,
433 			show_string(data, dlen, 20));
434 	}
435 
436 	if (flags & F_DTAIL) {
437 		(void) sprintf(pbuff, "%s:  ", pn);
438 		(void) sprintf(hbuff, "%s:  ", pn);
439 		show_header(pbuff, hbuff, dlen);
440 		show_space();
441 		(void) sprintf(get_line(0, 0),
442 			"\"%s\"",
443 			show_string(data, dlen, 60));
444 		show_trailer();
445 	}
446 	return (1);
447 }
448 
449 char *
450 show_string(const char *str, int dlen, int maxlen)
451 /*
452  *   Prints len bytes from str enclosed in quotes.
453  *   If len is negative, length is taken from strlen(str).
454  *   No more than maxlen bytes will be printed.  Longer
455  *   strings are flagged with ".." after the closing quote.
456  *   Non-printing characters are converted to C-style escape
457  *   codes or octal digits.
458  */
459 {
460 #define	TBSIZE	256
461 	static char tbuff[TBSIZE];
462 	const char *p;
463 	char *pp;
464 	int printable = 0;
465 	int c, len;
466 
467 	len = dlen > maxlen ? maxlen : dlen;
468 	dlen = len;
469 
470 	for (p = str, pp = tbuff; len; p++, len--) {
471 		switch (c = *p & 0xFF) {
472 		case '\n': (void) strcpy(pp, "\\n"); pp += 2; break;
473 		case '\b': (void) strcpy(pp, "\\b"); pp += 2; break;
474 		case '\t': (void) strcpy(pp, "\\t"); pp += 2; break;
475 		case '\r': (void) strcpy(pp, "\\r"); pp += 2; break;
476 		case '\f': (void) strcpy(pp, "\\f"); pp += 2; break;
477 		default:
478 			if (isascii(c) && isprint(c)) {
479 				*pp++ = c;
480 				printable++;
481 			} else {
482 				(void) sprintf(pp,
483 					isdigit(*(p + 1)) ?
484 					"\\%03o" : "\\%o", c);
485 				pp += strlen(pp);
486 			}
487 			break;
488 		}
489 		*pp = '\0';
490 		/*
491 		 * Check for overflow of temporary buffer.  Allow for
492 		 * the next character to be a \nnn followed by a trailing
493 		 * null.  If not, then just bail with what we have.
494 		 */
495 		if (pp + 5 >= &tbuff[TBSIZE]) {
496 			break;
497 		}
498 	}
499 	return (printable > dlen / 2 ? tbuff : "");
500 }
501