Merge branch 'maint-0.4.5' into maint-0.4.6
[tor.git] / src / trunnel / socks5.c
blobf32862e353dea4360bc4764b931e2c7b47b83a84
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"
8 #include "socks5.h"
10 #define TRUNNEL_SET_ERROR_CODE(obj) \
11 do { \
12 (obj)->trunnel_error_code_ = 1; \
13 } while (0)
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
24 #define CHECK_REMAINING(nbytes, label) \
25 do { \
26 if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \
27 goto label; \
28 } \
29 } while (0)
31 domainname_t *
32 domainname_new(void)
34 domainname_t *val = trunnel_calloc(1, sizeof(domainname_t));
35 if (NULL == val)
36 return NULL;
37 return val;
40 /** Release all storage held inside 'obj', but do not free 'obj'.
42 static void
43 domainname_clear(domainname_t *obj)
45 (void) obj;
46 TRUNNEL_DYNARRAY_WIPE(&obj->name);
47 TRUNNEL_DYNARRAY_CLEAR(&obj->name);
50 void
51 domainname_free(domainname_t *obj)
53 if (obj == NULL)
54 return;
55 domainname_clear(obj);
56 trunnel_memwipe(obj, sizeof(domainname_t));
57 trunnel_free_(obj);
60 uint8_t
61 domainname_get_len(const domainname_t *inp)
63 return inp->len;
65 int
66 domainname_set_len(domainname_t *inp, uint8_t val)
68 inp->len = val;
69 return 0;
71 size_t
72 domainname_getlen_name(const domainname_t *inp)
74 return TRUNNEL_DYNARRAY_LEN(&inp->name);
77 char
78 domainname_get_name(domainname_t *inp, size_t idx)
80 return TRUNNEL_DYNARRAY_GET(&inp->name, idx);
83 char
84 domainname_getconst_name(const domainname_t *inp, size_t idx)
86 return domainname_get_name((domainname_t*)inp, idx);
88 int
89 domainname_set_name(domainname_t *inp, size_t idx, char elt)
91 TRUNNEL_DYNARRAY_SET(&inp->name, idx, elt);
92 return 0;
94 int
95 domainname_add_name(domainname_t *inp, char elt)
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;
108 char *
109 domainname_getarray_name(domainname_t *inp)
111 return inp->name.elts_;
113 const char *
114 domainname_getconstarray_name(const domainname_t *inp)
116 return (const char *)domainname_getarray_name((domainname_t*)inp);
119 domainname_setlen_name(domainname_t *inp, size_t newlen)
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;
131 const char *
132 domainname_getstr_name(domainname_t *inp)
134 return trunnel_string_getstr(&inp->name);
137 domainname_setstr0_name(domainname_t *inp, const char *val, size_t len)
139 #if UINT8_MAX < SIZE_MAX
140 if (len > UINT8_MAX) {
141 TRUNNEL_SET_ERROR_CODE(inp);
142 return -1;
144 #endif
145 return trunnel_string_setstr0(&inp->name, val, len, &inp->trunnel_error_code_);
148 domainname_setstr_name(domainname_t *inp, const char *val)
150 return domainname_setstr0_name(inp, val, strlen(val));
152 const char *
153 domainname_check(const domainname_t *obj)
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;
164 ssize_t
165 domainname_encoded_len(const domainname_t *obj)
167 ssize_t result = 0;
169 if (NULL != domainname_check(obj))
170 return -1;
173 /* Length of u8 len */
174 result += 1;
176 /* Length of char name[len] */
177 result += TRUNNEL_DYNARRAY_LEN(&obj->name);
178 return result;
181 domainname_clear_errors(domainname_t *obj)
183 int r = obj->trunnel_error_code_;
184 obj->trunnel_error_code_ = 0;
185 return r;
187 ssize_t
188 domainname_encode(uint8_t *output, const size_t avail, const domainname_t *obj)
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
198 if (NULL != (msg = domainname_check(obj)))
199 goto check_failed;
201 #ifdef TRUNNEL_CHECK_ENCODED_LEN
202 trunnel_assert(encoded_len >= 0);
203 #endif
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;
212 /* Encode char name[len] */
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;
225 trunnel_assert(ptr == output + written);
226 #ifdef TRUNNEL_CHECK_ENCODED_LEN
228 trunnel_assert(encoded_len >= 0);
229 trunnel_assert((size_t)encoded_len == written);
232 #endif
234 return written;
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;
248 /** As domainname_parse(), but do not allocate the output object.
250 static ssize_t
251 domainname_parse_into(domainname_t *obj, const uint8_t *input, const size_t len_in)
253 const uint8_t *ptr = input;
254 size_t remaining = len_in;
255 ssize_t result = 0;
256 (void)result;
258 /* Parse u8 len */
259 CHECK_REMAINING(1, truncated);
260 obj->len = (trunnel_get_uint8(ptr));
261 remaining -= 1; ptr += 1;
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;
271 truncated:
272 return -2;
273 fail:
274 result = -1;
275 return result;
278 ssize_t
279 domainname_parse(domainname_t **output, const uint8_t *input, const size_t len_in)
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;
290 return result;
292 socks4_client_request_t *
293 socks4_client_request_new(void)
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;
303 /** Release all storage held inside 'obj', but do not free 'obj'.
305 static void
306 socks4_client_request_clear(socks4_client_request_t *obj)
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);
315 void
316 socks4_client_request_free(socks4_client_request_t *obj)
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);
325 uint8_t
326 socks4_client_request_get_version(const socks4_client_request_t *inp)
328 return inp->version;
331 socks4_client_request_set_version(socks4_client_request_t *inp, uint8_t val)
333 if (! ((val == 4))) {
334 TRUNNEL_SET_ERROR_CODE(inp);
335 return -1;
337 inp->version = val;
338 return 0;
340 uint8_t
341 socks4_client_request_get_command(const socks4_client_request_t *inp)
343 return inp->command;
346 socks4_client_request_set_command(socks4_client_request_t *inp, uint8_t val)
348 if (! ((val == CMD_BIND || val == CMD_CONNECT || val == CMD_RESOLVE || val == CMD_RESOLVE_PTR))) {
349 TRUNNEL_SET_ERROR_CODE(inp);
350 return -1;
352 inp->command = val;
353 return 0;
355 uint16_t
356 socks4_client_request_get_port(const socks4_client_request_t *inp)
358 return inp->port;
361 socks4_client_request_set_port(socks4_client_request_t *inp, uint16_t val)
363 inp->port = val;
364 return 0;
366 uint32_t
367 socks4_client_request_get_addr(const socks4_client_request_t *inp)
369 return inp->addr;
372 socks4_client_request_set_addr(socks4_client_request_t *inp, uint32_t val)
374 inp->addr = val;
375 return 0;
377 const char *
378 socks4_client_request_get_username(const socks4_client_request_t *inp)
380 return inp->username;
383 socks4_client_request_set_username(socks4_client_request_t *inp, const char *val)
385 trunnel_free(inp->username);
386 if (NULL == (inp->username = trunnel_strdup(val))) {
387 TRUNNEL_SET_ERROR_CODE(inp);
388 return -1;
390 return 0;
392 const char *
393 socks4_client_request_get_socks4a_addr_hostname(const socks4_client_request_t *inp)
395 return inp->socks4a_addr_hostname;
398 socks4_client_request_set_socks4a_addr_hostname(socks4_client_request_t *inp, const char *val)
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;
405 return 0;
407 const char *
408 socks4_client_request_check(const socks4_client_request_t *obj)
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) {
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;
681 default:
682 break;
684 return NULL;
687 ssize_t
688 socks4_client_request_encoded_len(const socks4_client_request_t *obj)
690 ssize_t result = 0;
692 if (NULL != socks4_client_request_check(obj))
693 return -1;
696 /* Length of u8 version IN [4] */
697 result += 1;
699 /* Length of u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR] */
700 result += 1;
702 /* Length of u16 port */
703 result += 2;
705 /* Length of u32 addr */
706 result += 4;
708 /* Length of nulterm username */
709 result += strlen(obj->username) + 1;
710 switch (obj->addr) {
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:
968 /* Length of nulterm socks4a_addr_hostname */
969 result += strlen(obj->socks4a_addr_hostname) + 1;
970 break;
972 default:
973 break;
975 return result;
978 socks4_client_request_clear_errors(socks4_client_request_t *obj)
980 int r = obj->trunnel_error_code_;
981 obj->trunnel_error_code_ = 0;
982 return r;
984 ssize_t
985 socks4_client_request_encode(uint8_t *output, const size_t avail, const socks4_client_request_t *obj)
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
995 if (NULL != (msg = socks4_client_request_check(obj)))
996 goto check_failed;
998 #ifdef TRUNNEL_CHECK_ENCODED_LEN
999 trunnel_assert(encoded_len >= 0);
1000 #endif
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;
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;
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;
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;
1030 /* Encode nulterm username */
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;
1040 /* Encode union socks4a_addr[addr] */
1041 trunnel_assert(written <= avail);
1042 switch (obj->addr) {
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:
1300 /* Encode nulterm socks4a_addr_hostname */
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;
1309 break;
1311 default:
1312 break;
1316 trunnel_assert(ptr == output + written);
1317 #ifdef TRUNNEL_CHECK_ENCODED_LEN
1319 trunnel_assert(encoded_len >= 0);
1320 trunnel_assert((size_t)encoded_len == written);
1323 #endif
1325 return written;
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;
1339 /** As socks4_client_request_parse(), but do not allocate the output
1340 * object.
1342 static ssize_t
1343 socks4_client_request_parse_into(socks4_client_request_t *obj, const uint8_t *input, const size_t len_in)
1345 const uint8_t *ptr = input;
1346 size_t remaining = len_in;
1347 ssize_t result = 0;
1348 (void)result;
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;
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;
1364 /* Parse u16 port */
1365 CHECK_REMAINING(2, truncated);
1366 obj->port = trunnel_ntohs(trunnel_get_uint16(ptr));
1367 remaining -= 2; ptr += 2;
1369 /* Parse u32 addr */
1370 CHECK_REMAINING(4, truncated);
1371 obj->addr = trunnel_ntohl(trunnel_get_uint32(ptr));
1372 remaining -= 4; ptr += 4;
1374 /* Parse nulterm username */
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;
1389 /* Parse union socks4a_addr[addr] */
1390 switch (obj->addr) {
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:
1648 /* Parse nulterm socks4a_addr_hostname */
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;
1662 break;
1664 default:
1665 break;
1667 trunnel_assert(ptr + remaining == input + len_in);
1668 return len_in - remaining;
1670 truncated:
1671 return -2;
1672 fail:
1673 result = -1;
1674 return result;
1677 ssize_t
1678 socks4_client_request_parse(socks4_client_request_t **output, const uint8_t *input, const size_t len_in)
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;
1689 return result;
1691 socks4_server_reply_t *
1692 socks4_server_reply_new(void)
1694 socks4_server_reply_t *val = trunnel_calloc(1, sizeof(socks4_server_reply_t));
1695 if (NULL == val)
1696 return NULL;
1697 return val;
1700 /** Release all storage held inside 'obj', but do not free 'obj'.
1702 static void
1703 socks4_server_reply_clear(socks4_server_reply_t *obj)
1705 (void) obj;
1708 void
1709 socks4_server_reply_free(socks4_server_reply_t *obj)
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);
1718 uint8_t
1719 socks4_server_reply_get_version(const socks4_server_reply_t *inp)
1721 return inp->version;
1724 socks4_server_reply_set_version(socks4_server_reply_t *inp, uint8_t val)
1726 if (! ((val == 0 || val == 4))) {
1727 TRUNNEL_SET_ERROR_CODE(inp);
1728 return -1;
1730 inp->version = val;
1731 return 0;
1733 uint8_t
1734 socks4_server_reply_get_status(const socks4_server_reply_t *inp)
1736 return inp->status;
1739 socks4_server_reply_set_status(socks4_server_reply_t *inp, uint8_t val)
1741 inp->status = val;
1742 return 0;
1744 uint16_t
1745 socks4_server_reply_get_port(const socks4_server_reply_t *inp)
1747 return inp->port;
1750 socks4_server_reply_set_port(socks4_server_reply_t *inp, uint16_t val)
1752 inp->port = val;
1753 return 0;
1755 uint32_t
1756 socks4_server_reply_get_addr(const socks4_server_reply_t *inp)
1758 return inp->addr;
1761 socks4_server_reply_set_addr(socks4_server_reply_t *inp, uint32_t val)
1763 inp->addr = val;
1764 return 0;
1766 const char *
1767 socks4_server_reply_check(const socks4_server_reply_t *obj)
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;
1778 ssize_t
1779 socks4_server_reply_encoded_len(const socks4_server_reply_t *obj)
1781 ssize_t result = 0;
1783 if (NULL != socks4_server_reply_check(obj))
1784 return -1;
1787 /* Length of u8 version IN [0, 4] */
1788 result += 1;
1790 /* Length of u8 status */
1791 result += 1;
1793 /* Length of u16 port */
1794 result += 2;
1796 /* Length of u32 addr */
1797 result += 4;
1798 return result;
1801 socks4_server_reply_clear_errors(socks4_server_reply_t *obj)
1803 int r = obj->trunnel_error_code_;
1804 obj->trunnel_error_code_ = 0;
1805 return r;
1807 ssize_t
1808 socks4_server_reply_encode(uint8_t *output, const size_t avail, const socks4_server_reply_t *obj)
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
1818 if (NULL != (msg = socks4_server_reply_check(obj)))
1819 goto check_failed;
1821 #ifdef TRUNNEL_CHECK_ENCODED_LEN
1822 trunnel_assert(encoded_len >= 0);
1823 #endif
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;
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;
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;
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;
1854 trunnel_assert(ptr == output + written);
1855 #ifdef TRUNNEL_CHECK_ENCODED_LEN
1857 trunnel_assert(encoded_len >= 0);
1858 trunnel_assert((size_t)encoded_len == written);
1861 #endif
1863 return written;
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;
1877 /** As socks4_server_reply_parse(), but do not allocate the output
1878 * object.
1880 static ssize_t
1881 socks4_server_reply_parse_into(socks4_server_reply_t *obj, const uint8_t *input, const size_t len_in)
1883 const uint8_t *ptr = input;
1884 size_t remaining = len_in;
1885 ssize_t result = 0;
1886 (void)result;
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;
1895 /* Parse u8 status */
1896 CHECK_REMAINING(1, truncated);
1897 obj->status = (trunnel_get_uint8(ptr));
1898 remaining -= 1; ptr += 1;
1900 /* Parse u16 port */
1901 CHECK_REMAINING(2, truncated);
1902 obj->port = trunnel_ntohs(trunnel_get_uint16(ptr));
1903 remaining -= 2; ptr += 2;
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;
1912 truncated:
1913 return -2;
1914 fail:
1915 result = -1;
1916 return result;
1919 ssize_t
1920 socks4_server_reply_parse(socks4_server_reply_t **output, const uint8_t *input, const size_t len_in)
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;
1931 return result;
1933 socks5_client_userpass_auth_t *
1934 socks5_client_userpass_auth_new(void)
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;
1943 /** Release all storage held inside 'obj', but do not free 'obj'.
1945 static void
1946 socks5_client_userpass_auth_clear(socks5_client_userpass_auth_t *obj)
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);
1955 void
1956 socks5_client_userpass_auth_free(socks5_client_userpass_auth_t *obj)
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);
1965 uint8_t
1966 socks5_client_userpass_auth_get_version(const socks5_client_userpass_auth_t *inp)
1968 return inp->version;
1971 socks5_client_userpass_auth_set_version(socks5_client_userpass_auth_t *inp, uint8_t val)
1973 if (! ((val == 1))) {
1974 TRUNNEL_SET_ERROR_CODE(inp);
1975 return -1;
1977 inp->version = val;
1978 return 0;
1980 uint8_t
1981 socks5_client_userpass_auth_get_username_len(const socks5_client_userpass_auth_t *inp)
1983 return inp->username_len;
1986 socks5_client_userpass_auth_set_username_len(socks5_client_userpass_auth_t *inp, uint8_t val)
1988 inp->username_len = val;
1989 return 0;
1991 size_t
1992 socks5_client_userpass_auth_getlen_username(const socks5_client_userpass_auth_t *inp)
1994 return TRUNNEL_DYNARRAY_LEN(&inp->username);
1997 char
1998 socks5_client_userpass_auth_get_username(socks5_client_userpass_auth_t *inp, size_t idx)
2000 return TRUNNEL_DYNARRAY_GET(&inp->username, idx);
2003 char
2004 socks5_client_userpass_auth_getconst_username(const socks5_client_userpass_auth_t *inp, size_t idx)
2006 return socks5_client_userpass_auth_get_username((socks5_client_userpass_auth_t*)inp, idx);
2009 socks5_client_userpass_auth_set_username(socks5_client_userpass_auth_t *inp, size_t idx, char elt)
2011 TRUNNEL_DYNARRAY_SET(&inp->username, idx, elt);
2012 return 0;
2015 socks5_client_userpass_auth_add_username(socks5_client_userpass_auth_t *inp, char elt)
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;
2028 char *
2029 socks5_client_userpass_auth_getarray_username(socks5_client_userpass_auth_t *inp)
2031 return inp->username.elts_;
2033 const char *
2034 socks5_client_userpass_auth_getconstarray_username(const socks5_client_userpass_auth_t *inp)
2036 return (const char *)socks5_client_userpass_auth_getarray_username((socks5_client_userpass_auth_t*)inp);
2039 socks5_client_userpass_auth_setlen_username(socks5_client_userpass_auth_t *inp, size_t newlen)
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;
2051 const char *
2052 socks5_client_userpass_auth_getstr_username(socks5_client_userpass_auth_t *inp)
2054 return trunnel_string_getstr(&inp->username);
2057 socks5_client_userpass_auth_setstr0_username(socks5_client_userpass_auth_t *inp, const char *val, size_t len)
2059 #if UINT8_MAX < SIZE_MAX
2060 if (len > UINT8_MAX) {
2061 TRUNNEL_SET_ERROR_CODE(inp);
2062 return -1;
2064 #endif
2065 return trunnel_string_setstr0(&inp->username, val, len, &inp->trunnel_error_code_);
2068 socks5_client_userpass_auth_setstr_username(socks5_client_userpass_auth_t *inp, const char *val)
2070 return socks5_client_userpass_auth_setstr0_username(inp, val, strlen(val));
2072 uint8_t
2073 socks5_client_userpass_auth_get_passwd_len(const socks5_client_userpass_auth_t *inp)
2075 return inp->passwd_len;
2078 socks5_client_userpass_auth_set_passwd_len(socks5_client_userpass_auth_t *inp, uint8_t val)
2080 inp->passwd_len = val;
2081 return 0;
2083 size_t
2084 socks5_client_userpass_auth_getlen_passwd(const socks5_client_userpass_auth_t *inp)
2086 return TRUNNEL_DYNARRAY_LEN(&inp->passwd);
2089 char
2090 socks5_client_userpass_auth_get_passwd(socks5_client_userpass_auth_t *inp, size_t idx)
2092 return TRUNNEL_DYNARRAY_GET(&inp->passwd, idx);
2095 char
2096 socks5_client_userpass_auth_getconst_passwd(const socks5_client_userpass_auth_t *inp, size_t idx)
2098 return socks5_client_userpass_auth_get_passwd((socks5_client_userpass_auth_t*)inp, idx);
2101 socks5_client_userpass_auth_set_passwd(socks5_client_userpass_auth_t *inp, size_t idx, char elt)
2103 TRUNNEL_DYNARRAY_SET(&inp->passwd, idx, elt);
2104 return 0;
2107 socks5_client_userpass_auth_add_passwd(socks5_client_userpass_auth_t *inp, char elt)
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;
2120 char *
2121 socks5_client_userpass_auth_getarray_passwd(socks5_client_userpass_auth_t *inp)
2123 return inp->passwd.elts_;
2125 const char *
2126 socks5_client_userpass_auth_getconstarray_passwd(const socks5_client_userpass_auth_t *inp)
2128 return (const char *)socks5_client_userpass_auth_getarray_passwd((socks5_client_userpass_auth_t*)inp);
2131 socks5_client_userpass_auth_setlen_passwd(socks5_client_userpass_auth_t *inp, size_t newlen)
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;
2143 const char *
2144 socks5_client_userpass_auth_getstr_passwd(socks5_client_userpass_auth_t *inp)
2146 return trunnel_string_getstr(&inp->passwd);
2149 socks5_client_userpass_auth_setstr0_passwd(socks5_client_userpass_auth_t *inp, const char *val, size_t len)
2151 #if UINT8_MAX < SIZE_MAX
2152 if (len > UINT8_MAX) {
2153 TRUNNEL_SET_ERROR_CODE(inp);
2154 return -1;
2156 #endif
2157 return trunnel_string_setstr0(&inp->passwd, val, len, &inp->trunnel_error_code_);
2160 socks5_client_userpass_auth_setstr_passwd(socks5_client_userpass_auth_t *inp, const char *val)
2162 return socks5_client_userpass_auth_setstr0_passwd(inp, val, strlen(val));
2164 const char *
2165 socks5_client_userpass_auth_check(const socks5_client_userpass_auth_t *obj)
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;
2180 ssize_t
2181 socks5_client_userpass_auth_encoded_len(const socks5_client_userpass_auth_t *obj)
2183 ssize_t result = 0;
2185 if (NULL != socks5_client_userpass_auth_check(obj))
2186 return -1;
2189 /* Length of u8 version IN [1] */
2190 result += 1;
2192 /* Length of u8 username_len */
2193 result += 1;
2195 /* Length of char username[username_len] */
2196 result += TRUNNEL_DYNARRAY_LEN(&obj->username);
2198 /* Length of u8 passwd_len */
2199 result += 1;
2201 /* Length of char passwd[passwd_len] */
2202 result += TRUNNEL_DYNARRAY_LEN(&obj->passwd);
2203 return result;
2206 socks5_client_userpass_auth_clear_errors(socks5_client_userpass_auth_t *obj)
2208 int r = obj->trunnel_error_code_;
2209 obj->trunnel_error_code_ = 0;
2210 return r;
2212 ssize_t
2213 socks5_client_userpass_auth_encode(uint8_t *output, const size_t avail, const socks5_client_userpass_auth_t *obj)
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
2223 if (NULL != (msg = socks5_client_userpass_auth_check(obj)))
2224 goto check_failed;
2226 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2227 trunnel_assert(encoded_len >= 0);
2228 #endif
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;
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;
2244 /* Encode char username[username_len] */
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;
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;
2263 /* Encode char passwd[passwd_len] */
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;
2276 trunnel_assert(ptr == output + written);
2277 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2279 trunnel_assert(encoded_len >= 0);
2280 trunnel_assert((size_t)encoded_len == written);
2283 #endif
2285 return written;
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;
2299 /** As socks5_client_userpass_auth_parse(), but do not allocate the
2300 * output object.
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)
2305 const uint8_t *ptr = input;
2306 size_t remaining = len_in;
2307 ssize_t result = 0;
2308 (void)result;
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;
2317 /* Parse u8 username_len */
2318 CHECK_REMAINING(1, truncated);
2319 obj->username_len = (trunnel_get_uint8(ptr));
2320 remaining -= 1; ptr += 1;
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;
2328 /* Parse u8 passwd_len */
2329 CHECK_REMAINING(1, truncated);
2330 obj->passwd_len = (trunnel_get_uint8(ptr));
2331 remaining -= 1; ptr += 1;
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;
2341 truncated:
2342 return -2;
2343 fail:
2344 result = -1;
2345 return result;
2348 ssize_t
2349 socks5_client_userpass_auth_parse(socks5_client_userpass_auth_t **output, const uint8_t *input, const size_t len_in)
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;
2360 return result;
2362 socks5_client_version_t *
2363 socks5_client_version_new(void)
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;
2372 /** Release all storage held inside 'obj', but do not free 'obj'.
2374 static void
2375 socks5_client_version_clear(socks5_client_version_t *obj)
2377 (void) obj;
2378 TRUNNEL_DYNARRAY_WIPE(&obj->methods);
2379 TRUNNEL_DYNARRAY_CLEAR(&obj->methods);
2382 void
2383 socks5_client_version_free(socks5_client_version_t *obj)
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);
2392 uint8_t
2393 socks5_client_version_get_version(const socks5_client_version_t *inp)
2395 return inp->version;
2398 socks5_client_version_set_version(socks5_client_version_t *inp, uint8_t val)
2400 if (! ((val == 5))) {
2401 TRUNNEL_SET_ERROR_CODE(inp);
2402 return -1;
2404 inp->version = val;
2405 return 0;
2407 uint8_t
2408 socks5_client_version_get_n_methods(const socks5_client_version_t *inp)
2410 return inp->n_methods;
2413 socks5_client_version_set_n_methods(socks5_client_version_t *inp, uint8_t val)
2415 inp->n_methods = val;
2416 return 0;
2418 size_t
2419 socks5_client_version_getlen_methods(const socks5_client_version_t *inp)
2421 return TRUNNEL_DYNARRAY_LEN(&inp->methods);
2424 uint8_t
2425 socks5_client_version_get_methods(socks5_client_version_t *inp, size_t idx)
2427 return TRUNNEL_DYNARRAY_GET(&inp->methods, idx);
2430 uint8_t
2431 socks5_client_version_getconst_methods(const socks5_client_version_t *inp, size_t idx)
2433 return socks5_client_version_get_methods((socks5_client_version_t*)inp, idx);
2436 socks5_client_version_set_methods(socks5_client_version_t *inp, size_t idx, uint8_t elt)
2438 TRUNNEL_DYNARRAY_SET(&inp->methods, idx, elt);
2439 return 0;
2442 socks5_client_version_add_methods(socks5_client_version_t *inp, uint8_t elt)
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;
2455 uint8_t *
2456 socks5_client_version_getarray_methods(socks5_client_version_t *inp)
2458 return inp->methods.elts_;
2460 const uint8_t *
2461 socks5_client_version_getconstarray_methods(const socks5_client_version_t *inp)
2463 return (const uint8_t *)socks5_client_version_getarray_methods((socks5_client_version_t*)inp);
2466 socks5_client_version_setlen_methods(socks5_client_version_t *inp, size_t newlen)
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;
2485 const char *
2486 socks5_client_version_check(const socks5_client_version_t *obj)
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;
2499 ssize_t
2500 socks5_client_version_encoded_len(const socks5_client_version_t *obj)
2502 ssize_t result = 0;
2504 if (NULL != socks5_client_version_check(obj))
2505 return -1;
2508 /* Length of u8 version IN [5] */
2509 result += 1;
2511 /* Length of u8 n_methods */
2512 result += 1;
2514 /* Length of u8 methods[n_methods] */
2515 result += TRUNNEL_DYNARRAY_LEN(&obj->methods);
2516 return result;
2519 socks5_client_version_clear_errors(socks5_client_version_t *obj)
2521 int r = obj->trunnel_error_code_;
2522 obj->trunnel_error_code_ = 0;
2523 return r;
2525 ssize_t
2526 socks5_client_version_encode(uint8_t *output, const size_t avail, const socks5_client_version_t *obj)
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
2536 if (NULL != (msg = socks5_client_version_check(obj)))
2537 goto check_failed;
2539 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2540 trunnel_assert(encoded_len >= 0);
2541 #endif
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;
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;
2557 /* Encode u8 methods[n_methods] */
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;
2570 trunnel_assert(ptr == output + written);
2571 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2573 trunnel_assert(encoded_len >= 0);
2574 trunnel_assert((size_t)encoded_len == written);
2577 #endif
2579 return written;
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;
2593 /** As socks5_client_version_parse(), but do not allocate the output
2594 * object.
2596 static ssize_t
2597 socks5_client_version_parse_into(socks5_client_version_t *obj, const uint8_t *input, const size_t len_in)
2599 const uint8_t *ptr = input;
2600 size_t remaining = len_in;
2601 ssize_t result = 0;
2602 (void)result;
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;
2611 /* Parse u8 n_methods */
2612 CHECK_REMAINING(1, truncated);
2613 obj->n_methods = (trunnel_get_uint8(ptr));
2614 remaining -= 1; ptr += 1;
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;
2626 truncated:
2627 return -2;
2628 trunnel_alloc_failed:
2629 return -1;
2630 fail:
2631 result = -1;
2632 return result;
2635 ssize_t
2636 socks5_client_version_parse(socks5_client_version_t **output, const uint8_t *input, const size_t len_in)
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;
2647 return result;
2649 socks5_server_method_t *
2650 socks5_server_method_new(void)
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;
2659 /** Release all storage held inside 'obj', but do not free 'obj'.
2661 static void
2662 socks5_server_method_clear(socks5_server_method_t *obj)
2664 (void) obj;
2667 void
2668 socks5_server_method_free(socks5_server_method_t *obj)
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);
2677 uint8_t
2678 socks5_server_method_get_version(const socks5_server_method_t *inp)
2680 return inp->version;
2683 socks5_server_method_set_version(socks5_server_method_t *inp, uint8_t val)
2685 if (! ((val == 5))) {
2686 TRUNNEL_SET_ERROR_CODE(inp);
2687 return -1;
2689 inp->version = val;
2690 return 0;
2692 uint8_t
2693 socks5_server_method_get_method(const socks5_server_method_t *inp)
2695 return inp->method;
2698 socks5_server_method_set_method(socks5_server_method_t *inp, uint8_t val)
2700 inp->method = val;
2701 return 0;
2703 const char *
2704 socks5_server_method_check(const socks5_server_method_t *obj)
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;
2715 ssize_t
2716 socks5_server_method_encoded_len(const socks5_server_method_t *obj)
2718 ssize_t result = 0;
2720 if (NULL != socks5_server_method_check(obj))
2721 return -1;
2724 /* Length of u8 version IN [5] */
2725 result += 1;
2727 /* Length of u8 method */
2728 result += 1;
2729 return result;
2732 socks5_server_method_clear_errors(socks5_server_method_t *obj)
2734 int r = obj->trunnel_error_code_;
2735 obj->trunnel_error_code_ = 0;
2736 return r;
2738 ssize_t
2739 socks5_server_method_encode(uint8_t *output, const size_t avail, const socks5_server_method_t *obj)
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
2749 if (NULL != (msg = socks5_server_method_check(obj)))
2750 goto check_failed;
2752 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2753 trunnel_assert(encoded_len >= 0);
2754 #endif
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;
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;
2771 trunnel_assert(ptr == output + written);
2772 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2774 trunnel_assert(encoded_len >= 0);
2775 trunnel_assert((size_t)encoded_len == written);
2778 #endif
2780 return written;
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;
2794 /** As socks5_server_method_parse(), but do not allocate the output
2795 * object.
2797 static ssize_t
2798 socks5_server_method_parse_into(socks5_server_method_t *obj, const uint8_t *input, const size_t len_in)
2800 const uint8_t *ptr = input;
2801 size_t remaining = len_in;
2802 ssize_t result = 0;
2803 (void)result;
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;
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;
2819 truncated:
2820 return -2;
2821 fail:
2822 result = -1;
2823 return result;
2826 ssize_t
2827 socks5_server_method_parse(socks5_server_method_t **output, const uint8_t *input, const size_t len_in)
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;
2838 return result;
2840 socks5_server_userpass_auth_t *
2841 socks5_server_userpass_auth_new(void)
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;
2850 /** Release all storage held inside 'obj', but do not free 'obj'.
2852 static void
2853 socks5_server_userpass_auth_clear(socks5_server_userpass_auth_t *obj)
2855 (void) obj;
2858 void
2859 socks5_server_userpass_auth_free(socks5_server_userpass_auth_t *obj)
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);
2868 uint8_t
2869 socks5_server_userpass_auth_get_version(const socks5_server_userpass_auth_t *inp)
2871 return inp->version;
2874 socks5_server_userpass_auth_set_version(socks5_server_userpass_auth_t *inp, uint8_t val)
2876 if (! ((val == 1))) {
2877 TRUNNEL_SET_ERROR_CODE(inp);
2878 return -1;
2880 inp->version = val;
2881 return 0;
2883 uint8_t
2884 socks5_server_userpass_auth_get_status(const socks5_server_userpass_auth_t *inp)
2886 return inp->status;
2889 socks5_server_userpass_auth_set_status(socks5_server_userpass_auth_t *inp, uint8_t val)
2891 inp->status = val;
2892 return 0;
2894 const char *
2895 socks5_server_userpass_auth_check(const socks5_server_userpass_auth_t *obj)
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;
2906 ssize_t
2907 socks5_server_userpass_auth_encoded_len(const socks5_server_userpass_auth_t *obj)
2909 ssize_t result = 0;
2911 if (NULL != socks5_server_userpass_auth_check(obj))
2912 return -1;
2915 /* Length of u8 version IN [1] */
2916 result += 1;
2918 /* Length of u8 status */
2919 result += 1;
2920 return result;
2923 socks5_server_userpass_auth_clear_errors(socks5_server_userpass_auth_t *obj)
2925 int r = obj->trunnel_error_code_;
2926 obj->trunnel_error_code_ = 0;
2927 return r;
2929 ssize_t
2930 socks5_server_userpass_auth_encode(uint8_t *output, const size_t avail, const socks5_server_userpass_auth_t *obj)
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
2940 if (NULL != (msg = socks5_server_userpass_auth_check(obj)))
2941 goto check_failed;
2943 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2944 trunnel_assert(encoded_len >= 0);
2945 #endif
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;
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;
2962 trunnel_assert(ptr == output + written);
2963 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2965 trunnel_assert(encoded_len >= 0);
2966 trunnel_assert((size_t)encoded_len == written);
2969 #endif
2971 return written;
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;
2985 /** As socks5_server_userpass_auth_parse(), but do not allocate the
2986 * output object.
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)
2991 const uint8_t *ptr = input;
2992 size_t remaining = len_in;
2993 ssize_t result = 0;
2994 (void)result;
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;
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;
3010 truncated:
3011 return -2;
3012 fail:
3013 result = -1;
3014 return result;
3017 ssize_t
3018 socks5_server_userpass_auth_parse(socks5_server_userpass_auth_t **output, const uint8_t *input, const size_t len_in)
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;
3029 return result;
3031 socks5_client_request_t *
3032 socks5_client_request_new(void)
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;
3042 /** Release all storage held inside 'obj', but do not free 'obj'.
3044 static void
3045 socks5_client_request_clear(socks5_client_request_t *obj)
3047 (void) obj;
3048 domainname_free(obj->dest_addr_domainname);
3049 obj->dest_addr_domainname = NULL;
3052 void
3053 socks5_client_request_free(socks5_client_request_t *obj)
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);
3062 uint8_t
3063 socks5_client_request_get_version(const socks5_client_request_t *inp)
3065 return inp->version;
3068 socks5_client_request_set_version(socks5_client_request_t *inp, uint8_t val)
3070 if (! ((val == 5))) {
3071 TRUNNEL_SET_ERROR_CODE(inp);
3072 return -1;
3074 inp->version = val;
3075 return 0;
3077 uint8_t
3078 socks5_client_request_get_command(const socks5_client_request_t *inp)
3080 return inp->command;
3083 socks5_client_request_set_command(socks5_client_request_t *inp, uint8_t val)
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;
3089 inp->command = val;
3090 return 0;
3092 uint8_t
3093 socks5_client_request_get_reserved(const socks5_client_request_t *inp)
3095 return inp->reserved;
3098 socks5_client_request_set_reserved(socks5_client_request_t *inp, uint8_t val)
3100 if (! ((val == 0))) {
3101 TRUNNEL_SET_ERROR_CODE(inp);
3102 return -1;
3104 inp->reserved = val;
3105 return 0;
3107 uint8_t
3108 socks5_client_request_get_atype(const socks5_client_request_t *inp)
3110 return inp->atype;
3113 socks5_client_request_set_atype(socks5_client_request_t *inp, uint8_t val)
3115 inp->atype = val;
3116 return 0;
3118 uint32_t
3119 socks5_client_request_get_dest_addr_ipv4(const socks5_client_request_t *inp)
3121 return inp->dest_addr_ipv4;
3124 socks5_client_request_set_dest_addr_ipv4(socks5_client_request_t *inp, uint32_t val)
3126 inp->dest_addr_ipv4 = val;
3127 return 0;
3129 size_t
3130 socks5_client_request_getlen_dest_addr_ipv6(const socks5_client_request_t *inp)
3132 (void)inp; return 16;
3135 uint8_t
3136 socks5_client_request_get_dest_addr_ipv6(socks5_client_request_t *inp, size_t idx)
3138 trunnel_assert(idx < 16);
3139 return inp->dest_addr_ipv6[idx];
3142 uint8_t
3143 socks5_client_request_getconst_dest_addr_ipv6(const socks5_client_request_t *inp, size_t idx)
3145 return socks5_client_request_get_dest_addr_ipv6((socks5_client_request_t*)inp, idx);
3148 socks5_client_request_set_dest_addr_ipv6(socks5_client_request_t *inp, size_t idx, uint8_t elt)
3150 trunnel_assert(idx < 16);
3151 inp->dest_addr_ipv6[idx] = elt;
3152 return 0;
3155 uint8_t *
3156 socks5_client_request_getarray_dest_addr_ipv6(socks5_client_request_t *inp)
3158 return inp->dest_addr_ipv6;
3160 const uint8_t *
3161 socks5_client_request_getconstarray_dest_addr_ipv6(const socks5_client_request_t *inp)
3163 return (const uint8_t *)socks5_client_request_getarray_dest_addr_ipv6((socks5_client_request_t*)inp);
3165 struct domainname_st *
3166 socks5_client_request_get_dest_addr_domainname(socks5_client_request_t *inp)
3168 return inp->dest_addr_domainname;
3170 const struct domainname_st *
3171 socks5_client_request_getconst_dest_addr_domainname(const socks5_client_request_t *inp)
3173 return socks5_client_request_get_dest_addr_domainname((socks5_client_request_t*) inp);
3176 socks5_client_request_set_dest_addr_domainname(socks5_client_request_t *inp, struct domainname_st *val)
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);
3183 socks5_client_request_set0_dest_addr_domainname(socks5_client_request_t *inp, struct domainname_st *val)
3185 inp->dest_addr_domainname = val;
3186 return 0;
3188 uint16_t
3189 socks5_client_request_get_dest_port(const socks5_client_request_t *inp)
3191 return inp->dest_port;
3194 socks5_client_request_set_dest_port(socks5_client_request_t *inp, uint16_t val)
3196 inp->dest_port = val;
3197 return 0;
3199 const char *
3200 socks5_client_request_check(const socks5_client_request_t *obj)
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) {
3214 case ATYPE_IPV4:
3215 break;
3217 case ATYPE_IPV6:
3218 break;
3220 case ATYPE_DOMAINNAME:
3222 const char *msg;
3223 if (NULL != (msg = domainname_check(obj->dest_addr_domainname)))
3224 return msg;
3226 break;
3228 default:
3229 return "Bad tag for union";
3230 break;
3232 return NULL;
3235 ssize_t
3236 socks5_client_request_encoded_len(const socks5_client_request_t *obj)
3238 ssize_t result = 0;
3240 if (NULL != socks5_client_request_check(obj))
3241 return -1;
3244 /* Length of u8 version IN [5] */
3245 result += 1;
3247 /* Length of u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR, CMD_UDP_ASSOCIATE] */
3248 result += 1;
3250 /* Length of u8 reserved IN [0] */
3251 result += 1;
3253 /* Length of u8 atype */
3254 result += 1;
3255 switch (obj->atype) {
3257 case ATYPE_IPV4:
3259 /* Length of u32 dest_addr_ipv4 */
3260 result += 4;
3261 break;
3263 case ATYPE_IPV6:
3265 /* Length of u8 dest_addr_ipv6[16] */
3266 result += 16;
3267 break;
3269 case ATYPE_DOMAINNAME:
3271 /* Length of struct domainname dest_addr_domainname */
3272 result += domainname_encoded_len(obj->dest_addr_domainname);
3273 break;
3275 default:
3276 trunnel_assert(0);
3277 break;
3280 /* Length of u16 dest_port */
3281 result += 2;
3282 return result;
3285 socks5_client_request_clear_errors(socks5_client_request_t *obj)
3287 int r = obj->trunnel_error_code_;
3288 obj->trunnel_error_code_ = 0;
3289 return r;
3291 ssize_t
3292 socks5_client_request_encode(uint8_t *output, const size_t avail, const socks5_client_request_t *obj)
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
3302 if (NULL != (msg = socks5_client_request_check(obj)))
3303 goto check_failed;
3305 #ifdef TRUNNEL_CHECK_ENCODED_LEN
3306 trunnel_assert(encoded_len >= 0);
3307 #endif
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;
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;
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;
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;
3337 /* Encode union dest_addr[atype] */
3338 trunnel_assert(written <= avail);
3339 switch (obj->atype) {
3341 case ATYPE_IPV4:
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;
3351 case ATYPE_IPV6:
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;
3361 case ATYPE_DOMAINNAME:
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;
3371 default:
3372 trunnel_assert(0);
3373 break;
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;
3384 trunnel_assert(ptr == output + written);
3385 #ifdef TRUNNEL_CHECK_ENCODED_LEN
3387 trunnel_assert(encoded_len >= 0);
3388 trunnel_assert((size_t)encoded_len == written);
3391 #endif
3393 return written;
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;
3407 /** As socks5_client_request_parse(), but do not allocate the output
3408 * object.
3410 static ssize_t
3411 socks5_client_request_parse_into(socks5_client_request_t *obj, const uint8_t *input, const size_t len_in)
3413 const uint8_t *ptr = input;
3414 size_t remaining = len_in;
3415 ssize_t result = 0;
3416 (void)result;
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;
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;
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;
3439 /* Parse u8 atype */
3440 CHECK_REMAINING(1, truncated);
3441 obj->atype = (trunnel_get_uint8(ptr));
3442 remaining -= 1; ptr += 1;
3444 /* Parse union dest_addr[atype] */
3445 switch (obj->atype) {
3447 case ATYPE_IPV4:
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;
3455 case ATYPE_IPV6:
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;
3463 case ATYPE_DOMAINNAME:
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;
3473 default:
3474 goto fail;
3475 break;
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;
3485 truncated:
3486 return -2;
3487 relay_fail:
3488 trunnel_assert(result < 0);
3489 return result;
3490 fail:
3491 result = -1;
3492 return result;
3495 ssize_t
3496 socks5_client_request_parse(socks5_client_request_t **output, const uint8_t *input, const size_t len_in)
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;
3507 return result;
3509 socks5_server_reply_t *
3510 socks5_server_reply_new(void)
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;
3519 /** Release all storage held inside 'obj', but do not free 'obj'.
3521 static void
3522 socks5_server_reply_clear(socks5_server_reply_t *obj)
3524 (void) obj;
3525 domainname_free(obj->bind_addr_domainname);
3526 obj->bind_addr_domainname = NULL;
3529 void
3530 socks5_server_reply_free(socks5_server_reply_t *obj)
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);
3539 uint8_t
3540 socks5_server_reply_get_version(const socks5_server_reply_t *inp)
3542 return inp->version;
3545 socks5_server_reply_set_version(socks5_server_reply_t *inp, uint8_t val)
3547 if (! ((val == 5))) {
3548 TRUNNEL_SET_ERROR_CODE(inp);
3549 return -1;
3551 inp->version = val;
3552 return 0;
3554 uint8_t
3555 socks5_server_reply_get_reply(const socks5_server_reply_t *inp)
3557 return inp->reply;
3560 socks5_server_reply_set_reply(socks5_server_reply_t *inp, uint8_t val)
3562 inp->reply = val;
3563 return 0;
3565 uint8_t
3566 socks5_server_reply_get_reserved(const socks5_server_reply_t *inp)
3568 return inp->reserved;
3571 socks5_server_reply_set_reserved(socks5_server_reply_t *inp, uint8_t val)
3573 if (! ((val == 0))) {
3574 TRUNNEL_SET_ERROR_CODE(inp);
3575 return -1;
3577 inp->reserved = val;
3578 return 0;
3580 uint8_t
3581 socks5_server_reply_get_atype(const socks5_server_reply_t *inp)
3583 return inp->atype;
3586 socks5_server_reply_set_atype(socks5_server_reply_t *inp, uint8_t val)
3588 inp->atype = val;
3589 return 0;
3591 uint32_t
3592 socks5_server_reply_get_bind_addr_ipv4(const socks5_server_reply_t *inp)
3594 return inp->bind_addr_ipv4;
3597 socks5_server_reply_set_bind_addr_ipv4(socks5_server_reply_t *inp, uint32_t val)
3599 inp->bind_addr_ipv4 = val;
3600 return 0;
3602 size_t
3603 socks5_server_reply_getlen_bind_addr_ipv6(const socks5_server_reply_t *inp)
3605 (void)inp; return 16;
3608 uint8_t
3609 socks5_server_reply_get_bind_addr_ipv6(socks5_server_reply_t *inp, size_t idx)
3611 trunnel_assert(idx < 16);
3612 return inp->bind_addr_ipv6[idx];
3615 uint8_t
3616 socks5_server_reply_getconst_bind_addr_ipv6(const socks5_server_reply_t *inp, size_t idx)
3618 return socks5_server_reply_get_bind_addr_ipv6((socks5_server_reply_t*)inp, idx);
3621 socks5_server_reply_set_bind_addr_ipv6(socks5_server_reply_t *inp, size_t idx, uint8_t elt)
3623 trunnel_assert(idx < 16);
3624 inp->bind_addr_ipv6[idx] = elt;
3625 return 0;
3628 uint8_t *
3629 socks5_server_reply_getarray_bind_addr_ipv6(socks5_server_reply_t *inp)
3631 return inp->bind_addr_ipv6;
3633 const uint8_t *
3634 socks5_server_reply_getconstarray_bind_addr_ipv6(const socks5_server_reply_t *inp)
3636 return (const uint8_t *)socks5_server_reply_getarray_bind_addr_ipv6((socks5_server_reply_t*)inp);
3638 struct domainname_st *
3639 socks5_server_reply_get_bind_addr_domainname(socks5_server_reply_t *inp)
3641 return inp->bind_addr_domainname;
3643 const struct domainname_st *
3644 socks5_server_reply_getconst_bind_addr_domainname(const socks5_server_reply_t *inp)
3646 return socks5_server_reply_get_bind_addr_domainname((socks5_server_reply_t*) inp);
3649 socks5_server_reply_set_bind_addr_domainname(socks5_server_reply_t *inp, struct domainname_st *val)
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);
3656 socks5_server_reply_set0_bind_addr_domainname(socks5_server_reply_t *inp, struct domainname_st *val)
3658 inp->bind_addr_domainname = val;
3659 return 0;
3661 uint16_t
3662 socks5_server_reply_get_bind_port(const socks5_server_reply_t *inp)
3664 return inp->bind_port;
3667 socks5_server_reply_set_bind_port(socks5_server_reply_t *inp, uint16_t val)
3669 inp->bind_port = val;
3670 return 0;
3672 const char *
3673 socks5_server_reply_check(const socks5_server_reply_t *obj)
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) {
3685 case ATYPE_IPV4:
3686 break;
3688 case ATYPE_IPV6:
3689 break;
3691 case ATYPE_DOMAINNAME:
3693 const char *msg;
3694 if (NULL != (msg = domainname_check(obj->bind_addr_domainname)))
3695 return msg;
3697 break;
3699 default:
3700 return "Bad tag for union";
3701 break;
3703 return NULL;
3706 ssize_t
3707 socks5_server_reply_encoded_len(const socks5_server_reply_t *obj)
3709 ssize_t result = 0;
3711 if (NULL != socks5_server_reply_check(obj))
3712 return -1;
3715 /* Length of u8 version IN [5] */
3716 result += 1;
3718 /* Length of u8 reply */
3719 result += 1;
3721 /* Length of u8 reserved IN [0] */
3722 result += 1;
3724 /* Length of u8 atype */
3725 result += 1;
3726 switch (obj->atype) {
3728 case ATYPE_IPV4:
3730 /* Length of u32 bind_addr_ipv4 */
3731 result += 4;
3732 break;
3734 case ATYPE_IPV6:
3736 /* Length of u8 bind_addr_ipv6[16] */
3737 result += 16;
3738 break;
3740 case ATYPE_DOMAINNAME:
3742 /* Length of struct domainname bind_addr_domainname */
3743 result += domainname_encoded_len(obj->bind_addr_domainname);
3744 break;
3746 default:
3747 trunnel_assert(0);
3748 break;
3751 /* Length of u16 bind_port */
3752 result += 2;
3753 return result;
3756 socks5_server_reply_clear_errors(socks5_server_reply_t *obj)
3758 int r = obj->trunnel_error_code_;
3759 obj->trunnel_error_code_ = 0;
3760 return r;
3762 ssize_t
3763 socks5_server_reply_encode(uint8_t *output, const size_t avail, const socks5_server_reply_t *obj)
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
3773 if (NULL != (msg = socks5_server_reply_check(obj)))
3774 goto check_failed;
3776 #ifdef TRUNNEL_CHECK_ENCODED_LEN
3777 trunnel_assert(encoded_len >= 0);
3778 #endif
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;
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;
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;
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;
3808 /* Encode union bind_addr[atype] */
3809 trunnel_assert(written <= avail);
3810 switch (obj->atype) {
3812 case ATYPE_IPV4:
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;
3822 case ATYPE_IPV6:
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;
3832 case ATYPE_DOMAINNAME:
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;
3842 default:
3843 trunnel_assert(0);
3844 break;
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;
3855 trunnel_assert(ptr == output + written);
3856 #ifdef TRUNNEL_CHECK_ENCODED_LEN
3858 trunnel_assert(encoded_len >= 0);
3859 trunnel_assert((size_t)encoded_len == written);
3862 #endif
3864 return written;
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;
3878 /** As socks5_server_reply_parse(), but do not allocate the output
3879 * object.
3881 static ssize_t
3882 socks5_server_reply_parse_into(socks5_server_reply_t *obj, const uint8_t *input, const size_t len_in)
3884 const uint8_t *ptr = input;
3885 size_t remaining = len_in;
3886 ssize_t result = 0;
3887 (void)result;
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;
3896 /* Parse u8 reply */
3897 CHECK_REMAINING(1, truncated);
3898 obj->reply = (trunnel_get_uint8(ptr));
3899 remaining -= 1; ptr += 1;
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;
3908 /* Parse u8 atype */
3909 CHECK_REMAINING(1, truncated);
3910 obj->atype = (trunnel_get_uint8(ptr));
3911 remaining -= 1; ptr += 1;
3913 /* Parse union bind_addr[atype] */
3914 switch (obj->atype) {
3916 case ATYPE_IPV4:
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;
3924 case ATYPE_IPV6:
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;
3932 case ATYPE_DOMAINNAME:
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;
3942 default:
3943 goto fail;
3944 break;
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;
3954 truncated:
3955 return -2;
3956 relay_fail:
3957 trunnel_assert(result < 0);
3958 return result;
3959 fail:
3960 result = -1;
3961 return result;
3964 ssize_t
3965 socks5_server_reply_parse(socks5_server_reply_t **output, const uint8_t *input, const size_t len_in)
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;
3976 return result;