socks5.c (84510B)
1 /* socks5.c -- generated by Trunnel v1.5.3. 2 * https://gitweb.torproject.org/trunnel.git 3 * You probably shouldn't edit this file. 4 */ 5 #include <stdlib.h> 6 #include "trunnel-impl.h" 7 8 #include "socks5.h" 9 10 #define TRUNNEL_SET_ERROR_CODE(obj) \ 11 do { \ 12 (obj)->trunnel_error_code_ = 1; \ 13 } while (0) 14 15 #if defined(__COVERITY__) || defined(__clang_analyzer__) 16 /* If we're running a static analysis tool, we don't want it to complain 17 * that some of our remaining-bytes checks are dead-code. */ 18 int socks_deadcode_dummy__ = 0; 19 #define OR_DEADCODE_DUMMY || socks_deadcode_dummy__ 20 #else 21 #define OR_DEADCODE_DUMMY 22 #endif 23 24 #define CHECK_REMAINING(nbytes, label) \ 25 do { \ 26 if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ 27 goto label; \ 28 } \ 29 } while (0) 30 31 domainname_t * 32 domainname_new(void) 33 { 34 domainname_t *val = trunnel_calloc(1, sizeof(domainname_t)); 35 if (NULL == val) 36 return NULL; 37 return val; 38 } 39 40 /** Release all storage held inside 'obj', but do not free 'obj'. 41 */ 42 static void 43 domainname_clear(domainname_t *obj) 44 { 45 (void) obj; 46 TRUNNEL_DYNARRAY_WIPE(&obj->name); 47 TRUNNEL_DYNARRAY_CLEAR(&obj->name); 48 } 49 50 void 51 domainname_free(domainname_t *obj) 52 { 53 if (obj == NULL) 54 return; 55 domainname_clear(obj); 56 trunnel_memwipe(obj, sizeof(domainname_t)); 57 trunnel_free_(obj); 58 } 59 60 uint8_t 61 domainname_get_len(const domainname_t *inp) 62 { 63 return inp->len; 64 } 65 int 66 domainname_set_len(domainname_t *inp, uint8_t val) 67 { 68 inp->len = val; 69 return 0; 70 } 71 size_t 72 domainname_getlen_name(const domainname_t *inp) 73 { 74 return TRUNNEL_DYNARRAY_LEN(&inp->name); 75 } 76 77 char 78 domainname_get_name(domainname_t *inp, size_t idx) 79 { 80 return TRUNNEL_DYNARRAY_GET(&inp->name, idx); 81 } 82 83 char 84 domainname_getconst_name(const domainname_t *inp, size_t idx) 85 { 86 return domainname_get_name((domainname_t*)inp, idx); 87 } 88 int 89 domainname_set_name(domainname_t *inp, size_t idx, char elt) 90 { 91 TRUNNEL_DYNARRAY_SET(&inp->name, idx, elt); 92 return 0; 93 } 94 int 95 domainname_add_name(domainname_t *inp, char elt) 96 { 97 #if SIZE_MAX >= UINT8_MAX 98 if (inp->name.n_ == UINT8_MAX) 99 goto trunnel_alloc_failed; 100 #endif 101 TRUNNEL_DYNARRAY_ADD(char, &inp->name, elt, {}); 102 return 0; 103 trunnel_alloc_failed: 104 TRUNNEL_SET_ERROR_CODE(inp); 105 return -1; 106 } 107 108 char * 109 domainname_getarray_name(domainname_t *inp) 110 { 111 return inp->name.elts_; 112 } 113 const char * 114 domainname_getconstarray_name(const domainname_t *inp) 115 { 116 return (const char *)domainname_getarray_name((domainname_t*)inp); 117 } 118 int 119 domainname_setlen_name(domainname_t *inp, size_t newlen) 120 { 121 #if UINT8_MAX < SIZE_MAX 122 if (newlen > UINT8_MAX) 123 goto trunnel_alloc_failed; 124 #endif 125 return trunnel_string_setlen(&inp->name, newlen, 126 &inp->trunnel_error_code_); 127 trunnel_alloc_failed: 128 TRUNNEL_SET_ERROR_CODE(inp); 129 return -1; 130 } 131 const char * 132 domainname_getstr_name(domainname_t *inp) 133 { 134 return trunnel_string_getstr(&inp->name); 135 } 136 int 137 domainname_setstr0_name(domainname_t *inp, const char *val, size_t len) 138 { 139 #if UINT8_MAX < SIZE_MAX 140 if (len > UINT8_MAX) { 141 TRUNNEL_SET_ERROR_CODE(inp); 142 return -1; 143 } 144 #endif 145 return trunnel_string_setstr0(&inp->name, val, len, &inp->trunnel_error_code_); 146 } 147 int 148 domainname_setstr_name(domainname_t *inp, const char *val) 149 { 150 return domainname_setstr0_name(inp, val, strlen(val)); 151 } 152 const char * 153 domainname_check(const domainname_t *obj) 154 { 155 if (obj == NULL) 156 return "Object was NULL"; 157 if (obj->trunnel_error_code_) 158 return "A set function failed on this object"; 159 if (TRUNNEL_DYNARRAY_LEN(&obj->name) != obj->len) 160 return "Length mismatch for name"; 161 return NULL; 162 } 163 164 ssize_t 165 domainname_encoded_len(const domainname_t *obj) 166 { 167 ssize_t result = 0; 168 169 if (NULL != domainname_check(obj)) 170 return -1; 171 172 173 /* Length of u8 len */ 174 result += 1; 175 176 /* Length of char name[len] */ 177 result += TRUNNEL_DYNARRAY_LEN(&obj->name); 178 return result; 179 } 180 int 181 domainname_clear_errors(domainname_t *obj) 182 { 183 int r = obj->trunnel_error_code_; 184 obj->trunnel_error_code_ = 0; 185 return r; 186 } 187 ssize_t 188 domainname_encode(uint8_t *output, const size_t avail, const domainname_t *obj) 189 { 190 ssize_t result = 0; 191 size_t written = 0; 192 uint8_t *ptr = output; 193 const char *msg; 194 #ifdef TRUNNEL_CHECK_ENCODED_LEN 195 const ssize_t encoded_len = domainname_encoded_len(obj); 196 #endif 197 198 if (NULL != (msg = domainname_check(obj))) 199 goto check_failed; 200 201 #ifdef TRUNNEL_CHECK_ENCODED_LEN 202 trunnel_assert(encoded_len >= 0); 203 #endif 204 205 /* Encode u8 len */ 206 trunnel_assert(written <= avail); 207 if (avail - written < 1) 208 goto truncated; 209 trunnel_set_uint8(ptr, (obj->len)); 210 written += 1; ptr += 1; 211 212 /* Encode char name[len] */ 213 { 214 size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->name); 215 trunnel_assert(obj->len == elt_len); 216 trunnel_assert(written <= avail); 217 if (avail - written < elt_len) 218 goto truncated; 219 if (elt_len) 220 memcpy(ptr, obj->name.elts_, elt_len); 221 written += elt_len; ptr += elt_len; 222 } 223 224 225 trunnel_assert(ptr == output + written); 226 #ifdef TRUNNEL_CHECK_ENCODED_LEN 227 { 228 trunnel_assert(encoded_len >= 0); 229 trunnel_assert((size_t)encoded_len == written); 230 } 231 232 #endif 233 234 return written; 235 236 truncated: 237 result = -2; 238 goto fail; 239 check_failed: 240 (void)msg; 241 result = -1; 242 goto fail; 243 fail: 244 trunnel_assert(result < 0); 245 return result; 246 } 247 248 /** As domainname_parse(), but do not allocate the output object. 249 */ 250 static ssize_t 251 domainname_parse_into(domainname_t *obj, const uint8_t *input, const size_t len_in) 252 { 253 const uint8_t *ptr = input; 254 size_t remaining = len_in; 255 ssize_t result = 0; 256 (void)result; 257 258 /* Parse u8 len */ 259 CHECK_REMAINING(1, truncated); 260 obj->len = (trunnel_get_uint8(ptr)); 261 remaining -= 1; ptr += 1; 262 263 /* Parse char name[len] */ 264 CHECK_REMAINING(obj->len, truncated); 265 if (domainname_setstr0_name(obj, (const char*)ptr, obj->len)) 266 goto fail; 267 ptr += obj->len; remaining -= obj->len; 268 trunnel_assert(ptr + remaining == input + len_in); 269 return len_in - remaining; 270 271 truncated: 272 return -2; 273 fail: 274 result = -1; 275 return result; 276 } 277 278 ssize_t 279 domainname_parse(domainname_t **output, const uint8_t *input, const size_t len_in) 280 { 281 ssize_t result; 282 *output = domainname_new(); 283 if (NULL == *output) 284 return -1; 285 result = domainname_parse_into(*output, input, len_in); 286 if (result < 0) { 287 domainname_free(*output); 288 *output = NULL; 289 } 290 return result; 291 } 292 socks4_client_request_t * 293 socks4_client_request_new(void) 294 { 295 socks4_client_request_t *val = trunnel_calloc(1, sizeof(socks4_client_request_t)); 296 if (NULL == val) 297 return NULL; 298 val->version = 4; 299 val->command = CMD_BIND; 300 return val; 301 } 302 303 /** Release all storage held inside 'obj', but do not free 'obj'. 304 */ 305 static void 306 socks4_client_request_clear(socks4_client_request_t *obj) 307 { 308 (void) obj; 309 trunnel_wipestr(obj->username); 310 trunnel_free(obj->username); 311 trunnel_wipestr(obj->socks4a_addr_hostname); 312 trunnel_free(obj->socks4a_addr_hostname); 313 } 314 315 void 316 socks4_client_request_free(socks4_client_request_t *obj) 317 { 318 if (obj == NULL) 319 return; 320 socks4_client_request_clear(obj); 321 trunnel_memwipe(obj, sizeof(socks4_client_request_t)); 322 trunnel_free_(obj); 323 } 324 325 uint8_t 326 socks4_client_request_get_version(const socks4_client_request_t *inp) 327 { 328 return inp->version; 329 } 330 int 331 socks4_client_request_set_version(socks4_client_request_t *inp, uint8_t val) 332 { 333 if (! ((val == 4))) { 334 TRUNNEL_SET_ERROR_CODE(inp); 335 return -1; 336 } 337 inp->version = val; 338 return 0; 339 } 340 uint8_t 341 socks4_client_request_get_command(const socks4_client_request_t *inp) 342 { 343 return inp->command; 344 } 345 int 346 socks4_client_request_set_command(socks4_client_request_t *inp, uint8_t val) 347 { 348 if (! ((val == CMD_BIND || val == CMD_CONNECT || val == CMD_RESOLVE || val == CMD_RESOLVE_PTR))) { 349 TRUNNEL_SET_ERROR_CODE(inp); 350 return -1; 351 } 352 inp->command = val; 353 return 0; 354 } 355 uint16_t 356 socks4_client_request_get_port(const socks4_client_request_t *inp) 357 { 358 return inp->port; 359 } 360 int 361 socks4_client_request_set_port(socks4_client_request_t *inp, uint16_t val) 362 { 363 inp->port = val; 364 return 0; 365 } 366 uint32_t 367 socks4_client_request_get_addr(const socks4_client_request_t *inp) 368 { 369 return inp->addr; 370 } 371 int 372 socks4_client_request_set_addr(socks4_client_request_t *inp, uint32_t val) 373 { 374 inp->addr = val; 375 return 0; 376 } 377 const char * 378 socks4_client_request_get_username(const socks4_client_request_t *inp) 379 { 380 return inp->username; 381 } 382 int 383 socks4_client_request_set_username(socks4_client_request_t *inp, const char *val) 384 { 385 trunnel_free(inp->username); 386 if (NULL == (inp->username = trunnel_strdup(val))) { 387 TRUNNEL_SET_ERROR_CODE(inp); 388 return -1; 389 } 390 return 0; 391 } 392 const char * 393 socks4_client_request_get_socks4a_addr_hostname(const socks4_client_request_t *inp) 394 { 395 return inp->socks4a_addr_hostname; 396 } 397 int 398 socks4_client_request_set_socks4a_addr_hostname(socks4_client_request_t *inp, const char *val) 399 { 400 trunnel_free(inp->socks4a_addr_hostname); 401 if (NULL == (inp->socks4a_addr_hostname = trunnel_strdup(val))) { 402 TRUNNEL_SET_ERROR_CODE(inp); 403 return -1; 404 } 405 return 0; 406 } 407 const char * 408 socks4_client_request_check(const socks4_client_request_t *obj) 409 { 410 if (obj == NULL) 411 return "Object was NULL"; 412 if (obj->trunnel_error_code_) 413 return "A set function failed on this object"; 414 if (! (obj->version == 4)) 415 return "Integer out of bounds"; 416 if (! (obj->command == CMD_BIND || obj->command == CMD_CONNECT || obj->command == CMD_RESOLVE || obj->command == CMD_RESOLVE_PTR)) 417 return "Integer out of bounds"; 418 if (NULL == obj->username) 419 return "Missing username"; 420 switch (obj->addr) { 421 422 case 1: 423 case 2: 424 case 3: 425 case 4: 426 case 5: 427 case 6: 428 case 7: 429 case 8: 430 case 9: 431 case 10: 432 case 11: 433 case 12: 434 case 13: 435 case 14: 436 case 15: 437 case 16: 438 case 17: 439 case 18: 440 case 19: 441 case 20: 442 case 21: 443 case 22: 444 case 23: 445 case 24: 446 case 25: 447 case 26: 448 case 27: 449 case 28: 450 case 29: 451 case 30: 452 case 31: 453 case 32: 454 case 33: 455 case 34: 456 case 35: 457 case 36: 458 case 37: 459 case 38: 460 case 39: 461 case 40: 462 case 41: 463 case 42: 464 case 43: 465 case 44: 466 case 45: 467 case 46: 468 case 47: 469 case 48: 470 case 49: 471 case 50: 472 case 51: 473 case 52: 474 case 53: 475 case 54: 476 case 55: 477 case 56: 478 case 57: 479 case 58: 480 case 59: 481 case 60: 482 case 61: 483 case 62: 484 case 63: 485 case 64: 486 case 65: 487 case 66: 488 case 67: 489 case 68: 490 case 69: 491 case 70: 492 case 71: 493 case 72: 494 case 73: 495 case 74: 496 case 75: 497 case 76: 498 case 77: 499 case 78: 500 case 79: 501 case 80: 502 case 81: 503 case 82: 504 case 83: 505 case 84: 506 case 85: 507 case 86: 508 case 87: 509 case 88: 510 case 89: 511 case 90: 512 case 91: 513 case 92: 514 case 93: 515 case 94: 516 case 95: 517 case 96: 518 case 97: 519 case 98: 520 case 99: 521 case 100: 522 case 101: 523 case 102: 524 case 103: 525 case 104: 526 case 105: 527 case 106: 528 case 107: 529 case 108: 530 case 109: 531 case 110: 532 case 111: 533 case 112: 534 case 113: 535 case 114: 536 case 115: 537 case 116: 538 case 117: 539 case 118: 540 case 119: 541 case 120: 542 case 121: 543 case 122: 544 case 123: 545 case 124: 546 case 125: 547 case 126: 548 case 127: 549 case 128: 550 case 129: 551 case 130: 552 case 131: 553 case 132: 554 case 133: 555 case 134: 556 case 135: 557 case 136: 558 case 137: 559 case 138: 560 case 139: 561 case 140: 562 case 141: 563 case 142: 564 case 143: 565 case 144: 566 case 145: 567 case 146: 568 case 147: 569 case 148: 570 case 149: 571 case 150: 572 case 151: 573 case 152: 574 case 153: 575 case 154: 576 case 155: 577 case 156: 578 case 157: 579 case 158: 580 case 159: 581 case 160: 582 case 161: 583 case 162: 584 case 163: 585 case 164: 586 case 165: 587 case 166: 588 case 167: 589 case 168: 590 case 169: 591 case 170: 592 case 171: 593 case 172: 594 case 173: 595 case 174: 596 case 175: 597 case 176: 598 case 177: 599 case 178: 600 case 179: 601 case 180: 602 case 181: 603 case 182: 604 case 183: 605 case 184: 606 case 185: 607 case 186: 608 case 187: 609 case 188: 610 case 189: 611 case 190: 612 case 191: 613 case 192: 614 case 193: 615 case 194: 616 case 195: 617 case 196: 618 case 197: 619 case 198: 620 case 199: 621 case 200: 622 case 201: 623 case 202: 624 case 203: 625 case 204: 626 case 205: 627 case 206: 628 case 207: 629 case 208: 630 case 209: 631 case 210: 632 case 211: 633 case 212: 634 case 213: 635 case 214: 636 case 215: 637 case 216: 638 case 217: 639 case 218: 640 case 219: 641 case 220: 642 case 221: 643 case 222: 644 case 223: 645 case 224: 646 case 225: 647 case 226: 648 case 227: 649 case 228: 650 case 229: 651 case 230: 652 case 231: 653 case 232: 654 case 233: 655 case 234: 656 case 235: 657 case 236: 658 case 237: 659 case 238: 660 case 239: 661 case 240: 662 case 241: 663 case 242: 664 case 243: 665 case 244: 666 case 245: 667 case 246: 668 case 247: 669 case 248: 670 case 249: 671 case 250: 672 case 251: 673 case 252: 674 case 253: 675 case 254: 676 case 255: 677 if (NULL == obj->socks4a_addr_hostname) 678 return "Missing socks4a_addr_hostname"; 679 break; 680 681 default: 682 break; 683 } 684 return NULL; 685 } 686 687 ssize_t 688 socks4_client_request_encoded_len(const socks4_client_request_t *obj) 689 { 690 ssize_t result = 0; 691 692 if (NULL != socks4_client_request_check(obj)) 693 return -1; 694 695 696 /* Length of u8 version IN [4] */ 697 result += 1; 698 699 /* Length of u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR] */ 700 result += 1; 701 702 /* Length of u16 port */ 703 result += 2; 704 705 /* Length of u32 addr */ 706 result += 4; 707 708 /* Length of nulterm username */ 709 result += strlen(obj->username) + 1; 710 switch (obj->addr) { 711 712 case 1: 713 case 2: 714 case 3: 715 case 4: 716 case 5: 717 case 6: 718 case 7: 719 case 8: 720 case 9: 721 case 10: 722 case 11: 723 case 12: 724 case 13: 725 case 14: 726 case 15: 727 case 16: 728 case 17: 729 case 18: 730 case 19: 731 case 20: 732 case 21: 733 case 22: 734 case 23: 735 case 24: 736 case 25: 737 case 26: 738 case 27: 739 case 28: 740 case 29: 741 case 30: 742 case 31: 743 case 32: 744 case 33: 745 case 34: 746 case 35: 747 case 36: 748 case 37: 749 case 38: 750 case 39: 751 case 40: 752 case 41: 753 case 42: 754 case 43: 755 case 44: 756 case 45: 757 case 46: 758 case 47: 759 case 48: 760 case 49: 761 case 50: 762 case 51: 763 case 52: 764 case 53: 765 case 54: 766 case 55: 767 case 56: 768 case 57: 769 case 58: 770 case 59: 771 case 60: 772 case 61: 773 case 62: 774 case 63: 775 case 64: 776 case 65: 777 case 66: 778 case 67: 779 case 68: 780 case 69: 781 case 70: 782 case 71: 783 case 72: 784 case 73: 785 case 74: 786 case 75: 787 case 76: 788 case 77: 789 case 78: 790 case 79: 791 case 80: 792 case 81: 793 case 82: 794 case 83: 795 case 84: 796 case 85: 797 case 86: 798 case 87: 799 case 88: 800 case 89: 801 case 90: 802 case 91: 803 case 92: 804 case 93: 805 case 94: 806 case 95: 807 case 96: 808 case 97: 809 case 98: 810 case 99: 811 case 100: 812 case 101: 813 case 102: 814 case 103: 815 case 104: 816 case 105: 817 case 106: 818 case 107: 819 case 108: 820 case 109: 821 case 110: 822 case 111: 823 case 112: 824 case 113: 825 case 114: 826 case 115: 827 case 116: 828 case 117: 829 case 118: 830 case 119: 831 case 120: 832 case 121: 833 case 122: 834 case 123: 835 case 124: 836 case 125: 837 case 126: 838 case 127: 839 case 128: 840 case 129: 841 case 130: 842 case 131: 843 case 132: 844 case 133: 845 case 134: 846 case 135: 847 case 136: 848 case 137: 849 case 138: 850 case 139: 851 case 140: 852 case 141: 853 case 142: 854 case 143: 855 case 144: 856 case 145: 857 case 146: 858 case 147: 859 case 148: 860 case 149: 861 case 150: 862 case 151: 863 case 152: 864 case 153: 865 case 154: 866 case 155: 867 case 156: 868 case 157: 869 case 158: 870 case 159: 871 case 160: 872 case 161: 873 case 162: 874 case 163: 875 case 164: 876 case 165: 877 case 166: 878 case 167: 879 case 168: 880 case 169: 881 case 170: 882 case 171: 883 case 172: 884 case 173: 885 case 174: 886 case 175: 887 case 176: 888 case 177: 889 case 178: 890 case 179: 891 case 180: 892 case 181: 893 case 182: 894 case 183: 895 case 184: 896 case 185: 897 case 186: 898 case 187: 899 case 188: 900 case 189: 901 case 190: 902 case 191: 903 case 192: 904 case 193: 905 case 194: 906 case 195: 907 case 196: 908 case 197: 909 case 198: 910 case 199: 911 case 200: 912 case 201: 913 case 202: 914 case 203: 915 case 204: 916 case 205: 917 case 206: 918 case 207: 919 case 208: 920 case 209: 921 case 210: 922 case 211: 923 case 212: 924 case 213: 925 case 214: 926 case 215: 927 case 216: 928 case 217: 929 case 218: 930 case 219: 931 case 220: 932 case 221: 933 case 222: 934 case 223: 935 case 224: 936 case 225: 937 case 226: 938 case 227: 939 case 228: 940 case 229: 941 case 230: 942 case 231: 943 case 232: 944 case 233: 945 case 234: 946 case 235: 947 case 236: 948 case 237: 949 case 238: 950 case 239: 951 case 240: 952 case 241: 953 case 242: 954 case 243: 955 case 244: 956 case 245: 957 case 246: 958 case 247: 959 case 248: 960 case 249: 961 case 250: 962 case 251: 963 case 252: 964 case 253: 965 case 254: 966 case 255: 967 968 /* Length of nulterm socks4a_addr_hostname */ 969 result += strlen(obj->socks4a_addr_hostname) + 1; 970 break; 971 972 default: 973 break; 974 } 975 return result; 976 } 977 int 978 socks4_client_request_clear_errors(socks4_client_request_t *obj) 979 { 980 int r = obj->trunnel_error_code_; 981 obj->trunnel_error_code_ = 0; 982 return r; 983 } 984 ssize_t 985 socks4_client_request_encode(uint8_t *output, const size_t avail, const socks4_client_request_t *obj) 986 { 987 ssize_t result = 0; 988 size_t written = 0; 989 uint8_t *ptr = output; 990 const char *msg; 991 #ifdef TRUNNEL_CHECK_ENCODED_LEN 992 const ssize_t encoded_len = socks4_client_request_encoded_len(obj); 993 #endif 994 995 if (NULL != (msg = socks4_client_request_check(obj))) 996 goto check_failed; 997 998 #ifdef TRUNNEL_CHECK_ENCODED_LEN 999 trunnel_assert(encoded_len >= 0); 1000 #endif 1001 1002 /* Encode u8 version IN [4] */ 1003 trunnel_assert(written <= avail); 1004 if (avail - written < 1) 1005 goto truncated; 1006 trunnel_set_uint8(ptr, (obj->version)); 1007 written += 1; ptr += 1; 1008 1009 /* Encode u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR] */ 1010 trunnel_assert(written <= avail); 1011 if (avail - written < 1) 1012 goto truncated; 1013 trunnel_set_uint8(ptr, (obj->command)); 1014 written += 1; ptr += 1; 1015 1016 /* Encode u16 port */ 1017 trunnel_assert(written <= avail); 1018 if (avail - written < 2) 1019 goto truncated; 1020 trunnel_set_uint16(ptr, trunnel_htons(obj->port)); 1021 written += 2; ptr += 2; 1022 1023 /* Encode u32 addr */ 1024 trunnel_assert(written <= avail); 1025 if (avail - written < 4) 1026 goto truncated; 1027 trunnel_set_uint32(ptr, trunnel_htonl(obj->addr)); 1028 written += 4; ptr += 4; 1029 1030 /* Encode nulterm username */ 1031 { 1032 size_t len = strlen(obj->username); 1033 trunnel_assert(written <= avail); 1034 if (avail - written < len + 1) 1035 goto truncated; 1036 memcpy(ptr, obj->username, len + 1); 1037 ptr += len + 1; written += len + 1; 1038 } 1039 1040 /* Encode union socks4a_addr[addr] */ 1041 trunnel_assert(written <= avail); 1042 switch (obj->addr) { 1043 1044 case 1: 1045 case 2: 1046 case 3: 1047 case 4: 1048 case 5: 1049 case 6: 1050 case 7: 1051 case 8: 1052 case 9: 1053 case 10: 1054 case 11: 1055 case 12: 1056 case 13: 1057 case 14: 1058 case 15: 1059 case 16: 1060 case 17: 1061 case 18: 1062 case 19: 1063 case 20: 1064 case 21: 1065 case 22: 1066 case 23: 1067 case 24: 1068 case 25: 1069 case 26: 1070 case 27: 1071 case 28: 1072 case 29: 1073 case 30: 1074 case 31: 1075 case 32: 1076 case 33: 1077 case 34: 1078 case 35: 1079 case 36: 1080 case 37: 1081 case 38: 1082 case 39: 1083 case 40: 1084 case 41: 1085 case 42: 1086 case 43: 1087 case 44: 1088 case 45: 1089 case 46: 1090 case 47: 1091 case 48: 1092 case 49: 1093 case 50: 1094 case 51: 1095 case 52: 1096 case 53: 1097 case 54: 1098 case 55: 1099 case 56: 1100 case 57: 1101 case 58: 1102 case 59: 1103 case 60: 1104 case 61: 1105 case 62: 1106 case 63: 1107 case 64: 1108 case 65: 1109 case 66: 1110 case 67: 1111 case 68: 1112 case 69: 1113 case 70: 1114 case 71: 1115 case 72: 1116 case 73: 1117 case 74: 1118 case 75: 1119 case 76: 1120 case 77: 1121 case 78: 1122 case 79: 1123 case 80: 1124 case 81: 1125 case 82: 1126 case 83: 1127 case 84: 1128 case 85: 1129 case 86: 1130 case 87: 1131 case 88: 1132 case 89: 1133 case 90: 1134 case 91: 1135 case 92: 1136 case 93: 1137 case 94: 1138 case 95: 1139 case 96: 1140 case 97: 1141 case 98: 1142 case 99: 1143 case 100: 1144 case 101: 1145 case 102: 1146 case 103: 1147 case 104: 1148 case 105: 1149 case 106: 1150 case 107: 1151 case 108: 1152 case 109: 1153 case 110: 1154 case 111: 1155 case 112: 1156 case 113: 1157 case 114: 1158 case 115: 1159 case 116: 1160 case 117: 1161 case 118: 1162 case 119: 1163 case 120: 1164 case 121: 1165 case 122: 1166 case 123: 1167 case 124: 1168 case 125: 1169 case 126: 1170 case 127: 1171 case 128: 1172 case 129: 1173 case 130: 1174 case 131: 1175 case 132: 1176 case 133: 1177 case 134: 1178 case 135: 1179 case 136: 1180 case 137: 1181 case 138: 1182 case 139: 1183 case 140: 1184 case 141: 1185 case 142: 1186 case 143: 1187 case 144: 1188 case 145: 1189 case 146: 1190 case 147: 1191 case 148: 1192 case 149: 1193 case 150: 1194 case 151: 1195 case 152: 1196 case 153: 1197 case 154: 1198 case 155: 1199 case 156: 1200 case 157: 1201 case 158: 1202 case 159: 1203 case 160: 1204 case 161: 1205 case 162: 1206 case 163: 1207 case 164: 1208 case 165: 1209 case 166: 1210 case 167: 1211 case 168: 1212 case 169: 1213 case 170: 1214 case 171: 1215 case 172: 1216 case 173: 1217 case 174: 1218 case 175: 1219 case 176: 1220 case 177: 1221 case 178: 1222 case 179: 1223 case 180: 1224 case 181: 1225 case 182: 1226 case 183: 1227 case 184: 1228 case 185: 1229 case 186: 1230 case 187: 1231 case 188: 1232 case 189: 1233 case 190: 1234 case 191: 1235 case 192: 1236 case 193: 1237 case 194: 1238 case 195: 1239 case 196: 1240 case 197: 1241 case 198: 1242 case 199: 1243 case 200: 1244 case 201: 1245 case 202: 1246 case 203: 1247 case 204: 1248 case 205: 1249 case 206: 1250 case 207: 1251 case 208: 1252 case 209: 1253 case 210: 1254 case 211: 1255 case 212: 1256 case 213: 1257 case 214: 1258 case 215: 1259 case 216: 1260 case 217: 1261 case 218: 1262 case 219: 1263 case 220: 1264 case 221: 1265 case 222: 1266 case 223: 1267 case 224: 1268 case 225: 1269 case 226: 1270 case 227: 1271 case 228: 1272 case 229: 1273 case 230: 1274 case 231: 1275 case 232: 1276 case 233: 1277 case 234: 1278 case 235: 1279 case 236: 1280 case 237: 1281 case 238: 1282 case 239: 1283 case 240: 1284 case 241: 1285 case 242: 1286 case 243: 1287 case 244: 1288 case 245: 1289 case 246: 1290 case 247: 1291 case 248: 1292 case 249: 1293 case 250: 1294 case 251: 1295 case 252: 1296 case 253: 1297 case 254: 1298 case 255: 1299 1300 /* Encode nulterm socks4a_addr_hostname */ 1301 { 1302 size_t len = strlen(obj->socks4a_addr_hostname); 1303 trunnel_assert(written <= avail); 1304 if (avail - written < len + 1) 1305 goto truncated; 1306 memcpy(ptr, obj->socks4a_addr_hostname, len + 1); 1307 ptr += len + 1; written += len + 1; 1308 } 1309 break; 1310 1311 default: 1312 break; 1313 } 1314 1315 1316 trunnel_assert(ptr == output + written); 1317 #ifdef TRUNNEL_CHECK_ENCODED_LEN 1318 { 1319 trunnel_assert(encoded_len >= 0); 1320 trunnel_assert((size_t)encoded_len == written); 1321 } 1322 1323 #endif 1324 1325 return written; 1326 1327 truncated: 1328 result = -2; 1329 goto fail; 1330 check_failed: 1331 (void)msg; 1332 result = -1; 1333 goto fail; 1334 fail: 1335 trunnel_assert(result < 0); 1336 return result; 1337 } 1338 1339 /** As socks4_client_request_parse(), but do not allocate the output 1340 * object. 1341 */ 1342 static ssize_t 1343 socks4_client_request_parse_into(socks4_client_request_t *obj, const uint8_t *input, const size_t len_in) 1344 { 1345 const uint8_t *ptr = input; 1346 size_t remaining = len_in; 1347 ssize_t result = 0; 1348 (void)result; 1349 1350 /* Parse u8 version IN [4] */ 1351 CHECK_REMAINING(1, truncated); 1352 obj->version = (trunnel_get_uint8(ptr)); 1353 remaining -= 1; ptr += 1; 1354 if (! (obj->version == 4)) 1355 goto fail; 1356 1357 /* Parse u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR] */ 1358 CHECK_REMAINING(1, truncated); 1359 obj->command = (trunnel_get_uint8(ptr)); 1360 remaining -= 1; ptr += 1; 1361 if (! (obj->command == CMD_BIND || obj->command == CMD_CONNECT || obj->command == CMD_RESOLVE || obj->command == CMD_RESOLVE_PTR)) 1362 goto fail; 1363 1364 /* Parse u16 port */ 1365 CHECK_REMAINING(2, truncated); 1366 obj->port = trunnel_ntohs(trunnel_get_uint16(ptr)); 1367 remaining -= 2; ptr += 2; 1368 1369 /* Parse u32 addr */ 1370 CHECK_REMAINING(4, truncated); 1371 obj->addr = trunnel_ntohl(trunnel_get_uint32(ptr)); 1372 remaining -= 4; ptr += 4; 1373 1374 /* Parse nulterm username */ 1375 { 1376 uint8_t *eos = (uint8_t*)memchr(ptr, 0, remaining); 1377 size_t memlen; 1378 if (eos == NULL) 1379 goto truncated; 1380 trunnel_assert(eos >= ptr); 1381 trunnel_assert((size_t)(eos - ptr) < SIZE_MAX - 1); 1382 memlen = ((size_t)(eos - ptr)) + 1; 1383 if (!(obj->username = trunnel_malloc(memlen))) 1384 goto fail; 1385 memcpy(obj->username, ptr, memlen); 1386 remaining -= memlen; ptr += memlen; 1387 } 1388 1389 /* Parse union socks4a_addr[addr] */ 1390 switch (obj->addr) { 1391 1392 case 1: 1393 case 2: 1394 case 3: 1395 case 4: 1396 case 5: 1397 case 6: 1398 case 7: 1399 case 8: 1400 case 9: 1401 case 10: 1402 case 11: 1403 case 12: 1404 case 13: 1405 case 14: 1406 case 15: 1407 case 16: 1408 case 17: 1409 case 18: 1410 case 19: 1411 case 20: 1412 case 21: 1413 case 22: 1414 case 23: 1415 case 24: 1416 case 25: 1417 case 26: 1418 case 27: 1419 case 28: 1420 case 29: 1421 case 30: 1422 case 31: 1423 case 32: 1424 case 33: 1425 case 34: 1426 case 35: 1427 case 36: 1428 case 37: 1429 case 38: 1430 case 39: 1431 case 40: 1432 case 41: 1433 case 42: 1434 case 43: 1435 case 44: 1436 case 45: 1437 case 46: 1438 case 47: 1439 case 48: 1440 case 49: 1441 case 50: 1442 case 51: 1443 case 52: 1444 case 53: 1445 case 54: 1446 case 55: 1447 case 56: 1448 case 57: 1449 case 58: 1450 case 59: 1451 case 60: 1452 case 61: 1453 case 62: 1454 case 63: 1455 case 64: 1456 case 65: 1457 case 66: 1458 case 67: 1459 case 68: 1460 case 69: 1461 case 70: 1462 case 71: 1463 case 72: 1464 case 73: 1465 case 74: 1466 case 75: 1467 case 76: 1468 case 77: 1469 case 78: 1470 case 79: 1471 case 80: 1472 case 81: 1473 case 82: 1474 case 83: 1475 case 84: 1476 case 85: 1477 case 86: 1478 case 87: 1479 case 88: 1480 case 89: 1481 case 90: 1482 case 91: 1483 case 92: 1484 case 93: 1485 case 94: 1486 case 95: 1487 case 96: 1488 case 97: 1489 case 98: 1490 case 99: 1491 case 100: 1492 case 101: 1493 case 102: 1494 case 103: 1495 case 104: 1496 case 105: 1497 case 106: 1498 case 107: 1499 case 108: 1500 case 109: 1501 case 110: 1502 case 111: 1503 case 112: 1504 case 113: 1505 case 114: 1506 case 115: 1507 case 116: 1508 case 117: 1509 case 118: 1510 case 119: 1511 case 120: 1512 case 121: 1513 case 122: 1514 case 123: 1515 case 124: 1516 case 125: 1517 case 126: 1518 case 127: 1519 case 128: 1520 case 129: 1521 case 130: 1522 case 131: 1523 case 132: 1524 case 133: 1525 case 134: 1526 case 135: 1527 case 136: 1528 case 137: 1529 case 138: 1530 case 139: 1531 case 140: 1532 case 141: 1533 case 142: 1534 case 143: 1535 case 144: 1536 case 145: 1537 case 146: 1538 case 147: 1539 case 148: 1540 case 149: 1541 case 150: 1542 case 151: 1543 case 152: 1544 case 153: 1545 case 154: 1546 case 155: 1547 case 156: 1548 case 157: 1549 case 158: 1550 case 159: 1551 case 160: 1552 case 161: 1553 case 162: 1554 case 163: 1555 case 164: 1556 case 165: 1557 case 166: 1558 case 167: 1559 case 168: 1560 case 169: 1561 case 170: 1562 case 171: 1563 case 172: 1564 case 173: 1565 case 174: 1566 case 175: 1567 case 176: 1568 case 177: 1569 case 178: 1570 case 179: 1571 case 180: 1572 case 181: 1573 case 182: 1574 case 183: 1575 case 184: 1576 case 185: 1577 case 186: 1578 case 187: 1579 case 188: 1580 case 189: 1581 case 190: 1582 case 191: 1583 case 192: 1584 case 193: 1585 case 194: 1586 case 195: 1587 case 196: 1588 case 197: 1589 case 198: 1590 case 199: 1591 case 200: 1592 case 201: 1593 case 202: 1594 case 203: 1595 case 204: 1596 case 205: 1597 case 206: 1598 case 207: 1599 case 208: 1600 case 209: 1601 case 210: 1602 case 211: 1603 case 212: 1604 case 213: 1605 case 214: 1606 case 215: 1607 case 216: 1608 case 217: 1609 case 218: 1610 case 219: 1611 case 220: 1612 case 221: 1613 case 222: 1614 case 223: 1615 case 224: 1616 case 225: 1617 case 226: 1618 case 227: 1619 case 228: 1620 case 229: 1621 case 230: 1622 case 231: 1623 case 232: 1624 case 233: 1625 case 234: 1626 case 235: 1627 case 236: 1628 case 237: 1629 case 238: 1630 case 239: 1631 case 240: 1632 case 241: 1633 case 242: 1634 case 243: 1635 case 244: 1636 case 245: 1637 case 246: 1638 case 247: 1639 case 248: 1640 case 249: 1641 case 250: 1642 case 251: 1643 case 252: 1644 case 253: 1645 case 254: 1646 case 255: 1647 1648 /* Parse nulterm socks4a_addr_hostname */ 1649 { 1650 uint8_t *eos = (uint8_t*)memchr(ptr, 0, remaining); 1651 size_t memlen; 1652 if (eos == NULL) 1653 goto truncated; 1654 trunnel_assert(eos >= ptr); 1655 trunnel_assert((size_t)(eos - ptr) < SIZE_MAX - 1); 1656 memlen = ((size_t)(eos - ptr)) + 1; 1657 if (!(obj->socks4a_addr_hostname = trunnel_malloc(memlen))) 1658 goto fail; 1659 memcpy(obj->socks4a_addr_hostname, ptr, memlen); 1660 remaining -= memlen; ptr += memlen; 1661 } 1662 break; 1663 1664 default: 1665 break; 1666 } 1667 trunnel_assert(ptr + remaining == input + len_in); 1668 return len_in - remaining; 1669 1670 truncated: 1671 return -2; 1672 fail: 1673 result = -1; 1674 return result; 1675 } 1676 1677 ssize_t 1678 socks4_client_request_parse(socks4_client_request_t **output, const uint8_t *input, const size_t len_in) 1679 { 1680 ssize_t result; 1681 *output = socks4_client_request_new(); 1682 if (NULL == *output) 1683 return -1; 1684 result = socks4_client_request_parse_into(*output, input, len_in); 1685 if (result < 0) { 1686 socks4_client_request_free(*output); 1687 *output = NULL; 1688 } 1689 return result; 1690 } 1691 socks4_server_reply_t * 1692 socks4_server_reply_new(void) 1693 { 1694 socks4_server_reply_t *val = trunnel_calloc(1, sizeof(socks4_server_reply_t)); 1695 if (NULL == val) 1696 return NULL; 1697 return val; 1698 } 1699 1700 /** Release all storage held inside 'obj', but do not free 'obj'. 1701 */ 1702 static void 1703 socks4_server_reply_clear(socks4_server_reply_t *obj) 1704 { 1705 (void) obj; 1706 } 1707 1708 void 1709 socks4_server_reply_free(socks4_server_reply_t *obj) 1710 { 1711 if (obj == NULL) 1712 return; 1713 socks4_server_reply_clear(obj); 1714 trunnel_memwipe(obj, sizeof(socks4_server_reply_t)); 1715 trunnel_free_(obj); 1716 } 1717 1718 uint8_t 1719 socks4_server_reply_get_version(const socks4_server_reply_t *inp) 1720 { 1721 return inp->version; 1722 } 1723 int 1724 socks4_server_reply_set_version(socks4_server_reply_t *inp, uint8_t val) 1725 { 1726 if (! ((val == 0 || val == 4))) { 1727 TRUNNEL_SET_ERROR_CODE(inp); 1728 return -1; 1729 } 1730 inp->version = val; 1731 return 0; 1732 } 1733 uint8_t 1734 socks4_server_reply_get_status(const socks4_server_reply_t *inp) 1735 { 1736 return inp->status; 1737 } 1738 int 1739 socks4_server_reply_set_status(socks4_server_reply_t *inp, uint8_t val) 1740 { 1741 inp->status = val; 1742 return 0; 1743 } 1744 uint16_t 1745 socks4_server_reply_get_port(const socks4_server_reply_t *inp) 1746 { 1747 return inp->port; 1748 } 1749 int 1750 socks4_server_reply_set_port(socks4_server_reply_t *inp, uint16_t val) 1751 { 1752 inp->port = val; 1753 return 0; 1754 } 1755 uint32_t 1756 socks4_server_reply_get_addr(const socks4_server_reply_t *inp) 1757 { 1758 return inp->addr; 1759 } 1760 int 1761 socks4_server_reply_set_addr(socks4_server_reply_t *inp, uint32_t val) 1762 { 1763 inp->addr = val; 1764 return 0; 1765 } 1766 const char * 1767 socks4_server_reply_check(const socks4_server_reply_t *obj) 1768 { 1769 if (obj == NULL) 1770 return "Object was NULL"; 1771 if (obj->trunnel_error_code_) 1772 return "A set function failed on this object"; 1773 if (! (obj->version == 0 || obj->version == 4)) 1774 return "Integer out of bounds"; 1775 return NULL; 1776 } 1777 1778 ssize_t 1779 socks4_server_reply_encoded_len(const socks4_server_reply_t *obj) 1780 { 1781 ssize_t result = 0; 1782 1783 if (NULL != socks4_server_reply_check(obj)) 1784 return -1; 1785 1786 1787 /* Length of u8 version IN [0, 4] */ 1788 result += 1; 1789 1790 /* Length of u8 status */ 1791 result += 1; 1792 1793 /* Length of u16 port */ 1794 result += 2; 1795 1796 /* Length of u32 addr */ 1797 result += 4; 1798 return result; 1799 } 1800 int 1801 socks4_server_reply_clear_errors(socks4_server_reply_t *obj) 1802 { 1803 int r = obj->trunnel_error_code_; 1804 obj->trunnel_error_code_ = 0; 1805 return r; 1806 } 1807 ssize_t 1808 socks4_server_reply_encode(uint8_t *output, const size_t avail, const socks4_server_reply_t *obj) 1809 { 1810 ssize_t result = 0; 1811 size_t written = 0; 1812 uint8_t *ptr = output; 1813 const char *msg; 1814 #ifdef TRUNNEL_CHECK_ENCODED_LEN 1815 const ssize_t encoded_len = socks4_server_reply_encoded_len(obj); 1816 #endif 1817 1818 if (NULL != (msg = socks4_server_reply_check(obj))) 1819 goto check_failed; 1820 1821 #ifdef TRUNNEL_CHECK_ENCODED_LEN 1822 trunnel_assert(encoded_len >= 0); 1823 #endif 1824 1825 /* Encode u8 version IN [0, 4] */ 1826 trunnel_assert(written <= avail); 1827 if (avail - written < 1) 1828 goto truncated; 1829 trunnel_set_uint8(ptr, (obj->version)); 1830 written += 1; ptr += 1; 1831 1832 /* Encode u8 status */ 1833 trunnel_assert(written <= avail); 1834 if (avail - written < 1) 1835 goto truncated; 1836 trunnel_set_uint8(ptr, (obj->status)); 1837 written += 1; ptr += 1; 1838 1839 /* Encode u16 port */ 1840 trunnel_assert(written <= avail); 1841 if (avail - written < 2) 1842 goto truncated; 1843 trunnel_set_uint16(ptr, trunnel_htons(obj->port)); 1844 written += 2; ptr += 2; 1845 1846 /* Encode u32 addr */ 1847 trunnel_assert(written <= avail); 1848 if (avail - written < 4) 1849 goto truncated; 1850 trunnel_set_uint32(ptr, trunnel_htonl(obj->addr)); 1851 written += 4; ptr += 4; 1852 1853 1854 trunnel_assert(ptr == output + written); 1855 #ifdef TRUNNEL_CHECK_ENCODED_LEN 1856 { 1857 trunnel_assert(encoded_len >= 0); 1858 trunnel_assert((size_t)encoded_len == written); 1859 } 1860 1861 #endif 1862 1863 return written; 1864 1865 truncated: 1866 result = -2; 1867 goto fail; 1868 check_failed: 1869 (void)msg; 1870 result = -1; 1871 goto fail; 1872 fail: 1873 trunnel_assert(result < 0); 1874 return result; 1875 } 1876 1877 /** As socks4_server_reply_parse(), but do not allocate the output 1878 * object. 1879 */ 1880 static ssize_t 1881 socks4_server_reply_parse_into(socks4_server_reply_t *obj, const uint8_t *input, const size_t len_in) 1882 { 1883 const uint8_t *ptr = input; 1884 size_t remaining = len_in; 1885 ssize_t result = 0; 1886 (void)result; 1887 1888 /* Parse u8 version IN [0, 4] */ 1889 CHECK_REMAINING(1, truncated); 1890 obj->version = (trunnel_get_uint8(ptr)); 1891 remaining -= 1; ptr += 1; 1892 if (! (obj->version == 0 || obj->version == 4)) 1893 goto fail; 1894 1895 /* Parse u8 status */ 1896 CHECK_REMAINING(1, truncated); 1897 obj->status = (trunnel_get_uint8(ptr)); 1898 remaining -= 1; ptr += 1; 1899 1900 /* Parse u16 port */ 1901 CHECK_REMAINING(2, truncated); 1902 obj->port = trunnel_ntohs(trunnel_get_uint16(ptr)); 1903 remaining -= 2; ptr += 2; 1904 1905 /* Parse u32 addr */ 1906 CHECK_REMAINING(4, truncated); 1907 obj->addr = trunnel_ntohl(trunnel_get_uint32(ptr)); 1908 remaining -= 4; ptr += 4; 1909 trunnel_assert(ptr + remaining == input + len_in); 1910 return len_in - remaining; 1911 1912 truncated: 1913 return -2; 1914 fail: 1915 result = -1; 1916 return result; 1917 } 1918 1919 ssize_t 1920 socks4_server_reply_parse(socks4_server_reply_t **output, const uint8_t *input, const size_t len_in) 1921 { 1922 ssize_t result; 1923 *output = socks4_server_reply_new(); 1924 if (NULL == *output) 1925 return -1; 1926 result = socks4_server_reply_parse_into(*output, input, len_in); 1927 if (result < 0) { 1928 socks4_server_reply_free(*output); 1929 *output = NULL; 1930 } 1931 return result; 1932 } 1933 socks5_client_userpass_auth_t * 1934 socks5_client_userpass_auth_new(void) 1935 { 1936 socks5_client_userpass_auth_t *val = trunnel_calloc(1, sizeof(socks5_client_userpass_auth_t)); 1937 if (NULL == val) 1938 return NULL; 1939 val->version = 1; 1940 return val; 1941 } 1942 1943 /** Release all storage held inside 'obj', but do not free 'obj'. 1944 */ 1945 static void 1946 socks5_client_userpass_auth_clear(socks5_client_userpass_auth_t *obj) 1947 { 1948 (void) obj; 1949 TRUNNEL_DYNARRAY_WIPE(&obj->username); 1950 TRUNNEL_DYNARRAY_CLEAR(&obj->username); 1951 TRUNNEL_DYNARRAY_WIPE(&obj->passwd); 1952 TRUNNEL_DYNARRAY_CLEAR(&obj->passwd); 1953 } 1954 1955 void 1956 socks5_client_userpass_auth_free(socks5_client_userpass_auth_t *obj) 1957 { 1958 if (obj == NULL) 1959 return; 1960 socks5_client_userpass_auth_clear(obj); 1961 trunnel_memwipe(obj, sizeof(socks5_client_userpass_auth_t)); 1962 trunnel_free_(obj); 1963 } 1964 1965 uint8_t 1966 socks5_client_userpass_auth_get_version(const socks5_client_userpass_auth_t *inp) 1967 { 1968 return inp->version; 1969 } 1970 int 1971 socks5_client_userpass_auth_set_version(socks5_client_userpass_auth_t *inp, uint8_t val) 1972 { 1973 if (! ((val == 1))) { 1974 TRUNNEL_SET_ERROR_CODE(inp); 1975 return -1; 1976 } 1977 inp->version = val; 1978 return 0; 1979 } 1980 uint8_t 1981 socks5_client_userpass_auth_get_username_len(const socks5_client_userpass_auth_t *inp) 1982 { 1983 return inp->username_len; 1984 } 1985 int 1986 socks5_client_userpass_auth_set_username_len(socks5_client_userpass_auth_t *inp, uint8_t val) 1987 { 1988 inp->username_len = val; 1989 return 0; 1990 } 1991 size_t 1992 socks5_client_userpass_auth_getlen_username(const socks5_client_userpass_auth_t *inp) 1993 { 1994 return TRUNNEL_DYNARRAY_LEN(&inp->username); 1995 } 1996 1997 char 1998 socks5_client_userpass_auth_get_username(socks5_client_userpass_auth_t *inp, size_t idx) 1999 { 2000 return TRUNNEL_DYNARRAY_GET(&inp->username, idx); 2001 } 2002 2003 char 2004 socks5_client_userpass_auth_getconst_username(const socks5_client_userpass_auth_t *inp, size_t idx) 2005 { 2006 return socks5_client_userpass_auth_get_username((socks5_client_userpass_auth_t*)inp, idx); 2007 } 2008 int 2009 socks5_client_userpass_auth_set_username(socks5_client_userpass_auth_t *inp, size_t idx, char elt) 2010 { 2011 TRUNNEL_DYNARRAY_SET(&inp->username, idx, elt); 2012 return 0; 2013 } 2014 int 2015 socks5_client_userpass_auth_add_username(socks5_client_userpass_auth_t *inp, char elt) 2016 { 2017 #if SIZE_MAX >= UINT8_MAX 2018 if (inp->username.n_ == UINT8_MAX) 2019 goto trunnel_alloc_failed; 2020 #endif 2021 TRUNNEL_DYNARRAY_ADD(char, &inp->username, elt, {}); 2022 return 0; 2023 trunnel_alloc_failed: 2024 TRUNNEL_SET_ERROR_CODE(inp); 2025 return -1; 2026 } 2027 2028 char * 2029 socks5_client_userpass_auth_getarray_username(socks5_client_userpass_auth_t *inp) 2030 { 2031 return inp->username.elts_; 2032 } 2033 const char * 2034 socks5_client_userpass_auth_getconstarray_username(const socks5_client_userpass_auth_t *inp) 2035 { 2036 return (const char *)socks5_client_userpass_auth_getarray_username((socks5_client_userpass_auth_t*)inp); 2037 } 2038 int 2039 socks5_client_userpass_auth_setlen_username(socks5_client_userpass_auth_t *inp, size_t newlen) 2040 { 2041 #if UINT8_MAX < SIZE_MAX 2042 if (newlen > UINT8_MAX) 2043 goto trunnel_alloc_failed; 2044 #endif 2045 return trunnel_string_setlen(&inp->username, newlen, 2046 &inp->trunnel_error_code_); 2047 trunnel_alloc_failed: 2048 TRUNNEL_SET_ERROR_CODE(inp); 2049 return -1; 2050 } 2051 const char * 2052 socks5_client_userpass_auth_getstr_username(socks5_client_userpass_auth_t *inp) 2053 { 2054 return trunnel_string_getstr(&inp->username); 2055 } 2056 int 2057 socks5_client_userpass_auth_setstr0_username(socks5_client_userpass_auth_t *inp, const char *val, size_t len) 2058 { 2059 #if UINT8_MAX < SIZE_MAX 2060 if (len > UINT8_MAX) { 2061 TRUNNEL_SET_ERROR_CODE(inp); 2062 return -1; 2063 } 2064 #endif 2065 return trunnel_string_setstr0(&inp->username, val, len, &inp->trunnel_error_code_); 2066 } 2067 int 2068 socks5_client_userpass_auth_setstr_username(socks5_client_userpass_auth_t *inp, const char *val) 2069 { 2070 return socks5_client_userpass_auth_setstr0_username(inp, val, strlen(val)); 2071 } 2072 uint8_t 2073 socks5_client_userpass_auth_get_passwd_len(const socks5_client_userpass_auth_t *inp) 2074 { 2075 return inp->passwd_len; 2076 } 2077 int 2078 socks5_client_userpass_auth_set_passwd_len(socks5_client_userpass_auth_t *inp, uint8_t val) 2079 { 2080 inp->passwd_len = val; 2081 return 0; 2082 } 2083 size_t 2084 socks5_client_userpass_auth_getlen_passwd(const socks5_client_userpass_auth_t *inp) 2085 { 2086 return TRUNNEL_DYNARRAY_LEN(&inp->passwd); 2087 } 2088 2089 char 2090 socks5_client_userpass_auth_get_passwd(socks5_client_userpass_auth_t *inp, size_t idx) 2091 { 2092 return TRUNNEL_DYNARRAY_GET(&inp->passwd, idx); 2093 } 2094 2095 char 2096 socks5_client_userpass_auth_getconst_passwd(const socks5_client_userpass_auth_t *inp, size_t idx) 2097 { 2098 return socks5_client_userpass_auth_get_passwd((socks5_client_userpass_auth_t*)inp, idx); 2099 } 2100 int 2101 socks5_client_userpass_auth_set_passwd(socks5_client_userpass_auth_t *inp, size_t idx, char elt) 2102 { 2103 TRUNNEL_DYNARRAY_SET(&inp->passwd, idx, elt); 2104 return 0; 2105 } 2106 int 2107 socks5_client_userpass_auth_add_passwd(socks5_client_userpass_auth_t *inp, char elt) 2108 { 2109 #if SIZE_MAX >= UINT8_MAX 2110 if (inp->passwd.n_ == UINT8_MAX) 2111 goto trunnel_alloc_failed; 2112 #endif 2113 TRUNNEL_DYNARRAY_ADD(char, &inp->passwd, elt, {}); 2114 return 0; 2115 trunnel_alloc_failed: 2116 TRUNNEL_SET_ERROR_CODE(inp); 2117 return -1; 2118 } 2119 2120 char * 2121 socks5_client_userpass_auth_getarray_passwd(socks5_client_userpass_auth_t *inp) 2122 { 2123 return inp->passwd.elts_; 2124 } 2125 const char * 2126 socks5_client_userpass_auth_getconstarray_passwd(const socks5_client_userpass_auth_t *inp) 2127 { 2128 return (const char *)socks5_client_userpass_auth_getarray_passwd((socks5_client_userpass_auth_t*)inp); 2129 } 2130 int 2131 socks5_client_userpass_auth_setlen_passwd(socks5_client_userpass_auth_t *inp, size_t newlen) 2132 { 2133 #if UINT8_MAX < SIZE_MAX 2134 if (newlen > UINT8_MAX) 2135 goto trunnel_alloc_failed; 2136 #endif 2137 return trunnel_string_setlen(&inp->passwd, newlen, 2138 &inp->trunnel_error_code_); 2139 trunnel_alloc_failed: 2140 TRUNNEL_SET_ERROR_CODE(inp); 2141 return -1; 2142 } 2143 const char * 2144 socks5_client_userpass_auth_getstr_passwd(socks5_client_userpass_auth_t *inp) 2145 { 2146 return trunnel_string_getstr(&inp->passwd); 2147 } 2148 int 2149 socks5_client_userpass_auth_setstr0_passwd(socks5_client_userpass_auth_t *inp, const char *val, size_t len) 2150 { 2151 #if UINT8_MAX < SIZE_MAX 2152 if (len > UINT8_MAX) { 2153 TRUNNEL_SET_ERROR_CODE(inp); 2154 return -1; 2155 } 2156 #endif 2157 return trunnel_string_setstr0(&inp->passwd, val, len, &inp->trunnel_error_code_); 2158 } 2159 int 2160 socks5_client_userpass_auth_setstr_passwd(socks5_client_userpass_auth_t *inp, const char *val) 2161 { 2162 return socks5_client_userpass_auth_setstr0_passwd(inp, val, strlen(val)); 2163 } 2164 const char * 2165 socks5_client_userpass_auth_check(const socks5_client_userpass_auth_t *obj) 2166 { 2167 if (obj == NULL) 2168 return "Object was NULL"; 2169 if (obj->trunnel_error_code_) 2170 return "A set function failed on this object"; 2171 if (! (obj->version == 1)) 2172 return "Integer out of bounds"; 2173 if (TRUNNEL_DYNARRAY_LEN(&obj->username) != obj->username_len) 2174 return "Length mismatch for username"; 2175 if (TRUNNEL_DYNARRAY_LEN(&obj->passwd) != obj->passwd_len) 2176 return "Length mismatch for passwd"; 2177 return NULL; 2178 } 2179 2180 ssize_t 2181 socks5_client_userpass_auth_encoded_len(const socks5_client_userpass_auth_t *obj) 2182 { 2183 ssize_t result = 0; 2184 2185 if (NULL != socks5_client_userpass_auth_check(obj)) 2186 return -1; 2187 2188 2189 /* Length of u8 version IN [1] */ 2190 result += 1; 2191 2192 /* Length of u8 username_len */ 2193 result += 1; 2194 2195 /* Length of char username[username_len] */ 2196 result += TRUNNEL_DYNARRAY_LEN(&obj->username); 2197 2198 /* Length of u8 passwd_len */ 2199 result += 1; 2200 2201 /* Length of char passwd[passwd_len] */ 2202 result += TRUNNEL_DYNARRAY_LEN(&obj->passwd); 2203 return result; 2204 } 2205 int 2206 socks5_client_userpass_auth_clear_errors(socks5_client_userpass_auth_t *obj) 2207 { 2208 int r = obj->trunnel_error_code_; 2209 obj->trunnel_error_code_ = 0; 2210 return r; 2211 } 2212 ssize_t 2213 socks5_client_userpass_auth_encode(uint8_t *output, const size_t avail, const socks5_client_userpass_auth_t *obj) 2214 { 2215 ssize_t result = 0; 2216 size_t written = 0; 2217 uint8_t *ptr = output; 2218 const char *msg; 2219 #ifdef TRUNNEL_CHECK_ENCODED_LEN 2220 const ssize_t encoded_len = socks5_client_userpass_auth_encoded_len(obj); 2221 #endif 2222 2223 if (NULL != (msg = socks5_client_userpass_auth_check(obj))) 2224 goto check_failed; 2225 2226 #ifdef TRUNNEL_CHECK_ENCODED_LEN 2227 trunnel_assert(encoded_len >= 0); 2228 #endif 2229 2230 /* Encode u8 version IN [1] */ 2231 trunnel_assert(written <= avail); 2232 if (avail - written < 1) 2233 goto truncated; 2234 trunnel_set_uint8(ptr, (obj->version)); 2235 written += 1; ptr += 1; 2236 2237 /* Encode u8 username_len */ 2238 trunnel_assert(written <= avail); 2239 if (avail - written < 1) 2240 goto truncated; 2241 trunnel_set_uint8(ptr, (obj->username_len)); 2242 written += 1; ptr += 1; 2243 2244 /* Encode char username[username_len] */ 2245 { 2246 size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->username); 2247 trunnel_assert(obj->username_len == elt_len); 2248 trunnel_assert(written <= avail); 2249 if (avail - written < elt_len) 2250 goto truncated; 2251 if (elt_len) 2252 memcpy(ptr, obj->username.elts_, elt_len); 2253 written += elt_len; ptr += elt_len; 2254 } 2255 2256 /* Encode u8 passwd_len */ 2257 trunnel_assert(written <= avail); 2258 if (avail - written < 1) 2259 goto truncated; 2260 trunnel_set_uint8(ptr, (obj->passwd_len)); 2261 written += 1; ptr += 1; 2262 2263 /* Encode char passwd[passwd_len] */ 2264 { 2265 size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->passwd); 2266 trunnel_assert(obj->passwd_len == elt_len); 2267 trunnel_assert(written <= avail); 2268 if (avail - written < elt_len) 2269 goto truncated; 2270 if (elt_len) 2271 memcpy(ptr, obj->passwd.elts_, elt_len); 2272 written += elt_len; ptr += elt_len; 2273 } 2274 2275 2276 trunnel_assert(ptr == output + written); 2277 #ifdef TRUNNEL_CHECK_ENCODED_LEN 2278 { 2279 trunnel_assert(encoded_len >= 0); 2280 trunnel_assert((size_t)encoded_len == written); 2281 } 2282 2283 #endif 2284 2285 return written; 2286 2287 truncated: 2288 result = -2; 2289 goto fail; 2290 check_failed: 2291 (void)msg; 2292 result = -1; 2293 goto fail; 2294 fail: 2295 trunnel_assert(result < 0); 2296 return result; 2297 } 2298 2299 /** As socks5_client_userpass_auth_parse(), but do not allocate the 2300 * output object. 2301 */ 2302 static ssize_t 2303 socks5_client_userpass_auth_parse_into(socks5_client_userpass_auth_t *obj, const uint8_t *input, const size_t len_in) 2304 { 2305 const uint8_t *ptr = input; 2306 size_t remaining = len_in; 2307 ssize_t result = 0; 2308 (void)result; 2309 2310 /* Parse u8 version IN [1] */ 2311 CHECK_REMAINING(1, truncated); 2312 obj->version = (trunnel_get_uint8(ptr)); 2313 remaining -= 1; ptr += 1; 2314 if (! (obj->version == 1)) 2315 goto fail; 2316 2317 /* Parse u8 username_len */ 2318 CHECK_REMAINING(1, truncated); 2319 obj->username_len = (trunnel_get_uint8(ptr)); 2320 remaining -= 1; ptr += 1; 2321 2322 /* Parse char username[username_len] */ 2323 CHECK_REMAINING(obj->username_len, truncated); 2324 if (socks5_client_userpass_auth_setstr0_username(obj, (const char*)ptr, obj->username_len)) 2325 goto fail; 2326 ptr += obj->username_len; remaining -= obj->username_len; 2327 2328 /* Parse u8 passwd_len */ 2329 CHECK_REMAINING(1, truncated); 2330 obj->passwd_len = (trunnel_get_uint8(ptr)); 2331 remaining -= 1; ptr += 1; 2332 2333 /* Parse char passwd[passwd_len] */ 2334 CHECK_REMAINING(obj->passwd_len, truncated); 2335 if (socks5_client_userpass_auth_setstr0_passwd(obj, (const char*)ptr, obj->passwd_len)) 2336 goto fail; 2337 ptr += obj->passwd_len; remaining -= obj->passwd_len; 2338 trunnel_assert(ptr + remaining == input + len_in); 2339 return len_in - remaining; 2340 2341 truncated: 2342 return -2; 2343 fail: 2344 result = -1; 2345 return result; 2346 } 2347 2348 ssize_t 2349 socks5_client_userpass_auth_parse(socks5_client_userpass_auth_t **output, const uint8_t *input, const size_t len_in) 2350 { 2351 ssize_t result; 2352 *output = socks5_client_userpass_auth_new(); 2353 if (NULL == *output) 2354 return -1; 2355 result = socks5_client_userpass_auth_parse_into(*output, input, len_in); 2356 if (result < 0) { 2357 socks5_client_userpass_auth_free(*output); 2358 *output = NULL; 2359 } 2360 return result; 2361 } 2362 socks5_client_version_t * 2363 socks5_client_version_new(void) 2364 { 2365 socks5_client_version_t *val = trunnel_calloc(1, sizeof(socks5_client_version_t)); 2366 if (NULL == val) 2367 return NULL; 2368 val->version = 5; 2369 return val; 2370 } 2371 2372 /** Release all storage held inside 'obj', but do not free 'obj'. 2373 */ 2374 static void 2375 socks5_client_version_clear(socks5_client_version_t *obj) 2376 { 2377 (void) obj; 2378 TRUNNEL_DYNARRAY_WIPE(&obj->methods); 2379 TRUNNEL_DYNARRAY_CLEAR(&obj->methods); 2380 } 2381 2382 void 2383 socks5_client_version_free(socks5_client_version_t *obj) 2384 { 2385 if (obj == NULL) 2386 return; 2387 socks5_client_version_clear(obj); 2388 trunnel_memwipe(obj, sizeof(socks5_client_version_t)); 2389 trunnel_free_(obj); 2390 } 2391 2392 uint8_t 2393 socks5_client_version_get_version(const socks5_client_version_t *inp) 2394 { 2395 return inp->version; 2396 } 2397 int 2398 socks5_client_version_set_version(socks5_client_version_t *inp, uint8_t val) 2399 { 2400 if (! ((val == 5))) { 2401 TRUNNEL_SET_ERROR_CODE(inp); 2402 return -1; 2403 } 2404 inp->version = val; 2405 return 0; 2406 } 2407 uint8_t 2408 socks5_client_version_get_n_methods(const socks5_client_version_t *inp) 2409 { 2410 return inp->n_methods; 2411 } 2412 int 2413 socks5_client_version_set_n_methods(socks5_client_version_t *inp, uint8_t val) 2414 { 2415 inp->n_methods = val; 2416 return 0; 2417 } 2418 size_t 2419 socks5_client_version_getlen_methods(const socks5_client_version_t *inp) 2420 { 2421 return TRUNNEL_DYNARRAY_LEN(&inp->methods); 2422 } 2423 2424 uint8_t 2425 socks5_client_version_get_methods(socks5_client_version_t *inp, size_t idx) 2426 { 2427 return TRUNNEL_DYNARRAY_GET(&inp->methods, idx); 2428 } 2429 2430 uint8_t 2431 socks5_client_version_getconst_methods(const socks5_client_version_t *inp, size_t idx) 2432 { 2433 return socks5_client_version_get_methods((socks5_client_version_t*)inp, idx); 2434 } 2435 int 2436 socks5_client_version_set_methods(socks5_client_version_t *inp, size_t idx, uint8_t elt) 2437 { 2438 TRUNNEL_DYNARRAY_SET(&inp->methods, idx, elt); 2439 return 0; 2440 } 2441 int 2442 socks5_client_version_add_methods(socks5_client_version_t *inp, uint8_t elt) 2443 { 2444 #if SIZE_MAX >= UINT8_MAX 2445 if (inp->methods.n_ == UINT8_MAX) 2446 goto trunnel_alloc_failed; 2447 #endif 2448 TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->methods, elt, {}); 2449 return 0; 2450 trunnel_alloc_failed: 2451 TRUNNEL_SET_ERROR_CODE(inp); 2452 return -1; 2453 } 2454 2455 uint8_t * 2456 socks5_client_version_getarray_methods(socks5_client_version_t *inp) 2457 { 2458 return inp->methods.elts_; 2459 } 2460 const uint8_t * 2461 socks5_client_version_getconstarray_methods(const socks5_client_version_t *inp) 2462 { 2463 return (const uint8_t *)socks5_client_version_getarray_methods((socks5_client_version_t*)inp); 2464 } 2465 int 2466 socks5_client_version_setlen_methods(socks5_client_version_t *inp, size_t newlen) 2467 { 2468 uint8_t *newptr; 2469 #if UINT8_MAX < SIZE_MAX 2470 if (newlen > UINT8_MAX) 2471 goto trunnel_alloc_failed; 2472 #endif 2473 newptr = trunnel_dynarray_setlen(&inp->methods.allocated_, 2474 &inp->methods.n_, inp->methods.elts_, newlen, 2475 sizeof(inp->methods.elts_[0]), (trunnel_free_fn_t) NULL, 2476 &inp->trunnel_error_code_); 2477 if (newlen != 0 && newptr == NULL) 2478 goto trunnel_alloc_failed; 2479 inp->methods.elts_ = newptr; 2480 return 0; 2481 trunnel_alloc_failed: 2482 TRUNNEL_SET_ERROR_CODE(inp); 2483 return -1; 2484 } 2485 const char * 2486 socks5_client_version_check(const socks5_client_version_t *obj) 2487 { 2488 if (obj == NULL) 2489 return "Object was NULL"; 2490 if (obj->trunnel_error_code_) 2491 return "A set function failed on this object"; 2492 if (! (obj->version == 5)) 2493 return "Integer out of bounds"; 2494 if (TRUNNEL_DYNARRAY_LEN(&obj->methods) != obj->n_methods) 2495 return "Length mismatch for methods"; 2496 return NULL; 2497 } 2498 2499 ssize_t 2500 socks5_client_version_encoded_len(const socks5_client_version_t *obj) 2501 { 2502 ssize_t result = 0; 2503 2504 if (NULL != socks5_client_version_check(obj)) 2505 return -1; 2506 2507 2508 /* Length of u8 version IN [5] */ 2509 result += 1; 2510 2511 /* Length of u8 n_methods */ 2512 result += 1; 2513 2514 /* Length of u8 methods[n_methods] */ 2515 result += TRUNNEL_DYNARRAY_LEN(&obj->methods); 2516 return result; 2517 } 2518 int 2519 socks5_client_version_clear_errors(socks5_client_version_t *obj) 2520 { 2521 int r = obj->trunnel_error_code_; 2522 obj->trunnel_error_code_ = 0; 2523 return r; 2524 } 2525 ssize_t 2526 socks5_client_version_encode(uint8_t *output, const size_t avail, const socks5_client_version_t *obj) 2527 { 2528 ssize_t result = 0; 2529 size_t written = 0; 2530 uint8_t *ptr = output; 2531 const char *msg; 2532 #ifdef TRUNNEL_CHECK_ENCODED_LEN 2533 const ssize_t encoded_len = socks5_client_version_encoded_len(obj); 2534 #endif 2535 2536 if (NULL != (msg = socks5_client_version_check(obj))) 2537 goto check_failed; 2538 2539 #ifdef TRUNNEL_CHECK_ENCODED_LEN 2540 trunnel_assert(encoded_len >= 0); 2541 #endif 2542 2543 /* Encode u8 version IN [5] */ 2544 trunnel_assert(written <= avail); 2545 if (avail - written < 1) 2546 goto truncated; 2547 trunnel_set_uint8(ptr, (obj->version)); 2548 written += 1; ptr += 1; 2549 2550 /* Encode u8 n_methods */ 2551 trunnel_assert(written <= avail); 2552 if (avail - written < 1) 2553 goto truncated; 2554 trunnel_set_uint8(ptr, (obj->n_methods)); 2555 written += 1; ptr += 1; 2556 2557 /* Encode u8 methods[n_methods] */ 2558 { 2559 size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->methods); 2560 trunnel_assert(obj->n_methods == elt_len); 2561 trunnel_assert(written <= avail); 2562 if (avail - written < elt_len) 2563 goto truncated; 2564 if (elt_len) 2565 memcpy(ptr, obj->methods.elts_, elt_len); 2566 written += elt_len; ptr += elt_len; 2567 } 2568 2569 2570 trunnel_assert(ptr == output + written); 2571 #ifdef TRUNNEL_CHECK_ENCODED_LEN 2572 { 2573 trunnel_assert(encoded_len >= 0); 2574 trunnel_assert((size_t)encoded_len == written); 2575 } 2576 2577 #endif 2578 2579 return written; 2580 2581 truncated: 2582 result = -2; 2583 goto fail; 2584 check_failed: 2585 (void)msg; 2586 result = -1; 2587 goto fail; 2588 fail: 2589 trunnel_assert(result < 0); 2590 return result; 2591 } 2592 2593 /** As socks5_client_version_parse(), but do not allocate the output 2594 * object. 2595 */ 2596 static ssize_t 2597 socks5_client_version_parse_into(socks5_client_version_t *obj, const uint8_t *input, const size_t len_in) 2598 { 2599 const uint8_t *ptr = input; 2600 size_t remaining = len_in; 2601 ssize_t result = 0; 2602 (void)result; 2603 2604 /* Parse u8 version IN [5] */ 2605 CHECK_REMAINING(1, truncated); 2606 obj->version = (trunnel_get_uint8(ptr)); 2607 remaining -= 1; ptr += 1; 2608 if (! (obj->version == 5)) 2609 goto fail; 2610 2611 /* Parse u8 n_methods */ 2612 CHECK_REMAINING(1, truncated); 2613 obj->n_methods = (trunnel_get_uint8(ptr)); 2614 remaining -= 1; ptr += 1; 2615 2616 /* Parse u8 methods[n_methods] */ 2617 CHECK_REMAINING(obj->n_methods, truncated); 2618 TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->methods, obj->n_methods, {}); 2619 obj->methods.n_ = obj->n_methods; 2620 if (obj->n_methods) 2621 memcpy(obj->methods.elts_, ptr, obj->n_methods); 2622 ptr += obj->n_methods; remaining -= obj->n_methods; 2623 trunnel_assert(ptr + remaining == input + len_in); 2624 return len_in - remaining; 2625 2626 truncated: 2627 return -2; 2628 trunnel_alloc_failed: 2629 return -1; 2630 fail: 2631 result = -1; 2632 return result; 2633 } 2634 2635 ssize_t 2636 socks5_client_version_parse(socks5_client_version_t **output, const uint8_t *input, const size_t len_in) 2637 { 2638 ssize_t result; 2639 *output = socks5_client_version_new(); 2640 if (NULL == *output) 2641 return -1; 2642 result = socks5_client_version_parse_into(*output, input, len_in); 2643 if (result < 0) { 2644 socks5_client_version_free(*output); 2645 *output = NULL; 2646 } 2647 return result; 2648 } 2649 socks5_server_method_t * 2650 socks5_server_method_new(void) 2651 { 2652 socks5_server_method_t *val = trunnel_calloc(1, sizeof(socks5_server_method_t)); 2653 if (NULL == val) 2654 return NULL; 2655 val->version = 5; 2656 return val; 2657 } 2658 2659 /** Release all storage held inside 'obj', but do not free 'obj'. 2660 */ 2661 static void 2662 socks5_server_method_clear(socks5_server_method_t *obj) 2663 { 2664 (void) obj; 2665 } 2666 2667 void 2668 socks5_server_method_free(socks5_server_method_t *obj) 2669 { 2670 if (obj == NULL) 2671 return; 2672 socks5_server_method_clear(obj); 2673 trunnel_memwipe(obj, sizeof(socks5_server_method_t)); 2674 trunnel_free_(obj); 2675 } 2676 2677 uint8_t 2678 socks5_server_method_get_version(const socks5_server_method_t *inp) 2679 { 2680 return inp->version; 2681 } 2682 int 2683 socks5_server_method_set_version(socks5_server_method_t *inp, uint8_t val) 2684 { 2685 if (! ((val == 5))) { 2686 TRUNNEL_SET_ERROR_CODE(inp); 2687 return -1; 2688 } 2689 inp->version = val; 2690 return 0; 2691 } 2692 uint8_t 2693 socks5_server_method_get_method(const socks5_server_method_t *inp) 2694 { 2695 return inp->method; 2696 } 2697 int 2698 socks5_server_method_set_method(socks5_server_method_t *inp, uint8_t val) 2699 { 2700 inp->method = val; 2701 return 0; 2702 } 2703 const char * 2704 socks5_server_method_check(const socks5_server_method_t *obj) 2705 { 2706 if (obj == NULL) 2707 return "Object was NULL"; 2708 if (obj->trunnel_error_code_) 2709 return "A set function failed on this object"; 2710 if (! (obj->version == 5)) 2711 return "Integer out of bounds"; 2712 return NULL; 2713 } 2714 2715 ssize_t 2716 socks5_server_method_encoded_len(const socks5_server_method_t *obj) 2717 { 2718 ssize_t result = 0; 2719 2720 if (NULL != socks5_server_method_check(obj)) 2721 return -1; 2722 2723 2724 /* Length of u8 version IN [5] */ 2725 result += 1; 2726 2727 /* Length of u8 method */ 2728 result += 1; 2729 return result; 2730 } 2731 int 2732 socks5_server_method_clear_errors(socks5_server_method_t *obj) 2733 { 2734 int r = obj->trunnel_error_code_; 2735 obj->trunnel_error_code_ = 0; 2736 return r; 2737 } 2738 ssize_t 2739 socks5_server_method_encode(uint8_t *output, const size_t avail, const socks5_server_method_t *obj) 2740 { 2741 ssize_t result = 0; 2742 size_t written = 0; 2743 uint8_t *ptr = output; 2744 const char *msg; 2745 #ifdef TRUNNEL_CHECK_ENCODED_LEN 2746 const ssize_t encoded_len = socks5_server_method_encoded_len(obj); 2747 #endif 2748 2749 if (NULL != (msg = socks5_server_method_check(obj))) 2750 goto check_failed; 2751 2752 #ifdef TRUNNEL_CHECK_ENCODED_LEN 2753 trunnel_assert(encoded_len >= 0); 2754 #endif 2755 2756 /* Encode u8 version IN [5] */ 2757 trunnel_assert(written <= avail); 2758 if (avail - written < 1) 2759 goto truncated; 2760 trunnel_set_uint8(ptr, (obj->version)); 2761 written += 1; ptr += 1; 2762 2763 /* Encode u8 method */ 2764 trunnel_assert(written <= avail); 2765 if (avail - written < 1) 2766 goto truncated; 2767 trunnel_set_uint8(ptr, (obj->method)); 2768 written += 1; ptr += 1; 2769 2770 2771 trunnel_assert(ptr == output + written); 2772 #ifdef TRUNNEL_CHECK_ENCODED_LEN 2773 { 2774 trunnel_assert(encoded_len >= 0); 2775 trunnel_assert((size_t)encoded_len == written); 2776 } 2777 2778 #endif 2779 2780 return written; 2781 2782 truncated: 2783 result = -2; 2784 goto fail; 2785 check_failed: 2786 (void)msg; 2787 result = -1; 2788 goto fail; 2789 fail: 2790 trunnel_assert(result < 0); 2791 return result; 2792 } 2793 2794 /** As socks5_server_method_parse(), but do not allocate the output 2795 * object. 2796 */ 2797 static ssize_t 2798 socks5_server_method_parse_into(socks5_server_method_t *obj, const uint8_t *input, const size_t len_in) 2799 { 2800 const uint8_t *ptr = input; 2801 size_t remaining = len_in; 2802 ssize_t result = 0; 2803 (void)result; 2804 2805 /* Parse u8 version IN [5] */ 2806 CHECK_REMAINING(1, truncated); 2807 obj->version = (trunnel_get_uint8(ptr)); 2808 remaining -= 1; ptr += 1; 2809 if (! (obj->version == 5)) 2810 goto fail; 2811 2812 /* Parse u8 method */ 2813 CHECK_REMAINING(1, truncated); 2814 obj->method = (trunnel_get_uint8(ptr)); 2815 remaining -= 1; ptr += 1; 2816 trunnel_assert(ptr + remaining == input + len_in); 2817 return len_in - remaining; 2818 2819 truncated: 2820 return -2; 2821 fail: 2822 result = -1; 2823 return result; 2824 } 2825 2826 ssize_t 2827 socks5_server_method_parse(socks5_server_method_t **output, const uint8_t *input, const size_t len_in) 2828 { 2829 ssize_t result; 2830 *output = socks5_server_method_new(); 2831 if (NULL == *output) 2832 return -1; 2833 result = socks5_server_method_parse_into(*output, input, len_in); 2834 if (result < 0) { 2835 socks5_server_method_free(*output); 2836 *output = NULL; 2837 } 2838 return result; 2839 } 2840 socks5_server_userpass_auth_t * 2841 socks5_server_userpass_auth_new(void) 2842 { 2843 socks5_server_userpass_auth_t *val = trunnel_calloc(1, sizeof(socks5_server_userpass_auth_t)); 2844 if (NULL == val) 2845 return NULL; 2846 val->version = 1; 2847 return val; 2848 } 2849 2850 /** Release all storage held inside 'obj', but do not free 'obj'. 2851 */ 2852 static void 2853 socks5_server_userpass_auth_clear(socks5_server_userpass_auth_t *obj) 2854 { 2855 (void) obj; 2856 } 2857 2858 void 2859 socks5_server_userpass_auth_free(socks5_server_userpass_auth_t *obj) 2860 { 2861 if (obj == NULL) 2862 return; 2863 socks5_server_userpass_auth_clear(obj); 2864 trunnel_memwipe(obj, sizeof(socks5_server_userpass_auth_t)); 2865 trunnel_free_(obj); 2866 } 2867 2868 uint8_t 2869 socks5_server_userpass_auth_get_version(const socks5_server_userpass_auth_t *inp) 2870 { 2871 return inp->version; 2872 } 2873 int 2874 socks5_server_userpass_auth_set_version(socks5_server_userpass_auth_t *inp, uint8_t val) 2875 { 2876 if (! ((val == 1))) { 2877 TRUNNEL_SET_ERROR_CODE(inp); 2878 return -1; 2879 } 2880 inp->version = val; 2881 return 0; 2882 } 2883 uint8_t 2884 socks5_server_userpass_auth_get_status(const socks5_server_userpass_auth_t *inp) 2885 { 2886 return inp->status; 2887 } 2888 int 2889 socks5_server_userpass_auth_set_status(socks5_server_userpass_auth_t *inp, uint8_t val) 2890 { 2891 inp->status = val; 2892 return 0; 2893 } 2894 const char * 2895 socks5_server_userpass_auth_check(const socks5_server_userpass_auth_t *obj) 2896 { 2897 if (obj == NULL) 2898 return "Object was NULL"; 2899 if (obj->trunnel_error_code_) 2900 return "A set function failed on this object"; 2901 if (! (obj->version == 1)) 2902 return "Integer out of bounds"; 2903 return NULL; 2904 } 2905 2906 ssize_t 2907 socks5_server_userpass_auth_encoded_len(const socks5_server_userpass_auth_t *obj) 2908 { 2909 ssize_t result = 0; 2910 2911 if (NULL != socks5_server_userpass_auth_check(obj)) 2912 return -1; 2913 2914 2915 /* Length of u8 version IN [1] */ 2916 result += 1; 2917 2918 /* Length of u8 status */ 2919 result += 1; 2920 return result; 2921 } 2922 int 2923 socks5_server_userpass_auth_clear_errors(socks5_server_userpass_auth_t *obj) 2924 { 2925 int r = obj->trunnel_error_code_; 2926 obj->trunnel_error_code_ = 0; 2927 return r; 2928 } 2929 ssize_t 2930 socks5_server_userpass_auth_encode(uint8_t *output, const size_t avail, const socks5_server_userpass_auth_t *obj) 2931 { 2932 ssize_t result = 0; 2933 size_t written = 0; 2934 uint8_t *ptr = output; 2935 const char *msg; 2936 #ifdef TRUNNEL_CHECK_ENCODED_LEN 2937 const ssize_t encoded_len = socks5_server_userpass_auth_encoded_len(obj); 2938 #endif 2939 2940 if (NULL != (msg = socks5_server_userpass_auth_check(obj))) 2941 goto check_failed; 2942 2943 #ifdef TRUNNEL_CHECK_ENCODED_LEN 2944 trunnel_assert(encoded_len >= 0); 2945 #endif 2946 2947 /* Encode u8 version IN [1] */ 2948 trunnel_assert(written <= avail); 2949 if (avail - written < 1) 2950 goto truncated; 2951 trunnel_set_uint8(ptr, (obj->version)); 2952 written += 1; ptr += 1; 2953 2954 /* Encode u8 status */ 2955 trunnel_assert(written <= avail); 2956 if (avail - written < 1) 2957 goto truncated; 2958 trunnel_set_uint8(ptr, (obj->status)); 2959 written += 1; ptr += 1; 2960 2961 2962 trunnel_assert(ptr == output + written); 2963 #ifdef TRUNNEL_CHECK_ENCODED_LEN 2964 { 2965 trunnel_assert(encoded_len >= 0); 2966 trunnel_assert((size_t)encoded_len == written); 2967 } 2968 2969 #endif 2970 2971 return written; 2972 2973 truncated: 2974 result = -2; 2975 goto fail; 2976 check_failed: 2977 (void)msg; 2978 result = -1; 2979 goto fail; 2980 fail: 2981 trunnel_assert(result < 0); 2982 return result; 2983 } 2984 2985 /** As socks5_server_userpass_auth_parse(), but do not allocate the 2986 * output object. 2987 */ 2988 static ssize_t 2989 socks5_server_userpass_auth_parse_into(socks5_server_userpass_auth_t *obj, const uint8_t *input, const size_t len_in) 2990 { 2991 const uint8_t *ptr = input; 2992 size_t remaining = len_in; 2993 ssize_t result = 0; 2994 (void)result; 2995 2996 /* Parse u8 version IN [1] */ 2997 CHECK_REMAINING(1, truncated); 2998 obj->version = (trunnel_get_uint8(ptr)); 2999 remaining -= 1; ptr += 1; 3000 if (! (obj->version == 1)) 3001 goto fail; 3002 3003 /* Parse u8 status */ 3004 CHECK_REMAINING(1, truncated); 3005 obj->status = (trunnel_get_uint8(ptr)); 3006 remaining -= 1; ptr += 1; 3007 trunnel_assert(ptr + remaining == input + len_in); 3008 return len_in - remaining; 3009 3010 truncated: 3011 return -2; 3012 fail: 3013 result = -1; 3014 return result; 3015 } 3016 3017 ssize_t 3018 socks5_server_userpass_auth_parse(socks5_server_userpass_auth_t **output, const uint8_t *input, const size_t len_in) 3019 { 3020 ssize_t result; 3021 *output = socks5_server_userpass_auth_new(); 3022 if (NULL == *output) 3023 return -1; 3024 result = socks5_server_userpass_auth_parse_into(*output, input, len_in); 3025 if (result < 0) { 3026 socks5_server_userpass_auth_free(*output); 3027 *output = NULL; 3028 } 3029 return result; 3030 } 3031 socks5_client_request_t * 3032 socks5_client_request_new(void) 3033 { 3034 socks5_client_request_t *val = trunnel_calloc(1, sizeof(socks5_client_request_t)); 3035 if (NULL == val) 3036 return NULL; 3037 val->version = 5; 3038 val->command = CMD_BIND; 3039 return val; 3040 } 3041 3042 /** Release all storage held inside 'obj', but do not free 'obj'. 3043 */ 3044 static void 3045 socks5_client_request_clear(socks5_client_request_t *obj) 3046 { 3047 (void) obj; 3048 domainname_free(obj->dest_addr_domainname); 3049 obj->dest_addr_domainname = NULL; 3050 } 3051 3052 void 3053 socks5_client_request_free(socks5_client_request_t *obj) 3054 { 3055 if (obj == NULL) 3056 return; 3057 socks5_client_request_clear(obj); 3058 trunnel_memwipe(obj, sizeof(socks5_client_request_t)); 3059 trunnel_free_(obj); 3060 } 3061 3062 uint8_t 3063 socks5_client_request_get_version(const socks5_client_request_t *inp) 3064 { 3065 return inp->version; 3066 } 3067 int 3068 socks5_client_request_set_version(socks5_client_request_t *inp, uint8_t val) 3069 { 3070 if (! ((val == 5))) { 3071 TRUNNEL_SET_ERROR_CODE(inp); 3072 return -1; 3073 } 3074 inp->version = val; 3075 return 0; 3076 } 3077 uint8_t 3078 socks5_client_request_get_command(const socks5_client_request_t *inp) 3079 { 3080 return inp->command; 3081 } 3082 int 3083 socks5_client_request_set_command(socks5_client_request_t *inp, uint8_t val) 3084 { 3085 if (! ((val == CMD_BIND || val == CMD_CONNECT || val == CMD_RESOLVE || val == CMD_RESOLVE_PTR || val == CMD_UDP_ASSOCIATE))) { 3086 TRUNNEL_SET_ERROR_CODE(inp); 3087 return -1; 3088 } 3089 inp->command = val; 3090 return 0; 3091 } 3092 uint8_t 3093 socks5_client_request_get_reserved(const socks5_client_request_t *inp) 3094 { 3095 return inp->reserved; 3096 } 3097 int 3098 socks5_client_request_set_reserved(socks5_client_request_t *inp, uint8_t val) 3099 { 3100 if (! ((val == 0))) { 3101 TRUNNEL_SET_ERROR_CODE(inp); 3102 return -1; 3103 } 3104 inp->reserved = val; 3105 return 0; 3106 } 3107 uint8_t 3108 socks5_client_request_get_atype(const socks5_client_request_t *inp) 3109 { 3110 return inp->atype; 3111 } 3112 int 3113 socks5_client_request_set_atype(socks5_client_request_t *inp, uint8_t val) 3114 { 3115 inp->atype = val; 3116 return 0; 3117 } 3118 uint32_t 3119 socks5_client_request_get_dest_addr_ipv4(const socks5_client_request_t *inp) 3120 { 3121 return inp->dest_addr_ipv4; 3122 } 3123 int 3124 socks5_client_request_set_dest_addr_ipv4(socks5_client_request_t *inp, uint32_t val) 3125 { 3126 inp->dest_addr_ipv4 = val; 3127 return 0; 3128 } 3129 size_t 3130 socks5_client_request_getlen_dest_addr_ipv6(const socks5_client_request_t *inp) 3131 { 3132 (void)inp; return 16; 3133 } 3134 3135 uint8_t 3136 socks5_client_request_get_dest_addr_ipv6(socks5_client_request_t *inp, size_t idx) 3137 { 3138 trunnel_assert(idx < 16); 3139 return inp->dest_addr_ipv6[idx]; 3140 } 3141 3142 uint8_t 3143 socks5_client_request_getconst_dest_addr_ipv6(const socks5_client_request_t *inp, size_t idx) 3144 { 3145 return socks5_client_request_get_dest_addr_ipv6((socks5_client_request_t*)inp, idx); 3146 } 3147 int 3148 socks5_client_request_set_dest_addr_ipv6(socks5_client_request_t *inp, size_t idx, uint8_t elt) 3149 { 3150 trunnel_assert(idx < 16); 3151 inp->dest_addr_ipv6[idx] = elt; 3152 return 0; 3153 } 3154 3155 uint8_t * 3156 socks5_client_request_getarray_dest_addr_ipv6(socks5_client_request_t *inp) 3157 { 3158 return inp->dest_addr_ipv6; 3159 } 3160 const uint8_t * 3161 socks5_client_request_getconstarray_dest_addr_ipv6(const socks5_client_request_t *inp) 3162 { 3163 return (const uint8_t *)socks5_client_request_getarray_dest_addr_ipv6((socks5_client_request_t*)inp); 3164 } 3165 struct domainname_st * 3166 socks5_client_request_get_dest_addr_domainname(socks5_client_request_t *inp) 3167 { 3168 return inp->dest_addr_domainname; 3169 } 3170 const struct domainname_st * 3171 socks5_client_request_getconst_dest_addr_domainname(const socks5_client_request_t *inp) 3172 { 3173 return socks5_client_request_get_dest_addr_domainname((socks5_client_request_t*) inp); 3174 } 3175 int 3176 socks5_client_request_set_dest_addr_domainname(socks5_client_request_t *inp, struct domainname_st *val) 3177 { 3178 if (inp->dest_addr_domainname && inp->dest_addr_domainname != val) 3179 domainname_free(inp->dest_addr_domainname); 3180 return socks5_client_request_set0_dest_addr_domainname(inp, val); 3181 } 3182 int 3183 socks5_client_request_set0_dest_addr_domainname(socks5_client_request_t *inp, struct domainname_st *val) 3184 { 3185 inp->dest_addr_domainname = val; 3186 return 0; 3187 } 3188 uint16_t 3189 socks5_client_request_get_dest_port(const socks5_client_request_t *inp) 3190 { 3191 return inp->dest_port; 3192 } 3193 int 3194 socks5_client_request_set_dest_port(socks5_client_request_t *inp, uint16_t val) 3195 { 3196 inp->dest_port = val; 3197 return 0; 3198 } 3199 const char * 3200 socks5_client_request_check(const socks5_client_request_t *obj) 3201 { 3202 if (obj == NULL) 3203 return "Object was NULL"; 3204 if (obj->trunnel_error_code_) 3205 return "A set function failed on this object"; 3206 if (! (obj->version == 5)) 3207 return "Integer out of bounds"; 3208 if (! (obj->command == CMD_BIND || obj->command == CMD_CONNECT || obj->command == CMD_RESOLVE || obj->command == CMD_RESOLVE_PTR || obj->command == CMD_UDP_ASSOCIATE)) 3209 return "Integer out of bounds"; 3210 if (! (obj->reserved == 0)) 3211 return "Integer out of bounds"; 3212 switch (obj->atype) { 3213 3214 case ATYPE_IPV4: 3215 break; 3216 3217 case ATYPE_IPV6: 3218 break; 3219 3220 case ATYPE_DOMAINNAME: 3221 { 3222 const char *msg; 3223 if (NULL != (msg = domainname_check(obj->dest_addr_domainname))) 3224 return msg; 3225 } 3226 break; 3227 3228 default: 3229 return "Bad tag for union"; 3230 break; 3231 } 3232 return NULL; 3233 } 3234 3235 ssize_t 3236 socks5_client_request_encoded_len(const socks5_client_request_t *obj) 3237 { 3238 ssize_t result = 0; 3239 3240 if (NULL != socks5_client_request_check(obj)) 3241 return -1; 3242 3243 3244 /* Length of u8 version IN [5] */ 3245 result += 1; 3246 3247 /* Length of u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR, CMD_UDP_ASSOCIATE] */ 3248 result += 1; 3249 3250 /* Length of u8 reserved IN [0] */ 3251 result += 1; 3252 3253 /* Length of u8 atype */ 3254 result += 1; 3255 switch (obj->atype) { 3256 3257 case ATYPE_IPV4: 3258 3259 /* Length of u32 dest_addr_ipv4 */ 3260 result += 4; 3261 break; 3262 3263 case ATYPE_IPV6: 3264 3265 /* Length of u8 dest_addr_ipv6[16] */ 3266 result += 16; 3267 break; 3268 3269 case ATYPE_DOMAINNAME: 3270 3271 /* Length of struct domainname dest_addr_domainname */ 3272 result += domainname_encoded_len(obj->dest_addr_domainname); 3273 break; 3274 3275 default: 3276 trunnel_assert(0); 3277 break; 3278 } 3279 3280 /* Length of u16 dest_port */ 3281 result += 2; 3282 return result; 3283 } 3284 int 3285 socks5_client_request_clear_errors(socks5_client_request_t *obj) 3286 { 3287 int r = obj->trunnel_error_code_; 3288 obj->trunnel_error_code_ = 0; 3289 return r; 3290 } 3291 ssize_t 3292 socks5_client_request_encode(uint8_t *output, const size_t avail, const socks5_client_request_t *obj) 3293 { 3294 ssize_t result = 0; 3295 size_t written = 0; 3296 uint8_t *ptr = output; 3297 const char *msg; 3298 #ifdef TRUNNEL_CHECK_ENCODED_LEN 3299 const ssize_t encoded_len = socks5_client_request_encoded_len(obj); 3300 #endif 3301 3302 if (NULL != (msg = socks5_client_request_check(obj))) 3303 goto check_failed; 3304 3305 #ifdef TRUNNEL_CHECK_ENCODED_LEN 3306 trunnel_assert(encoded_len >= 0); 3307 #endif 3308 3309 /* Encode u8 version IN [5] */ 3310 trunnel_assert(written <= avail); 3311 if (avail - written < 1) 3312 goto truncated; 3313 trunnel_set_uint8(ptr, (obj->version)); 3314 written += 1; ptr += 1; 3315 3316 /* Encode u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR, CMD_UDP_ASSOCIATE] */ 3317 trunnel_assert(written <= avail); 3318 if (avail - written < 1) 3319 goto truncated; 3320 trunnel_set_uint8(ptr, (obj->command)); 3321 written += 1; ptr += 1; 3322 3323 /* Encode u8 reserved IN [0] */ 3324 trunnel_assert(written <= avail); 3325 if (avail - written < 1) 3326 goto truncated; 3327 trunnel_set_uint8(ptr, (obj->reserved)); 3328 written += 1; ptr += 1; 3329 3330 /* Encode u8 atype */ 3331 trunnel_assert(written <= avail); 3332 if (avail - written < 1) 3333 goto truncated; 3334 trunnel_set_uint8(ptr, (obj->atype)); 3335 written += 1; ptr += 1; 3336 3337 /* Encode union dest_addr[atype] */ 3338 trunnel_assert(written <= avail); 3339 switch (obj->atype) { 3340 3341 case ATYPE_IPV4: 3342 3343 /* Encode u32 dest_addr_ipv4 */ 3344 trunnel_assert(written <= avail); 3345 if (avail - written < 4) 3346 goto truncated; 3347 trunnel_set_uint32(ptr, trunnel_htonl(obj->dest_addr_ipv4)); 3348 written += 4; ptr += 4; 3349 break; 3350 3351 case ATYPE_IPV6: 3352 3353 /* Encode u8 dest_addr_ipv6[16] */ 3354 trunnel_assert(written <= avail); 3355 if (avail - written < 16) 3356 goto truncated; 3357 memcpy(ptr, obj->dest_addr_ipv6, 16); 3358 written += 16; ptr += 16; 3359 break; 3360 3361 case ATYPE_DOMAINNAME: 3362 3363 /* Encode struct domainname dest_addr_domainname */ 3364 trunnel_assert(written <= avail); 3365 result = domainname_encode(ptr, avail - written, obj->dest_addr_domainname); 3366 if (result < 0) 3367 goto fail; /* XXXXXXX !*/ 3368 written += result; ptr += result; 3369 break; 3370 3371 default: 3372 trunnel_assert(0); 3373 break; 3374 } 3375 3376 /* Encode u16 dest_port */ 3377 trunnel_assert(written <= avail); 3378 if (avail - written < 2) 3379 goto truncated; 3380 trunnel_set_uint16(ptr, trunnel_htons(obj->dest_port)); 3381 written += 2; ptr += 2; 3382 3383 3384 trunnel_assert(ptr == output + written); 3385 #ifdef TRUNNEL_CHECK_ENCODED_LEN 3386 { 3387 trunnel_assert(encoded_len >= 0); 3388 trunnel_assert((size_t)encoded_len == written); 3389 } 3390 3391 #endif 3392 3393 return written; 3394 3395 truncated: 3396 result = -2; 3397 goto fail; 3398 check_failed: 3399 (void)msg; 3400 result = -1; 3401 goto fail; 3402 fail: 3403 trunnel_assert(result < 0); 3404 return result; 3405 } 3406 3407 /** As socks5_client_request_parse(), but do not allocate the output 3408 * object. 3409 */ 3410 static ssize_t 3411 socks5_client_request_parse_into(socks5_client_request_t *obj, const uint8_t *input, const size_t len_in) 3412 { 3413 const uint8_t *ptr = input; 3414 size_t remaining = len_in; 3415 ssize_t result = 0; 3416 (void)result; 3417 3418 /* Parse u8 version IN [5] */ 3419 CHECK_REMAINING(1, truncated); 3420 obj->version = (trunnel_get_uint8(ptr)); 3421 remaining -= 1; ptr += 1; 3422 if (! (obj->version == 5)) 3423 goto fail; 3424 3425 /* Parse u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR, CMD_UDP_ASSOCIATE] */ 3426 CHECK_REMAINING(1, truncated); 3427 obj->command = (trunnel_get_uint8(ptr)); 3428 remaining -= 1; ptr += 1; 3429 if (! (obj->command == CMD_BIND || obj->command == CMD_CONNECT || obj->command == CMD_RESOLVE || obj->command == CMD_RESOLVE_PTR || obj->command == CMD_UDP_ASSOCIATE)) 3430 goto fail; 3431 3432 /* Parse u8 reserved IN [0] */ 3433 CHECK_REMAINING(1, truncated); 3434 obj->reserved = (trunnel_get_uint8(ptr)); 3435 remaining -= 1; ptr += 1; 3436 if (! (obj->reserved == 0)) 3437 goto fail; 3438 3439 /* Parse u8 atype */ 3440 CHECK_REMAINING(1, truncated); 3441 obj->atype = (trunnel_get_uint8(ptr)); 3442 remaining -= 1; ptr += 1; 3443 3444 /* Parse union dest_addr[atype] */ 3445 switch (obj->atype) { 3446 3447 case ATYPE_IPV4: 3448 3449 /* Parse u32 dest_addr_ipv4 */ 3450 CHECK_REMAINING(4, truncated); 3451 obj->dest_addr_ipv4 = trunnel_ntohl(trunnel_get_uint32(ptr)); 3452 remaining -= 4; ptr += 4; 3453 break; 3454 3455 case ATYPE_IPV6: 3456 3457 /* Parse u8 dest_addr_ipv6[16] */ 3458 CHECK_REMAINING(16, truncated); 3459 memcpy(obj->dest_addr_ipv6, ptr, 16); 3460 remaining -= 16; ptr += 16; 3461 break; 3462 3463 case ATYPE_DOMAINNAME: 3464 3465 /* Parse struct domainname dest_addr_domainname */ 3466 result = domainname_parse(&obj->dest_addr_domainname, ptr, remaining); 3467 if (result < 0) 3468 goto relay_fail; 3469 trunnel_assert((size_t)result <= remaining); 3470 remaining -= result; ptr += result; 3471 break; 3472 3473 default: 3474 goto fail; 3475 break; 3476 } 3477 3478 /* Parse u16 dest_port */ 3479 CHECK_REMAINING(2, truncated); 3480 obj->dest_port = trunnel_ntohs(trunnel_get_uint16(ptr)); 3481 remaining -= 2; ptr += 2; 3482 trunnel_assert(ptr + remaining == input + len_in); 3483 return len_in - remaining; 3484 3485 truncated: 3486 return -2; 3487 relay_fail: 3488 trunnel_assert(result < 0); 3489 return result; 3490 fail: 3491 result = -1; 3492 return result; 3493 } 3494 3495 ssize_t 3496 socks5_client_request_parse(socks5_client_request_t **output, const uint8_t *input, const size_t len_in) 3497 { 3498 ssize_t result; 3499 *output = socks5_client_request_new(); 3500 if (NULL == *output) 3501 return -1; 3502 result = socks5_client_request_parse_into(*output, input, len_in); 3503 if (result < 0) { 3504 socks5_client_request_free(*output); 3505 *output = NULL; 3506 } 3507 return result; 3508 } 3509 socks5_server_reply_t * 3510 socks5_server_reply_new(void) 3511 { 3512 socks5_server_reply_t *val = trunnel_calloc(1, sizeof(socks5_server_reply_t)); 3513 if (NULL == val) 3514 return NULL; 3515 val->version = 5; 3516 return val; 3517 } 3518 3519 /** Release all storage held inside 'obj', but do not free 'obj'. 3520 */ 3521 static void 3522 socks5_server_reply_clear(socks5_server_reply_t *obj) 3523 { 3524 (void) obj; 3525 domainname_free(obj->bind_addr_domainname); 3526 obj->bind_addr_domainname = NULL; 3527 } 3528 3529 void 3530 socks5_server_reply_free(socks5_server_reply_t *obj) 3531 { 3532 if (obj == NULL) 3533 return; 3534 socks5_server_reply_clear(obj); 3535 trunnel_memwipe(obj, sizeof(socks5_server_reply_t)); 3536 trunnel_free_(obj); 3537 } 3538 3539 uint8_t 3540 socks5_server_reply_get_version(const socks5_server_reply_t *inp) 3541 { 3542 return inp->version; 3543 } 3544 int 3545 socks5_server_reply_set_version(socks5_server_reply_t *inp, uint8_t val) 3546 { 3547 if (! ((val == 5))) { 3548 TRUNNEL_SET_ERROR_CODE(inp); 3549 return -1; 3550 } 3551 inp->version = val; 3552 return 0; 3553 } 3554 uint8_t 3555 socks5_server_reply_get_reply(const socks5_server_reply_t *inp) 3556 { 3557 return inp->reply; 3558 } 3559 int 3560 socks5_server_reply_set_reply(socks5_server_reply_t *inp, uint8_t val) 3561 { 3562 inp->reply = val; 3563 return 0; 3564 } 3565 uint8_t 3566 socks5_server_reply_get_reserved(const socks5_server_reply_t *inp) 3567 { 3568 return inp->reserved; 3569 } 3570 int 3571 socks5_server_reply_set_reserved(socks5_server_reply_t *inp, uint8_t val) 3572 { 3573 if (! ((val == 0))) { 3574 TRUNNEL_SET_ERROR_CODE(inp); 3575 return -1; 3576 } 3577 inp->reserved = val; 3578 return 0; 3579 } 3580 uint8_t 3581 socks5_server_reply_get_atype(const socks5_server_reply_t *inp) 3582 { 3583 return inp->atype; 3584 } 3585 int 3586 socks5_server_reply_set_atype(socks5_server_reply_t *inp, uint8_t val) 3587 { 3588 inp->atype = val; 3589 return 0; 3590 } 3591 uint32_t 3592 socks5_server_reply_get_bind_addr_ipv4(const socks5_server_reply_t *inp) 3593 { 3594 return inp->bind_addr_ipv4; 3595 } 3596 int 3597 socks5_server_reply_set_bind_addr_ipv4(socks5_server_reply_t *inp, uint32_t val) 3598 { 3599 inp->bind_addr_ipv4 = val; 3600 return 0; 3601 } 3602 size_t 3603 socks5_server_reply_getlen_bind_addr_ipv6(const socks5_server_reply_t *inp) 3604 { 3605 (void)inp; return 16; 3606 } 3607 3608 uint8_t 3609 socks5_server_reply_get_bind_addr_ipv6(socks5_server_reply_t *inp, size_t idx) 3610 { 3611 trunnel_assert(idx < 16); 3612 return inp->bind_addr_ipv6[idx]; 3613 } 3614 3615 uint8_t 3616 socks5_server_reply_getconst_bind_addr_ipv6(const socks5_server_reply_t *inp, size_t idx) 3617 { 3618 return socks5_server_reply_get_bind_addr_ipv6((socks5_server_reply_t*)inp, idx); 3619 } 3620 int 3621 socks5_server_reply_set_bind_addr_ipv6(socks5_server_reply_t *inp, size_t idx, uint8_t elt) 3622 { 3623 trunnel_assert(idx < 16); 3624 inp->bind_addr_ipv6[idx] = elt; 3625 return 0; 3626 } 3627 3628 uint8_t * 3629 socks5_server_reply_getarray_bind_addr_ipv6(socks5_server_reply_t *inp) 3630 { 3631 return inp->bind_addr_ipv6; 3632 } 3633 const uint8_t * 3634 socks5_server_reply_getconstarray_bind_addr_ipv6(const socks5_server_reply_t *inp) 3635 { 3636 return (const uint8_t *)socks5_server_reply_getarray_bind_addr_ipv6((socks5_server_reply_t*)inp); 3637 } 3638 struct domainname_st * 3639 socks5_server_reply_get_bind_addr_domainname(socks5_server_reply_t *inp) 3640 { 3641 return inp->bind_addr_domainname; 3642 } 3643 const struct domainname_st * 3644 socks5_server_reply_getconst_bind_addr_domainname(const socks5_server_reply_t *inp) 3645 { 3646 return socks5_server_reply_get_bind_addr_domainname((socks5_server_reply_t*) inp); 3647 } 3648 int 3649 socks5_server_reply_set_bind_addr_domainname(socks5_server_reply_t *inp, struct domainname_st *val) 3650 { 3651 if (inp->bind_addr_domainname && inp->bind_addr_domainname != val) 3652 domainname_free(inp->bind_addr_domainname); 3653 return socks5_server_reply_set0_bind_addr_domainname(inp, val); 3654 } 3655 int 3656 socks5_server_reply_set0_bind_addr_domainname(socks5_server_reply_t *inp, struct domainname_st *val) 3657 { 3658 inp->bind_addr_domainname = val; 3659 return 0; 3660 } 3661 uint16_t 3662 socks5_server_reply_get_bind_port(const socks5_server_reply_t *inp) 3663 { 3664 return inp->bind_port; 3665 } 3666 int 3667 socks5_server_reply_set_bind_port(socks5_server_reply_t *inp, uint16_t val) 3668 { 3669 inp->bind_port = val; 3670 return 0; 3671 } 3672 const char * 3673 socks5_server_reply_check(const socks5_server_reply_t *obj) 3674 { 3675 if (obj == NULL) 3676 return "Object was NULL"; 3677 if (obj->trunnel_error_code_) 3678 return "A set function failed on this object"; 3679 if (! (obj->version == 5)) 3680 return "Integer out of bounds"; 3681 if (! (obj->reserved == 0)) 3682 return "Integer out of bounds"; 3683 switch (obj->atype) { 3684 3685 case ATYPE_IPV4: 3686 break; 3687 3688 case ATYPE_IPV6: 3689 break; 3690 3691 case ATYPE_DOMAINNAME: 3692 { 3693 const char *msg; 3694 if (NULL != (msg = domainname_check(obj->bind_addr_domainname))) 3695 return msg; 3696 } 3697 break; 3698 3699 default: 3700 return "Bad tag for union"; 3701 break; 3702 } 3703 return NULL; 3704 } 3705 3706 ssize_t 3707 socks5_server_reply_encoded_len(const socks5_server_reply_t *obj) 3708 { 3709 ssize_t result = 0; 3710 3711 if (NULL != socks5_server_reply_check(obj)) 3712 return -1; 3713 3714 3715 /* Length of u8 version IN [5] */ 3716 result += 1; 3717 3718 /* Length of u8 reply */ 3719 result += 1; 3720 3721 /* Length of u8 reserved IN [0] */ 3722 result += 1; 3723 3724 /* Length of u8 atype */ 3725 result += 1; 3726 switch (obj->atype) { 3727 3728 case ATYPE_IPV4: 3729 3730 /* Length of u32 bind_addr_ipv4 */ 3731 result += 4; 3732 break; 3733 3734 case ATYPE_IPV6: 3735 3736 /* Length of u8 bind_addr_ipv6[16] */ 3737 result += 16; 3738 break; 3739 3740 case ATYPE_DOMAINNAME: 3741 3742 /* Length of struct domainname bind_addr_domainname */ 3743 result += domainname_encoded_len(obj->bind_addr_domainname); 3744 break; 3745 3746 default: 3747 trunnel_assert(0); 3748 break; 3749 } 3750 3751 /* Length of u16 bind_port */ 3752 result += 2; 3753 return result; 3754 } 3755 int 3756 socks5_server_reply_clear_errors(socks5_server_reply_t *obj) 3757 { 3758 int r = obj->trunnel_error_code_; 3759 obj->trunnel_error_code_ = 0; 3760 return r; 3761 } 3762 ssize_t 3763 socks5_server_reply_encode(uint8_t *output, const size_t avail, const socks5_server_reply_t *obj) 3764 { 3765 ssize_t result = 0; 3766 size_t written = 0; 3767 uint8_t *ptr = output; 3768 const char *msg; 3769 #ifdef TRUNNEL_CHECK_ENCODED_LEN 3770 const ssize_t encoded_len = socks5_server_reply_encoded_len(obj); 3771 #endif 3772 3773 if (NULL != (msg = socks5_server_reply_check(obj))) 3774 goto check_failed; 3775 3776 #ifdef TRUNNEL_CHECK_ENCODED_LEN 3777 trunnel_assert(encoded_len >= 0); 3778 #endif 3779 3780 /* Encode u8 version IN [5] */ 3781 trunnel_assert(written <= avail); 3782 if (avail - written < 1) 3783 goto truncated; 3784 trunnel_set_uint8(ptr, (obj->version)); 3785 written += 1; ptr += 1; 3786 3787 /* Encode u8 reply */ 3788 trunnel_assert(written <= avail); 3789 if (avail - written < 1) 3790 goto truncated; 3791 trunnel_set_uint8(ptr, (obj->reply)); 3792 written += 1; ptr += 1; 3793 3794 /* Encode u8 reserved IN [0] */ 3795 trunnel_assert(written <= avail); 3796 if (avail - written < 1) 3797 goto truncated; 3798 trunnel_set_uint8(ptr, (obj->reserved)); 3799 written += 1; ptr += 1; 3800 3801 /* Encode u8 atype */ 3802 trunnel_assert(written <= avail); 3803 if (avail - written < 1) 3804 goto truncated; 3805 trunnel_set_uint8(ptr, (obj->atype)); 3806 written += 1; ptr += 1; 3807 3808 /* Encode union bind_addr[atype] */ 3809 trunnel_assert(written <= avail); 3810 switch (obj->atype) { 3811 3812 case ATYPE_IPV4: 3813 3814 /* Encode u32 bind_addr_ipv4 */ 3815 trunnel_assert(written <= avail); 3816 if (avail - written < 4) 3817 goto truncated; 3818 trunnel_set_uint32(ptr, trunnel_htonl(obj->bind_addr_ipv4)); 3819 written += 4; ptr += 4; 3820 break; 3821 3822 case ATYPE_IPV6: 3823 3824 /* Encode u8 bind_addr_ipv6[16] */ 3825 trunnel_assert(written <= avail); 3826 if (avail - written < 16) 3827 goto truncated; 3828 memcpy(ptr, obj->bind_addr_ipv6, 16); 3829 written += 16; ptr += 16; 3830 break; 3831 3832 case ATYPE_DOMAINNAME: 3833 3834 /* Encode struct domainname bind_addr_domainname */ 3835 trunnel_assert(written <= avail); 3836 result = domainname_encode(ptr, avail - written, obj->bind_addr_domainname); 3837 if (result < 0) 3838 goto fail; /* XXXXXXX !*/ 3839 written += result; ptr += result; 3840 break; 3841 3842 default: 3843 trunnel_assert(0); 3844 break; 3845 } 3846 3847 /* Encode u16 bind_port */ 3848 trunnel_assert(written <= avail); 3849 if (avail - written < 2) 3850 goto truncated; 3851 trunnel_set_uint16(ptr, trunnel_htons(obj->bind_port)); 3852 written += 2; ptr += 2; 3853 3854 3855 trunnel_assert(ptr == output + written); 3856 #ifdef TRUNNEL_CHECK_ENCODED_LEN 3857 { 3858 trunnel_assert(encoded_len >= 0); 3859 trunnel_assert((size_t)encoded_len == written); 3860 } 3861 3862 #endif 3863 3864 return written; 3865 3866 truncated: 3867 result = -2; 3868 goto fail; 3869 check_failed: 3870 (void)msg; 3871 result = -1; 3872 goto fail; 3873 fail: 3874 trunnel_assert(result < 0); 3875 return result; 3876 } 3877 3878 /** As socks5_server_reply_parse(), but do not allocate the output 3879 * object. 3880 */ 3881 static ssize_t 3882 socks5_server_reply_parse_into(socks5_server_reply_t *obj, const uint8_t *input, const size_t len_in) 3883 { 3884 const uint8_t *ptr = input; 3885 size_t remaining = len_in; 3886 ssize_t result = 0; 3887 (void)result; 3888 3889 /* Parse u8 version IN [5] */ 3890 CHECK_REMAINING(1, truncated); 3891 obj->version = (trunnel_get_uint8(ptr)); 3892 remaining -= 1; ptr += 1; 3893 if (! (obj->version == 5)) 3894 goto fail; 3895 3896 /* Parse u8 reply */ 3897 CHECK_REMAINING(1, truncated); 3898 obj->reply = (trunnel_get_uint8(ptr)); 3899 remaining -= 1; ptr += 1; 3900 3901 /* Parse u8 reserved IN [0] */ 3902 CHECK_REMAINING(1, truncated); 3903 obj->reserved = (trunnel_get_uint8(ptr)); 3904 remaining -= 1; ptr += 1; 3905 if (! (obj->reserved == 0)) 3906 goto fail; 3907 3908 /* Parse u8 atype */ 3909 CHECK_REMAINING(1, truncated); 3910 obj->atype = (trunnel_get_uint8(ptr)); 3911 remaining -= 1; ptr += 1; 3912 3913 /* Parse union bind_addr[atype] */ 3914 switch (obj->atype) { 3915 3916 case ATYPE_IPV4: 3917 3918 /* Parse u32 bind_addr_ipv4 */ 3919 CHECK_REMAINING(4, truncated); 3920 obj->bind_addr_ipv4 = trunnel_ntohl(trunnel_get_uint32(ptr)); 3921 remaining -= 4; ptr += 4; 3922 break; 3923 3924 case ATYPE_IPV6: 3925 3926 /* Parse u8 bind_addr_ipv6[16] */ 3927 CHECK_REMAINING(16, truncated); 3928 memcpy(obj->bind_addr_ipv6, ptr, 16); 3929 remaining -= 16; ptr += 16; 3930 break; 3931 3932 case ATYPE_DOMAINNAME: 3933 3934 /* Parse struct domainname bind_addr_domainname */ 3935 result = domainname_parse(&obj->bind_addr_domainname, ptr, remaining); 3936 if (result < 0) 3937 goto relay_fail; 3938 trunnel_assert((size_t)result <= remaining); 3939 remaining -= result; ptr += result; 3940 break; 3941 3942 default: 3943 goto fail; 3944 break; 3945 } 3946 3947 /* Parse u16 bind_port */ 3948 CHECK_REMAINING(2, truncated); 3949 obj->bind_port = trunnel_ntohs(trunnel_get_uint16(ptr)); 3950 remaining -= 2; ptr += 2; 3951 trunnel_assert(ptr + remaining == input + len_in); 3952 return len_in - remaining; 3953 3954 truncated: 3955 return -2; 3956 relay_fail: 3957 trunnel_assert(result < 0); 3958 return result; 3959 fail: 3960 result = -1; 3961 return result; 3962 } 3963 3964 ssize_t 3965 socks5_server_reply_parse(socks5_server_reply_t **output, const uint8_t *input, const size_t len_in) 3966 { 3967 ssize_t result; 3968 *output = socks5_server_reply_new(); 3969 if (NULL == *output) 3970 return -1; 3971 result = socks5_server_reply_parse_into(*output, input, len_in); 3972 if (result < 0) { 3973 socks5_server_reply_free(*output); 3974 *output = NULL; 3975 } 3976 return result; 3977 }