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 out:
247 return (fraglen);
248 }
249
250 int
interpret_socks_reply(flags,line,fraglen)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
put_method(char * cp,int method)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
put_socks5_addr(char * cp,const unsigned char * buf,int fraglen)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
put_socks4_res(char * cp,int code)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
put_socks5_res(char * cp,int code)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