xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_socks.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1998-1999,2001 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <string.h>
33 #include "snoop.h"
34 
35 static void put_method(char *cp, int method);
36 static void put_socks5_addr(char *cp, const unsigned char *buf, int fraglen);
37 static void put_socks4_res(char *cp, int code);
38 static void put_socks5_res(char *cp, int code);
39 
40 int
41 interpret_socks_call(flags, line, fraglen)
42 	int flags;
43 	char *line;
44 	int fraglen;
45 {
46 	unsigned char	*buf = (unsigned char *)line;
47 	char		*cp;
48 	struct in_addr	ipaddr;
49 	int		i, n;
50 
51 	if (flags & F_SUM) {
52 	cp = get_sum_line();
53 	if (fraglen >= 2) {
54 		switch (buf[0]) {
55 		case 4:		/* SOCKS4 */
56 			n = buf[1];
57 			switch (n) {
58 			case 1:
59 			case 2:
60 				if (fraglen >= 8) {
61 					(void) memcpy(&ipaddr, &buf[4],
62 					    sizeof (ipaddr));
63 					(void) sprintf(cp,
64 					    "SOCKS4 %s %s:%u",
65 					    addrtoname(AF_INET, &ipaddr),
66 					    (n == 1)? "CONNECT": "BIND",
67 					    (buf[2] << 8) | buf[3]);
68 					cp += strlen(cp);
69 					if (fraglen > 8) {
70 						(void) sprintf(cp, " User=");
71 						cp += strlen(cp);
72 						for (i = 8;
73 							i < 40 && i < fraglen;
74 							++i) {
75 							if (buf[i] == '\0')
76 								break;
77 							*cp++ = buf[i];
78 						}
79 						if (i == 40) {
80 							*cp++ = '.';
81 							*cp++ = '.';
82 							*cp++ = '.';
83 						}
84 						*cp = '\0';
85 					}
86 				}
87 				break;
88 			default:
89 				(void) sprintf(cp, "SOCKS4 OP=%u", n);
90 			}
91 			break;
92 		case 5:		/* SOCKS5 */
93 			n = buf[1];
94 			if (2 + n == fraglen) {
95 				(void) sprintf(cp,
96 					"SOCKS5 CONTACT NMETHODS=%d:", n);
97 				cp += strlen(cp);
98 				for (i = 0; i < n && 2 + i < fraglen; ++i) {
99 					put_method(cp, buf[2 + i]);
100 					cp += strlen(cp);
101 				}
102 			} else if (fraglen >= 6 && buf[2] == 0) {
103 				const char	*cmd;
104 
105 				if (n < 1 || n > 3) {
106 					(void) sprintf(cp,
107 						"SOCKS (send data): %s",
108 						show_string(line, fraglen, 20));
109 				} else {
110 					switch (n) {
111 					case 1:
112 						cmd = "CONNECT";
113 						break;
114 					case 2:
115 						cmd = "BIND";
116 						break;
117 					case 3:
118 						cmd = "ASSOCIATE_UDP";
119 						break;
120 					}
121 					(void) sprintf(cp, "SOCKS5 %s ", cmd);
122 					cp += strlen(cp);
123 					put_socks5_addr(cp, &buf[3],
124 						fraglen - 3);
125 				}
126 			} else {
127 				(void) sprintf(cp, "SOCKS (send data): %s",
128 					show_string(line, fraglen, 20));
129 			}
130 			break;
131 		default:
132 			(void) sprintf(cp, "SOCKS (send data): %s",
133 				show_string(line, fraglen, 20));
134 		}
135 	} else {
136 		(void) sprintf(cp, "SOCKS (send data): %s",
137 			show_string(line, fraglen, 20));
138 	}
139 
140 	} /* if (flags & F_SUM) */
141 
142 	if (flags & F_DTAIL) {
143 		show_header("SOCKS: ", "SOCKS Header", fraglen);
144 		show_space();
145 		cp = get_line(0, 0);
146 		if (fraglen >= 2) {
147 			switch (buf[0]) {
148 			case 4:
149 				(void) sprintf(cp, "Version = 4");
150 				n = buf[1];
151 				switch (n) {
152 				case 1:
153 				case 2:
154 					(void) sprintf(get_line(0, 0),
155 					    "Operation = %s",
156 					    (n == 1)? "CONNECT": "BIND");
157 					if (fraglen >= 8) {
158 						(void) memcpy(&ipaddr, &buf[4],
159 						    sizeof (ipaddr));
160 						(void) sprintf(get_line(0, 0),
161 						    "Destination = %s:%u",
162 						    addrtoname(AF_INET,
163 						    &ipaddr),
164 						    (buf[2] << 8) | buf[3]);
165 						if (fraglen > 8) {
166 							cp = get_line(0, 0);
167 							(void) sprintf(cp,
168 							    "User = ");
169 							cp += strlen(cp);
170 							for (i = 8;
171 								i < 40; ++i) {
172 								if
173 								(buf[i] == '\0')
174 									break;
175 								*cp++ = buf[i];
176 							}
177 							if (i == 40) {
178 								*cp++ = '.';
179 								*cp++ = '.';
180 								*cp++ = '.';
181 							}
182 							*cp = '\0';
183 						}
184 					}
185 					break;
186 				default:
187 					(void) sprintf(get_line(0, 0),
188 					    "Operation = %u (unknown)", n);
189 				}
190 				break;
191 			case 5:		/* SOCKS5 */
192 				(void) sprintf(cp, "Version = 5");
193 				n = buf[1];
194 				if (2 + n == fraglen) {
195 					(void) sprintf(get_line(0, 0),
196 					    "Number of methods = %u", n);
197 					for (i = 0;
198 						i < n && 2 + i < fraglen; ++i) {
199 						cp = get_line(0, 0);
200 						(void) sprintf(cp,
201 							"Method %3u =", i);
202 						cp += strlen(cp);
203 						put_method(cp, buf[2 + i]);
204 					}
205 				} else if (fraglen >= 6 && buf[2] == 0) {
206 					const char	*cmd;
207 					if (n < 1 || n > 3) {
208 						(void) sprintf(cp,
209 							"SOCKS (send data): %s",
210 							show_string(line,
211 							fraglen, 20));
212 					} else {
213 						switch (n) {
214 						case 1:
215 							cmd = "CONNECT";
216 							break;
217 						case 2:
218 							cmd = "BIND";
219 							break;
220 						case 3:
221 							cmd = "ASSOCIATE_UDP";
222 							break;
223 						}
224 						(void) sprintf(get_line(0, 0),
225 						    "Operation = %s ", cmd);
226 						put_socks5_addr(get_line(0, 0),
227 						    &buf[3], fraglen - 3);
228 						break;
229 					}
230 				} else
231 					(void) sprintf(cp,
232 						" SOCKS (send data): %s",
233 						show_string(line, fraglen,
234 						20));
235 				break;
236 			default:
237 				(void) sprintf(cp,
238 					"SOCKS (send data): %s",
239 					show_string(line, fraglen, 20));
240 			}
241 			show_space();
242 		} else
243 			(void) sprintf(cp,
244 				"SOCKS (send data): %s",
245 				show_string(line, fraglen, 20));
246 	}
247 
248 out:
249 	return (fraglen);
250 }
251 
252 int
253 interpret_socks_reply(flags, line, fraglen)
254 	int flags;
255 	char *line;
256 	int fraglen;
257 {
258 	unsigned char	*buf = (unsigned char *)line;
259 	char		*cp;
260 	struct in_addr	ipaddr;
261 
262 	if (flags & F_SUM) {
263 		cp = get_sum_line();
264 		if (fraglen >= 2) {
265 			switch (buf[0]) {
266 			case 0:
267 				(void) sprintf(cp, "SOCKS4 ");
268 				cp += strlen(cp);
269 				if (fraglen >= 8) {
270 					(void) memcpy(&ipaddr, &buf[4],
271 					    sizeof (ipaddr));
272 					(void) sprintf(cp, "%s:%u ",
273 					    addrtoname(AF_INET, &ipaddr),
274 					    (buf[2] << 8) | buf[3]);
275 					cp += strlen(cp);
276 				}
277 				/* reply version, no SOCKS version in v4 */
278 				put_socks4_res(cp, buf[1]);
279 				break;
280 			case 5:
281 				(void) sprintf(cp, "SOCKS5 method accepted:");
282 				cp += strlen(cp);
283 				put_method(cp, buf[1]);
284 				break;
285 			default:
286 				(void) sprintf(cp, "SOCKS (recv data)");
287 			}
288 		} else
289 			(void) sprintf(cp, "SOCKS (recv data)");
290 	}
291 
292 	if (flags & F_DTAIL) {
293 		show_header("SOCKS: ", "SOCKS Header", fraglen);
294 		show_space();
295 		cp = get_line(0, 0);
296 		if (fraglen >= 2) {
297 			switch (buf[0]) {
298 			case 0:
299 				/* reply version, no SOCKS version in v4 */
300 				(void) sprintf(cp,
301 				    "Reply version = 0 (SOCKS version 4)");
302 				if (fraglen >= 8) {
303 					(void) memcpy(&ipaddr, &buf[4],
304 					    sizeof (ipaddr));
305 					(void) sprintf(get_line(0, 0),
306 					    "Destination %s:%u ",
307 					    addrtoname(AF_INET, &ipaddr),
308 					    (buf[2] << 8) | buf[3]);
309 				}
310 				cp = get_line(0, 0);
311 				(void) sprintf(cp, "Result code = %u ", buf[1]);
312 				cp += strlen(cp);
313 				put_socks4_res(cp, buf[1]);
314 				break;
315 			case 5:
316 				(void) sprintf(cp, "Reply version = 5");
317 				if (fraglen == 2) {
318 					cp = get_line(0, 0);
319 					(void) sprintf(cp, "Method accepted =");
320 					cp += strlen(cp);
321 					put_method(cp, buf[1]);
322 				} else if (fraglen >= 6 && buf[2] == 0x00) {
323 					cp = get_line(0, 0);
324 					(void) sprintf(cp, "Status = ");
325 					cp += strlen(cp);
326 					put_socks5_res(cp, buf[1]);
327 					put_socks5_addr(get_line(0, 0),
328 					    &buf[3], fraglen - 3);
329 				}
330 				break;
331 			default:
332 				(void) sprintf(cp, "(recv data)");
333 			}
334 		} else
335 			(void) sprintf(cp, "(recv data)");
336 		show_space();
337 	}
338 
339 out:
340 	return (fraglen);
341 }
342 
343 static void
344 put_method(char *cp, int method)
345 {
346 	switch (method) {
347 	case 0:
348 		(void) sprintf(cp, " NOAUTH");
349 		break;
350 	case 1:
351 		(void) sprintf(cp, " GSSAPI");
352 		break;
353 	case 2:
354 		(void) sprintf(cp, " USERNAME/PASSWD");
355 		break;
356 	case 255:
357 		(void) sprintf(cp, " NONE");
358 		break;
359 	default:
360 		(void) sprintf(cp, " 0x%02x (unknown)", method);
361 	}
362 }
363 
364 static void
365 put_socks5_addr(char *cp, const unsigned char *buf, int fraglen)
366 {
367 	struct in_addr	ipaddr;
368 	int		i;
369 
370 	switch (buf[0]) {
371 	case 1:
372 		/* IPv4 */
373 		(void) sprintf(cp, "Address = ");
374 		cp += strlen(cp);
375 		if (1 + 4 + 2 <= fraglen) {
376 			(void) memcpy(&ipaddr, &buf[1], sizeof (ipaddr));
377 			(void) sprintf(cp, "%s:%u",
378 			    addrtoname(AF_INET, &ipaddr),
379 			    (buf[5] << 8) | buf[5 + 1]);
380 		} else
381 			(void) strcat(cp, "(IPv4)");
382 		break;
383 	case 3:
384 		/* domain name */
385 		(void) sprintf(cp, "Domain name = ");
386 		cp += strlen(cp);
387 		for (i = 0; i <= buf[1] && 1 + i < fraglen; ++i)
388 			*cp++ = buf[1 + i];
389 		if (1 + i + 2 <= fraglen)
390 			(void) sprintf(cp, ":%u",
391 			    (buf[1 + i] << 8) | buf[1 + i + 1]);
392 		else
393 			*cp = '\0';
394 		break;
395 	case 4:
396 		/* IPv6 */
397 		(void) sprintf(cp, "Address = ");
398 		if (1 + 16 <= fraglen) {
399 			for (i = 0; i < 16; ++i) {
400 				if (i > 0)
401 					*cp++ = '.';
402 				(void) sprintf(cp, "%u", buf[1 + i]);
403 				cp += strlen(cp);
404 			}
405 			if (1 + 16 + 2 <= fraglen) {
406 				(void) sprintf(cp, ":%u",
407 				    (buf[1 + 16] << 8) | buf[1 + 16 + 1]);
408 			}
409 		} else
410 			(void) strcat(cp, "(IPv6)");
411 		break;
412 	default:
413 		(void) sprintf(cp, "Address type = 0x%02x (unknown)", buf[0]);
414 	}
415 }
416 
417 static void
418 put_socks4_res(char *cp, int code)
419 {
420 	switch (code) {
421 	case 90:
422 		(void) sprintf(cp, "request granted");
423 		break;
424 	case 91:
425 		(void) sprintf(cp, "request rejected or failed");
426 		break;
427 	case 92:
428 		(void) sprintf(cp, "socksd can't connect to client's identd");
429 		break;
430 	case 93:
431 		(void) sprintf(cp, "identity mismatch");
432 		break;
433 	default:
434 		(void) sprintf(cp, "0x%02x (unknown)", code);
435 	}
436 }
437 
438 static void
439 put_socks5_res(char *cp, int code)
440 {
441 	switch (code) {
442 	case 0:
443 		(void) strcpy(cp, "succeeded");
444 		break;
445 	case 1:
446 		(void) strcpy(cp, "general SOCKS server failure");
447 		break;
448 	case 2:
449 		(void) strcpy(cp, "connection not allowed by ruleset");
450 		break;
451 	case 3:
452 		(void) strcpy(cp, "network unreachable");
453 		break;
454 	case 4:
455 		(void) strcpy(cp, "host unreachable");
456 		break;
457 	case 5:
458 		(void) strcpy(cp, "connection refused");
459 		break;
460 	case 6:
461 		(void) strcpy(cp, "TTL expired");
462 		break;
463 	case 7:
464 		(void) strcpy(cp, "command not supported");
465 		break;
466 	case 8:
467 		(void) strcpy(cp, "address type not supported");
468 		break;
469 	default:
470 		(void) sprintf(cp, "code 0x%02x", code);
471 	}
472 }
473