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