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 }