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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <strings.h>
  29 #include <sys/sysmacros.h>
  30 #include <sys/types.h>
  31 #include <sys/errno.h>
  32 #include <setjmp.h>
  33 #include <sys/socket.h>
  34 #include <net/if.h>
  35 #include <netinet/in_systm.h>
  36 #include <netinet/in.h>
  37 #include <netinet/ip.h>
  38 #include <netinet/if_ether.h>
  39 #include "snoop.h"
  40 
  41 struct porttable {
  42         int     pt_num;
  43         char    *pt_short;
  44 };
  45 
  46 static const struct porttable pt_udp[] = {
  47         { IPPORT_ECHO,          "ECHO" },
  48         { IPPORT_DISCARD,       "DISCARD" },
  49         { IPPORT_DAYTIME,       "DAYTIME" },
  50         { IPPORT_CHARGEN,       "CHARGEN" },
  51         { IPPORT_TIMESERVER,    "TIME" },
  52         { IPPORT_NAMESERVER,    "NAME" },
  53         { IPPORT_DOMAIN,        "DNS" },
  54         { IPPORT_MDNS,          "MDNS" },
  55         { IPPORT_BOOTPS,        "BOOTPS" },
  56         { IPPORT_BOOTPC,        "BOOTPC" },
  57         { IPPORT_TFTP,          "TFTP" },
  58         { IPPORT_FINGER,        "FINGER" },
  59 /*      { 111,                  "PORTMAP" }, Just Sun RPC */
  60         { IPPORT_NTP,           "NTP" },
  61         { IPPORT_NETBIOS_NS,    "NBNS" },
  62         { IPPORT_NETBIOS_DGM,   "NBDG" },
  63         { IPPORT_LDAP,          "LDAP" },
  64         { IPPORT_SLP,           "SLP" },
  65 /* Mobile IP defines a set of new control messages sent over UDP port 434 */
  66         { IPPORT_MIP,           "Mobile IP" },
  67         { IPPORT_BIFFUDP,       "BIFF" },
  68         { IPPORT_WHOSERVER,     "WHO" },
  69         { IPPORT_SYSLOG,        "SYSLOG" },
  70         { IPPORT_TALK,          "TALK" },
  71         { IPPORT_ROUTESERVER,   "RIP" },
  72         { IPPORT_RIPNG,         "RIPng" },
  73         { IPPORT_DHCPV6C,       "DHCPv6C" },
  74         { IPPORT_DHCPV6S,       "DHCPv6S" },
  75         { 550,                  "NEW-RWHO" },
  76         { 560,                  "RMONITOR" },
  77         { 561,                  "MONITOR" },
  78         { IPPORT_SOCKS,         "SOCKS" },
  79         { 0,                    NULL }
  80 };
  81 
  82 static struct porttable pt_tcp[] = {
  83         { 1,                    "TCPMUX" },
  84         { IPPORT_ECHO,          "ECHO" },
  85         { IPPORT_DISCARD,       "DISCARD" },
  86         { IPPORT_SYSTAT,        "SYSTAT" },
  87         { IPPORT_DAYTIME,       "DAYTIME" },
  88         { IPPORT_NETSTAT,       "NETSTAT" },
  89         { IPPORT_CHARGEN,       "CHARGEN" },
  90         { 20,                   "FTP-DATA" },
  91         { IPPORT_FTP,           "FTP" },
  92         { IPPORT_TELNET,        "TELNET" },
  93         { IPPORT_SMTP,          "SMTP" },
  94         { IPPORT_TIMESERVER,    "TIME" },
  95         { 39,                   "RLP" },
  96         { IPPORT_NAMESERVER,    "NAMESERVER" },
  97         { IPPORT_WHOIS,         "NICNAME" },
  98         { IPPORT_DOMAIN,        "DNS" },
  99         { 70,                   "GOPHER" },
 100         { IPPORT_RJE,           "RJE" },
 101         { IPPORT_FINGER,        "FINGER" },
 102         { IPPORT_HTTP,          "HTTP" },
 103         { IPPORT_TTYLINK,       "LINK" },
 104         { IPPORT_SUPDUP,        "SUPDUP" },
 105         { 101,                  "HOSTNAME" },
 106         { 102,                  "ISO-TSAP" },
 107         { 103,                  "X400" },
 108         { 104,                  "X400-SND" },
 109         { 105,                  "CSNET-NS" },
 110         { 109,                  "POP-2" },
 111 /*      { 111,                  "PORTMAP" }, Just Sun RPC */
 112         { 113,                  "AUTH" },
 113         { 117,                  "UUCP-PATH" },
 114         { 119,                  "NNTP" },
 115         { IPPORT_NTP,           "NTP" },
 116         { IPPORT_NETBIOS_SSN,   "NBT" },
 117         { 143,                  "IMAP" },
 118         { 144,                  "NeWS" },
 119         { IPPORT_LDAP,          "LDAP" },
 120         { IPPORT_SLP,           "SLP" },
 121         { 443,                  "HTTPS" },
 122         { 445,                  "SMB" },
 123         { IPPORT_EXECSERVER,    "EXEC" },
 124         { IPPORT_LOGINSERVER,   "RLOGIN" },
 125         { IPPORT_CMDSERVER,     "RSHELL" },
 126         { IPPORT_PRINTER,       "PRINTER" },
 127         { 530,                  "COURIER" },
 128         { 540,                  "UUCP" },
 129         { 600,                  "PCSERVER" },
 130         { IPPORT_SOCKS,         "SOCKS" },
 131         { 1524,                 "INGRESLOCK" },
 132         { 2904,                 "M2UA" },
 133         { 2905,                 "M3UA" },
 134         { 6000,                 "XWIN" },
 135         { IPPORT_HTTP_ALT,      "HTTP (proxy)" },
 136         { 9900,                 "IUA" },
 137         { 0,                    NULL },
 138 };
 139 
 140 char *
 141 getportname(int proto, in_port_t port)
 142 {
 143         const struct porttable *p, *pt;
 144 
 145         switch (proto) {
 146         case IPPROTO_DCCP: /* fallthru */
 147         case IPPROTO_SCTP:
 148         case IPPROTO_TCP: pt = pt_tcp; break;
 149         case IPPROTO_UDP: pt = pt_udp; break;
 150         default: return (NULL);
 151         }
 152 
 153         for (p = pt; p->pt_num; p++) {
 154                 if (port == p->pt_num)
 155                         return (p->pt_short);
 156         }
 157         return (NULL);
 158 }
 159 
 160 int
 161 reservedport(int proto, int port)
 162 {
 163         const struct porttable *p, *pt;
 164 
 165         switch (proto) {
 166         case IPPROTO_TCP: pt = pt_tcp; break;
 167         case IPPROTO_UDP: pt = pt_udp; break;
 168         default: return (NULL);
 169         }
 170         for (p = pt; p->pt_num; p++) {
 171                 if (port == p->pt_num)
 172                         return (1);
 173         }
 174         return (0);
 175 }
 176 
 177 /*
 178  * Need to be able to register an
 179  * interpreter for transient ports.
 180  * See TFTP interpreter.
 181  */
 182 #define MAXTRANS 64
 183 static struct ttable {
 184         int t_port;
 185         int (*t_proc)(int, char *, int);
 186 } transients [MAXTRANS];
 187 
 188 int
 189 add_transient(int port, int (*proc)(int, char *, int))
 190 {
 191         static struct ttable *next = transients;
 192 
 193         next->t_port = port;
 194         next->t_proc = proc;
 195 
 196         if (++next >= &transients[MAXTRANS])
 197                 next = transients;
 198 
 199         return (1);
 200 }
 201 
 202 static struct ttable *
 203 is_transient(int port)
 204 {
 205         struct ttable *p;
 206 
 207         for (p = transients; p->t_port && p < &transients[MAXTRANS]; p++) {
 208                 if (port == p->t_port)
 209                         return (p);
 210         }
 211 
 212         return (NULL);
 213 }
 214 
 215 void
 216 del_transient(int port)
 217 {
 218         struct ttable *p;
 219 
 220         for (p = transients; p->t_port && p < &transients[MAXTRANS]; p++) {
 221                 if (port == p->t_port)
 222                         p->t_port = -1;
 223         }
 224 }
 225 
 226 static void
 227 interpret_syslog(int flags, char dir, int port, const char *syslogstr,
 228     int dlen)
 229 {
 230         static const char *pris[] = {
 231             "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug"
 232         };
 233         static const char *facs[] = {
 234             "kern", "user", "mail", "daemon", "auth", "syslog", "lpr", "news",
 235             "uucp", NULL, NULL, NULL, NULL, "audit", NULL, "cron", "local0",
 236             "local1", "local2", "local3", "local4", "local5", "local6", "local7"
 237         };
 238 
 239         int composit;
 240         int pri = -1;
 241         int facil = -1;
 242         boolean_t bogus = B_TRUE;
 243         int priostrlen = 0;
 244         int datalen = dlen;
 245         char unknown[4];        /* for unrecognized ones */
 246         const char *facilstr = "BAD";
 247         const char *pristr = "FMT";
 248         const char *data = syslogstr;
 249 
 250         /*
 251          * Is there enough data to interpret (left bracket + at least 3 chars
 252          * which could be digits, right bracket, or space)?
 253          */
 254         if (datalen >= 4 && data != NULL) {
 255                 if (*data == '<') {
 256                         const int FACS_LEN = sizeof (facs) / sizeof (facs[0]);
 257                         char buffer[4];
 258                         char *end;
 259 
 260                         data++;
 261                         datalen--;
 262 
 263                         (void) strlcpy(buffer, data, sizeof (buffer));
 264                         composit = strtoul(buffer, &end, 0);
 265                         data += end - buffer;
 266                         if (*data == '>') {
 267                                 data++;
 268                                 datalen -= end - buffer + 1;
 269 
 270                                 pri = composit & 0x7;
 271                                 facil = (composit & 0xF8) >> 3;
 272 
 273                                 if ((facil >= FACS_LEN) ||
 274                                     (facs[facil] == NULL)) {
 275                                         snprintf(unknown, sizeof (unknown),
 276                                             "%d", facil);
 277                                         facilstr = unknown;
 278                                 } else {
 279                                         facilstr = facs[facil];
 280                                 }
 281                                 pristr = pris[pri];
 282                                 priostrlen = dlen - datalen;
 283                                 bogus = B_FALSE;
 284                         } else {
 285                                 data = syslogstr;
 286                                 datalen = dlen;
 287                         }
 288                 }
 289         }
 290 
 291         if (flags & F_SUM) {
 292                 (void) snprintf(get_sum_line(), MAXLINE,
 293                     "SYSLOG %c port=%d %s.%s: %s",
 294                     dir, port, facilstr, pristr,
 295                     show_string(syslogstr, dlen, 20));
 296 
 297         }
 298 
 299         if (flags & F_DTAIL) {
 300                 static char syslog[] = "SYSLOG:  ";
 301                 show_header(syslog, syslog, dlen);
 302                 show_space();
 303                 (void) snprintf(get_detail_line(0, 0), MAXLINE,
 304                     "%s%sPriority: %.*s%s(%s.%s)", prot_nest_prefix, syslog,
 305                     priostrlen, syslogstr, bogus ? "" : " ",
 306                     facilstr, pristr);
 307                 (void) snprintf(get_line(0, 0), get_line_remain(),
 308                     "\"%s\"",
 309                     show_string(syslogstr, dlen, 60));
 310                 show_trailer();
 311         }
 312 }
 313 
 314 int src_port, dst_port, curr_proto;
 315 
 316 int
 317 interpret_reserved(int flags, int proto, in_port_t src, in_port_t dst,
 318     char *data, int dlen)
 319 {
 320         const char *pn;
 321         int dir, port, which;
 322         char pbuff[16], hbuff[32];
 323         struct ttable *ttabp;
 324 
 325         src_port = src;
 326         dst_port = dst;
 327         curr_proto = proto;
 328 
 329         pn = getportname(proto, src);
 330         if (pn != NULL) {
 331                 dir = 'R';
 332                 port = dst;
 333                 which = src;
 334         } else {
 335                 pn = getportname(proto, dst);
 336                 if (pn == NULL) {
 337                         ttabp = is_transient(src);
 338                         if (ttabp) {
 339                                 (ttabp->t_proc)(flags, data, dlen);
 340                                 return (1);
 341                         }
 342                         ttabp = is_transient(dst);
 343                         if (ttabp) {
 344                                 (ttabp->t_proc)(flags, data, dlen);
 345                                 return (1);
 346                         }
 347                         return (0);
 348                 }
 349 
 350                 dir = 'C';
 351                 port = src;
 352                 which = dst;
 353         }
 354 
 355         if ((dst == IPPORT_DOMAIN || src == IPPORT_DOMAIN ||
 356             dst == IPPORT_MDNS || src == IPPORT_MDNS) &&
 357             proto != IPPROTO_TCP) {
 358                 interpret_dns(flags, proto, (uchar_t *)data, dlen, which);
 359                 return (1);
 360         }
 361 
 362         if (dst == IPPORT_SYSLOG && proto != IPPROTO_TCP) {
 363                 /*
 364                  * TCP port 514 is rshell.  UDP port 514 is syslog.
 365                  */
 366                 interpret_syslog(flags, dir, port, (const char *)data, dlen);
 367                 return (1);
 368         }
 369 
 370         if (dlen > 0) {
 371                 switch (which) {
 372                 case  IPPORT_BOOTPS:
 373                 case  IPPORT_BOOTPC:
 374                         (void) interpret_dhcp(flags, (struct dhcp *)data,
 375                             dlen);
 376                         return (1);
 377                 case IPPORT_DHCPV6S:
 378                 case IPPORT_DHCPV6C:
 379                         (void) interpret_dhcpv6(flags, (uint8_t *)data, dlen);
 380                         return (1);
 381                 case  IPPORT_TFTP:
 382                         (void) interpret_tftp(flags, (struct tftphdr *)data,
 383                             dlen);
 384                         return (1);
 385                 case  IPPORT_HTTP:
 386                 case  IPPORT_HTTP_ALT:
 387                         (void) interpret_http(flags, data, dlen);
 388                         return (1);
 389                 case IPPORT_NTP:
 390                         (void) interpret_ntp(flags, (struct ntpdata *)data,
 391                             dlen);
 392                         return (1);
 393                 case IPPORT_NETBIOS_NS:
 394                         interpret_netbios_ns(flags, (uchar_t *)data, dlen);
 395                         return (1);
 396                 case IPPORT_NETBIOS_DGM:
 397                         interpret_netbios_datagram(flags, (uchar_t *)data,
 398                             dlen);
 399                         return (1);
 400                 case IPPORT_NETBIOS_SSN:
 401                 case 445:
 402                         /*
 403                          * SMB on port 445 is a subset of NetBIOS SMB
 404                          * on port 139.  The same interpreter can be used
 405                          * for both.
 406                          */
 407                         interpret_netbios_ses(flags, (uchar_t *)data, dlen);
 408                         return (1);
 409                 case IPPORT_LDAP:
 410                         interpret_ldap(flags, data, dlen, src, dst);
 411                         return (1);
 412                 case IPPORT_SLP:
 413                         interpret_slp(flags, data, dlen);
 414                         return (1);
 415                 case IPPORT_MIP:
 416                         interpret_mip_cntrlmsg(flags, (uchar_t *)data, dlen);
 417                         return (1);
 418                 case IPPORT_ROUTESERVER:
 419                         (void) interpret_rip(flags, (struct rip *)data, dlen);
 420                         return (1);
 421                 case IPPORT_RIPNG:
 422                         (void) interpret_rip6(flags, (struct rip6 *)data,
 423                             dlen);
 424                         return (1);
 425                 case IPPORT_SOCKS:
 426                         if (dir == 'C')
 427                                 (void) interpret_socks_call(flags, data, dlen);
 428                         else
 429                                 (void) interpret_socks_reply(flags, data,
 430                                     dlen);
 431                         return (1);
 432                 }
 433         }
 434 
 435         if (flags & F_SUM) {
 436                 (void) snprintf(get_sum_line(), MAXLINE,
 437                     "%s %c port=%d %s",
 438                     pn, dir, port,
 439                     show_string(data, dlen, 20));
 440         }
 441 
 442         if (flags & F_DTAIL) {
 443                 (void) snprintf(pbuff, sizeof (pbuff), "%s:  ", pn);
 444                 (void) snprintf(hbuff, sizeof (hbuff), "%s:  ", pn);
 445                 show_header(pbuff, hbuff, dlen);
 446                 show_space();
 447                 (void) snprintf(get_line(0, 0), get_line_remain(),
 448                     "\"%s\"",
 449                     show_string(data, dlen, 60));
 450                 show_trailer();
 451         }
 452         return (1);
 453 }