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_SCTP: /* fallthru */
 147         case IPPROTO_TCP: pt = pt_tcp; break;
 148         case IPPROTO_UDP: pt = pt_udp; break;
 149         default: return (NULL);
 150         }
 151 
 152         for (p = pt; p->pt_num; p++) {
 153                 if (port == p->pt_num)
 154                         return (p->pt_short);
 155         }
 156         return (NULL);
 157 }
 158 
 159 int
 160 reservedport(int proto, int port)
 161 {
 162         const struct porttable *p, *pt;
 163 
 164         switch (proto) {
 165         case IPPROTO_TCP: pt = pt_tcp; break;
 166         case IPPROTO_UDP: pt = pt_udp; break;
 167         default: return (NULL);
 168         }
 169         for (p = pt; p->pt_num; p++) {
 170                 if (port == p->pt_num)
 171                         return (1);
 172         }
 173         return (0);
 174 }
 175 
 176 /*
 177  * Need to be able to register an
 178  * interpreter for transient ports.
 179  * See TFTP interpreter.
 180  */
 181 #define MAXTRANS 64
 182 static struct ttable {
 183         int t_port;
 184         int (*t_proc)(int, char *, int);
 185 } transients [MAXTRANS];
 186 
 187 int
 188 add_transient(int port, int (*proc)(int, char *, int))
 189 {
 190         static struct ttable *next = transients;
 191 
 192         next->t_port = port;
 193         next->t_proc = proc;
 194 
 195         if (++next >= &transients[MAXTRANS])
 196                 next = transients;
 197 
 198         return (1);
 199 }
 200 
 201 static struct ttable *
 202 is_transient(int port)
 203 {
 204         struct ttable *p;
 205 
 206         for (p = transients; p->t_port && p < &transients[MAXTRANS]; p++) {
 207                 if (port == p->t_port)
 208                         return (p);
 209         }
 210 
 211         return (NULL);
 212 }
 213 
 214 void
 215 del_transient(int port)
 216 {
 217         struct ttable *p;
 218 
 219         for (p = transients; p->t_port && p < &transients[MAXTRANS]; p++) {
 220                 if (port == p->t_port)
 221                         p->t_port = -1;
 222         }
 223 }
 224 
 225 static void
 226 interpret_syslog(int flags, char dir, int port, const char *syslogstr,
 227     int dlen)
 228 {
 229         static const char *pris[] = {
 230             "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug"
 231         };
 232         static const char *facs[] = {
 233             "kern", "user", "mail", "daemon", "auth", "syslog", "lpr", "news",
 234             "uucp", NULL, NULL, NULL, NULL, "audit", NULL, "cron", "local0",
 235             "local1", "local2", "local3", "local4", "local5", "local6", "local7"
 236         };
 237 
 238         int composit;
 239         int pri = -1;
 240         int facil = -1;
 241         boolean_t bogus = B_TRUE;
 242         int priostrlen = 0;
 243         int datalen = dlen;
 244         char unknown[4];        /* for unrecognized ones */
 245         const char *facilstr = "BAD";
 246         const char *pristr = "FMT";
 247         const char *data = syslogstr;
 248 
 249         /*
 250          * Is there enough data to interpret (left bracket + at least 3 chars
 251          * which could be digits, right bracket, or space)?
 252          */
 253         if (datalen >= 4 && data != NULL) {
 254                 if (*data == '<') {
 255                         const int FACS_LEN = sizeof (facs) / sizeof (facs[0]);
 256                         char buffer[4];
 257                         char *end;
 258 
 259                         data++;
 260                         datalen--;
 261 
 262                         (void) strlcpy(buffer, data, sizeof (buffer));
 263                         composit = strtoul(buffer, &end, 0);
 264                         data += end - buffer;
 265                         if (*data == '>') {
 266                                 data++;
 267                                 datalen -= end - buffer + 1;
 268 
 269                                 pri = composit & 0x7;
 270                                 facil = (composit & 0xF8) >> 3;
 271 
 272                                 if ((facil >= FACS_LEN) ||
 273                                     (facs[facil] == NULL)) {
 274                                         snprintf(unknown, sizeof (unknown),
 275                                             "%d", facil);
 276                                         facilstr = unknown;
 277                                 } else {
 278                                         facilstr = facs[facil];
 279                                 }
 280                                 pristr = pris[pri];
 281                                 priostrlen = dlen - datalen;
 282                                 bogus = B_FALSE;
 283                         } else {
 284                                 data = syslogstr;
 285                                 datalen = dlen;
 286                         }
 287                 }
 288         }
 289 
 290         if (flags & F_SUM) {
 291                 (void) snprintf(get_sum_line(), MAXLINE,
 292                     "SYSLOG %c port=%d %s.%s: %s",
 293                     dir, port, facilstr, pristr,
 294                     show_string(syslogstr, dlen, 20));
 295 
 296         }
 297 
 298         if (flags & F_DTAIL) {
 299                 static char syslog[] = "SYSLOG:  ";
 300                 show_header(syslog, syslog, dlen);
 301                 show_space();
 302                 (void) snprintf(get_detail_line(0, 0), MAXLINE,
 303                     "%s%sPriority: %.*s%s(%s.%s)", prot_nest_prefix, syslog,
 304                     priostrlen, syslogstr, bogus ? "" : " ",
 305                     facilstr, pristr);
 306                 (void) snprintf(get_line(0, 0), get_line_remain(),
 307                     "\"%s\"",
 308                     show_string(syslogstr, dlen, 60));
 309                 show_trailer();
 310         }
 311 }
 312 
 313 int src_port, dst_port, curr_proto;
 314 
 315 int
 316 interpret_reserved(int flags, int proto, in_port_t src, in_port_t dst,
 317     char *data, int dlen)
 318 {
 319         const char *pn;
 320         int dir, port, which;
 321         char pbuff[16], hbuff[32];
 322         struct ttable *ttabp;
 323 
 324         src_port = src;
 325         dst_port = dst;
 326         curr_proto = proto;
 327 
 328         pn = getportname(proto, src);
 329         if (pn != NULL) {
 330                 dir = 'R';
 331                 port = dst;
 332                 which = src;
 333         } else {
 334                 pn = getportname(proto, dst);
 335                 if (pn == NULL) {
 336                         ttabp = is_transient(src);
 337                         if (ttabp) {
 338                                 (ttabp->t_proc)(flags, data, dlen);
 339                                 return (1);
 340                         }
 341                         ttabp = is_transient(dst);
 342                         if (ttabp) {
 343                                 (ttabp->t_proc)(flags, data, dlen);
 344                                 return (1);
 345                         }
 346                         return (0);
 347                 }
 348 
 349                 dir = 'C';
 350                 port = src;
 351                 which = dst;
 352         }
 353 
 354         if ((dst == IPPORT_DOMAIN || src == IPPORT_DOMAIN ||
 355             dst == IPPORT_MDNS || src == IPPORT_MDNS) &&
 356             proto != IPPROTO_TCP) {
 357                 interpret_dns(flags, proto, (uchar_t *)data, dlen, which);
 358                 return (1);
 359         }
 360 
 361         if (dst == IPPORT_SYSLOG && proto != IPPROTO_TCP) {
 362                 /*
 363                  * TCP port 514 is rshell.  UDP port 514 is syslog.
 364                  */
 365                 interpret_syslog(flags, dir, port, (const char *)data, dlen);
 366                 return (1);
 367         }
 368 
 369         if (dlen > 0) {
 370                 switch (which) {
 371                 case  IPPORT_BOOTPS:
 372                 case  IPPORT_BOOTPC:
 373                         (void) interpret_dhcp(flags, (struct dhcp *)data,
 374                             dlen);
 375                         return (1);
 376                 case IPPORT_DHCPV6S:
 377                 case IPPORT_DHCPV6C:
 378                         (void) interpret_dhcpv6(flags, (uint8_t *)data, dlen);
 379                         return (1);
 380                 case  IPPORT_TFTP:
 381                         (void) interpret_tftp(flags, (struct tftphdr *)data,
 382                             dlen);
 383                         return (1);
 384                 case  IPPORT_HTTP:
 385                 case  IPPORT_HTTP_ALT:
 386                         (void) interpret_http(flags, data, dlen);
 387                         return (1);
 388                 case IPPORT_NTP:
 389                         (void) interpret_ntp(flags, (struct ntpdata *)data,
 390                             dlen);
 391                         return (1);
 392                 case IPPORT_NETBIOS_NS:
 393                         interpret_netbios_ns(flags, (uchar_t *)data, dlen);
 394                         return (1);
 395                 case IPPORT_NETBIOS_DGM:
 396                         interpret_netbios_datagram(flags, (uchar_t *)data,
 397                             dlen);
 398                         return (1);
 399                 case IPPORT_NETBIOS_SSN:
 400                 case 445:
 401                         /*
 402                          * SMB on port 445 is a subset of NetBIOS SMB
 403                          * on port 139.  The same interpreter can be used
 404                          * for both.
 405                          */
 406                         interpret_netbios_ses(flags, (uchar_t *)data, dlen);
 407                         return (1);
 408                 case IPPORT_LDAP:
 409                         interpret_ldap(flags, data, dlen, src, dst);
 410                         return (1);
 411                 case IPPORT_SLP:
 412                         interpret_slp(flags, data, dlen);
 413                         return (1);
 414                 case IPPORT_MIP:
 415                         interpret_mip_cntrlmsg(flags, (uchar_t *)data, dlen);
 416                         return (1);
 417                 case IPPORT_ROUTESERVER:
 418                         (void) interpret_rip(flags, (struct rip *)data, dlen);
 419                         return (1);
 420                 case IPPORT_RIPNG:
 421                         (void) interpret_rip6(flags, (struct rip6 *)data,
 422                             dlen);
 423                         return (1);
 424                 case IPPORT_SOCKS:
 425                         if (dir == 'C')
 426                                 (void) interpret_socks_call(flags, data, dlen);
 427                         else
 428                                 (void) interpret_socks_reply(flags, data,
 429                                     dlen);
 430                         return (1);
 431                 }
 432         }
 433 
 434         if (flags & F_SUM) {
 435                 (void) snprintf(get_sum_line(), MAXLINE,
 436                     "%s %c port=%d %s",
 437                     pn, dir, port,
 438                     show_string(data, dlen, 20));
 439         }
 440 
 441         if (flags & F_DTAIL) {
 442                 (void) snprintf(pbuff, sizeof (pbuff), "%s:  ", pn);
 443                 (void) snprintf(hbuff, sizeof (hbuff), "%s:  ", pn);
 444                 show_header(pbuff, hbuff, dlen);
 445                 show_space();
 446                 (void) snprintf(get_line(0, 0), get_line_remain(),
 447                     "\"%s\"",
 448                     show_string(data, dlen, 60));
 449                 show_trailer();
 450         }
 451         return (1);
 452 }