view usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rport.c @ 13340:43bfdefd2c41

895 snoop lies about SMB errors Reviewed by: Richard Lowe <richlowe@richlowe.net> Reviewed by: richard.elling@richardelling.com Approved by: Albert Lee <trisk@opensolaris.org>
author Gordon Ross <gwr@nexenta.com>
date Sun, 17 Apr 2011 19:11:45 -0400
parents cd464a980538
children
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <setjmp.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include "snoop.h"

struct porttable {
	int	pt_num;
	char	*pt_short;
};

static const struct porttable pt_udp[] = {
	{ IPPORT_ECHO,		"ECHO" },
	{ IPPORT_DISCARD,	"DISCARD" },
	{ IPPORT_DAYTIME,	"DAYTIME" },
	{ IPPORT_CHARGEN,	"CHARGEN" },
	{ IPPORT_TIMESERVER,	"TIME" },
	{ IPPORT_NAMESERVER,	"NAME" },
	{ IPPORT_DOMAIN,	"DNS" },
	{ IPPORT_MDNS,		"MDNS" },
	{ IPPORT_BOOTPS,	"BOOTPS" },
	{ IPPORT_BOOTPC,	"BOOTPC" },
	{ IPPORT_TFTP,		"TFTP" },
	{ IPPORT_FINGER,	"FINGER" },
/*	{ 111,			"PORTMAP" }, Just Sun RPC */
	{ IPPORT_NTP,		"NTP" },
	{ IPPORT_NETBIOS_NS,	"NBNS" },
	{ IPPORT_NETBIOS_DGM,	"NBDG" },
	{ IPPORT_LDAP,		"LDAP" },
	{ IPPORT_SLP,		"SLP" },
/* Mobile IP defines a set of new control messages sent over UDP port 434 */
	{ IPPORT_MIP,		"Mobile IP" },
	{ IPPORT_BIFFUDP,	"BIFF" },
	{ IPPORT_WHOSERVER,	"WHO" },
	{ IPPORT_SYSLOG,	"SYSLOG" },
	{ IPPORT_TALK,		"TALK" },
	{ IPPORT_ROUTESERVER,	"RIP" },
	{ IPPORT_RIPNG,		"RIPng" },
	{ IPPORT_DHCPV6C,	"DHCPv6C" },
	{ IPPORT_DHCPV6S,	"DHCPv6S" },
	{ 550,			"NEW-RWHO" },
	{ 560,			"RMONITOR" },
	{ 561,			"MONITOR" },
	{ IPPORT_SOCKS,		"SOCKS" },
	{ 0,			NULL }
};

static struct porttable pt_tcp[] = {
	{ 1,			"TCPMUX" },
	{ IPPORT_ECHO,		"ECHO" },
	{ IPPORT_DISCARD,	"DISCARD" },
	{ IPPORT_SYSTAT,	"SYSTAT" },
	{ IPPORT_DAYTIME,	"DAYTIME" },
	{ IPPORT_NETSTAT,	"NETSTAT" },
	{ IPPORT_CHARGEN,	"CHARGEN" },
	{ 20,			"FTP-DATA" },
	{ IPPORT_FTP,		"FTP" },
	{ IPPORT_TELNET,	"TELNET" },
	{ IPPORT_SMTP,		"SMTP" },
	{ IPPORT_TIMESERVER,	"TIME" },
	{ 39,			"RLP" },
	{ IPPORT_NAMESERVER,	"NAMESERVER" },
	{ IPPORT_WHOIS,		"NICNAME" },
	{ IPPORT_DOMAIN,	"DNS" },
	{ 70,			"GOPHER" },
	{ IPPORT_RJE,		"RJE" },
	{ IPPORT_FINGER,	"FINGER" },
	{ IPPORT_HTTP,		"HTTP" },
	{ IPPORT_TTYLINK,	"LINK" },
	{ IPPORT_SUPDUP,	"SUPDUP" },
	{ 101,			"HOSTNAME" },
	{ 102,			"ISO-TSAP" },
	{ 103,			"X400" },
	{ 104,			"X400-SND" },
	{ 105,			"CSNET-NS" },
	{ 109,			"POP-2" },
/*	{ 111,			"PORTMAP" }, Just Sun RPC */
	{ 113,			"AUTH" },
	{ 117,			"UUCP-PATH" },
	{ 119,			"NNTP" },
	{ IPPORT_NTP,		"NTP" },
	{ IPPORT_NETBIOS_SSN,	"NBT" },
	{ 143,			"IMAP" },
	{ 144,			"NeWS" },
	{ IPPORT_LDAP,		"LDAP" },
	{ IPPORT_SLP,		"SLP" },
	{ 443,			"HTTPS" },
	{ 445,			"SMB" },
	{ IPPORT_EXECSERVER,	"EXEC" },
	{ IPPORT_LOGINSERVER,	"RLOGIN" },
	{ IPPORT_CMDSERVER,	"RSHELL" },
	{ IPPORT_PRINTER,	"PRINTER" },
	{ 530,			"COURIER" },
	{ 540,			"UUCP" },
	{ 600,			"PCSERVER" },
	{ IPPORT_SOCKS,		"SOCKS" },
	{ 1524,			"INGRESLOCK" },
	{ 2904,			"M2UA" },
	{ 2905,			"M3UA" },
	{ 6000,			"XWIN" },
	{ IPPORT_HTTP_ALT,	"HTTP (proxy)" },
	{ 9900,			"IUA" },
	{ 0,			NULL },
};

char *
getportname(int proto, in_port_t port)
{
	const struct porttable *p, *pt;

	switch (proto) {
	case IPPROTO_SCTP: /* fallthru */
	case IPPROTO_TCP: pt = pt_tcp; break;
	case IPPROTO_UDP: pt = pt_udp; break;
	default: return (NULL);
	}

	for (p = pt; p->pt_num; p++) {
		if (port == p->pt_num)
			return (p->pt_short);
	}
	return (NULL);
}

int
reservedport(int proto, int port)
{
	const struct porttable *p, *pt;

	switch (proto) {
	case IPPROTO_TCP: pt = pt_tcp; break;
	case IPPROTO_UDP: pt = pt_udp; break;
	default: return (NULL);
	}
	for (p = pt; p->pt_num; p++) {
		if (port == p->pt_num)
			return (1);
	}
	return (0);
}

/*
 * Need to be able to register an
 * interpreter for transient ports.
 * See TFTP interpreter.
 */
#define	MAXTRANS 64
static struct ttable {
	int t_port;
	int (*t_proc)(int, char *, int);
} transients [MAXTRANS];

int
add_transient(int port, int (*proc)(int, char *, int))
{
	static struct ttable *next = transients;

	next->t_port = port;
	next->t_proc = proc;

	if (++next >= &transients[MAXTRANS])
		next = transients;

	return (1);
}

static struct ttable *
is_transient(int port)
{
	struct ttable *p;

	for (p = transients; p->t_port && p < &transients[MAXTRANS]; p++) {
		if (port == p->t_port)
			return (p);
	}

	return (NULL);
}

void
del_transient(int port)
{
	struct ttable *p;

	for (p = transients; p->t_port && p < &transients[MAXTRANS]; p++) {
		if (port == p->t_port)
			p->t_port = -1;
	}
}

static void
interpret_syslog(int flags, char dir, int port, const char *syslogstr,
    int dlen)
{
	static const char *pris[] = {
	    "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug"
	};
	static const char *facs[] = {
	    "kern", "user", "mail", "daemon", "auth", "syslog", "lpr", "news",
	    "uucp", NULL, NULL, NULL, NULL, "audit", NULL, "cron", "local0",
	    "local1", "local2", "local3", "local4", "local5", "local6", "local7"
	};

	int composit;
	int pri = -1;
	int facil = -1;
	boolean_t bogus = B_TRUE;
	int priostrlen = 0;
	int datalen = dlen;
	char unknown[4];	/* for unrecognized ones */
	const char *facilstr = "BAD";
	const char *pristr = "FMT";
	const char *data = syslogstr;

	/*
	 * Is there enough data to interpret (left bracket + at least 3 chars
	 * which could be digits, right bracket, or space)?
	 */
	if (datalen >= 4 && data != NULL) {
		if (*data == '<') {
			const int FACS_LEN = sizeof (facs) / sizeof (facs[0]);
			char buffer[4];
			char *end;

			data++;
			datalen--;

			(void) strlcpy(buffer, data, sizeof (buffer));
			composit = strtoul(buffer, &end, 0);
			data += end - buffer;
			if (*data == '>') {
				data++;
				datalen -= end - buffer + 1;

				pri = composit & 0x7;
				facil = (composit & 0xF8) >> 3;

				if ((facil >= FACS_LEN) ||
				    (facs[facil] == NULL)) {
					snprintf(unknown, sizeof (unknown),
					    "%d", facil);
					facilstr = unknown;
				} else {
					facilstr = facs[facil];
				}
				pristr = pris[pri];
				priostrlen = dlen - datalen;
				bogus = B_FALSE;
			} else {
				data = syslogstr;
				datalen = dlen;
			}
		}
	}

	if (flags & F_SUM) {
		(void) snprintf(get_sum_line(), MAXLINE,
		    "SYSLOG %c port=%d %s.%s: %s",
		    dir, port, facilstr, pristr,
		    show_string(syslogstr, dlen, 20));

	}

	if (flags & F_DTAIL) {
		static char syslog[] = "SYSLOG:  ";
		show_header(syslog, syslog, dlen);
		show_space();
		(void) snprintf(get_detail_line(0, 0), MAXLINE,
		    "%s%sPriority: %.*s%s(%s.%s)", prot_nest_prefix, syslog,
		    priostrlen, syslogstr, bogus ? "" : " ",
		    facilstr, pristr);
		(void) snprintf(get_line(0, 0), get_line_remain(),
		    "\"%s\"",
		    show_string(syslogstr, dlen, 60));
		show_trailer();
	}
}

int src_port, dst_port, curr_proto;

int
interpret_reserved(int flags, int proto, in_port_t src, in_port_t dst,
    char *data, int dlen)
{
	const char *pn;
	int dir, port, which;
	char pbuff[16], hbuff[32];
	struct ttable *ttabp;

	src_port = src;
	dst_port = dst;
	curr_proto = proto;

	pn = getportname(proto, src);
	if (pn != NULL) {
		dir = 'R';
		port = dst;
		which = src;
	} else {
		pn = getportname(proto, dst);
		if (pn == NULL) {
			ttabp = is_transient(src);
			if (ttabp) {
				(ttabp->t_proc)(flags, data, dlen);
				return (1);
			}
			ttabp = is_transient(dst);
			if (ttabp) {
				(ttabp->t_proc)(flags, data, dlen);
				return (1);
			}
			return (0);
		}

		dir = 'C';
		port = src;
		which = dst;
	}

	if ((dst == IPPORT_DOMAIN || src == IPPORT_DOMAIN ||
	    dst == IPPORT_MDNS || src == IPPORT_MDNS) &&
	    proto != IPPROTO_TCP) {
		interpret_dns(flags, proto, (uchar_t *)data, dlen, which);
		return (1);
	}

	if (dst == IPPORT_SYSLOG && proto != IPPROTO_TCP) {
		/*
		 * TCP port 514 is rshell.  UDP port 514 is syslog.
		 */
		interpret_syslog(flags, dir, port, (const char *)data, dlen);
		return (1);
	}

	if (dlen > 0) {
		switch (which) {
		case  IPPORT_BOOTPS:
		case  IPPORT_BOOTPC:
			(void) interpret_dhcp(flags, (struct dhcp *)data,
			    dlen);
			return (1);
		case IPPORT_DHCPV6S:
		case IPPORT_DHCPV6C:
			(void) interpret_dhcpv6(flags, (uint8_t *)data, dlen);
			return (1);
		case  IPPORT_TFTP:
			(void) interpret_tftp(flags, (struct tftphdr *)data,
			    dlen);
			return (1);
		case  IPPORT_HTTP:
		case  IPPORT_HTTP_ALT:
			(void) interpret_http(flags, data, dlen);
			return (1);
		case IPPORT_NTP:
			(void) interpret_ntp(flags, (struct ntpdata *)data,
			    dlen);
			return (1);
		case IPPORT_NETBIOS_NS:
			interpret_netbios_ns(flags, (uchar_t *)data, dlen);
			return (1);
		case IPPORT_NETBIOS_DGM:
			interpret_netbios_datagram(flags, (uchar_t *)data,
			    dlen);
			return (1);
		case IPPORT_NETBIOS_SSN:
		case 445:
			/*
			 * SMB on port 445 is a subset of NetBIOS SMB
			 * on port 139.  The same interpreter can be used
			 * for both.
			 */
			interpret_netbios_ses(flags, (uchar_t *)data, dlen);
			return (1);
		case IPPORT_LDAP:
			interpret_ldap(flags, data, dlen, src, dst);
			return (1);
		case IPPORT_SLP:
			interpret_slp(flags, data, dlen);
			return (1);
		case IPPORT_MIP:
			interpret_mip_cntrlmsg(flags, (uchar_t *)data, dlen);
			return (1);
		case IPPORT_ROUTESERVER:
			(void) interpret_rip(flags, (struct rip *)data, dlen);
			return (1);
		case IPPORT_RIPNG:
			(void) interpret_rip6(flags, (struct rip6 *)data,
			    dlen);
			return (1);
		case IPPORT_SOCKS:
			if (dir == 'C')
				(void) interpret_socks_call(flags, data, dlen);
			else
				(void) interpret_socks_reply(flags, data,
				    dlen);
			return (1);
		}
	}

	if (flags & F_SUM) {
		(void) snprintf(get_sum_line(), MAXLINE,
		    "%s %c port=%d %s",
		    pn, dir, port,
		    show_string(data, dlen, 20));
	}

	if (flags & F_DTAIL) {
		(void) snprintf(pbuff, sizeof (pbuff), "%s:  ", pn);
		(void) snprintf(hbuff, sizeof (hbuff), "%s:  ", pn);
		show_header(pbuff, hbuff, dlen);
		show_space();
		(void) snprintf(get_line(0, 0), get_line_remain(),
		    "\"%s\"",
		    show_string(data, dlen, 60));
		show_trailer();
	}
	return (1);
}