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