1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 0 stevel * Common Development and Distribution License, Version 1.0 only 6 0 stevel * (the "License"). You may not use this file except in compliance 7 0 stevel * with the License. 8 0 stevel * 9 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 0 stevel * or http://www.opensolaris.org/os/licensing. 11 0 stevel * See the License for the specific language governing permissions 12 0 stevel * and limitations under the License. 13 0 stevel * 14 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 15 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 0 stevel * If applicable, add the following below this CDDL HEADER, with the 17 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 18 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 19 0 stevel * 20 0 stevel * CDDL HEADER END 21 0 stevel */ 22 0 stevel /* 23 0 stevel * Copyright (c) 1998-1999,2001 by Sun Microsystems, Inc. 24 0 stevel * All rights reserved. 25 0 stevel */ 26 0 stevel 27 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 28 0 stevel 29 0 stevel #include <stdio.h> 30 0 stevel #include <sys/socket.h> 31 0 stevel #include <netinet/in.h> 32 0 stevel #include <string.h> 33 0 stevel #include "snoop.h" 34 0 stevel 35 0 stevel static void put_method(char *cp, int method); 36 0 stevel static void put_socks5_addr(char *cp, const unsigned char *buf, int fraglen); 37 0 stevel static void put_socks4_res(char *cp, int code); 38 0 stevel static void put_socks5_res(char *cp, int code); 39 0 stevel 40 0 stevel int 41 0 stevel interpret_socks_call(flags, line, fraglen) 42 0 stevel int flags; 43 0 stevel char *line; 44 0 stevel int fraglen; 45 0 stevel { 46 0 stevel unsigned char *buf = (unsigned char *)line; 47 0 stevel char *cp; 48 0 stevel struct in_addr ipaddr; 49 0 stevel int i, n; 50 0 stevel 51 0 stevel if (flags & F_SUM) { 52 0 stevel cp = get_sum_line(); 53 0 stevel if (fraglen >= 2) { 54 0 stevel switch (buf[0]) { 55 0 stevel case 4: /* SOCKS4 */ 56 0 stevel n = buf[1]; 57 0 stevel switch (n) { 58 0 stevel case 1: 59 0 stevel case 2: 60 0 stevel if (fraglen >= 8) { 61 0 stevel (void) memcpy(&ipaddr, &buf[4], 62 0 stevel sizeof (ipaddr)); 63 0 stevel (void) sprintf(cp, 64 0 stevel "SOCKS4 %s %s:%u", 65 0 stevel addrtoname(AF_INET, &ipaddr), 66 0 stevel (n == 1)? "CONNECT": "BIND", 67 0 stevel (buf[2] << 8) | buf[3]); 68 0 stevel cp += strlen(cp); 69 0 stevel if (fraglen > 8) { 70 0 stevel (void) sprintf(cp, " User="); 71 0 stevel cp += strlen(cp); 72 0 stevel for (i = 8; 73 0 stevel i < 40 && i < fraglen; 74 0 stevel ++i) { 75 0 stevel if (buf[i] == '\0') 76 0 stevel break; 77 0 stevel *cp++ = buf[i]; 78 0 stevel } 79 0 stevel if (i == 40) { 80 0 stevel *cp++ = '.'; 81 0 stevel *cp++ = '.'; 82 0 stevel *cp++ = '.'; 83 0 stevel } 84 0 stevel *cp = '\0'; 85 0 stevel } 86 0 stevel } 87 0 stevel break; 88 0 stevel default: 89 0 stevel (void) sprintf(cp, "SOCKS4 OP=%u", n); 90 0 stevel } 91 0 stevel break; 92 0 stevel case 5: /* SOCKS5 */ 93 0 stevel n = buf[1]; 94 0 stevel if (2 + n == fraglen) { 95 0 stevel (void) sprintf(cp, 96 0 stevel "SOCKS5 CONTACT NMETHODS=%d:", n); 97 0 stevel cp += strlen(cp); 98 0 stevel for (i = 0; i < n && 2 + i < fraglen; ++i) { 99 0 stevel put_method(cp, buf[2 + i]); 100 0 stevel cp += strlen(cp); 101 0 stevel } 102 0 stevel } else if (fraglen >= 6 && buf[2] == 0) { 103 0 stevel const char *cmd; 104 0 stevel 105 0 stevel if (n < 1 || n > 3) { 106 0 stevel (void) sprintf(cp, 107 0 stevel "SOCKS (send data): %s", 108 0 stevel show_string(line, fraglen, 20)); 109 0 stevel } else { 110 0 stevel switch (n) { 111 0 stevel case 1: 112 0 stevel cmd = "CONNECT"; 113 0 stevel break; 114 0 stevel case 2: 115 0 stevel cmd = "BIND"; 116 0 stevel break; 117 0 stevel case 3: 118 0 stevel cmd = "ASSOCIATE_UDP"; 119 0 stevel break; 120 0 stevel } 121 0 stevel (void) sprintf(cp, "SOCKS5 %s ", cmd); 122 0 stevel cp += strlen(cp); 123 0 stevel put_socks5_addr(cp, &buf[3], 124 0 stevel fraglen - 3); 125 0 stevel } 126 0 stevel } else { 127 0 stevel (void) sprintf(cp, "SOCKS (send data): %s", 128 0 stevel show_string(line, fraglen, 20)); 129 0 stevel } 130 0 stevel break; 131 0 stevel default: 132 0 stevel (void) sprintf(cp, "SOCKS (send data): %s", 133 0 stevel show_string(line, fraglen, 20)); 134 0 stevel } 135 0 stevel } else { 136 0 stevel (void) sprintf(cp, "SOCKS (send data): %s", 137 0 stevel show_string(line, fraglen, 20)); 138 0 stevel } 139 0 stevel 140 0 stevel } /* if (flags & F_SUM) */ 141 0 stevel 142 0 stevel if (flags & F_DTAIL) { 143 0 stevel show_header("SOCKS: ", "SOCKS Header", fraglen); 144 0 stevel show_space(); 145 0 stevel cp = get_line(0, 0); 146 0 stevel if (fraglen >= 2) { 147 0 stevel switch (buf[0]) { 148 0 stevel case 4: 149 0 stevel (void) sprintf(cp, "Version = 4"); 150 0 stevel n = buf[1]; 151 0 stevel switch (n) { 152 0 stevel case 1: 153 0 stevel case 2: 154 0 stevel (void) sprintf(get_line(0, 0), 155 0 stevel "Operation = %s", 156 0 stevel (n == 1)? "CONNECT": "BIND"); 157 0 stevel if (fraglen >= 8) { 158 0 stevel (void) memcpy(&ipaddr, &buf[4], 159 0 stevel sizeof (ipaddr)); 160 0 stevel (void) sprintf(get_line(0, 0), 161 0 stevel "Destination = %s:%u", 162 0 stevel addrtoname(AF_INET, 163 0 stevel &ipaddr), 164 0 stevel (buf[2] << 8) | buf[3]); 165 0 stevel if (fraglen > 8) { 166 0 stevel cp = get_line(0, 0); 167 0 stevel (void) sprintf(cp, 168 0 stevel "User = "); 169 0 stevel cp += strlen(cp); 170 0 stevel for (i = 8; 171 0 stevel i < 40; ++i) { 172 0 stevel if 173 0 stevel (buf[i] == '\0') 174 0 stevel break; 175 0 stevel *cp++ = buf[i]; 176 0 stevel } 177 0 stevel if (i == 40) { 178 0 stevel *cp++ = '.'; 179 0 stevel *cp++ = '.'; 180 0 stevel *cp++ = '.'; 181 0 stevel } 182 0 stevel *cp = '\0'; 183 0 stevel } 184 0 stevel } 185 0 stevel break; 186 0 stevel default: 187 0 stevel (void) sprintf(get_line(0, 0), 188 0 stevel "Operation = %u (unknown)", n); 189 0 stevel } 190 0 stevel break; 191 0 stevel case 5: /* SOCKS5 */ 192 0 stevel (void) sprintf(cp, "Version = 5"); 193 0 stevel n = buf[1]; 194 0 stevel if (2 + n == fraglen) { 195 0 stevel (void) sprintf(get_line(0, 0), 196 0 stevel "Number of methods = %u", n); 197 0 stevel for (i = 0; 198 0 stevel i < n && 2 + i < fraglen; ++i) { 199 0 stevel cp = get_line(0, 0); 200 0 stevel (void) sprintf(cp, 201 0 stevel "Method %3u =", i); 202 0 stevel cp += strlen(cp); 203 0 stevel put_method(cp, buf[2 + i]); 204 0 stevel } 205 0 stevel } else if (fraglen >= 6 && buf[2] == 0) { 206 0 stevel const char *cmd; 207 0 stevel if (n < 1 || n > 3) { 208 0 stevel (void) sprintf(cp, 209 0 stevel "SOCKS (send data): %s", 210 0 stevel show_string(line, 211 0 stevel fraglen, 20)); 212 0 stevel } else { 213 0 stevel switch (n) { 214 0 stevel case 1: 215 0 stevel cmd = "CONNECT"; 216 0 stevel break; 217 0 stevel case 2: 218 0 stevel cmd = "BIND"; 219 0 stevel break; 220 0 stevel case 3: 221 0 stevel cmd = "ASSOCIATE_UDP"; 222 0 stevel break; 223 0 stevel } 224 0 stevel (void) sprintf(get_line(0, 0), 225 0 stevel "Operation = %s ", cmd); 226 0 stevel put_socks5_addr(get_line(0, 0), 227 0 stevel &buf[3], fraglen - 3); 228 0 stevel break; 229 0 stevel } 230 0 stevel } else 231 0 stevel (void) sprintf(cp, 232 0 stevel " SOCKS (send data): %s", 233 0 stevel show_string(line, fraglen, 234 0 stevel 20)); 235 0 stevel break; 236 0 stevel default: 237 0 stevel (void) sprintf(cp, 238 0 stevel "SOCKS (send data): %s", 239 0 stevel show_string(line, fraglen, 20)); 240 0 stevel } 241 0 stevel show_space(); 242 0 stevel } else 243 0 stevel (void) sprintf(cp, 244 0 stevel "SOCKS (send data): %s", 245 0 stevel show_string(line, fraglen, 20)); 246 0 stevel } 247 0 stevel 248 0 stevel out: 249 0 stevel return (fraglen); 250 0 stevel } 251 0 stevel 252 0 stevel int 253 0 stevel interpret_socks_reply(flags, line, fraglen) 254 0 stevel int flags; 255 0 stevel char *line; 256 0 stevel int fraglen; 257 0 stevel { 258 0 stevel unsigned char *buf = (unsigned char *)line; 259 0 stevel char *cp; 260 0 stevel struct in_addr ipaddr; 261 0 stevel 262 0 stevel if (flags & F_SUM) { 263 0 stevel cp = get_sum_line(); 264 0 stevel if (fraglen >= 2) { 265 0 stevel switch (buf[0]) { 266 0 stevel case 0: 267 0 stevel (void) sprintf(cp, "SOCKS4 "); 268 0 stevel cp += strlen(cp); 269 0 stevel if (fraglen >= 8) { 270 0 stevel (void) memcpy(&ipaddr, &buf[4], 271 0 stevel sizeof (ipaddr)); 272 0 stevel (void) sprintf(cp, "%s:%u ", 273 0 stevel addrtoname(AF_INET, &ipaddr), 274 0 stevel (buf[2] << 8) | buf[3]); 275 0 stevel cp += strlen(cp); 276 0 stevel } 277 0 stevel /* reply version, no SOCKS version in v4 */ 278 0 stevel put_socks4_res(cp, buf[1]); 279 0 stevel break; 280 0 stevel case 5: 281 0 stevel (void) sprintf(cp, "SOCKS5 method accepted:"); 282 0 stevel cp += strlen(cp); 283 0 stevel put_method(cp, buf[1]); 284 0 stevel break; 285 0 stevel default: 286 0 stevel (void) sprintf(cp, "SOCKS (recv data)"); 287 0 stevel } 288 0 stevel } else 289 0 stevel (void) sprintf(cp, "SOCKS (recv data)"); 290 0 stevel } 291 0 stevel 292 0 stevel if (flags & F_DTAIL) { 293 0 stevel show_header("SOCKS: ", "SOCKS Header", fraglen); 294 0 stevel show_space(); 295 0 stevel cp = get_line(0, 0); 296 0 stevel if (fraglen >= 2) { 297 0 stevel switch (buf[0]) { 298 0 stevel case 0: 299 0 stevel /* reply version, no SOCKS version in v4 */ 300 0 stevel (void) sprintf(cp, 301 0 stevel "Reply version = 0 (SOCKS version 4)"); 302 0 stevel if (fraglen >= 8) { 303 0 stevel (void) memcpy(&ipaddr, &buf[4], 304 0 stevel sizeof (ipaddr)); 305 0 stevel (void) sprintf(get_line(0, 0), 306 0 stevel "Destination %s:%u ", 307 0 stevel addrtoname(AF_INET, &ipaddr), 308 0 stevel (buf[2] << 8) | buf[3]); 309 0 stevel } 310 0 stevel cp = get_line(0, 0); 311 0 stevel (void) sprintf(cp, "Result code = %u ", buf[1]); 312 0 stevel cp += strlen(cp); 313 0 stevel put_socks4_res(cp, buf[1]); 314 0 stevel break; 315 0 stevel case 5: 316 0 stevel (void) sprintf(cp, "Reply version = 5"); 317 0 stevel if (fraglen == 2) { 318 0 stevel cp = get_line(0, 0); 319 0 stevel (void) sprintf(cp, "Method accepted ="); 320 0 stevel cp += strlen(cp); 321 0 stevel put_method(cp, buf[1]); 322 0 stevel } else if (fraglen >= 6 && buf[2] == 0x00) { 323 0 stevel cp = get_line(0, 0); 324 0 stevel (void) sprintf(cp, "Status = "); 325 0 stevel cp += strlen(cp); 326 0 stevel put_socks5_res(cp, buf[1]); 327 0 stevel put_socks5_addr(get_line(0, 0), 328 0 stevel &buf[3], fraglen - 3); 329 0 stevel } 330 0 stevel break; 331 0 stevel default: 332 0 stevel (void) sprintf(cp, "(recv data)"); 333 0 stevel } 334 0 stevel } else 335 0 stevel (void) sprintf(cp, "(recv data)"); 336 0 stevel show_space(); 337 0 stevel } 338 0 stevel 339 0 stevel out: 340 0 stevel return (fraglen); 341 0 stevel } 342 0 stevel 343 0 stevel static void 344 0 stevel put_method(char *cp, int method) 345 0 stevel { 346 0 stevel switch (method) { 347 0 stevel case 0: 348 0 stevel (void) sprintf(cp, " NOAUTH"); 349 0 stevel break; 350 0 stevel case 1: 351 0 stevel (void) sprintf(cp, " GSSAPI"); 352 0 stevel break; 353 0 stevel case 2: 354 0 stevel (void) sprintf(cp, " USERNAME/PASSWD"); 355 0 stevel break; 356 0 stevel case 255: 357 0 stevel (void) sprintf(cp, " NONE"); 358 0 stevel break; 359 0 stevel default: 360 0 stevel (void) sprintf(cp, " 0x%02x (unknown)", method); 361 0 stevel } 362 0 stevel } 363 0 stevel 364 0 stevel static void 365 0 stevel put_socks5_addr(char *cp, const unsigned char *buf, int fraglen) 366 0 stevel { 367 0 stevel struct in_addr ipaddr; 368 0 stevel int i; 369 0 stevel 370 0 stevel switch (buf[0]) { 371 0 stevel case 1: 372 0 stevel /* IPv4 */ 373 0 stevel (void) sprintf(cp, "Address = "); 374 0 stevel cp += strlen(cp); 375 0 stevel if (1 + 4 + 2 <= fraglen) { 376 0 stevel (void) memcpy(&ipaddr, &buf[1], sizeof (ipaddr)); 377 0 stevel (void) sprintf(cp, "%s:%u", 378 0 stevel addrtoname(AF_INET, &ipaddr), 379 0 stevel (buf[5] << 8) | buf[5 + 1]); 380 0 stevel } else 381 0 stevel (void) strcat(cp, "(IPv4)"); 382 0 stevel break; 383 0 stevel case 3: 384 0 stevel /* domain name */ 385 0 stevel (void) sprintf(cp, "Domain name = "); 386 0 stevel cp += strlen(cp); 387 0 stevel for (i = 0; i <= buf[1] && 1 + i < fraglen; ++i) 388 0 stevel *cp++ = buf[1 + i]; 389 0 stevel if (1 + i + 2 <= fraglen) 390 0 stevel (void) sprintf(cp, ":%u", 391 0 stevel (buf[1 + i] << 8) | buf[1 + i + 1]); 392 0 stevel else 393 0 stevel *cp = '\0'; 394 0 stevel break; 395 0 stevel case 4: 396 0 stevel /* IPv6 */ 397 0 stevel (void) sprintf(cp, "Address = "); 398 0 stevel if (1 + 16 <= fraglen) { 399 0 stevel for (i = 0; i < 16; ++i) { 400 0 stevel if (i > 0) 401 0 stevel *cp++ = '.'; 402 0 stevel (void) sprintf(cp, "%u", buf[1 + i]); 403 0 stevel cp += strlen(cp); 404 0 stevel } 405 0 stevel if (1 + 16 + 2 <= fraglen) { 406 0 stevel (void) sprintf(cp, ":%u", 407 0 stevel (buf[1 + 16] << 8) | buf[1 + 16 + 1]); 408 0 stevel } 409 0 stevel } else 410 0 stevel (void) strcat(cp, "(IPv6)"); 411 0 stevel break; 412 0 stevel default: 413 0 stevel (void) sprintf(cp, "Address type = 0x%02x (unknown)", buf[0]); 414 0 stevel } 415 0 stevel } 416 0 stevel 417 0 stevel static void 418 0 stevel put_socks4_res(char *cp, int code) 419 0 stevel { 420 0 stevel switch (code) { 421 0 stevel case 90: 422 0 stevel (void) sprintf(cp, "request granted"); 423 0 stevel break; 424 0 stevel case 91: 425 0 stevel (void) sprintf(cp, "request rejected or failed"); 426 0 stevel break; 427 0 stevel case 92: 428 0 stevel (void) sprintf(cp, "socksd can't connect to client's identd"); 429 0 stevel break; 430 0 stevel case 93: 431 0 stevel (void) sprintf(cp, "identity mismatch"); 432 0 stevel break; 433 0 stevel default: 434 0 stevel (void) sprintf(cp, "0x%02x (unknown)", code); 435 0 stevel } 436 0 stevel } 437 0 stevel 438 0 stevel static void 439 0 stevel put_socks5_res(char *cp, int code) 440 0 stevel { 441 0 stevel switch (code) { 442 0 stevel case 0: 443 0 stevel (void) strcpy(cp, "succeeded"); 444 0 stevel break; 445 0 stevel case 1: 446 0 stevel (void) strcpy(cp, "general SOCKS server failure"); 447 0 stevel break; 448 0 stevel case 2: 449 0 stevel (void) strcpy(cp, "connection not allowed by ruleset"); 450 0 stevel break; 451 0 stevel case 3: 452 0 stevel (void) strcpy(cp, "network unreachable"); 453 0 stevel break; 454 0 stevel case 4: 455 0 stevel (void) strcpy(cp, "host unreachable"); 456 0 stevel break; 457 0 stevel case 5: 458 0 stevel (void) strcpy(cp, "connection refused"); 459 0 stevel break; 460 0 stevel case 6: 461 0 stevel (void) strcpy(cp, "TTL expired"); 462 0 stevel break; 463 0 stevel case 7: 464 0 stevel (void) strcpy(cp, "command not supported"); 465 0 stevel break; 466 0 stevel case 8: 467 0 stevel (void) strcpy(cp, "address type not supported"); 468 0 stevel break; 469 0 stevel default: 470 0 stevel (void) sprintf(cp, "code 0x%02x", code); 471 0 stevel } 472 0 stevel } 473