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
interpret_socks_call(flags,line,fraglen)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
interpret_socks_reply(flags,line,fraglen)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
put_method(char * cp,int method)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
put_socks5_addr(char * cp,const unsigned char * buf,int fraglen)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
put_socks4_res(char * cp,int code)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
put_socks5_res(char * cp,int code)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