xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_socks.c (revision 33efde4275d24731ef87927237b0ffb0630b6b2d)
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
interpret_socks_call(flags,line,fraglen)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 	return (fraglen);
247 }
248 
249 int
interpret_socks_reply(flags,line,fraglen)250 interpret_socks_reply(flags, line, fraglen)
251 	int flags;
252 	char *line;
253 	int fraglen;
254 {
255 	unsigned char	*buf = (unsigned char *)line;
256 	char		*cp;
257 	struct in_addr	ipaddr;
258 
259 	if (flags & F_SUM) {
260 		cp = get_sum_line();
261 		if (fraglen >= 2) {
262 			switch (buf[0]) {
263 			case 0:
264 				(void) sprintf(cp, "SOCKS4 ");
265 				cp += strlen(cp);
266 				if (fraglen >= 8) {
267 					(void) memcpy(&ipaddr, &buf[4],
268 					    sizeof (ipaddr));
269 					(void) sprintf(cp, "%s:%u ",
270 					    addrtoname(AF_INET, &ipaddr),
271 					    (buf[2] << 8) | buf[3]);
272 					cp += strlen(cp);
273 				}
274 				/* reply version, no SOCKS version in v4 */
275 				put_socks4_res(cp, buf[1]);
276 				break;
277 			case 5:
278 				(void) sprintf(cp, "SOCKS5 method accepted:");
279 				cp += strlen(cp);
280 				put_method(cp, buf[1]);
281 				break;
282 			default:
283 				(void) sprintf(cp, "SOCKS (recv data)");
284 			}
285 		} else
286 			(void) sprintf(cp, "SOCKS (recv data)");
287 	}
288 
289 	if (flags & F_DTAIL) {
290 		show_header("SOCKS: ", "SOCKS Header", fraglen);
291 		show_space();
292 		cp = get_line(0, 0);
293 		if (fraglen >= 2) {
294 			switch (buf[0]) {
295 			case 0:
296 				/* reply version, no SOCKS version in v4 */
297 				(void) sprintf(cp,
298 				    "Reply version = 0 (SOCKS version 4)");
299 				if (fraglen >= 8) {
300 					(void) memcpy(&ipaddr, &buf[4],
301 					    sizeof (ipaddr));
302 					(void) sprintf(get_line(0, 0),
303 					    "Destination %s:%u ",
304 					    addrtoname(AF_INET, &ipaddr),
305 					    (buf[2] << 8) | buf[3]);
306 				}
307 				cp = get_line(0, 0);
308 				(void) sprintf(cp, "Result code = %u ", buf[1]);
309 				cp += strlen(cp);
310 				put_socks4_res(cp, buf[1]);
311 				break;
312 			case 5:
313 				(void) sprintf(cp, "Reply version = 5");
314 				if (fraglen == 2) {
315 					cp = get_line(0, 0);
316 					(void) sprintf(cp, "Method accepted =");
317 					cp += strlen(cp);
318 					put_method(cp, buf[1]);
319 				} else if (fraglen >= 6 && buf[2] == 0x00) {
320 					cp = get_line(0, 0);
321 					(void) sprintf(cp, "Status = ");
322 					cp += strlen(cp);
323 					put_socks5_res(cp, buf[1]);
324 					put_socks5_addr(get_line(0, 0),
325 					    &buf[3], fraglen - 3);
326 				}
327 				break;
328 			default:
329 				(void) sprintf(cp, "(recv data)");
330 			}
331 		} else
332 			(void) sprintf(cp, "(recv data)");
333 		show_space();
334 	}
335 
336 	return (fraglen);
337 }
338 
339 static void
put_method(char * cp,int method)340 put_method(char *cp, int method)
341 {
342 	switch (method) {
343 	case 0:
344 		(void) sprintf(cp, " NOAUTH");
345 		break;
346 	case 1:
347 		(void) sprintf(cp, " GSSAPI");
348 		break;
349 	case 2:
350 		(void) sprintf(cp, " USERNAME/PASSWD");
351 		break;
352 	case 255:
353 		(void) sprintf(cp, " NONE");
354 		break;
355 	default:
356 		(void) sprintf(cp, " 0x%02x (unknown)", method);
357 	}
358 }
359 
360 static void
put_socks5_addr(char * cp,const unsigned char * buf,int fraglen)361 put_socks5_addr(char *cp, const unsigned char *buf, int fraglen)
362 {
363 	struct in_addr	ipaddr;
364 	int		i;
365 
366 	switch (buf[0]) {
367 	case 1:
368 		/* IPv4 */
369 		(void) sprintf(cp, "Address = ");
370 		cp += strlen(cp);
371 		if (1 + 4 + 2 <= fraglen) {
372 			(void) memcpy(&ipaddr, &buf[1], sizeof (ipaddr));
373 			(void) sprintf(cp, "%s:%u",
374 			    addrtoname(AF_INET, &ipaddr),
375 			    (buf[5] << 8) | buf[5 + 1]);
376 		} else
377 			(void) strcat(cp, "(IPv4)");
378 		break;
379 	case 3:
380 		/* domain name */
381 		(void) sprintf(cp, "Domain name = ");
382 		cp += strlen(cp);
383 		for (i = 0; i <= buf[1] && 1 + i < fraglen; ++i)
384 			*cp++ = buf[1 + i];
385 		if (1 + i + 2 <= fraglen)
386 			(void) sprintf(cp, ":%u",
387 			    (buf[1 + i] << 8) | buf[1 + i + 1]);
388 		else
389 			*cp = '\0';
390 		break;
391 	case 4:
392 		/* IPv6 */
393 		(void) sprintf(cp, "Address = ");
394 		if (1 + 16 <= fraglen) {
395 			for (i = 0; i < 16; ++i) {
396 				if (i > 0)
397 					*cp++ = '.';
398 				(void) sprintf(cp, "%u", buf[1 + i]);
399 				cp += strlen(cp);
400 			}
401 			if (1 + 16 + 2 <= fraglen) {
402 				(void) sprintf(cp, ":%u",
403 				    (buf[1 + 16] << 8) | buf[1 + 16 + 1]);
404 			}
405 		} else
406 			(void) strcat(cp, "(IPv6)");
407 		break;
408 	default:
409 		(void) sprintf(cp, "Address type = 0x%02x (unknown)", buf[0]);
410 	}
411 }
412 
413 static void
put_socks4_res(char * cp,int code)414 put_socks4_res(char *cp, int code)
415 {
416 	switch (code) {
417 	case 90:
418 		(void) sprintf(cp, "request granted");
419 		break;
420 	case 91:
421 		(void) sprintf(cp, "request rejected or failed");
422 		break;
423 	case 92:
424 		(void) sprintf(cp, "socksd can't connect to client's identd");
425 		break;
426 	case 93:
427 		(void) sprintf(cp, "identity mismatch");
428 		break;
429 	default:
430 		(void) sprintf(cp, "0x%02x (unknown)", code);
431 	}
432 }
433 
434 static void
put_socks5_res(char * cp,int code)435 put_socks5_res(char *cp, int code)
436 {
437 	switch (code) {
438 	case 0:
439 		(void) strcpy(cp, "succeeded");
440 		break;
441 	case 1:
442 		(void) strcpy(cp, "general SOCKS server failure");
443 		break;
444 	case 2:
445 		(void) strcpy(cp, "connection not allowed by ruleset");
446 		break;
447 	case 3:
448 		(void) strcpy(cp, "network unreachable");
449 		break;
450 	case 4:
451 		(void) strcpy(cp, "host unreachable");
452 		break;
453 	case 5:
454 		(void) strcpy(cp, "connection refused");
455 		break;
456 	case 6:
457 		(void) strcpy(cp, "TTL expired");
458 		break;
459 	case 7:
460 		(void) strcpy(cp, "command not supported");
461 		break;
462 	case 8:
463 		(void) strcpy(cp, "address type not supported");
464 		break;
465 	default:
466 		(void) sprintf(cp, "code 0x%02x", code);
467 	}
468 }
469