Parallelize src/test/test into chunks.
[tor.git] / src / trunnel / socks5.c
blob9e5f6fcfed136b2e6c98e50689509058dba7d127
1 /* socks5.c -- generated by Trunnel v1.5.2.
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 val->version = 4;
1698 return val;
1701 /** Release all storage held inside 'obj', but do not free 'obj'.
1703 static void
1704 socks4_server_reply_clear(socks4_server_reply_t *obj)
1706 (void) obj;
1709 void
1710 socks4_server_reply_free(socks4_server_reply_t *obj)
1712 if (obj == NULL)
1713 return;
1714 socks4_server_reply_clear(obj);
1715 trunnel_memwipe(obj, sizeof(socks4_server_reply_t));
1716 trunnel_free_(obj);
1719 uint8_t
1720 socks4_server_reply_get_version(const socks4_server_reply_t *inp)
1722 return inp->version;
1725 socks4_server_reply_set_version(socks4_server_reply_t *inp, uint8_t val)
1727 if (! ((val == 4))) {
1728 TRUNNEL_SET_ERROR_CODE(inp);
1729 return -1;
1731 inp->version = val;
1732 return 0;
1734 uint8_t
1735 socks4_server_reply_get_status(const socks4_server_reply_t *inp)
1737 return inp->status;
1740 socks4_server_reply_set_status(socks4_server_reply_t *inp, uint8_t val)
1742 inp->status = val;
1743 return 0;
1745 uint16_t
1746 socks4_server_reply_get_port(const socks4_server_reply_t *inp)
1748 return inp->port;
1751 socks4_server_reply_set_port(socks4_server_reply_t *inp, uint16_t val)
1753 inp->port = val;
1754 return 0;
1756 uint32_t
1757 socks4_server_reply_get_addr(const socks4_server_reply_t *inp)
1759 return inp->addr;
1762 socks4_server_reply_set_addr(socks4_server_reply_t *inp, uint32_t val)
1764 inp->addr = val;
1765 return 0;
1767 const char *
1768 socks4_server_reply_check(const socks4_server_reply_t *obj)
1770 if (obj == NULL)
1771 return "Object was NULL";
1772 if (obj->trunnel_error_code_)
1773 return "A set function failed on this object";
1774 if (! (obj->version == 4))
1775 return "Integer out of bounds";
1776 return NULL;
1779 ssize_t
1780 socks4_server_reply_encoded_len(const socks4_server_reply_t *obj)
1782 ssize_t result = 0;
1784 if (NULL != socks4_server_reply_check(obj))
1785 return -1;
1788 /* Length of u8 version IN [4] */
1789 result += 1;
1791 /* Length of u8 status */
1792 result += 1;
1794 /* Length of u16 port */
1795 result += 2;
1797 /* Length of u32 addr */
1798 result += 4;
1799 return result;
1802 socks4_server_reply_clear_errors(socks4_server_reply_t *obj)
1804 int r = obj->trunnel_error_code_;
1805 obj->trunnel_error_code_ = 0;
1806 return r;
1808 ssize_t
1809 socks4_server_reply_encode(uint8_t *output, const size_t avail, const socks4_server_reply_t *obj)
1811 ssize_t result = 0;
1812 size_t written = 0;
1813 uint8_t *ptr = output;
1814 const char *msg;
1815 #ifdef TRUNNEL_CHECK_ENCODED_LEN
1816 const ssize_t encoded_len = socks4_server_reply_encoded_len(obj);
1817 #endif
1819 if (NULL != (msg = socks4_server_reply_check(obj)))
1820 goto check_failed;
1822 #ifdef TRUNNEL_CHECK_ENCODED_LEN
1823 trunnel_assert(encoded_len >= 0);
1824 #endif
1826 /* Encode u8 version IN [4] */
1827 trunnel_assert(written <= avail);
1828 if (avail - written < 1)
1829 goto truncated;
1830 trunnel_set_uint8(ptr, (obj->version));
1831 written += 1; ptr += 1;
1833 /* Encode u8 status */
1834 trunnel_assert(written <= avail);
1835 if (avail - written < 1)
1836 goto truncated;
1837 trunnel_set_uint8(ptr, (obj->status));
1838 written += 1; ptr += 1;
1840 /* Encode u16 port */
1841 trunnel_assert(written <= avail);
1842 if (avail - written < 2)
1843 goto truncated;
1844 trunnel_set_uint16(ptr, trunnel_htons(obj->port));
1845 written += 2; ptr += 2;
1847 /* Encode u32 addr */
1848 trunnel_assert(written <= avail);
1849 if (avail - written < 4)
1850 goto truncated;
1851 trunnel_set_uint32(ptr, trunnel_htonl(obj->addr));
1852 written += 4; ptr += 4;
1855 trunnel_assert(ptr == output + written);
1856 #ifdef TRUNNEL_CHECK_ENCODED_LEN
1858 trunnel_assert(encoded_len >= 0);
1859 trunnel_assert((size_t)encoded_len == written);
1862 #endif
1864 return written;
1866 truncated:
1867 result = -2;
1868 goto fail;
1869 check_failed:
1870 (void)msg;
1871 result = -1;
1872 goto fail;
1873 fail:
1874 trunnel_assert(result < 0);
1875 return result;
1878 /** As socks4_server_reply_parse(), but do not allocate the output
1879 * object.
1881 static ssize_t
1882 socks4_server_reply_parse_into(socks4_server_reply_t *obj, const uint8_t *input, const size_t len_in)
1884 const uint8_t *ptr = input;
1885 size_t remaining = len_in;
1886 ssize_t result = 0;
1887 (void)result;
1889 /* Parse u8 version IN [4] */
1890 CHECK_REMAINING(1, truncated);
1891 obj->version = (trunnel_get_uint8(ptr));
1892 remaining -= 1; ptr += 1;
1893 if (! (obj->version == 4))
1894 goto fail;
1896 /* Parse u8 status */
1897 CHECK_REMAINING(1, truncated);
1898 obj->status = (trunnel_get_uint8(ptr));
1899 remaining -= 1; ptr += 1;
1901 /* Parse u16 port */
1902 CHECK_REMAINING(2, truncated);
1903 obj->port = trunnel_ntohs(trunnel_get_uint16(ptr));
1904 remaining -= 2; ptr += 2;
1906 /* Parse u32 addr */
1907 CHECK_REMAINING(4, truncated);
1908 obj->addr = trunnel_ntohl(trunnel_get_uint32(ptr));
1909 remaining -= 4; ptr += 4;
1910 trunnel_assert(ptr + remaining == input + len_in);
1911 return len_in - remaining;
1913 truncated:
1914 return -2;
1915 fail:
1916 result = -1;
1917 return result;
1920 ssize_t
1921 socks4_server_reply_parse(socks4_server_reply_t **output, const uint8_t *input, const size_t len_in)
1923 ssize_t result;
1924 *output = socks4_server_reply_new();
1925 if (NULL == *output)
1926 return -1;
1927 result = socks4_server_reply_parse_into(*output, input, len_in);
1928 if (result < 0) {
1929 socks4_server_reply_free(*output);
1930 *output = NULL;
1932 return result;
1934 socks5_client_userpass_auth_t *
1935 socks5_client_userpass_auth_new(void)
1937 socks5_client_userpass_auth_t *val = trunnel_calloc(1, sizeof(socks5_client_userpass_auth_t));
1938 if (NULL == val)
1939 return NULL;
1940 val->version = 1;
1941 return val;
1944 /** Release all storage held inside 'obj', but do not free 'obj'.
1946 static void
1947 socks5_client_userpass_auth_clear(socks5_client_userpass_auth_t *obj)
1949 (void) obj;
1950 TRUNNEL_DYNARRAY_WIPE(&obj->username);
1951 TRUNNEL_DYNARRAY_CLEAR(&obj->username);
1952 TRUNNEL_DYNARRAY_WIPE(&obj->passwd);
1953 TRUNNEL_DYNARRAY_CLEAR(&obj->passwd);
1956 void
1957 socks5_client_userpass_auth_free(socks5_client_userpass_auth_t *obj)
1959 if (obj == NULL)
1960 return;
1961 socks5_client_userpass_auth_clear(obj);
1962 trunnel_memwipe(obj, sizeof(socks5_client_userpass_auth_t));
1963 trunnel_free_(obj);
1966 uint8_t
1967 socks5_client_userpass_auth_get_version(const socks5_client_userpass_auth_t *inp)
1969 return inp->version;
1972 socks5_client_userpass_auth_set_version(socks5_client_userpass_auth_t *inp, uint8_t val)
1974 if (! ((val == 1))) {
1975 TRUNNEL_SET_ERROR_CODE(inp);
1976 return -1;
1978 inp->version = val;
1979 return 0;
1981 uint8_t
1982 socks5_client_userpass_auth_get_username_len(const socks5_client_userpass_auth_t *inp)
1984 return inp->username_len;
1987 socks5_client_userpass_auth_set_username_len(socks5_client_userpass_auth_t *inp, uint8_t val)
1989 inp->username_len = val;
1990 return 0;
1992 size_t
1993 socks5_client_userpass_auth_getlen_username(const socks5_client_userpass_auth_t *inp)
1995 return TRUNNEL_DYNARRAY_LEN(&inp->username);
1998 char
1999 socks5_client_userpass_auth_get_username(socks5_client_userpass_auth_t *inp, size_t idx)
2001 return TRUNNEL_DYNARRAY_GET(&inp->username, idx);
2004 char
2005 socks5_client_userpass_auth_getconst_username(const socks5_client_userpass_auth_t *inp, size_t idx)
2007 return socks5_client_userpass_auth_get_username((socks5_client_userpass_auth_t*)inp, idx);
2010 socks5_client_userpass_auth_set_username(socks5_client_userpass_auth_t *inp, size_t idx, char elt)
2012 TRUNNEL_DYNARRAY_SET(&inp->username, idx, elt);
2013 return 0;
2016 socks5_client_userpass_auth_add_username(socks5_client_userpass_auth_t *inp, char elt)
2018 #if SIZE_MAX >= UINT8_MAX
2019 if (inp->username.n_ == UINT8_MAX)
2020 goto trunnel_alloc_failed;
2021 #endif
2022 TRUNNEL_DYNARRAY_ADD(char, &inp->username, elt, {});
2023 return 0;
2024 trunnel_alloc_failed:
2025 TRUNNEL_SET_ERROR_CODE(inp);
2026 return -1;
2029 char *
2030 socks5_client_userpass_auth_getarray_username(socks5_client_userpass_auth_t *inp)
2032 return inp->username.elts_;
2034 const char *
2035 socks5_client_userpass_auth_getconstarray_username(const socks5_client_userpass_auth_t *inp)
2037 return (const char *)socks5_client_userpass_auth_getarray_username((socks5_client_userpass_auth_t*)inp);
2040 socks5_client_userpass_auth_setlen_username(socks5_client_userpass_auth_t *inp, size_t newlen)
2042 #if UINT8_MAX < SIZE_MAX
2043 if (newlen > UINT8_MAX)
2044 goto trunnel_alloc_failed;
2045 #endif
2046 return trunnel_string_setlen(&inp->username, newlen,
2047 &inp->trunnel_error_code_);
2048 trunnel_alloc_failed:
2049 TRUNNEL_SET_ERROR_CODE(inp);
2050 return -1;
2052 const char *
2053 socks5_client_userpass_auth_getstr_username(socks5_client_userpass_auth_t *inp)
2055 return trunnel_string_getstr(&inp->username);
2058 socks5_client_userpass_auth_setstr0_username(socks5_client_userpass_auth_t *inp, const char *val, size_t len)
2060 #if UINT8_MAX < SIZE_MAX
2061 if (len > UINT8_MAX) {
2062 TRUNNEL_SET_ERROR_CODE(inp);
2063 return -1;
2065 #endif
2066 return trunnel_string_setstr0(&inp->username, val, len, &inp->trunnel_error_code_);
2069 socks5_client_userpass_auth_setstr_username(socks5_client_userpass_auth_t *inp, const char *val)
2071 return socks5_client_userpass_auth_setstr0_username(inp, val, strlen(val));
2073 uint8_t
2074 socks5_client_userpass_auth_get_passwd_len(const socks5_client_userpass_auth_t *inp)
2076 return inp->passwd_len;
2079 socks5_client_userpass_auth_set_passwd_len(socks5_client_userpass_auth_t *inp, uint8_t val)
2081 inp->passwd_len = val;
2082 return 0;
2084 size_t
2085 socks5_client_userpass_auth_getlen_passwd(const socks5_client_userpass_auth_t *inp)
2087 return TRUNNEL_DYNARRAY_LEN(&inp->passwd);
2090 char
2091 socks5_client_userpass_auth_get_passwd(socks5_client_userpass_auth_t *inp, size_t idx)
2093 return TRUNNEL_DYNARRAY_GET(&inp->passwd, idx);
2096 char
2097 socks5_client_userpass_auth_getconst_passwd(const socks5_client_userpass_auth_t *inp, size_t idx)
2099 return socks5_client_userpass_auth_get_passwd((socks5_client_userpass_auth_t*)inp, idx);
2102 socks5_client_userpass_auth_set_passwd(socks5_client_userpass_auth_t *inp, size_t idx, char elt)
2104 TRUNNEL_DYNARRAY_SET(&inp->passwd, idx, elt);
2105 return 0;
2108 socks5_client_userpass_auth_add_passwd(socks5_client_userpass_auth_t *inp, char elt)
2110 #if SIZE_MAX >= UINT8_MAX
2111 if (inp->passwd.n_ == UINT8_MAX)
2112 goto trunnel_alloc_failed;
2113 #endif
2114 TRUNNEL_DYNARRAY_ADD(char, &inp->passwd, elt, {});
2115 return 0;
2116 trunnel_alloc_failed:
2117 TRUNNEL_SET_ERROR_CODE(inp);
2118 return -1;
2121 char *
2122 socks5_client_userpass_auth_getarray_passwd(socks5_client_userpass_auth_t *inp)
2124 return inp->passwd.elts_;
2126 const char *
2127 socks5_client_userpass_auth_getconstarray_passwd(const socks5_client_userpass_auth_t *inp)
2129 return (const char *)socks5_client_userpass_auth_getarray_passwd((socks5_client_userpass_auth_t*)inp);
2132 socks5_client_userpass_auth_setlen_passwd(socks5_client_userpass_auth_t *inp, size_t newlen)
2134 #if UINT8_MAX < SIZE_MAX
2135 if (newlen > UINT8_MAX)
2136 goto trunnel_alloc_failed;
2137 #endif
2138 return trunnel_string_setlen(&inp->passwd, newlen,
2139 &inp->trunnel_error_code_);
2140 trunnel_alloc_failed:
2141 TRUNNEL_SET_ERROR_CODE(inp);
2142 return -1;
2144 const char *
2145 socks5_client_userpass_auth_getstr_passwd(socks5_client_userpass_auth_t *inp)
2147 return trunnel_string_getstr(&inp->passwd);
2150 socks5_client_userpass_auth_setstr0_passwd(socks5_client_userpass_auth_t *inp, const char *val, size_t len)
2152 #if UINT8_MAX < SIZE_MAX
2153 if (len > UINT8_MAX) {
2154 TRUNNEL_SET_ERROR_CODE(inp);
2155 return -1;
2157 #endif
2158 return trunnel_string_setstr0(&inp->passwd, val, len, &inp->trunnel_error_code_);
2161 socks5_client_userpass_auth_setstr_passwd(socks5_client_userpass_auth_t *inp, const char *val)
2163 return socks5_client_userpass_auth_setstr0_passwd(inp, val, strlen(val));
2165 const char *
2166 socks5_client_userpass_auth_check(const socks5_client_userpass_auth_t *obj)
2168 if (obj == NULL)
2169 return "Object was NULL";
2170 if (obj->trunnel_error_code_)
2171 return "A set function failed on this object";
2172 if (! (obj->version == 1))
2173 return "Integer out of bounds";
2174 if (TRUNNEL_DYNARRAY_LEN(&obj->username) != obj->username_len)
2175 return "Length mismatch for username";
2176 if (TRUNNEL_DYNARRAY_LEN(&obj->passwd) != obj->passwd_len)
2177 return "Length mismatch for passwd";
2178 return NULL;
2181 ssize_t
2182 socks5_client_userpass_auth_encoded_len(const socks5_client_userpass_auth_t *obj)
2184 ssize_t result = 0;
2186 if (NULL != socks5_client_userpass_auth_check(obj))
2187 return -1;
2190 /* Length of u8 version IN [1] */
2191 result += 1;
2193 /* Length of u8 username_len */
2194 result += 1;
2196 /* Length of char username[username_len] */
2197 result += TRUNNEL_DYNARRAY_LEN(&obj->username);
2199 /* Length of u8 passwd_len */
2200 result += 1;
2202 /* Length of char passwd[passwd_len] */
2203 result += TRUNNEL_DYNARRAY_LEN(&obj->passwd);
2204 return result;
2207 socks5_client_userpass_auth_clear_errors(socks5_client_userpass_auth_t *obj)
2209 int r = obj->trunnel_error_code_;
2210 obj->trunnel_error_code_ = 0;
2211 return r;
2213 ssize_t
2214 socks5_client_userpass_auth_encode(uint8_t *output, const size_t avail, const socks5_client_userpass_auth_t *obj)
2216 ssize_t result = 0;
2217 size_t written = 0;
2218 uint8_t *ptr = output;
2219 const char *msg;
2220 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2221 const ssize_t encoded_len = socks5_client_userpass_auth_encoded_len(obj);
2222 #endif
2224 if (NULL != (msg = socks5_client_userpass_auth_check(obj)))
2225 goto check_failed;
2227 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2228 trunnel_assert(encoded_len >= 0);
2229 #endif
2231 /* Encode u8 version IN [1] */
2232 trunnel_assert(written <= avail);
2233 if (avail - written < 1)
2234 goto truncated;
2235 trunnel_set_uint8(ptr, (obj->version));
2236 written += 1; ptr += 1;
2238 /* Encode u8 username_len */
2239 trunnel_assert(written <= avail);
2240 if (avail - written < 1)
2241 goto truncated;
2242 trunnel_set_uint8(ptr, (obj->username_len));
2243 written += 1; ptr += 1;
2245 /* Encode char username[username_len] */
2247 size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->username);
2248 trunnel_assert(obj->username_len == elt_len);
2249 trunnel_assert(written <= avail);
2250 if (avail - written < elt_len)
2251 goto truncated;
2252 if (elt_len)
2253 memcpy(ptr, obj->username.elts_, elt_len);
2254 written += elt_len; ptr += elt_len;
2257 /* Encode u8 passwd_len */
2258 trunnel_assert(written <= avail);
2259 if (avail - written < 1)
2260 goto truncated;
2261 trunnel_set_uint8(ptr, (obj->passwd_len));
2262 written += 1; ptr += 1;
2264 /* Encode char passwd[passwd_len] */
2266 size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->passwd);
2267 trunnel_assert(obj->passwd_len == elt_len);
2268 trunnel_assert(written <= avail);
2269 if (avail - written < elt_len)
2270 goto truncated;
2271 if (elt_len)
2272 memcpy(ptr, obj->passwd.elts_, elt_len);
2273 written += elt_len; ptr += elt_len;
2277 trunnel_assert(ptr == output + written);
2278 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2280 trunnel_assert(encoded_len >= 0);
2281 trunnel_assert((size_t)encoded_len == written);
2284 #endif
2286 return written;
2288 truncated:
2289 result = -2;
2290 goto fail;
2291 check_failed:
2292 (void)msg;
2293 result = -1;
2294 goto fail;
2295 fail:
2296 trunnel_assert(result < 0);
2297 return result;
2300 /** As socks5_client_userpass_auth_parse(), but do not allocate the
2301 * output object.
2303 static ssize_t
2304 socks5_client_userpass_auth_parse_into(socks5_client_userpass_auth_t *obj, const uint8_t *input, const size_t len_in)
2306 const uint8_t *ptr = input;
2307 size_t remaining = len_in;
2308 ssize_t result = 0;
2309 (void)result;
2311 /* Parse u8 version IN [1] */
2312 CHECK_REMAINING(1, truncated);
2313 obj->version = (trunnel_get_uint8(ptr));
2314 remaining -= 1; ptr += 1;
2315 if (! (obj->version == 1))
2316 goto fail;
2318 /* Parse u8 username_len */
2319 CHECK_REMAINING(1, truncated);
2320 obj->username_len = (trunnel_get_uint8(ptr));
2321 remaining -= 1; ptr += 1;
2323 /* Parse char username[username_len] */
2324 CHECK_REMAINING(obj->username_len, truncated);
2325 if (socks5_client_userpass_auth_setstr0_username(obj, (const char*)ptr, obj->username_len))
2326 goto fail;
2327 ptr += obj->username_len; remaining -= obj->username_len;
2329 /* Parse u8 passwd_len */
2330 CHECK_REMAINING(1, truncated);
2331 obj->passwd_len = (trunnel_get_uint8(ptr));
2332 remaining -= 1; ptr += 1;
2334 /* Parse char passwd[passwd_len] */
2335 CHECK_REMAINING(obj->passwd_len, truncated);
2336 if (socks5_client_userpass_auth_setstr0_passwd(obj, (const char*)ptr, obj->passwd_len))
2337 goto fail;
2338 ptr += obj->passwd_len; remaining -= obj->passwd_len;
2339 trunnel_assert(ptr + remaining == input + len_in);
2340 return len_in - remaining;
2342 truncated:
2343 return -2;
2344 fail:
2345 result = -1;
2346 return result;
2349 ssize_t
2350 socks5_client_userpass_auth_parse(socks5_client_userpass_auth_t **output, const uint8_t *input, const size_t len_in)
2352 ssize_t result;
2353 *output = socks5_client_userpass_auth_new();
2354 if (NULL == *output)
2355 return -1;
2356 result = socks5_client_userpass_auth_parse_into(*output, input, len_in);
2357 if (result < 0) {
2358 socks5_client_userpass_auth_free(*output);
2359 *output = NULL;
2361 return result;
2363 socks5_client_version_t *
2364 socks5_client_version_new(void)
2366 socks5_client_version_t *val = trunnel_calloc(1, sizeof(socks5_client_version_t));
2367 if (NULL == val)
2368 return NULL;
2369 val->version = 5;
2370 return val;
2373 /** Release all storage held inside 'obj', but do not free 'obj'.
2375 static void
2376 socks5_client_version_clear(socks5_client_version_t *obj)
2378 (void) obj;
2379 TRUNNEL_DYNARRAY_WIPE(&obj->methods);
2380 TRUNNEL_DYNARRAY_CLEAR(&obj->methods);
2383 void
2384 socks5_client_version_free(socks5_client_version_t *obj)
2386 if (obj == NULL)
2387 return;
2388 socks5_client_version_clear(obj);
2389 trunnel_memwipe(obj, sizeof(socks5_client_version_t));
2390 trunnel_free_(obj);
2393 uint8_t
2394 socks5_client_version_get_version(const socks5_client_version_t *inp)
2396 return inp->version;
2399 socks5_client_version_set_version(socks5_client_version_t *inp, uint8_t val)
2401 if (! ((val == 5))) {
2402 TRUNNEL_SET_ERROR_CODE(inp);
2403 return -1;
2405 inp->version = val;
2406 return 0;
2408 uint8_t
2409 socks5_client_version_get_n_methods(const socks5_client_version_t *inp)
2411 return inp->n_methods;
2414 socks5_client_version_set_n_methods(socks5_client_version_t *inp, uint8_t val)
2416 inp->n_methods = val;
2417 return 0;
2419 size_t
2420 socks5_client_version_getlen_methods(const socks5_client_version_t *inp)
2422 return TRUNNEL_DYNARRAY_LEN(&inp->methods);
2425 uint8_t
2426 socks5_client_version_get_methods(socks5_client_version_t *inp, size_t idx)
2428 return TRUNNEL_DYNARRAY_GET(&inp->methods, idx);
2431 uint8_t
2432 socks5_client_version_getconst_methods(const socks5_client_version_t *inp, size_t idx)
2434 return socks5_client_version_get_methods((socks5_client_version_t*)inp, idx);
2437 socks5_client_version_set_methods(socks5_client_version_t *inp, size_t idx, uint8_t elt)
2439 TRUNNEL_DYNARRAY_SET(&inp->methods, idx, elt);
2440 return 0;
2443 socks5_client_version_add_methods(socks5_client_version_t *inp, uint8_t elt)
2445 #if SIZE_MAX >= UINT8_MAX
2446 if (inp->methods.n_ == UINT8_MAX)
2447 goto trunnel_alloc_failed;
2448 #endif
2449 TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->methods, elt, {});
2450 return 0;
2451 trunnel_alloc_failed:
2452 TRUNNEL_SET_ERROR_CODE(inp);
2453 return -1;
2456 uint8_t *
2457 socks5_client_version_getarray_methods(socks5_client_version_t *inp)
2459 return inp->methods.elts_;
2461 const uint8_t *
2462 socks5_client_version_getconstarray_methods(const socks5_client_version_t *inp)
2464 return (const uint8_t *)socks5_client_version_getarray_methods((socks5_client_version_t*)inp);
2467 socks5_client_version_setlen_methods(socks5_client_version_t *inp, size_t newlen)
2469 uint8_t *newptr;
2470 #if UINT8_MAX < SIZE_MAX
2471 if (newlen > UINT8_MAX)
2472 goto trunnel_alloc_failed;
2473 #endif
2474 newptr = trunnel_dynarray_setlen(&inp->methods.allocated_,
2475 &inp->methods.n_, inp->methods.elts_, newlen,
2476 sizeof(inp->methods.elts_[0]), (trunnel_free_fn_t) NULL,
2477 &inp->trunnel_error_code_);
2478 if (newlen != 0 && newptr == NULL)
2479 goto trunnel_alloc_failed;
2480 inp->methods.elts_ = newptr;
2481 return 0;
2482 trunnel_alloc_failed:
2483 TRUNNEL_SET_ERROR_CODE(inp);
2484 return -1;
2486 const char *
2487 socks5_client_version_check(const socks5_client_version_t *obj)
2489 if (obj == NULL)
2490 return "Object was NULL";
2491 if (obj->trunnel_error_code_)
2492 return "A set function failed on this object";
2493 if (! (obj->version == 5))
2494 return "Integer out of bounds";
2495 if (TRUNNEL_DYNARRAY_LEN(&obj->methods) != obj->n_methods)
2496 return "Length mismatch for methods";
2497 return NULL;
2500 ssize_t
2501 socks5_client_version_encoded_len(const socks5_client_version_t *obj)
2503 ssize_t result = 0;
2505 if (NULL != socks5_client_version_check(obj))
2506 return -1;
2509 /* Length of u8 version IN [5] */
2510 result += 1;
2512 /* Length of u8 n_methods */
2513 result += 1;
2515 /* Length of u8 methods[n_methods] */
2516 result += TRUNNEL_DYNARRAY_LEN(&obj->methods);
2517 return result;
2520 socks5_client_version_clear_errors(socks5_client_version_t *obj)
2522 int r = obj->trunnel_error_code_;
2523 obj->trunnel_error_code_ = 0;
2524 return r;
2526 ssize_t
2527 socks5_client_version_encode(uint8_t *output, const size_t avail, const socks5_client_version_t *obj)
2529 ssize_t result = 0;
2530 size_t written = 0;
2531 uint8_t *ptr = output;
2532 const char *msg;
2533 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2534 const ssize_t encoded_len = socks5_client_version_encoded_len(obj);
2535 #endif
2537 if (NULL != (msg = socks5_client_version_check(obj)))
2538 goto check_failed;
2540 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2541 trunnel_assert(encoded_len >= 0);
2542 #endif
2544 /* Encode u8 version IN [5] */
2545 trunnel_assert(written <= avail);
2546 if (avail - written < 1)
2547 goto truncated;
2548 trunnel_set_uint8(ptr, (obj->version));
2549 written += 1; ptr += 1;
2551 /* Encode u8 n_methods */
2552 trunnel_assert(written <= avail);
2553 if (avail - written < 1)
2554 goto truncated;
2555 trunnel_set_uint8(ptr, (obj->n_methods));
2556 written += 1; ptr += 1;
2558 /* Encode u8 methods[n_methods] */
2560 size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->methods);
2561 trunnel_assert(obj->n_methods == elt_len);
2562 trunnel_assert(written <= avail);
2563 if (avail - written < elt_len)
2564 goto truncated;
2565 if (elt_len)
2566 memcpy(ptr, obj->methods.elts_, elt_len);
2567 written += elt_len; ptr += elt_len;
2571 trunnel_assert(ptr == output + written);
2572 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2574 trunnel_assert(encoded_len >= 0);
2575 trunnel_assert((size_t)encoded_len == written);
2578 #endif
2580 return written;
2582 truncated:
2583 result = -2;
2584 goto fail;
2585 check_failed:
2586 (void)msg;
2587 result = -1;
2588 goto fail;
2589 fail:
2590 trunnel_assert(result < 0);
2591 return result;
2594 /** As socks5_client_version_parse(), but do not allocate the output
2595 * object.
2597 static ssize_t
2598 socks5_client_version_parse_into(socks5_client_version_t *obj, const uint8_t *input, const size_t len_in)
2600 const uint8_t *ptr = input;
2601 size_t remaining = len_in;
2602 ssize_t result = 0;
2603 (void)result;
2605 /* Parse u8 version IN [5] */
2606 CHECK_REMAINING(1, truncated);
2607 obj->version = (trunnel_get_uint8(ptr));
2608 remaining -= 1; ptr += 1;
2609 if (! (obj->version == 5))
2610 goto fail;
2612 /* Parse u8 n_methods */
2613 CHECK_REMAINING(1, truncated);
2614 obj->n_methods = (trunnel_get_uint8(ptr));
2615 remaining -= 1; ptr += 1;
2617 /* Parse u8 methods[n_methods] */
2618 CHECK_REMAINING(obj->n_methods, truncated);
2619 TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->methods, obj->n_methods, {});
2620 obj->methods.n_ = obj->n_methods;
2621 if (obj->n_methods)
2622 memcpy(obj->methods.elts_, ptr, obj->n_methods);
2623 ptr += obj->n_methods; remaining -= obj->n_methods;
2624 trunnel_assert(ptr + remaining == input + len_in);
2625 return len_in - remaining;
2627 truncated:
2628 return -2;
2629 trunnel_alloc_failed:
2630 return -1;
2631 fail:
2632 result = -1;
2633 return result;
2636 ssize_t
2637 socks5_client_version_parse(socks5_client_version_t **output, const uint8_t *input, const size_t len_in)
2639 ssize_t result;
2640 *output = socks5_client_version_new();
2641 if (NULL == *output)
2642 return -1;
2643 result = socks5_client_version_parse_into(*output, input, len_in);
2644 if (result < 0) {
2645 socks5_client_version_free(*output);
2646 *output = NULL;
2648 return result;
2650 socks5_server_method_t *
2651 socks5_server_method_new(void)
2653 socks5_server_method_t *val = trunnel_calloc(1, sizeof(socks5_server_method_t));
2654 if (NULL == val)
2655 return NULL;
2656 val->version = 5;
2657 return val;
2660 /** Release all storage held inside 'obj', but do not free 'obj'.
2662 static void
2663 socks5_server_method_clear(socks5_server_method_t *obj)
2665 (void) obj;
2668 void
2669 socks5_server_method_free(socks5_server_method_t *obj)
2671 if (obj == NULL)
2672 return;
2673 socks5_server_method_clear(obj);
2674 trunnel_memwipe(obj, sizeof(socks5_server_method_t));
2675 trunnel_free_(obj);
2678 uint8_t
2679 socks5_server_method_get_version(const socks5_server_method_t *inp)
2681 return inp->version;
2684 socks5_server_method_set_version(socks5_server_method_t *inp, uint8_t val)
2686 if (! ((val == 5))) {
2687 TRUNNEL_SET_ERROR_CODE(inp);
2688 return -1;
2690 inp->version = val;
2691 return 0;
2693 uint8_t
2694 socks5_server_method_get_method(const socks5_server_method_t *inp)
2696 return inp->method;
2699 socks5_server_method_set_method(socks5_server_method_t *inp, uint8_t val)
2701 inp->method = val;
2702 return 0;
2704 const char *
2705 socks5_server_method_check(const socks5_server_method_t *obj)
2707 if (obj == NULL)
2708 return "Object was NULL";
2709 if (obj->trunnel_error_code_)
2710 return "A set function failed on this object";
2711 if (! (obj->version == 5))
2712 return "Integer out of bounds";
2713 return NULL;
2716 ssize_t
2717 socks5_server_method_encoded_len(const socks5_server_method_t *obj)
2719 ssize_t result = 0;
2721 if (NULL != socks5_server_method_check(obj))
2722 return -1;
2725 /* Length of u8 version IN [5] */
2726 result += 1;
2728 /* Length of u8 method */
2729 result += 1;
2730 return result;
2733 socks5_server_method_clear_errors(socks5_server_method_t *obj)
2735 int r = obj->trunnel_error_code_;
2736 obj->trunnel_error_code_ = 0;
2737 return r;
2739 ssize_t
2740 socks5_server_method_encode(uint8_t *output, const size_t avail, const socks5_server_method_t *obj)
2742 ssize_t result = 0;
2743 size_t written = 0;
2744 uint8_t *ptr = output;
2745 const char *msg;
2746 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2747 const ssize_t encoded_len = socks5_server_method_encoded_len(obj);
2748 #endif
2750 if (NULL != (msg = socks5_server_method_check(obj)))
2751 goto check_failed;
2753 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2754 trunnel_assert(encoded_len >= 0);
2755 #endif
2757 /* Encode u8 version IN [5] */
2758 trunnel_assert(written <= avail);
2759 if (avail - written < 1)
2760 goto truncated;
2761 trunnel_set_uint8(ptr, (obj->version));
2762 written += 1; ptr += 1;
2764 /* Encode u8 method */
2765 trunnel_assert(written <= avail);
2766 if (avail - written < 1)
2767 goto truncated;
2768 trunnel_set_uint8(ptr, (obj->method));
2769 written += 1; ptr += 1;
2772 trunnel_assert(ptr == output + written);
2773 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2775 trunnel_assert(encoded_len >= 0);
2776 trunnel_assert((size_t)encoded_len == written);
2779 #endif
2781 return written;
2783 truncated:
2784 result = -2;
2785 goto fail;
2786 check_failed:
2787 (void)msg;
2788 result = -1;
2789 goto fail;
2790 fail:
2791 trunnel_assert(result < 0);
2792 return result;
2795 /** As socks5_server_method_parse(), but do not allocate the output
2796 * object.
2798 static ssize_t
2799 socks5_server_method_parse_into(socks5_server_method_t *obj, const uint8_t *input, const size_t len_in)
2801 const uint8_t *ptr = input;
2802 size_t remaining = len_in;
2803 ssize_t result = 0;
2804 (void)result;
2806 /* Parse u8 version IN [5] */
2807 CHECK_REMAINING(1, truncated);
2808 obj->version = (trunnel_get_uint8(ptr));
2809 remaining -= 1; ptr += 1;
2810 if (! (obj->version == 5))
2811 goto fail;
2813 /* Parse u8 method */
2814 CHECK_REMAINING(1, truncated);
2815 obj->method = (trunnel_get_uint8(ptr));
2816 remaining -= 1; ptr += 1;
2817 trunnel_assert(ptr + remaining == input + len_in);
2818 return len_in - remaining;
2820 truncated:
2821 return -2;
2822 fail:
2823 result = -1;
2824 return result;
2827 ssize_t
2828 socks5_server_method_parse(socks5_server_method_t **output, const uint8_t *input, const size_t len_in)
2830 ssize_t result;
2831 *output = socks5_server_method_new();
2832 if (NULL == *output)
2833 return -1;
2834 result = socks5_server_method_parse_into(*output, input, len_in);
2835 if (result < 0) {
2836 socks5_server_method_free(*output);
2837 *output = NULL;
2839 return result;
2841 socks5_server_userpass_auth_t *
2842 socks5_server_userpass_auth_new(void)
2844 socks5_server_userpass_auth_t *val = trunnel_calloc(1, sizeof(socks5_server_userpass_auth_t));
2845 if (NULL == val)
2846 return NULL;
2847 val->version = 1;
2848 return val;
2851 /** Release all storage held inside 'obj', but do not free 'obj'.
2853 static void
2854 socks5_server_userpass_auth_clear(socks5_server_userpass_auth_t *obj)
2856 (void) obj;
2859 void
2860 socks5_server_userpass_auth_free(socks5_server_userpass_auth_t *obj)
2862 if (obj == NULL)
2863 return;
2864 socks5_server_userpass_auth_clear(obj);
2865 trunnel_memwipe(obj, sizeof(socks5_server_userpass_auth_t));
2866 trunnel_free_(obj);
2869 uint8_t
2870 socks5_server_userpass_auth_get_version(const socks5_server_userpass_auth_t *inp)
2872 return inp->version;
2875 socks5_server_userpass_auth_set_version(socks5_server_userpass_auth_t *inp, uint8_t val)
2877 if (! ((val == 1))) {
2878 TRUNNEL_SET_ERROR_CODE(inp);
2879 return -1;
2881 inp->version = val;
2882 return 0;
2884 uint8_t
2885 socks5_server_userpass_auth_get_status(const socks5_server_userpass_auth_t *inp)
2887 return inp->status;
2890 socks5_server_userpass_auth_set_status(socks5_server_userpass_auth_t *inp, uint8_t val)
2892 inp->status = val;
2893 return 0;
2895 const char *
2896 socks5_server_userpass_auth_check(const socks5_server_userpass_auth_t *obj)
2898 if (obj == NULL)
2899 return "Object was NULL";
2900 if (obj->trunnel_error_code_)
2901 return "A set function failed on this object";
2902 if (! (obj->version == 1))
2903 return "Integer out of bounds";
2904 return NULL;
2907 ssize_t
2908 socks5_server_userpass_auth_encoded_len(const socks5_server_userpass_auth_t *obj)
2910 ssize_t result = 0;
2912 if (NULL != socks5_server_userpass_auth_check(obj))
2913 return -1;
2916 /* Length of u8 version IN [1] */
2917 result += 1;
2919 /* Length of u8 status */
2920 result += 1;
2921 return result;
2924 socks5_server_userpass_auth_clear_errors(socks5_server_userpass_auth_t *obj)
2926 int r = obj->trunnel_error_code_;
2927 obj->trunnel_error_code_ = 0;
2928 return r;
2930 ssize_t
2931 socks5_server_userpass_auth_encode(uint8_t *output, const size_t avail, const socks5_server_userpass_auth_t *obj)
2933 ssize_t result = 0;
2934 size_t written = 0;
2935 uint8_t *ptr = output;
2936 const char *msg;
2937 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2938 const ssize_t encoded_len = socks5_server_userpass_auth_encoded_len(obj);
2939 #endif
2941 if (NULL != (msg = socks5_server_userpass_auth_check(obj)))
2942 goto check_failed;
2944 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2945 trunnel_assert(encoded_len >= 0);
2946 #endif
2948 /* Encode u8 version IN [1] */
2949 trunnel_assert(written <= avail);
2950 if (avail - written < 1)
2951 goto truncated;
2952 trunnel_set_uint8(ptr, (obj->version));
2953 written += 1; ptr += 1;
2955 /* Encode u8 status */
2956 trunnel_assert(written <= avail);
2957 if (avail - written < 1)
2958 goto truncated;
2959 trunnel_set_uint8(ptr, (obj->status));
2960 written += 1; ptr += 1;
2963 trunnel_assert(ptr == output + written);
2964 #ifdef TRUNNEL_CHECK_ENCODED_LEN
2966 trunnel_assert(encoded_len >= 0);
2967 trunnel_assert((size_t)encoded_len == written);
2970 #endif
2972 return written;
2974 truncated:
2975 result = -2;
2976 goto fail;
2977 check_failed:
2978 (void)msg;
2979 result = -1;
2980 goto fail;
2981 fail:
2982 trunnel_assert(result < 0);
2983 return result;
2986 /** As socks5_server_userpass_auth_parse(), but do not allocate the
2987 * output object.
2989 static ssize_t
2990 socks5_server_userpass_auth_parse_into(socks5_server_userpass_auth_t *obj, const uint8_t *input, const size_t len_in)
2992 const uint8_t *ptr = input;
2993 size_t remaining = len_in;
2994 ssize_t result = 0;
2995 (void)result;
2997 /* Parse u8 version IN [1] */
2998 CHECK_REMAINING(1, truncated);
2999 obj->version = (trunnel_get_uint8(ptr));
3000 remaining -= 1; ptr += 1;
3001 if (! (obj->version == 1))
3002 goto fail;
3004 /* Parse u8 status */
3005 CHECK_REMAINING(1, truncated);
3006 obj->status = (trunnel_get_uint8(ptr));
3007 remaining -= 1; ptr += 1;
3008 trunnel_assert(ptr + remaining == input + len_in);
3009 return len_in - remaining;
3011 truncated:
3012 return -2;
3013 fail:
3014 result = -1;
3015 return result;
3018 ssize_t
3019 socks5_server_userpass_auth_parse(socks5_server_userpass_auth_t **output, const uint8_t *input, const size_t len_in)
3021 ssize_t result;
3022 *output = socks5_server_userpass_auth_new();
3023 if (NULL == *output)
3024 return -1;
3025 result = socks5_server_userpass_auth_parse_into(*output, input, len_in);
3026 if (result < 0) {
3027 socks5_server_userpass_auth_free(*output);
3028 *output = NULL;
3030 return result;
3032 socks5_client_request_t *
3033 socks5_client_request_new(void)
3035 socks5_client_request_t *val = trunnel_calloc(1, sizeof(socks5_client_request_t));
3036 if (NULL == val)
3037 return NULL;
3038 val->version = 5;
3039 val->command = CMD_BIND;
3040 return val;
3043 /** Release all storage held inside 'obj', but do not free 'obj'.
3045 static void
3046 socks5_client_request_clear(socks5_client_request_t *obj)
3048 (void) obj;
3049 domainname_free(obj->dest_addr_domainname);
3050 obj->dest_addr_domainname = NULL;
3053 void
3054 socks5_client_request_free(socks5_client_request_t *obj)
3056 if (obj == NULL)
3057 return;
3058 socks5_client_request_clear(obj);
3059 trunnel_memwipe(obj, sizeof(socks5_client_request_t));
3060 trunnel_free_(obj);
3063 uint8_t
3064 socks5_client_request_get_version(const socks5_client_request_t *inp)
3066 return inp->version;
3069 socks5_client_request_set_version(socks5_client_request_t *inp, uint8_t val)
3071 if (! ((val == 5))) {
3072 TRUNNEL_SET_ERROR_CODE(inp);
3073 return -1;
3075 inp->version = val;
3076 return 0;
3078 uint8_t
3079 socks5_client_request_get_command(const socks5_client_request_t *inp)
3081 return inp->command;
3084 socks5_client_request_set_command(socks5_client_request_t *inp, uint8_t val)
3086 if (! ((val == CMD_BIND || val == CMD_CONNECT || val == CMD_RESOLVE || val == CMD_RESOLVE_PTR || val == CMD_UDP_ASSOCIATE))) {
3087 TRUNNEL_SET_ERROR_CODE(inp);
3088 return -1;
3090 inp->command = val;
3091 return 0;
3093 uint8_t
3094 socks5_client_request_get_reserved(const socks5_client_request_t *inp)
3096 return inp->reserved;
3099 socks5_client_request_set_reserved(socks5_client_request_t *inp, uint8_t val)
3101 if (! ((val == 0))) {
3102 TRUNNEL_SET_ERROR_CODE(inp);
3103 return -1;
3105 inp->reserved = val;
3106 return 0;
3108 uint8_t
3109 socks5_client_request_get_atype(const socks5_client_request_t *inp)
3111 return inp->atype;
3114 socks5_client_request_set_atype(socks5_client_request_t *inp, uint8_t val)
3116 inp->atype = val;
3117 return 0;
3119 uint32_t
3120 socks5_client_request_get_dest_addr_ipv4(const socks5_client_request_t *inp)
3122 return inp->dest_addr_ipv4;
3125 socks5_client_request_set_dest_addr_ipv4(socks5_client_request_t *inp, uint32_t val)
3127 inp->dest_addr_ipv4 = val;
3128 return 0;
3130 size_t
3131 socks5_client_request_getlen_dest_addr_ipv6(const socks5_client_request_t *inp)
3133 (void)inp; return 16;
3136 uint8_t
3137 socks5_client_request_get_dest_addr_ipv6(socks5_client_request_t *inp, size_t idx)
3139 trunnel_assert(idx < 16);
3140 return inp->dest_addr_ipv6[idx];
3143 uint8_t
3144 socks5_client_request_getconst_dest_addr_ipv6(const socks5_client_request_t *inp, size_t idx)
3146 return socks5_client_request_get_dest_addr_ipv6((socks5_client_request_t*)inp, idx);
3149 socks5_client_request_set_dest_addr_ipv6(socks5_client_request_t *inp, size_t idx, uint8_t elt)
3151 trunnel_assert(idx < 16);
3152 inp->dest_addr_ipv6[idx] = elt;
3153 return 0;
3156 uint8_t *
3157 socks5_client_request_getarray_dest_addr_ipv6(socks5_client_request_t *inp)
3159 return inp->dest_addr_ipv6;
3161 const uint8_t *
3162 socks5_client_request_getconstarray_dest_addr_ipv6(const socks5_client_request_t *inp)
3164 return (const uint8_t *)socks5_client_request_getarray_dest_addr_ipv6((socks5_client_request_t*)inp);
3166 struct domainname_st *
3167 socks5_client_request_get_dest_addr_domainname(socks5_client_request_t *inp)
3169 return inp->dest_addr_domainname;
3171 const struct domainname_st *
3172 socks5_client_request_getconst_dest_addr_domainname(const socks5_client_request_t *inp)
3174 return socks5_client_request_get_dest_addr_domainname((socks5_client_request_t*) inp);
3177 socks5_client_request_set_dest_addr_domainname(socks5_client_request_t *inp, struct domainname_st *val)
3179 if (inp->dest_addr_domainname && inp->dest_addr_domainname != val)
3180 domainname_free(inp->dest_addr_domainname);
3181 return socks5_client_request_set0_dest_addr_domainname(inp, val);
3184 socks5_client_request_set0_dest_addr_domainname(socks5_client_request_t *inp, struct domainname_st *val)
3186 inp->dest_addr_domainname = val;
3187 return 0;
3189 uint16_t
3190 socks5_client_request_get_dest_port(const socks5_client_request_t *inp)
3192 return inp->dest_port;
3195 socks5_client_request_set_dest_port(socks5_client_request_t *inp, uint16_t val)
3197 inp->dest_port = val;
3198 return 0;
3200 const char *
3201 socks5_client_request_check(const socks5_client_request_t *obj)
3203 if (obj == NULL)
3204 return "Object was NULL";
3205 if (obj->trunnel_error_code_)
3206 return "A set function failed on this object";
3207 if (! (obj->version == 5))
3208 return "Integer out of bounds";
3209 if (! (obj->command == CMD_BIND || obj->command == CMD_CONNECT || obj->command == CMD_RESOLVE || obj->command == CMD_RESOLVE_PTR || obj->command == CMD_UDP_ASSOCIATE))
3210 return "Integer out of bounds";
3211 if (! (obj->reserved == 0))
3212 return "Integer out of bounds";
3213 switch (obj->atype) {
3215 case ATYPE_IPV4:
3216 break;
3218 case ATYPE_IPV6:
3219 break;
3221 case ATYPE_DOMAINNAME:
3223 const char *msg;
3224 if (NULL != (msg = domainname_check(obj->dest_addr_domainname)))
3225 return msg;
3227 break;
3229 default:
3230 return "Bad tag for union";
3231 break;
3233 return NULL;
3236 ssize_t
3237 socks5_client_request_encoded_len(const socks5_client_request_t *obj)
3239 ssize_t result = 0;
3241 if (NULL != socks5_client_request_check(obj))
3242 return -1;
3245 /* Length of u8 version IN [5] */
3246 result += 1;
3248 /* Length of u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR, CMD_UDP_ASSOCIATE] */
3249 result += 1;
3251 /* Length of u8 reserved IN [0] */
3252 result += 1;
3254 /* Length of u8 atype */
3255 result += 1;
3256 switch (obj->atype) {
3258 case ATYPE_IPV4:
3260 /* Length of u32 dest_addr_ipv4 */
3261 result += 4;
3262 break;
3264 case ATYPE_IPV6:
3266 /* Length of u8 dest_addr_ipv6[16] */
3267 result += 16;
3268 break;
3270 case ATYPE_DOMAINNAME:
3272 /* Length of struct domainname dest_addr_domainname */
3273 result += domainname_encoded_len(obj->dest_addr_domainname);
3274 break;
3276 default:
3277 trunnel_assert(0);
3278 break;
3281 /* Length of u16 dest_port */
3282 result += 2;
3283 return result;
3286 socks5_client_request_clear_errors(socks5_client_request_t *obj)
3288 int r = obj->trunnel_error_code_;
3289 obj->trunnel_error_code_ = 0;
3290 return r;
3292 ssize_t
3293 socks5_client_request_encode(uint8_t *output, const size_t avail, const socks5_client_request_t *obj)
3295 ssize_t result = 0;
3296 size_t written = 0;
3297 uint8_t *ptr = output;
3298 const char *msg;
3299 #ifdef TRUNNEL_CHECK_ENCODED_LEN
3300 const ssize_t encoded_len = socks5_client_request_encoded_len(obj);
3301 #endif
3303 if (NULL != (msg = socks5_client_request_check(obj)))
3304 goto check_failed;
3306 #ifdef TRUNNEL_CHECK_ENCODED_LEN
3307 trunnel_assert(encoded_len >= 0);
3308 #endif
3310 /* Encode u8 version IN [5] */
3311 trunnel_assert(written <= avail);
3312 if (avail - written < 1)
3313 goto truncated;
3314 trunnel_set_uint8(ptr, (obj->version));
3315 written += 1; ptr += 1;
3317 /* Encode u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR, CMD_UDP_ASSOCIATE] */
3318 trunnel_assert(written <= avail);
3319 if (avail - written < 1)
3320 goto truncated;
3321 trunnel_set_uint8(ptr, (obj->command));
3322 written += 1; ptr += 1;
3324 /* Encode u8 reserved IN [0] */
3325 trunnel_assert(written <= avail);
3326 if (avail - written < 1)
3327 goto truncated;
3328 trunnel_set_uint8(ptr, (obj->reserved));
3329 written += 1; ptr += 1;
3331 /* Encode u8 atype */
3332 trunnel_assert(written <= avail);
3333 if (avail - written < 1)
3334 goto truncated;
3335 trunnel_set_uint8(ptr, (obj->atype));
3336 written += 1; ptr += 1;
3338 /* Encode union dest_addr[atype] */
3339 trunnel_assert(written <= avail);
3340 switch (obj->atype) {
3342 case ATYPE_IPV4:
3344 /* Encode u32 dest_addr_ipv4 */
3345 trunnel_assert(written <= avail);
3346 if (avail - written < 4)
3347 goto truncated;
3348 trunnel_set_uint32(ptr, trunnel_htonl(obj->dest_addr_ipv4));
3349 written += 4; ptr += 4;
3350 break;
3352 case ATYPE_IPV6:
3354 /* Encode u8 dest_addr_ipv6[16] */
3355 trunnel_assert(written <= avail);
3356 if (avail - written < 16)
3357 goto truncated;
3358 memcpy(ptr, obj->dest_addr_ipv6, 16);
3359 written += 16; ptr += 16;
3360 break;
3362 case ATYPE_DOMAINNAME:
3364 /* Encode struct domainname dest_addr_domainname */
3365 trunnel_assert(written <= avail);
3366 result = domainname_encode(ptr, avail - written, obj->dest_addr_domainname);
3367 if (result < 0)
3368 goto fail; /* XXXXXXX !*/
3369 written += result; ptr += result;
3370 break;
3372 default:
3373 trunnel_assert(0);
3374 break;
3377 /* Encode u16 dest_port */
3378 trunnel_assert(written <= avail);
3379 if (avail - written < 2)
3380 goto truncated;
3381 trunnel_set_uint16(ptr, trunnel_htons(obj->dest_port));
3382 written += 2; ptr += 2;
3385 trunnel_assert(ptr == output + written);
3386 #ifdef TRUNNEL_CHECK_ENCODED_LEN
3388 trunnel_assert(encoded_len >= 0);
3389 trunnel_assert((size_t)encoded_len == written);
3392 #endif
3394 return written;
3396 truncated:
3397 result = -2;
3398 goto fail;
3399 check_failed:
3400 (void)msg;
3401 result = -1;
3402 goto fail;
3403 fail:
3404 trunnel_assert(result < 0);
3405 return result;
3408 /** As socks5_client_request_parse(), but do not allocate the output
3409 * object.
3411 static ssize_t
3412 socks5_client_request_parse_into(socks5_client_request_t *obj, const uint8_t *input, const size_t len_in)
3414 const uint8_t *ptr = input;
3415 size_t remaining = len_in;
3416 ssize_t result = 0;
3417 (void)result;
3419 /* Parse u8 version IN [5] */
3420 CHECK_REMAINING(1, truncated);
3421 obj->version = (trunnel_get_uint8(ptr));
3422 remaining -= 1; ptr += 1;
3423 if (! (obj->version == 5))
3424 goto fail;
3426 /* Parse u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR, CMD_UDP_ASSOCIATE] */
3427 CHECK_REMAINING(1, truncated);
3428 obj->command = (trunnel_get_uint8(ptr));
3429 remaining -= 1; ptr += 1;
3430 if (! (obj->command == CMD_BIND || obj->command == CMD_CONNECT || obj->command == CMD_RESOLVE || obj->command == CMD_RESOLVE_PTR || obj->command == CMD_UDP_ASSOCIATE))
3431 goto fail;
3433 /* Parse u8 reserved IN [0] */
3434 CHECK_REMAINING(1, truncated);
3435 obj->reserved = (trunnel_get_uint8(ptr));
3436 remaining -= 1; ptr += 1;
3437 if (! (obj->reserved == 0))
3438 goto fail;
3440 /* Parse u8 atype */
3441 CHECK_REMAINING(1, truncated);
3442 obj->atype = (trunnel_get_uint8(ptr));
3443 remaining -= 1; ptr += 1;
3445 /* Parse union dest_addr[atype] */
3446 switch (obj->atype) {
3448 case ATYPE_IPV4:
3450 /* Parse u32 dest_addr_ipv4 */
3451 CHECK_REMAINING(4, truncated);
3452 obj->dest_addr_ipv4 = trunnel_ntohl(trunnel_get_uint32(ptr));
3453 remaining -= 4; ptr += 4;
3454 break;
3456 case ATYPE_IPV6:
3458 /* Parse u8 dest_addr_ipv6[16] */
3459 CHECK_REMAINING(16, truncated);
3460 memcpy(obj->dest_addr_ipv6, ptr, 16);
3461 remaining -= 16; ptr += 16;
3462 break;
3464 case ATYPE_DOMAINNAME:
3466 /* Parse struct domainname dest_addr_domainname */
3467 result = domainname_parse(&obj->dest_addr_domainname, ptr, remaining);
3468 if (result < 0)
3469 goto relay_fail;
3470 trunnel_assert((size_t)result <= remaining);
3471 remaining -= result; ptr += result;
3472 break;
3474 default:
3475 goto fail;
3476 break;
3479 /* Parse u16 dest_port */
3480 CHECK_REMAINING(2, truncated);
3481 obj->dest_port = trunnel_ntohs(trunnel_get_uint16(ptr));
3482 remaining -= 2; ptr += 2;
3483 trunnel_assert(ptr + remaining == input + len_in);
3484 return len_in - remaining;
3486 truncated:
3487 return -2;
3488 relay_fail:
3489 trunnel_assert(result < 0);
3490 return result;
3491 fail:
3492 result = -1;
3493 return result;
3496 ssize_t
3497 socks5_client_request_parse(socks5_client_request_t **output, const uint8_t *input, const size_t len_in)
3499 ssize_t result;
3500 *output = socks5_client_request_new();
3501 if (NULL == *output)
3502 return -1;
3503 result = socks5_client_request_parse_into(*output, input, len_in);
3504 if (result < 0) {
3505 socks5_client_request_free(*output);
3506 *output = NULL;
3508 return result;
3510 socks5_server_reply_t *
3511 socks5_server_reply_new(void)
3513 socks5_server_reply_t *val = trunnel_calloc(1, sizeof(socks5_server_reply_t));
3514 if (NULL == val)
3515 return NULL;
3516 val->version = 5;
3517 return val;
3520 /** Release all storage held inside 'obj', but do not free 'obj'.
3522 static void
3523 socks5_server_reply_clear(socks5_server_reply_t *obj)
3525 (void) obj;
3526 domainname_free(obj->bind_addr_domainname);
3527 obj->bind_addr_domainname = NULL;
3530 void
3531 socks5_server_reply_free(socks5_server_reply_t *obj)
3533 if (obj == NULL)
3534 return;
3535 socks5_server_reply_clear(obj);
3536 trunnel_memwipe(obj, sizeof(socks5_server_reply_t));
3537 trunnel_free_(obj);
3540 uint8_t
3541 socks5_server_reply_get_version(const socks5_server_reply_t *inp)
3543 return inp->version;
3546 socks5_server_reply_set_version(socks5_server_reply_t *inp, uint8_t val)
3548 if (! ((val == 5))) {
3549 TRUNNEL_SET_ERROR_CODE(inp);
3550 return -1;
3552 inp->version = val;
3553 return 0;
3555 uint8_t
3556 socks5_server_reply_get_reply(const socks5_server_reply_t *inp)
3558 return inp->reply;
3561 socks5_server_reply_set_reply(socks5_server_reply_t *inp, uint8_t val)
3563 inp->reply = val;
3564 return 0;
3566 uint8_t
3567 socks5_server_reply_get_reserved(const socks5_server_reply_t *inp)
3569 return inp->reserved;
3572 socks5_server_reply_set_reserved(socks5_server_reply_t *inp, uint8_t val)
3574 if (! ((val == 0))) {
3575 TRUNNEL_SET_ERROR_CODE(inp);
3576 return -1;
3578 inp->reserved = val;
3579 return 0;
3581 uint8_t
3582 socks5_server_reply_get_atype(const socks5_server_reply_t *inp)
3584 return inp->atype;
3587 socks5_server_reply_set_atype(socks5_server_reply_t *inp, uint8_t val)
3589 inp->atype = val;
3590 return 0;
3592 uint32_t
3593 socks5_server_reply_get_bind_addr_ipv4(const socks5_server_reply_t *inp)
3595 return inp->bind_addr_ipv4;
3598 socks5_server_reply_set_bind_addr_ipv4(socks5_server_reply_t *inp, uint32_t val)
3600 inp->bind_addr_ipv4 = val;
3601 return 0;
3603 size_t
3604 socks5_server_reply_getlen_bind_addr_ipv6(const socks5_server_reply_t *inp)
3606 (void)inp; return 16;
3609 uint8_t
3610 socks5_server_reply_get_bind_addr_ipv6(socks5_server_reply_t *inp, size_t idx)
3612 trunnel_assert(idx < 16);
3613 return inp->bind_addr_ipv6[idx];
3616 uint8_t
3617 socks5_server_reply_getconst_bind_addr_ipv6(const socks5_server_reply_t *inp, size_t idx)
3619 return socks5_server_reply_get_bind_addr_ipv6((socks5_server_reply_t*)inp, idx);
3622 socks5_server_reply_set_bind_addr_ipv6(socks5_server_reply_t *inp, size_t idx, uint8_t elt)
3624 trunnel_assert(idx < 16);
3625 inp->bind_addr_ipv6[idx] = elt;
3626 return 0;
3629 uint8_t *
3630 socks5_server_reply_getarray_bind_addr_ipv6(socks5_server_reply_t *inp)
3632 return inp->bind_addr_ipv6;
3634 const uint8_t *
3635 socks5_server_reply_getconstarray_bind_addr_ipv6(const socks5_server_reply_t *inp)
3637 return (const uint8_t *)socks5_server_reply_getarray_bind_addr_ipv6((socks5_server_reply_t*)inp);
3639 struct domainname_st *
3640 socks5_server_reply_get_bind_addr_domainname(socks5_server_reply_t *inp)
3642 return inp->bind_addr_domainname;
3644 const struct domainname_st *
3645 socks5_server_reply_getconst_bind_addr_domainname(const socks5_server_reply_t *inp)
3647 return socks5_server_reply_get_bind_addr_domainname((socks5_server_reply_t*) inp);
3650 socks5_server_reply_set_bind_addr_domainname(socks5_server_reply_t *inp, struct domainname_st *val)
3652 if (inp->bind_addr_domainname && inp->bind_addr_domainname != val)
3653 domainname_free(inp->bind_addr_domainname);
3654 return socks5_server_reply_set0_bind_addr_domainname(inp, val);
3657 socks5_server_reply_set0_bind_addr_domainname(socks5_server_reply_t *inp, struct domainname_st *val)
3659 inp->bind_addr_domainname = val;
3660 return 0;
3662 uint16_t
3663 socks5_server_reply_get_bind_port(const socks5_server_reply_t *inp)
3665 return inp->bind_port;
3668 socks5_server_reply_set_bind_port(socks5_server_reply_t *inp, uint16_t val)
3670 inp->bind_port = val;
3671 return 0;
3673 const char *
3674 socks5_server_reply_check(const socks5_server_reply_t *obj)
3676 if (obj == NULL)
3677 return "Object was NULL";
3678 if (obj->trunnel_error_code_)
3679 return "A set function failed on this object";
3680 if (! (obj->version == 5))
3681 return "Integer out of bounds";
3682 if (! (obj->reserved == 0))
3683 return "Integer out of bounds";
3684 switch (obj->atype) {
3686 case ATYPE_IPV4:
3687 break;
3689 case ATYPE_IPV6:
3690 break;
3692 case ATYPE_DOMAINNAME:
3694 const char *msg;
3695 if (NULL != (msg = domainname_check(obj->bind_addr_domainname)))
3696 return msg;
3698 break;
3700 default:
3701 return "Bad tag for union";
3702 break;
3704 return NULL;
3707 ssize_t
3708 socks5_server_reply_encoded_len(const socks5_server_reply_t *obj)
3710 ssize_t result = 0;
3712 if (NULL != socks5_server_reply_check(obj))
3713 return -1;
3716 /* Length of u8 version IN [5] */
3717 result += 1;
3719 /* Length of u8 reply */
3720 result += 1;
3722 /* Length of u8 reserved IN [0] */
3723 result += 1;
3725 /* Length of u8 atype */
3726 result += 1;
3727 switch (obj->atype) {
3729 case ATYPE_IPV4:
3731 /* Length of u32 bind_addr_ipv4 */
3732 result += 4;
3733 break;
3735 case ATYPE_IPV6:
3737 /* Length of u8 bind_addr_ipv6[16] */
3738 result += 16;
3739 break;
3741 case ATYPE_DOMAINNAME:
3743 /* Length of struct domainname bind_addr_domainname */
3744 result += domainname_encoded_len(obj->bind_addr_domainname);
3745 break;
3747 default:
3748 trunnel_assert(0);
3749 break;
3752 /* Length of u16 bind_port */
3753 result += 2;
3754 return result;
3757 socks5_server_reply_clear_errors(socks5_server_reply_t *obj)
3759 int r = obj->trunnel_error_code_;
3760 obj->trunnel_error_code_ = 0;
3761 return r;
3763 ssize_t
3764 socks5_server_reply_encode(uint8_t *output, const size_t avail, const socks5_server_reply_t *obj)
3766 ssize_t result = 0;
3767 size_t written = 0;
3768 uint8_t *ptr = output;
3769 const char *msg;
3770 #ifdef TRUNNEL_CHECK_ENCODED_LEN
3771 const ssize_t encoded_len = socks5_server_reply_encoded_len(obj);
3772 #endif
3774 if (NULL != (msg = socks5_server_reply_check(obj)))
3775 goto check_failed;
3777 #ifdef TRUNNEL_CHECK_ENCODED_LEN
3778 trunnel_assert(encoded_len >= 0);
3779 #endif
3781 /* Encode u8 version IN [5] */
3782 trunnel_assert(written <= avail);
3783 if (avail - written < 1)
3784 goto truncated;
3785 trunnel_set_uint8(ptr, (obj->version));
3786 written += 1; ptr += 1;
3788 /* Encode u8 reply */
3789 trunnel_assert(written <= avail);
3790 if (avail - written < 1)
3791 goto truncated;
3792 trunnel_set_uint8(ptr, (obj->reply));
3793 written += 1; ptr += 1;
3795 /* Encode u8 reserved IN [0] */
3796 trunnel_assert(written <= avail);
3797 if (avail - written < 1)
3798 goto truncated;
3799 trunnel_set_uint8(ptr, (obj->reserved));
3800 written += 1; ptr += 1;
3802 /* Encode u8 atype */
3803 trunnel_assert(written <= avail);
3804 if (avail - written < 1)
3805 goto truncated;
3806 trunnel_set_uint8(ptr, (obj->atype));
3807 written += 1; ptr += 1;
3809 /* Encode union bind_addr[atype] */
3810 trunnel_assert(written <= avail);
3811 switch (obj->atype) {
3813 case ATYPE_IPV4:
3815 /* Encode u32 bind_addr_ipv4 */
3816 trunnel_assert(written <= avail);
3817 if (avail - written < 4)
3818 goto truncated;
3819 trunnel_set_uint32(ptr, trunnel_htonl(obj->bind_addr_ipv4));
3820 written += 4; ptr += 4;
3821 break;
3823 case ATYPE_IPV6:
3825 /* Encode u8 bind_addr_ipv6[16] */
3826 trunnel_assert(written <= avail);
3827 if (avail - written < 16)
3828 goto truncated;
3829 memcpy(ptr, obj->bind_addr_ipv6, 16);
3830 written += 16; ptr += 16;
3831 break;
3833 case ATYPE_DOMAINNAME:
3835 /* Encode struct domainname bind_addr_domainname */
3836 trunnel_assert(written <= avail);
3837 result = domainname_encode(ptr, avail - written, obj->bind_addr_domainname);
3838 if (result < 0)
3839 goto fail; /* XXXXXXX !*/
3840 written += result; ptr += result;
3841 break;
3843 default:
3844 trunnel_assert(0);
3845 break;
3848 /* Encode u16 bind_port */
3849 trunnel_assert(written <= avail);
3850 if (avail - written < 2)
3851 goto truncated;
3852 trunnel_set_uint16(ptr, trunnel_htons(obj->bind_port));
3853 written += 2; ptr += 2;
3856 trunnel_assert(ptr == output + written);
3857 #ifdef TRUNNEL_CHECK_ENCODED_LEN
3859 trunnel_assert(encoded_len >= 0);
3860 trunnel_assert((size_t)encoded_len == written);
3863 #endif
3865 return written;
3867 truncated:
3868 result = -2;
3869 goto fail;
3870 check_failed:
3871 (void)msg;
3872 result = -1;
3873 goto fail;
3874 fail:
3875 trunnel_assert(result < 0);
3876 return result;
3879 /** As socks5_server_reply_parse(), but do not allocate the output
3880 * object.
3882 static ssize_t
3883 socks5_server_reply_parse_into(socks5_server_reply_t *obj, const uint8_t *input, const size_t len_in)
3885 const uint8_t *ptr = input;
3886 size_t remaining = len_in;
3887 ssize_t result = 0;
3888 (void)result;
3890 /* Parse u8 version IN [5] */
3891 CHECK_REMAINING(1, truncated);
3892 obj->version = (trunnel_get_uint8(ptr));
3893 remaining -= 1; ptr += 1;
3894 if (! (obj->version == 5))
3895 goto fail;
3897 /* Parse u8 reply */
3898 CHECK_REMAINING(1, truncated);
3899 obj->reply = (trunnel_get_uint8(ptr));
3900 remaining -= 1; ptr += 1;
3902 /* Parse u8 reserved IN [0] */
3903 CHECK_REMAINING(1, truncated);
3904 obj->reserved = (trunnel_get_uint8(ptr));
3905 remaining -= 1; ptr += 1;
3906 if (! (obj->reserved == 0))
3907 goto fail;
3909 /* Parse u8 atype */
3910 CHECK_REMAINING(1, truncated);
3911 obj->atype = (trunnel_get_uint8(ptr));
3912 remaining -= 1; ptr += 1;
3914 /* Parse union bind_addr[atype] */
3915 switch (obj->atype) {
3917 case ATYPE_IPV4:
3919 /* Parse u32 bind_addr_ipv4 */
3920 CHECK_REMAINING(4, truncated);
3921 obj->bind_addr_ipv4 = trunnel_ntohl(trunnel_get_uint32(ptr));
3922 remaining -= 4; ptr += 4;
3923 break;
3925 case ATYPE_IPV6:
3927 /* Parse u8 bind_addr_ipv6[16] */
3928 CHECK_REMAINING(16, truncated);
3929 memcpy(obj->bind_addr_ipv6, ptr, 16);
3930 remaining -= 16; ptr += 16;
3931 break;
3933 case ATYPE_DOMAINNAME:
3935 /* Parse struct domainname bind_addr_domainname */
3936 result = domainname_parse(&obj->bind_addr_domainname, ptr, remaining);
3937 if (result < 0)
3938 goto relay_fail;
3939 trunnel_assert((size_t)result <= remaining);
3940 remaining -= result; ptr += result;
3941 break;
3943 default:
3944 goto fail;
3945 break;
3948 /* Parse u16 bind_port */
3949 CHECK_REMAINING(2, truncated);
3950 obj->bind_port = trunnel_ntohs(trunnel_get_uint16(ptr));
3951 remaining -= 2; ptr += 2;
3952 trunnel_assert(ptr + remaining == input + len_in);
3953 return len_in - remaining;
3955 truncated:
3956 return -2;
3957 relay_fail:
3958 trunnel_assert(result < 0);
3959 return result;
3960 fail:
3961 result = -1;
3962 return result;
3965 ssize_t
3966 socks5_server_reply_parse(socks5_server_reply_t **output, const uint8_t *input, const size_t len_in)
3968 ssize_t result;
3969 *output = socks5_server_reply_new();
3970 if (NULL == *output)
3971 return -1;
3972 result = socks5_server_reply_parse_into(*output, input, len_in);
3973 if (result < 0) {
3974 socks5_server_reply_free(*output);
3975 *output = NULL;
3977 return result;