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 }