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