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