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 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 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 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 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 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 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