/* * 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. */ #pragma ident "%Z%%M% %I% %E% SMI" /* SunOS */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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_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) && proto != IPPROTO_TCP) { interpret_dns(flags, proto, (uchar_t *)data, dlen); 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); } char * show_string(const char *str, int dlen, int maxlen) /* * Prints len bytes from str enclosed in quotes. * If len is negative, length is taken from strlen(str). * No more than maxlen bytes will be printed. Longer * strings are flagged with ".." after the closing quote. * Non-printing characters are converted to C-style escape * codes or octal digits. */ { #define TBSIZE 256 static char tbuff[TBSIZE]; const char *p; char *pp; int printable = 0; int c, len; len = dlen > maxlen ? maxlen : dlen; dlen = len; for (p = str, pp = tbuff; len; p++, len--) { switch (c = *p & 0xFF) { case '\n': (void) strcpy(pp, "\\n"); pp += 2; break; case '\b': (void) strcpy(pp, "\\b"); pp += 2; break; case '\t': (void) strcpy(pp, "\\t"); pp += 2; break; case '\r': (void) strcpy(pp, "\\r"); pp += 2; break; case '\f': (void) strcpy(pp, "\\f"); pp += 2; break; default: if (isascii(c) && isprint(c)) { *pp++ = c; printable++; } else { (void) snprintf(pp, TBSIZE - (pp - tbuff), isdigit(*(p + 1)) ? "\\%03o" : "\\%o", c); pp += strlen(pp); } break; } *pp = '\0'; /* * Check for overflow of temporary buffer. Allow for * the next character to be a \nnn followed by a trailing * null. If not, then just bail with what we have. */ if (pp + 5 >= &tbuff[TBSIZE]) { break; } } return (printable > dlen / 2 ? tbuff : ""); }