From f27dc41627517ebec3feae6ca00eee544d9dcd59 Mon Sep 17 00:00:00 2001 From: rl1987 Date: Tue, 26 Jun 2018 19:31:26 +0300 Subject: Remove prop229 stuff from socks5.trunnel --- src/trunnel/socks5.c | 2128 +++++++++++++------------------------------------- 1 file changed, 526 insertions(+), 1602 deletions(-) (limited to 'src/trunnel/socks5.c') diff --git a/src/trunnel/socks5.c b/src/trunnel/socks5.c index 7f4702fb5d..9e5f6fcfed 100644 --- a/src/trunnel/socks5.c +++ b/src/trunnel/socks5.c @@ -3029,1585 +3029,358 @@ socks5_server_userpass_auth_parse(socks5_server_userpass_auth_t **output, const } return result; } -tor_socksauth_keyval_t * -tor_socksauth_keyval_new(void) +socks5_client_request_t * +socks5_client_request_new(void) { - tor_socksauth_keyval_t *val = trunnel_calloc(1, sizeof(tor_socksauth_keyval_t)); + socks5_client_request_t *val = trunnel_calloc(1, sizeof(socks5_client_request_t)); if (NULL == val) return NULL; + val->version = 5; + val->command = CMD_BIND; return val; } /** Release all storage held inside 'obj', but do not free 'obj'. */ static void -tor_socksauth_keyval_clear(tor_socksauth_keyval_t *obj) +socks5_client_request_clear(socks5_client_request_t *obj) { (void) obj; - TRUNNEL_DYNARRAY_WIPE(&obj->key); - TRUNNEL_DYNARRAY_CLEAR(&obj->key); - TRUNNEL_DYNARRAY_WIPE(&obj->val); - TRUNNEL_DYNARRAY_CLEAR(&obj->val); + domainname_free(obj->dest_addr_domainname); + obj->dest_addr_domainname = NULL; } void -tor_socksauth_keyval_free(tor_socksauth_keyval_t *obj) +socks5_client_request_free(socks5_client_request_t *obj) { if (obj == NULL) return; - tor_socksauth_keyval_clear(obj); - trunnel_memwipe(obj, sizeof(tor_socksauth_keyval_t)); + socks5_client_request_clear(obj); + trunnel_memwipe(obj, sizeof(socks5_client_request_t)); trunnel_free_(obj); } -uint16_t -tor_socksauth_keyval_get_keylen(const tor_socksauth_keyval_t *inp) +uint8_t +socks5_client_request_get_version(const socks5_client_request_t *inp) { - return inp->keylen; + return inp->version; } int -tor_socksauth_keyval_set_keylen(tor_socksauth_keyval_t *inp, uint16_t val) +socks5_client_request_set_version(socks5_client_request_t *inp, uint8_t val) { - inp->keylen = val; + if (! ((val == 5))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->version = val; return 0; } -size_t -tor_socksauth_keyval_getlen_key(const tor_socksauth_keyval_t *inp) -{ - return TRUNNEL_DYNARRAY_LEN(&inp->key); -} - -char -tor_socksauth_keyval_get_key(tor_socksauth_keyval_t *inp, size_t idx) -{ - return TRUNNEL_DYNARRAY_GET(&inp->key, idx); -} - -char -tor_socksauth_keyval_getconst_key(const tor_socksauth_keyval_t *inp, size_t idx) -{ - return tor_socksauth_keyval_get_key((tor_socksauth_keyval_t*)inp, idx); -} -int -tor_socksauth_keyval_set_key(tor_socksauth_keyval_t *inp, size_t idx, char elt) +uint8_t +socks5_client_request_get_command(const socks5_client_request_t *inp) { - TRUNNEL_DYNARRAY_SET(&inp->key, idx, elt); - return 0; + return inp->command; } int -tor_socksauth_keyval_add_key(tor_socksauth_keyval_t *inp, char elt) +socks5_client_request_set_command(socks5_client_request_t *inp, uint8_t val) { -#if SIZE_MAX >= UINT16_MAX - if (inp->key.n_ == UINT16_MAX) - goto trunnel_alloc_failed; -#endif - TRUNNEL_DYNARRAY_ADD(char, &inp->key, elt, {}); + if (! ((val == CMD_BIND || val == CMD_CONNECT || val == CMD_RESOLVE || val == CMD_RESOLVE_PTR || val == CMD_UDP_ASSOCIATE))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->command = val; return 0; - trunnel_alloc_failed: - TRUNNEL_SET_ERROR_CODE(inp); - return -1; } - -char * -tor_socksauth_keyval_getarray_key(tor_socksauth_keyval_t *inp) -{ - return inp->key.elts_; -} -const char * -tor_socksauth_keyval_getconstarray_key(const tor_socksauth_keyval_t *inp) +uint8_t +socks5_client_request_get_reserved(const socks5_client_request_t *inp) { - return (const char *)tor_socksauth_keyval_getarray_key((tor_socksauth_keyval_t*)inp); + return inp->reserved; } int -tor_socksauth_keyval_setlen_key(tor_socksauth_keyval_t *inp, size_t newlen) -{ -#if UINT16_MAX < SIZE_MAX - if (newlen > UINT16_MAX) - goto trunnel_alloc_failed; -#endif - return trunnel_string_setlen(&inp->key, newlen, - &inp->trunnel_error_code_); - trunnel_alloc_failed: - TRUNNEL_SET_ERROR_CODE(inp); - return -1; -} -const char * -tor_socksauth_keyval_getstr_key(tor_socksauth_keyval_t *inp) +socks5_client_request_set_reserved(socks5_client_request_t *inp, uint8_t val) { - return trunnel_string_getstr(&inp->key); + if (! ((val == 0))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->reserved = val; + return 0; } -int -tor_socksauth_keyval_setstr0_key(tor_socksauth_keyval_t *inp, const char *val, size_t len) +uint8_t +socks5_client_request_get_atype(const socks5_client_request_t *inp) { -#if UINT16_MAX < SIZE_MAX - if (len > UINT16_MAX) { - TRUNNEL_SET_ERROR_CODE(inp); - return -1; - } -#endif - return trunnel_string_setstr0(&inp->key, val, len, &inp->trunnel_error_code_); + return inp->atype; } int -tor_socksauth_keyval_setstr_key(tor_socksauth_keyval_t *inp, const char *val) +socks5_client_request_set_atype(socks5_client_request_t *inp, uint8_t val) { - return tor_socksauth_keyval_setstr0_key(inp, val, strlen(val)); + inp->atype = val; + return 0; } -uint16_t -tor_socksauth_keyval_get_vallen(const tor_socksauth_keyval_t *inp) +uint32_t +socks5_client_request_get_dest_addr_ipv4(const socks5_client_request_t *inp) { - return inp->vallen; + return inp->dest_addr_ipv4; } int -tor_socksauth_keyval_set_vallen(tor_socksauth_keyval_t *inp, uint16_t val) +socks5_client_request_set_dest_addr_ipv4(socks5_client_request_t *inp, uint32_t val) { - inp->vallen = val; + inp->dest_addr_ipv4 = val; return 0; } size_t -tor_socksauth_keyval_getlen_val(const tor_socksauth_keyval_t *inp) +socks5_client_request_getlen_dest_addr_ipv6(const socks5_client_request_t *inp) { - return TRUNNEL_DYNARRAY_LEN(&inp->val); + (void)inp; return 16; } -char -tor_socksauth_keyval_get_val(tor_socksauth_keyval_t *inp, size_t idx) +uint8_t +socks5_client_request_get_dest_addr_ipv6(socks5_client_request_t *inp, size_t idx) { - return TRUNNEL_DYNARRAY_GET(&inp->val, idx); + trunnel_assert(idx < 16); + return inp->dest_addr_ipv6[idx]; } -char -tor_socksauth_keyval_getconst_val(const tor_socksauth_keyval_t *inp, size_t idx) -{ - return tor_socksauth_keyval_get_val((tor_socksauth_keyval_t*)inp, idx); -} -int -tor_socksauth_keyval_set_val(tor_socksauth_keyval_t *inp, size_t idx, char elt) +uint8_t +socks5_client_request_getconst_dest_addr_ipv6(const socks5_client_request_t *inp, size_t idx) { - TRUNNEL_DYNARRAY_SET(&inp->val, idx, elt); - return 0; + return socks5_client_request_get_dest_addr_ipv6((socks5_client_request_t*)inp, idx); } int -tor_socksauth_keyval_add_val(tor_socksauth_keyval_t *inp, char elt) +socks5_client_request_set_dest_addr_ipv6(socks5_client_request_t *inp, size_t idx, uint8_t elt) { -#if SIZE_MAX >= UINT16_MAX - if (inp->val.n_ == UINT16_MAX) - goto trunnel_alloc_failed; -#endif - TRUNNEL_DYNARRAY_ADD(char, &inp->val, elt, {}); + trunnel_assert(idx < 16); + inp->dest_addr_ipv6[idx] = elt; return 0; - trunnel_alloc_failed: - TRUNNEL_SET_ERROR_CODE(inp); - return -1; } -char * -tor_socksauth_keyval_getarray_val(tor_socksauth_keyval_t *inp) +uint8_t * +socks5_client_request_getarray_dest_addr_ipv6(socks5_client_request_t *inp) { - return inp->val.elts_; + return inp->dest_addr_ipv6; } -const char * -tor_socksauth_keyval_getconstarray_val(const tor_socksauth_keyval_t *inp) +const uint8_t * +socks5_client_request_getconstarray_dest_addr_ipv6(const socks5_client_request_t *inp) { - return (const char *)tor_socksauth_keyval_getarray_val((tor_socksauth_keyval_t*)inp); + return (const uint8_t *)socks5_client_request_getarray_dest_addr_ipv6((socks5_client_request_t*)inp); } -int -tor_socksauth_keyval_setlen_val(tor_socksauth_keyval_t *inp, size_t newlen) +struct domainname_st * +socks5_client_request_get_dest_addr_domainname(socks5_client_request_t *inp) { -#if UINT16_MAX < SIZE_MAX - if (newlen > UINT16_MAX) - goto trunnel_alloc_failed; -#endif - return trunnel_string_setlen(&inp->val, newlen, - &inp->trunnel_error_code_); - trunnel_alloc_failed: - TRUNNEL_SET_ERROR_CODE(inp); - return -1; + return inp->dest_addr_domainname; } -const char * -tor_socksauth_keyval_getstr_val(tor_socksauth_keyval_t *inp) +const struct domainname_st * +socks5_client_request_getconst_dest_addr_domainname(const socks5_client_request_t *inp) { - return trunnel_string_getstr(&inp->val); + return socks5_client_request_get_dest_addr_domainname((socks5_client_request_t*) inp); } int -tor_socksauth_keyval_setstr0_val(tor_socksauth_keyval_t *inp, const char *val, size_t len) +socks5_client_request_set_dest_addr_domainname(socks5_client_request_t *inp, struct domainname_st *val) { -#if UINT16_MAX < SIZE_MAX - if (len > UINT16_MAX) { - TRUNNEL_SET_ERROR_CODE(inp); - return -1; - } -#endif - return trunnel_string_setstr0(&inp->val, val, len, &inp->trunnel_error_code_); + if (inp->dest_addr_domainname && inp->dest_addr_domainname != val) + domainname_free(inp->dest_addr_domainname); + return socks5_client_request_set0_dest_addr_domainname(inp, val); } int -tor_socksauth_keyval_setstr_val(tor_socksauth_keyval_t *inp, const char *val) -{ - return tor_socksauth_keyval_setstr0_val(inp, val, strlen(val)); -} -const char * -tor_socksauth_keyval_check(const tor_socksauth_keyval_t *obj) +socks5_client_request_set0_dest_addr_domainname(socks5_client_request_t *inp, struct domainname_st *val) { - if (obj == NULL) - return "Object was NULL"; - if (obj->trunnel_error_code_) - return "A set function failed on this object"; - if (TRUNNEL_DYNARRAY_LEN(&obj->key) != obj->keylen) - return "Length mismatch for key"; - if (TRUNNEL_DYNARRAY_LEN(&obj->val) != obj->vallen) - return "Length mismatch for val"; - return NULL; + inp->dest_addr_domainname = val; + return 0; } - -ssize_t -tor_socksauth_keyval_encoded_len(const tor_socksauth_keyval_t *obj) +uint16_t +socks5_client_request_get_dest_port(const socks5_client_request_t *inp) { - ssize_t result = 0; - - if (NULL != tor_socksauth_keyval_check(obj)) - return -1; - - - /* Length of u16 keylen */ - result += 2; - - /* Length of char key[keylen] */ - result += TRUNNEL_DYNARRAY_LEN(&obj->key); - - /* Length of u16 vallen */ - result += 2; - - /* Length of char val[vallen] */ - result += TRUNNEL_DYNARRAY_LEN(&obj->val); - return result; -} -int -tor_socksauth_keyval_clear_errors(tor_socksauth_keyval_t *obj) -{ - int r = obj->trunnel_error_code_; - obj->trunnel_error_code_ = 0; - return r; -} -ssize_t -tor_socksauth_keyval_encode(uint8_t *output, const size_t avail, const tor_socksauth_keyval_t *obj) -{ - ssize_t result = 0; - size_t written = 0; - uint8_t *ptr = output; - const char *msg; -#ifdef TRUNNEL_CHECK_ENCODED_LEN - const ssize_t encoded_len = tor_socksauth_keyval_encoded_len(obj); -#endif - - if (NULL != (msg = tor_socksauth_keyval_check(obj))) - goto check_failed; - -#ifdef TRUNNEL_CHECK_ENCODED_LEN - trunnel_assert(encoded_len >= 0); -#endif - - /* Encode u16 keylen */ - trunnel_assert(written <= avail); - if (avail - written < 2) - goto truncated; - trunnel_set_uint16(ptr, trunnel_htons(obj->keylen)); - written += 2; ptr += 2; - - /* Encode char key[keylen] */ - { - size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->key); - trunnel_assert(obj->keylen == elt_len); - trunnel_assert(written <= avail); - if (avail - written < elt_len) - goto truncated; - if (elt_len) - memcpy(ptr, obj->key.elts_, elt_len); - written += elt_len; ptr += elt_len; - } - - /* Encode u16 vallen */ - trunnel_assert(written <= avail); - if (avail - written < 2) - goto truncated; - trunnel_set_uint16(ptr, trunnel_htons(obj->vallen)); - written += 2; ptr += 2; - - /* Encode char val[vallen] */ - { - size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->val); - trunnel_assert(obj->vallen == elt_len); - trunnel_assert(written <= avail); - if (avail - written < elt_len) - goto truncated; - if (elt_len) - memcpy(ptr, obj->val.elts_, elt_len); - written += elt_len; ptr += elt_len; - } - - - trunnel_assert(ptr == output + written); -#ifdef TRUNNEL_CHECK_ENCODED_LEN - { - trunnel_assert(encoded_len >= 0); - trunnel_assert((size_t)encoded_len == written); - } - -#endif - - return written; - - truncated: - result = -2; - goto fail; - check_failed: - (void)msg; - result = -1; - goto fail; - fail: - trunnel_assert(result < 0); - return result; -} - -/** As tor_socksauth_keyval_parse(), but do not allocate the output - * object. - */ -static ssize_t -tor_socksauth_keyval_parse_into(tor_socksauth_keyval_t *obj, const uint8_t *input, const size_t len_in) -{ - const uint8_t *ptr = input; - size_t remaining = len_in; - ssize_t result = 0; - (void)result; - - /* Parse u16 keylen */ - CHECK_REMAINING(2, truncated); - obj->keylen = trunnel_ntohs(trunnel_get_uint16(ptr)); - remaining -= 2; ptr += 2; - - /* Parse char key[keylen] */ - CHECK_REMAINING(obj->keylen, truncated); - if (tor_socksauth_keyval_setstr0_key(obj, (const char*)ptr, obj->keylen)) - goto fail; - ptr += obj->keylen; remaining -= obj->keylen; - - /* Parse u16 vallen */ - CHECK_REMAINING(2, truncated); - obj->vallen = trunnel_ntohs(trunnel_get_uint16(ptr)); - remaining -= 2; ptr += 2; - - /* Parse char val[vallen] */ - CHECK_REMAINING(obj->vallen, truncated); - if (tor_socksauth_keyval_setstr0_val(obj, (const char*)ptr, obj->vallen)) - goto fail; - ptr += obj->vallen; remaining -= obj->vallen; - trunnel_assert(ptr + remaining == input + len_in); - return len_in - remaining; - - truncated: - return -2; - fail: - result = -1; - return result; -} - -ssize_t -tor_socksauth_keyval_parse(tor_socksauth_keyval_t **output, const uint8_t *input, const size_t len_in) -{ - ssize_t result; - *output = tor_socksauth_keyval_new(); - if (NULL == *output) - return -1; - result = tor_socksauth_keyval_parse_into(*output, input, len_in); - if (result < 0) { - tor_socksauth_keyval_free(*output); - *output = NULL; - } - return result; -} -socks5_client_request_t * -socks5_client_request_new(void) -{ - socks5_client_request_t *val = trunnel_calloc(1, sizeof(socks5_client_request_t)); - if (NULL == val) - return NULL; - val->version = 5; - val->command = CMD_BIND; - return val; -} - -/** Release all storage held inside 'obj', but do not free 'obj'. - */ -static void -socks5_client_request_clear(socks5_client_request_t *obj) -{ - (void) obj; - domainname_free(obj->dest_addr_domainname); - obj->dest_addr_domainname = NULL; -} - -void -socks5_client_request_free(socks5_client_request_t *obj) -{ - if (obj == NULL) - return; - socks5_client_request_clear(obj); - trunnel_memwipe(obj, sizeof(socks5_client_request_t)); - trunnel_free_(obj); -} - -uint8_t -socks5_client_request_get_version(const socks5_client_request_t *inp) -{ - return inp->version; -} -int -socks5_client_request_set_version(socks5_client_request_t *inp, uint8_t val) -{ - if (! ((val == 5))) { - TRUNNEL_SET_ERROR_CODE(inp); - return -1; - } - inp->version = val; - return 0; -} -uint8_t -socks5_client_request_get_command(const socks5_client_request_t *inp) -{ - return inp->command; -} -int -socks5_client_request_set_command(socks5_client_request_t *inp, uint8_t val) -{ - if (! ((val == CMD_BIND || val == CMD_CONNECT || val == CMD_RESOLVE || val == CMD_RESOLVE_PTR || val == CMD_UDP_ASSOCIATE))) { - TRUNNEL_SET_ERROR_CODE(inp); - return -1; - } - inp->command = val; - return 0; -} -uint8_t -socks5_client_request_get_reserved(const socks5_client_request_t *inp) -{ - return inp->reserved; -} -int -socks5_client_request_set_reserved(socks5_client_request_t *inp, uint8_t val) -{ - if (! ((val == 0))) { - TRUNNEL_SET_ERROR_CODE(inp); - return -1; - } - inp->reserved = val; - return 0; -} -uint8_t -socks5_client_request_get_atype(const socks5_client_request_t *inp) -{ - return inp->atype; -} -int -socks5_client_request_set_atype(socks5_client_request_t *inp, uint8_t val) -{ - inp->atype = val; - return 0; -} -uint32_t -socks5_client_request_get_dest_addr_ipv4(const socks5_client_request_t *inp) -{ - return inp->dest_addr_ipv4; -} -int -socks5_client_request_set_dest_addr_ipv4(socks5_client_request_t *inp, uint32_t val) -{ - inp->dest_addr_ipv4 = val; - return 0; -} -size_t -socks5_client_request_getlen_dest_addr_ipv6(const socks5_client_request_t *inp) -{ - (void)inp; return 16; -} - -uint8_t -socks5_client_request_get_dest_addr_ipv6(socks5_client_request_t *inp, size_t idx) -{ - trunnel_assert(idx < 16); - return inp->dest_addr_ipv6[idx]; -} - -uint8_t -socks5_client_request_getconst_dest_addr_ipv6(const socks5_client_request_t *inp, size_t idx) -{ - return socks5_client_request_get_dest_addr_ipv6((socks5_client_request_t*)inp, idx); -} -int -socks5_client_request_set_dest_addr_ipv6(socks5_client_request_t *inp, size_t idx, uint8_t elt) -{ - trunnel_assert(idx < 16); - inp->dest_addr_ipv6[idx] = elt; - return 0; -} - -uint8_t * -socks5_client_request_getarray_dest_addr_ipv6(socks5_client_request_t *inp) -{ - return inp->dest_addr_ipv6; -} -const uint8_t * -socks5_client_request_getconstarray_dest_addr_ipv6(const socks5_client_request_t *inp) -{ - return (const uint8_t *)socks5_client_request_getarray_dest_addr_ipv6((socks5_client_request_t*)inp); -} -struct domainname_st * -socks5_client_request_get_dest_addr_domainname(socks5_client_request_t *inp) -{ - return inp->dest_addr_domainname; -} -const struct domainname_st * -socks5_client_request_getconst_dest_addr_domainname(const socks5_client_request_t *inp) -{ - return socks5_client_request_get_dest_addr_domainname((socks5_client_request_t*) inp); -} -int -socks5_client_request_set_dest_addr_domainname(socks5_client_request_t *inp, struct domainname_st *val) -{ - if (inp->dest_addr_domainname && inp->dest_addr_domainname != val) - domainname_free(inp->dest_addr_domainname); - return socks5_client_request_set0_dest_addr_domainname(inp, val); -} -int -socks5_client_request_set0_dest_addr_domainname(socks5_client_request_t *inp, struct domainname_st *val) -{ - inp->dest_addr_domainname = val; - return 0; -} -uint16_t -socks5_client_request_get_dest_port(const socks5_client_request_t *inp) -{ - return inp->dest_port; + return inp->dest_port; } int socks5_client_request_set_dest_port(socks5_client_request_t *inp, uint16_t val) { - inp->dest_port = val; - return 0; -} -const char * -socks5_client_request_check(const socks5_client_request_t *obj) -{ - if (obj == NULL) - return "Object was NULL"; - if (obj->trunnel_error_code_) - return "A set function failed on this object"; - if (! (obj->version == 5)) - return "Integer out of bounds"; - if (! (obj->command == CMD_BIND || obj->command == CMD_CONNECT || obj->command == CMD_RESOLVE || obj->command == CMD_RESOLVE_PTR || obj->command == CMD_UDP_ASSOCIATE)) - return "Integer out of bounds"; - if (! (obj->reserved == 0)) - return "Integer out of bounds"; - switch (obj->atype) { - - case ATYPE_IPV4: - break; - - case ATYPE_IPV6: - break; - - case ATYPE_DOMAINNAME: - { - const char *msg; - if (NULL != (msg = domainname_check(obj->dest_addr_domainname))) - return msg; - } - break; - - default: - return "Bad tag for union"; - break; - } - return NULL; -} - -ssize_t -socks5_client_request_encoded_len(const socks5_client_request_t *obj) -{ - ssize_t result = 0; - - if (NULL != socks5_client_request_check(obj)) - return -1; - - - /* Length of u8 version IN [5] */ - result += 1; - - /* Length of u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR, CMD_UDP_ASSOCIATE] */ - result += 1; - - /* Length of u8 reserved IN [0] */ - result += 1; - - /* Length of u8 atype */ - result += 1; - switch (obj->atype) { - - case ATYPE_IPV4: - - /* Length of u32 dest_addr_ipv4 */ - result += 4; - break; - - case ATYPE_IPV6: - - /* Length of u8 dest_addr_ipv6[16] */ - result += 16; - break; - - case ATYPE_DOMAINNAME: - - /* Length of struct domainname dest_addr_domainname */ - result += domainname_encoded_len(obj->dest_addr_domainname); - break; - - default: - trunnel_assert(0); - break; - } - - /* Length of u16 dest_port */ - result += 2; - return result; -} -int -socks5_client_request_clear_errors(socks5_client_request_t *obj) -{ - int r = obj->trunnel_error_code_; - obj->trunnel_error_code_ = 0; - return r; -} -ssize_t -socks5_client_request_encode(uint8_t *output, const size_t avail, const socks5_client_request_t *obj) -{ - ssize_t result = 0; - size_t written = 0; - uint8_t *ptr = output; - const char *msg; -#ifdef TRUNNEL_CHECK_ENCODED_LEN - const ssize_t encoded_len = socks5_client_request_encoded_len(obj); -#endif - - if (NULL != (msg = socks5_client_request_check(obj))) - goto check_failed; - -#ifdef TRUNNEL_CHECK_ENCODED_LEN - trunnel_assert(encoded_len >= 0); -#endif - - /* Encode u8 version IN [5] */ - trunnel_assert(written <= avail); - if (avail - written < 1) - goto truncated; - trunnel_set_uint8(ptr, (obj->version)); - written += 1; ptr += 1; - - /* Encode u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR, CMD_UDP_ASSOCIATE] */ - trunnel_assert(written <= avail); - if (avail - written < 1) - goto truncated; - trunnel_set_uint8(ptr, (obj->command)); - written += 1; ptr += 1; - - /* Encode u8 reserved IN [0] */ - trunnel_assert(written <= avail); - if (avail - written < 1) - goto truncated; - trunnel_set_uint8(ptr, (obj->reserved)); - written += 1; ptr += 1; - - /* Encode u8 atype */ - trunnel_assert(written <= avail); - if (avail - written < 1) - goto truncated; - trunnel_set_uint8(ptr, (obj->atype)); - written += 1; ptr += 1; - - /* Encode union dest_addr[atype] */ - trunnel_assert(written <= avail); - switch (obj->atype) { - - case ATYPE_IPV4: - - /* Encode u32 dest_addr_ipv4 */ - trunnel_assert(written <= avail); - if (avail - written < 4) - goto truncated; - trunnel_set_uint32(ptr, trunnel_htonl(obj->dest_addr_ipv4)); - written += 4; ptr += 4; - break; - - case ATYPE_IPV6: - - /* Encode u8 dest_addr_ipv6[16] */ - trunnel_assert(written <= avail); - if (avail - written < 16) - goto truncated; - memcpy(ptr, obj->dest_addr_ipv6, 16); - written += 16; ptr += 16; - break; - - case ATYPE_DOMAINNAME: - - /* Encode struct domainname dest_addr_domainname */ - trunnel_assert(written <= avail); - result = domainname_encode(ptr, avail - written, obj->dest_addr_domainname); - if (result < 0) - goto fail; /* XXXXXXX !*/ - written += result; ptr += result; - break; - - default: - trunnel_assert(0); - break; - } - - /* Encode u16 dest_port */ - trunnel_assert(written <= avail); - if (avail - written < 2) - goto truncated; - trunnel_set_uint16(ptr, trunnel_htons(obj->dest_port)); - written += 2; ptr += 2; - - - trunnel_assert(ptr == output + written); -#ifdef TRUNNEL_CHECK_ENCODED_LEN - { - trunnel_assert(encoded_len >= 0); - trunnel_assert((size_t)encoded_len == written); - } - -#endif - - return written; - - truncated: - result = -2; - goto fail; - check_failed: - (void)msg; - result = -1; - goto fail; - fail: - trunnel_assert(result < 0); - return result; -} - -/** As socks5_client_request_parse(), but do not allocate the output - * object. - */ -static ssize_t -socks5_client_request_parse_into(socks5_client_request_t *obj, const uint8_t *input, const size_t len_in) -{ - const uint8_t *ptr = input; - size_t remaining = len_in; - ssize_t result = 0; - (void)result; - - /* Parse u8 version IN [5] */ - CHECK_REMAINING(1, truncated); - obj->version = (trunnel_get_uint8(ptr)); - remaining -= 1; ptr += 1; - if (! (obj->version == 5)) - goto fail; - - /* Parse u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR, CMD_UDP_ASSOCIATE] */ - CHECK_REMAINING(1, truncated); - obj->command = (trunnel_get_uint8(ptr)); - remaining -= 1; ptr += 1; - if (! (obj->command == CMD_BIND || obj->command == CMD_CONNECT || obj->command == CMD_RESOLVE || obj->command == CMD_RESOLVE_PTR || obj->command == CMD_UDP_ASSOCIATE)) - goto fail; - - /* Parse u8 reserved IN [0] */ - CHECK_REMAINING(1, truncated); - obj->reserved = (trunnel_get_uint8(ptr)); - remaining -= 1; ptr += 1; - if (! (obj->reserved == 0)) - goto fail; - - /* Parse u8 atype */ - CHECK_REMAINING(1, truncated); - obj->atype = (trunnel_get_uint8(ptr)); - remaining -= 1; ptr += 1; - - /* Parse union dest_addr[atype] */ - switch (obj->atype) { - - case ATYPE_IPV4: - - /* Parse u32 dest_addr_ipv4 */ - CHECK_REMAINING(4, truncated); - obj->dest_addr_ipv4 = trunnel_ntohl(trunnel_get_uint32(ptr)); - remaining -= 4; ptr += 4; - break; - - case ATYPE_IPV6: - - /* Parse u8 dest_addr_ipv6[16] */ - CHECK_REMAINING(16, truncated); - memcpy(obj->dest_addr_ipv6, ptr, 16); - remaining -= 16; ptr += 16; - break; - - case ATYPE_DOMAINNAME: - - /* Parse struct domainname dest_addr_domainname */ - result = domainname_parse(&obj->dest_addr_domainname, ptr, remaining); - if (result < 0) - goto relay_fail; - trunnel_assert((size_t)result <= remaining); - remaining -= result; ptr += result; - break; - - default: - goto fail; - break; - } - - /* Parse u16 dest_port */ - CHECK_REMAINING(2, truncated); - obj->dest_port = trunnel_ntohs(trunnel_get_uint16(ptr)); - remaining -= 2; ptr += 2; - trunnel_assert(ptr + remaining == input + len_in); - return len_in - remaining; - - truncated: - return -2; - relay_fail: - trunnel_assert(result < 0); - return result; - fail: - result = -1; - return result; -} - -ssize_t -socks5_client_request_parse(socks5_client_request_t **output, const uint8_t *input, const size_t len_in) -{ - ssize_t result; - *output = socks5_client_request_new(); - if (NULL == *output) - return -1; - result = socks5_client_request_parse_into(*output, input, len_in); - if (result < 0) { - socks5_client_request_free(*output); - *output = NULL; - } - return result; -} -socks5_server_reply_t * -socks5_server_reply_new(void) -{ - socks5_server_reply_t *val = trunnel_calloc(1, sizeof(socks5_server_reply_t)); - if (NULL == val) - return NULL; - val->version = 5; - return val; -} - -/** Release all storage held inside 'obj', but do not free 'obj'. - */ -static void -socks5_server_reply_clear(socks5_server_reply_t *obj) -{ - (void) obj; - domainname_free(obj->bind_addr_domainname); - obj->bind_addr_domainname = NULL; -} - -void -socks5_server_reply_free(socks5_server_reply_t *obj) -{ - if (obj == NULL) - return; - socks5_server_reply_clear(obj); - trunnel_memwipe(obj, sizeof(socks5_server_reply_t)); - trunnel_free_(obj); -} - -uint8_t -socks5_server_reply_get_version(const socks5_server_reply_t *inp) -{ - return inp->version; -} -int -socks5_server_reply_set_version(socks5_server_reply_t *inp, uint8_t val) -{ - if (! ((val == 5))) { - TRUNNEL_SET_ERROR_CODE(inp); - return -1; - } - inp->version = val; - return 0; -} -uint8_t -socks5_server_reply_get_reply(const socks5_server_reply_t *inp) -{ - return inp->reply; -} -int -socks5_server_reply_set_reply(socks5_server_reply_t *inp, uint8_t val) -{ - inp->reply = val; - return 0; -} -uint8_t -socks5_server_reply_get_reserved(const socks5_server_reply_t *inp) -{ - return inp->reserved; -} -int -socks5_server_reply_set_reserved(socks5_server_reply_t *inp, uint8_t val) -{ - if (! ((val == 0))) { - TRUNNEL_SET_ERROR_CODE(inp); - return -1; - } - inp->reserved = val; - return 0; -} -uint8_t -socks5_server_reply_get_atype(const socks5_server_reply_t *inp) -{ - return inp->atype; -} -int -socks5_server_reply_set_atype(socks5_server_reply_t *inp, uint8_t val) -{ - inp->atype = val; - return 0; -} -uint32_t -socks5_server_reply_get_bind_addr_ipv4(const socks5_server_reply_t *inp) -{ - return inp->bind_addr_ipv4; -} -int -socks5_server_reply_set_bind_addr_ipv4(socks5_server_reply_t *inp, uint32_t val) -{ - inp->bind_addr_ipv4 = val; - return 0; -} -size_t -socks5_server_reply_getlen_bind_addr_ipv6(const socks5_server_reply_t *inp) -{ - (void)inp; return 16; -} - -uint8_t -socks5_server_reply_get_bind_addr_ipv6(socks5_server_reply_t *inp, size_t idx) -{ - trunnel_assert(idx < 16); - return inp->bind_addr_ipv6[idx]; -} - -uint8_t -socks5_server_reply_getconst_bind_addr_ipv6(const socks5_server_reply_t *inp, size_t idx) -{ - return socks5_server_reply_get_bind_addr_ipv6((socks5_server_reply_t*)inp, idx); -} -int -socks5_server_reply_set_bind_addr_ipv6(socks5_server_reply_t *inp, size_t idx, uint8_t elt) -{ - trunnel_assert(idx < 16); - inp->bind_addr_ipv6[idx] = elt; - return 0; -} - -uint8_t * -socks5_server_reply_getarray_bind_addr_ipv6(socks5_server_reply_t *inp) -{ - return inp->bind_addr_ipv6; -} -const uint8_t * -socks5_server_reply_getconstarray_bind_addr_ipv6(const socks5_server_reply_t *inp) -{ - return (const uint8_t *)socks5_server_reply_getarray_bind_addr_ipv6((socks5_server_reply_t*)inp); -} -struct domainname_st * -socks5_server_reply_get_bind_addr_domainname(socks5_server_reply_t *inp) -{ - return inp->bind_addr_domainname; -} -const struct domainname_st * -socks5_server_reply_getconst_bind_addr_domainname(const socks5_server_reply_t *inp) -{ - return socks5_server_reply_get_bind_addr_domainname((socks5_server_reply_t*) inp); -} -int -socks5_server_reply_set_bind_addr_domainname(socks5_server_reply_t *inp, struct domainname_st *val) -{ - if (inp->bind_addr_domainname && inp->bind_addr_domainname != val) - domainname_free(inp->bind_addr_domainname); - return socks5_server_reply_set0_bind_addr_domainname(inp, val); -} -int -socks5_server_reply_set0_bind_addr_domainname(socks5_server_reply_t *inp, struct domainname_st *val) -{ - inp->bind_addr_domainname = val; - return 0; -} -uint16_t -socks5_server_reply_get_bind_port(const socks5_server_reply_t *inp) -{ - return inp->bind_port; -} -int -socks5_server_reply_set_bind_port(socks5_server_reply_t *inp, uint16_t val) -{ - inp->bind_port = val; - return 0; -} -const char * -socks5_server_reply_check(const socks5_server_reply_t *obj) -{ - if (obj == NULL) - return "Object was NULL"; - if (obj->trunnel_error_code_) - return "A set function failed on this object"; - if (! (obj->version == 5)) - return "Integer out of bounds"; - if (! (obj->reserved == 0)) - return "Integer out of bounds"; - switch (obj->atype) { - - case ATYPE_IPV4: - break; - - case ATYPE_IPV6: - break; - - case ATYPE_DOMAINNAME: - { - const char *msg; - if (NULL != (msg = domainname_check(obj->bind_addr_domainname))) - return msg; - } - break; - - default: - return "Bad tag for union"; - break; - } - return NULL; -} - -ssize_t -socks5_server_reply_encoded_len(const socks5_server_reply_t *obj) -{ - ssize_t result = 0; - - if (NULL != socks5_server_reply_check(obj)) - return -1; - - - /* Length of u8 version IN [5] */ - result += 1; - - /* Length of u8 reply */ - result += 1; - - /* Length of u8 reserved IN [0] */ - result += 1; - - /* Length of u8 atype */ - result += 1; - switch (obj->atype) { - - case ATYPE_IPV4: - - /* Length of u32 bind_addr_ipv4 */ - result += 4; - break; - - case ATYPE_IPV6: - - /* Length of u8 bind_addr_ipv6[16] */ - result += 16; - break; - - case ATYPE_DOMAINNAME: - - /* Length of struct domainname bind_addr_domainname */ - result += domainname_encoded_len(obj->bind_addr_domainname); - break; - - default: - trunnel_assert(0); - break; - } - - /* Length of u16 bind_port */ - result += 2; - return result; -} -int -socks5_server_reply_clear_errors(socks5_server_reply_t *obj) -{ - int r = obj->trunnel_error_code_; - obj->trunnel_error_code_ = 0; - return r; -} -ssize_t -socks5_server_reply_encode(uint8_t *output, const size_t avail, const socks5_server_reply_t *obj) -{ - ssize_t result = 0; - size_t written = 0; - uint8_t *ptr = output; - const char *msg; -#ifdef TRUNNEL_CHECK_ENCODED_LEN - const ssize_t encoded_len = socks5_server_reply_encoded_len(obj); -#endif - - if (NULL != (msg = socks5_server_reply_check(obj))) - goto check_failed; - -#ifdef TRUNNEL_CHECK_ENCODED_LEN - trunnel_assert(encoded_len >= 0); -#endif - - /* Encode u8 version IN [5] */ - trunnel_assert(written <= avail); - if (avail - written < 1) - goto truncated; - trunnel_set_uint8(ptr, (obj->version)); - written += 1; ptr += 1; - - /* Encode u8 reply */ - trunnel_assert(written <= avail); - if (avail - written < 1) - goto truncated; - trunnel_set_uint8(ptr, (obj->reply)); - written += 1; ptr += 1; - - /* Encode u8 reserved IN [0] */ - trunnel_assert(written <= avail); - if (avail - written < 1) - goto truncated; - trunnel_set_uint8(ptr, (obj->reserved)); - written += 1; ptr += 1; - - /* Encode u8 atype */ - trunnel_assert(written <= avail); - if (avail - written < 1) - goto truncated; - trunnel_set_uint8(ptr, (obj->atype)); - written += 1; ptr += 1; - - /* Encode union bind_addr[atype] */ - trunnel_assert(written <= avail); - switch (obj->atype) { - - case ATYPE_IPV4: - - /* Encode u32 bind_addr_ipv4 */ - trunnel_assert(written <= avail); - if (avail - written < 4) - goto truncated; - trunnel_set_uint32(ptr, trunnel_htonl(obj->bind_addr_ipv4)); - written += 4; ptr += 4; - break; - - case ATYPE_IPV6: - - /* Encode u8 bind_addr_ipv6[16] */ - trunnel_assert(written <= avail); - if (avail - written < 16) - goto truncated; - memcpy(ptr, obj->bind_addr_ipv6, 16); - written += 16; ptr += 16; - break; - - case ATYPE_DOMAINNAME: - - /* Encode struct domainname bind_addr_domainname */ - trunnel_assert(written <= avail); - result = domainname_encode(ptr, avail - written, obj->bind_addr_domainname); - if (result < 0) - goto fail; /* XXXXXXX !*/ - written += result; ptr += result; - break; - - default: - trunnel_assert(0); - break; - } - - /* Encode u16 bind_port */ - trunnel_assert(written <= avail); - if (avail - written < 2) - goto truncated; - trunnel_set_uint16(ptr, trunnel_htons(obj->bind_port)); - written += 2; ptr += 2; - - - trunnel_assert(ptr == output + written); -#ifdef TRUNNEL_CHECK_ENCODED_LEN - { - trunnel_assert(encoded_len >= 0); - trunnel_assert((size_t)encoded_len == written); - } - -#endif - - return written; - - truncated: - result = -2; - goto fail; - check_failed: - (void)msg; - result = -1; - goto fail; - fail: - trunnel_assert(result < 0); - return result; -} - -/** As socks5_server_reply_parse(), but do not allocate the output - * object. - */ -static ssize_t -socks5_server_reply_parse_into(socks5_server_reply_t *obj, const uint8_t *input, const size_t len_in) -{ - const uint8_t *ptr = input; - size_t remaining = len_in; - ssize_t result = 0; - (void)result; - - /* Parse u8 version IN [5] */ - CHECK_REMAINING(1, truncated); - obj->version = (trunnel_get_uint8(ptr)); - remaining -= 1; ptr += 1; - if (! (obj->version == 5)) - goto fail; - - /* Parse u8 reply */ - CHECK_REMAINING(1, truncated); - obj->reply = (trunnel_get_uint8(ptr)); - remaining -= 1; ptr += 1; - - /* Parse u8 reserved IN [0] */ - CHECK_REMAINING(1, truncated); - obj->reserved = (trunnel_get_uint8(ptr)); - remaining -= 1; ptr += 1; - if (! (obj->reserved == 0)) - goto fail; - - /* Parse u8 atype */ - CHECK_REMAINING(1, truncated); - obj->atype = (trunnel_get_uint8(ptr)); - remaining -= 1; ptr += 1; - - /* Parse union bind_addr[atype] */ - switch (obj->atype) { - - case ATYPE_IPV4: - - /* Parse u32 bind_addr_ipv4 */ - CHECK_REMAINING(4, truncated); - obj->bind_addr_ipv4 = trunnel_ntohl(trunnel_get_uint32(ptr)); - remaining -= 4; ptr += 4; - break; - - case ATYPE_IPV6: - - /* Parse u8 bind_addr_ipv6[16] */ - CHECK_REMAINING(16, truncated); - memcpy(obj->bind_addr_ipv6, ptr, 16); - remaining -= 16; ptr += 16; - break; - - case ATYPE_DOMAINNAME: - - /* Parse struct domainname bind_addr_domainname */ - result = domainname_parse(&obj->bind_addr_domainname, ptr, remaining); - if (result < 0) - goto relay_fail; - trunnel_assert((size_t)result <= remaining); - remaining -= result; ptr += result; - break; - - default: - goto fail; - break; - } - - /* Parse u16 bind_port */ - CHECK_REMAINING(2, truncated); - obj->bind_port = trunnel_ntohs(trunnel_get_uint16(ptr)); - remaining -= 2; ptr += 2; - trunnel_assert(ptr + remaining == input + len_in); - return len_in - remaining; - - truncated: - return -2; - relay_fail: - trunnel_assert(result < 0); - return result; - fail: - result = -1; - return result; -} - -ssize_t -socks5_server_reply_parse(socks5_server_reply_t **output, const uint8_t *input, const size_t len_in) -{ - ssize_t result; - *output = socks5_server_reply_new(); - if (NULL == *output) - return -1; - result = socks5_server_reply_parse_into(*output, input, len_in); - if (result < 0) { - socks5_server_reply_free(*output); - *output = NULL; - } - return result; -} -tor_extended_socks_auth_request_t * -tor_extended_socks_auth_request_new(void) -{ - tor_extended_socks_auth_request_t *val = trunnel_calloc(1, sizeof(tor_extended_socks_auth_request_t)); - if (NULL == val) - return NULL; - val->version = 1; - return val; -} - -/** Release all storage held inside 'obj', but do not free 'obj'. - */ -static void -tor_extended_socks_auth_request_clear(tor_extended_socks_auth_request_t *obj) -{ - (void) obj; - { - - unsigned idx; - for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->pairs); ++idx) { - tor_socksauth_keyval_free(TRUNNEL_DYNARRAY_GET(&obj->pairs, idx)); - } - } - TRUNNEL_DYNARRAY_WIPE(&obj->pairs); - TRUNNEL_DYNARRAY_CLEAR(&obj->pairs); -} - -void -tor_extended_socks_auth_request_free(tor_extended_socks_auth_request_t *obj) -{ - if (obj == NULL) - return; - tor_extended_socks_auth_request_clear(obj); - trunnel_memwipe(obj, sizeof(tor_extended_socks_auth_request_t)); - trunnel_free_(obj); -} - -uint8_t -tor_extended_socks_auth_request_get_version(const tor_extended_socks_auth_request_t *inp) -{ - return inp->version; -} -int -tor_extended_socks_auth_request_set_version(tor_extended_socks_auth_request_t *inp, uint8_t val) -{ - if (! ((val == 1))) { - TRUNNEL_SET_ERROR_CODE(inp); - return -1; - } - inp->version = val; - return 0; -} -uint16_t -tor_extended_socks_auth_request_get_npairs(const tor_extended_socks_auth_request_t *inp) -{ - return inp->npairs; -} -int -tor_extended_socks_auth_request_set_npairs(tor_extended_socks_auth_request_t *inp, uint16_t val) -{ - inp->npairs = val; - return 0; -} -size_t -tor_extended_socks_auth_request_getlen_pairs(const tor_extended_socks_auth_request_t *inp) -{ - return TRUNNEL_DYNARRAY_LEN(&inp->pairs); -} - -struct tor_socksauth_keyval_st * -tor_extended_socks_auth_request_get_pairs(tor_extended_socks_auth_request_t *inp, size_t idx) -{ - return TRUNNEL_DYNARRAY_GET(&inp->pairs, idx); -} - - const struct tor_socksauth_keyval_st * -tor_extended_socks_auth_request_getconst_pairs(const tor_extended_socks_auth_request_t *inp, size_t idx) -{ - return tor_extended_socks_auth_request_get_pairs((tor_extended_socks_auth_request_t*)inp, idx); -} -int -tor_extended_socks_auth_request_set_pairs(tor_extended_socks_auth_request_t *inp, size_t idx, struct tor_socksauth_keyval_st * elt) -{ - tor_socksauth_keyval_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->pairs, idx); - if (oldval && oldval != elt) - tor_socksauth_keyval_free(oldval); - return tor_extended_socks_auth_request_set0_pairs(inp, idx, elt); -} -int -tor_extended_socks_auth_request_set0_pairs(tor_extended_socks_auth_request_t *inp, size_t idx, struct tor_socksauth_keyval_st * elt) -{ - TRUNNEL_DYNARRAY_SET(&inp->pairs, idx, elt); - return 0; -} -int -tor_extended_socks_auth_request_add_pairs(tor_extended_socks_auth_request_t *inp, struct tor_socksauth_keyval_st * elt) -{ -#if SIZE_MAX >= UINT16_MAX - if (inp->pairs.n_ == UINT16_MAX) - goto trunnel_alloc_failed; -#endif - TRUNNEL_DYNARRAY_ADD(struct tor_socksauth_keyval_st *, &inp->pairs, elt, {}); - return 0; - trunnel_alloc_failed: - TRUNNEL_SET_ERROR_CODE(inp); - return -1; -} - -struct tor_socksauth_keyval_st * * -tor_extended_socks_auth_request_getarray_pairs(tor_extended_socks_auth_request_t *inp) -{ - return inp->pairs.elts_; -} -const struct tor_socksauth_keyval_st * const * -tor_extended_socks_auth_request_getconstarray_pairs(const tor_extended_socks_auth_request_t *inp) -{ - return (const struct tor_socksauth_keyval_st * const *)tor_extended_socks_auth_request_getarray_pairs((tor_extended_socks_auth_request_t*)inp); -} -int -tor_extended_socks_auth_request_setlen_pairs(tor_extended_socks_auth_request_t *inp, size_t newlen) -{ - struct tor_socksauth_keyval_st * *newptr; -#if UINT16_MAX < SIZE_MAX - if (newlen > UINT16_MAX) - goto trunnel_alloc_failed; -#endif - newptr = trunnel_dynarray_setlen(&inp->pairs.allocated_, - &inp->pairs.n_, inp->pairs.elts_, newlen, - sizeof(inp->pairs.elts_[0]), (trunnel_free_fn_t) tor_socksauth_keyval_free, - &inp->trunnel_error_code_); - if (newlen != 0 && newptr == NULL) - goto trunnel_alloc_failed; - inp->pairs.elts_ = newptr; + inp->dest_port = val; return 0; - trunnel_alloc_failed: - TRUNNEL_SET_ERROR_CODE(inp); - return -1; } const char * -tor_extended_socks_auth_request_check(const tor_extended_socks_auth_request_t *obj) +socks5_client_request_check(const socks5_client_request_t *obj) { if (obj == NULL) return "Object was NULL"; if (obj->trunnel_error_code_) return "A set function failed on this object"; - if (! (obj->version == 1)) + if (! (obj->version == 5)) return "Integer out of bounds"; - { - const char *msg; + if (! (obj->command == CMD_BIND || obj->command == CMD_CONNECT || obj->command == CMD_RESOLVE || obj->command == CMD_RESOLVE_PTR || obj->command == CMD_UDP_ASSOCIATE)) + return "Integer out of bounds"; + if (! (obj->reserved == 0)) + return "Integer out of bounds"; + switch (obj->atype) { + + case ATYPE_IPV4: + break; + + case ATYPE_IPV6: + break; + + case ATYPE_DOMAINNAME: + { + const char *msg; + if (NULL != (msg = domainname_check(obj->dest_addr_domainname))) + return msg; + } + break; - unsigned idx; - for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->pairs); ++idx) { - if (NULL != (msg = tor_socksauth_keyval_check(TRUNNEL_DYNARRAY_GET(&obj->pairs, idx)))) - return msg; - } + default: + return "Bad tag for union"; + break; } - if (TRUNNEL_DYNARRAY_LEN(&obj->pairs) != obj->npairs) - return "Length mismatch for pairs"; return NULL; } ssize_t -tor_extended_socks_auth_request_encoded_len(const tor_extended_socks_auth_request_t *obj) +socks5_client_request_encoded_len(const socks5_client_request_t *obj) { ssize_t result = 0; - if (NULL != tor_extended_socks_auth_request_check(obj)) + if (NULL != socks5_client_request_check(obj)) return -1; - /* Length of u8 version IN [1] */ + /* Length of u8 version IN [5] */ result += 1; - /* Length of u16 npairs */ - result += 2; + /* Length of u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR, CMD_UDP_ASSOCIATE] */ + result += 1; - /* Length of struct tor_socksauth_keyval pairs[npairs] */ - { + /* Length of u8 reserved IN [0] */ + result += 1; + + /* Length of u8 atype */ + result += 1; + switch (obj->atype) { + + case ATYPE_IPV4: + + /* Length of u32 dest_addr_ipv4 */ + result += 4; + break; + + case ATYPE_IPV6: + + /* Length of u8 dest_addr_ipv6[16] */ + result += 16; + break; + + case ATYPE_DOMAINNAME: + + /* Length of struct domainname dest_addr_domainname */ + result += domainname_encoded_len(obj->dest_addr_domainname); + break; - unsigned idx; - for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->pairs); ++idx) { - result += tor_socksauth_keyval_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->pairs, idx)); - } + default: + trunnel_assert(0); + break; } + + /* Length of u16 dest_port */ + result += 2; return result; } int -tor_extended_socks_auth_request_clear_errors(tor_extended_socks_auth_request_t *obj) +socks5_client_request_clear_errors(socks5_client_request_t *obj) { int r = obj->trunnel_error_code_; obj->trunnel_error_code_ = 0; return r; } ssize_t -tor_extended_socks_auth_request_encode(uint8_t *output, const size_t avail, const tor_extended_socks_auth_request_t *obj) +socks5_client_request_encode(uint8_t *output, const size_t avail, const socks5_client_request_t *obj) { ssize_t result = 0; size_t written = 0; uint8_t *ptr = output; const char *msg; #ifdef TRUNNEL_CHECK_ENCODED_LEN - const ssize_t encoded_len = tor_extended_socks_auth_request_encoded_len(obj); + const ssize_t encoded_len = socks5_client_request_encoded_len(obj); #endif - if (NULL != (msg = tor_extended_socks_auth_request_check(obj))) + if (NULL != (msg = socks5_client_request_check(obj))) goto check_failed; #ifdef TRUNNEL_CHECK_ENCODED_LEN trunnel_assert(encoded_len >= 0); #endif - /* Encode u8 version IN [1] */ + /* Encode u8 version IN [5] */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->version)); written += 1; ptr += 1; - /* Encode u16 npairs */ + /* Encode u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR, CMD_UDP_ASSOCIATE] */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->command)); + written += 1; ptr += 1; + + /* Encode u8 reserved IN [0] */ trunnel_assert(written <= avail); - if (avail - written < 2) + if (avail - written < 1) goto truncated; - trunnel_set_uint16(ptr, trunnel_htons(obj->npairs)); - written += 2; ptr += 2; + trunnel_set_uint8(ptr, (obj->reserved)); + written += 1; ptr += 1; - /* Encode struct tor_socksauth_keyval pairs[npairs] */ - { + /* Encode u8 atype */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->atype)); + written += 1; ptr += 1; + + /* Encode union dest_addr[atype] */ + trunnel_assert(written <= avail); + switch (obj->atype) { + + case ATYPE_IPV4: + + /* Encode u32 dest_addr_ipv4 */ + trunnel_assert(written <= avail); + if (avail - written < 4) + goto truncated; + trunnel_set_uint32(ptr, trunnel_htonl(obj->dest_addr_ipv4)); + written += 4; ptr += 4; + break; + + case ATYPE_IPV6: + + /* Encode u8 dest_addr_ipv6[16] */ + trunnel_assert(written <= avail); + if (avail - written < 16) + goto truncated; + memcpy(ptr, obj->dest_addr_ipv6, 16); + written += 16; ptr += 16; + break; + + case ATYPE_DOMAINNAME: - unsigned idx; - for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->pairs); ++idx) { + /* Encode struct domainname dest_addr_domainname */ trunnel_assert(written <= avail); - result = tor_socksauth_keyval_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->pairs, idx)); + result = domainname_encode(ptr, avail - written, obj->dest_addr_domainname); if (result < 0) goto fail; /* XXXXXXX !*/ written += result; ptr += result; - } + break; + + default: + trunnel_assert(0); + break; } + /* Encode u16 dest_port */ + trunnel_assert(written <= avail); + if (avail - written < 2) + goto truncated; + trunnel_set_uint16(ptr, trunnel_htons(obj->dest_port)); + written += 2; ptr += 2; + trunnel_assert(ptr == output + written); #ifdef TRUNNEL_CHECK_ENCODED_LEN @@ -4632,43 +3405,81 @@ tor_extended_socks_auth_request_encode(uint8_t *output, const size_t avail, cons return result; } -/** As tor_extended_socks_auth_request_parse(), but do not allocate - * the output object. +/** As socks5_client_request_parse(), but do not allocate the output + * object. */ static ssize_t -tor_extended_socks_auth_request_parse_into(tor_extended_socks_auth_request_t *obj, const uint8_t *input, const size_t len_in) +socks5_client_request_parse_into(socks5_client_request_t *obj, const uint8_t *input, const size_t len_in) { const uint8_t *ptr = input; size_t remaining = len_in; ssize_t result = 0; (void)result; - /* Parse u8 version IN [1] */ + /* Parse u8 version IN [5] */ CHECK_REMAINING(1, truncated); obj->version = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; - if (! (obj->version == 1)) + if (! (obj->version == 5)) goto fail; - /* Parse u16 npairs */ - CHECK_REMAINING(2, truncated); - obj->npairs = trunnel_ntohs(trunnel_get_uint16(ptr)); - remaining -= 2; ptr += 2; + /* Parse u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR, CMD_UDP_ASSOCIATE] */ + CHECK_REMAINING(1, truncated); + obj->command = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->command == CMD_BIND || obj->command == CMD_CONNECT || obj->command == CMD_RESOLVE || obj->command == CMD_RESOLVE_PTR || obj->command == CMD_UDP_ASSOCIATE)) + goto fail; - /* Parse struct tor_socksauth_keyval pairs[npairs] */ - TRUNNEL_DYNARRAY_EXPAND(tor_socksauth_keyval_t *, &obj->pairs, obj->npairs, {}); - { - tor_socksauth_keyval_t * elt; - unsigned idx; - for (idx = 0; idx < obj->npairs; ++idx) { - result = tor_socksauth_keyval_parse(&elt, ptr, remaining); + /* Parse u8 reserved IN [0] */ + CHECK_REMAINING(1, truncated); + obj->reserved = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->reserved == 0)) + goto fail; + + /* Parse u8 atype */ + CHECK_REMAINING(1, truncated); + obj->atype = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + + /* Parse union dest_addr[atype] */ + switch (obj->atype) { + + case ATYPE_IPV4: + + /* Parse u32 dest_addr_ipv4 */ + CHECK_REMAINING(4, truncated); + obj->dest_addr_ipv4 = trunnel_ntohl(trunnel_get_uint32(ptr)); + remaining -= 4; ptr += 4; + break; + + case ATYPE_IPV6: + + /* Parse u8 dest_addr_ipv6[16] */ + CHECK_REMAINING(16, truncated); + memcpy(obj->dest_addr_ipv6, ptr, 16); + remaining -= 16; ptr += 16; + break; + + case ATYPE_DOMAINNAME: + + /* Parse struct domainname dest_addr_domainname */ + result = domainname_parse(&obj->dest_addr_domainname, ptr, remaining); if (result < 0) goto relay_fail; trunnel_assert((size_t)result <= remaining); remaining -= result; ptr += result; - TRUNNEL_DYNARRAY_ADD(tor_socksauth_keyval_t *, &obj->pairs, elt, {tor_socksauth_keyval_free(elt);}); - } + break; + + default: + goto fail; + break; } + + /* Parse u16 dest_port */ + CHECK_REMAINING(2, truncated); + obj->dest_port = trunnel_ntohs(trunnel_get_uint16(ptr)); + remaining -= 2; ptr += 2; trunnel_assert(ptr + remaining == input + len_in); return len_in - remaining; @@ -4677,73 +3488,64 @@ tor_extended_socks_auth_request_parse_into(tor_extended_socks_auth_request_t *ob relay_fail: trunnel_assert(result < 0); return result; - trunnel_alloc_failed: - return -1; fail: result = -1; return result; } ssize_t -tor_extended_socks_auth_request_parse(tor_extended_socks_auth_request_t **output, const uint8_t *input, const size_t len_in) +socks5_client_request_parse(socks5_client_request_t **output, const uint8_t *input, const size_t len_in) { ssize_t result; - *output = tor_extended_socks_auth_request_new(); + *output = socks5_client_request_new(); if (NULL == *output) return -1; - result = tor_extended_socks_auth_request_parse_into(*output, input, len_in); + result = socks5_client_request_parse_into(*output, input, len_in); if (result < 0) { - tor_extended_socks_auth_request_free(*output); + socks5_client_request_free(*output); *output = NULL; } return result; } -tor_extended_socks_auth_response_t * -tor_extended_socks_auth_response_new(void) +socks5_server_reply_t * +socks5_server_reply_new(void) { - tor_extended_socks_auth_response_t *val = trunnel_calloc(1, sizeof(tor_extended_socks_auth_response_t)); + socks5_server_reply_t *val = trunnel_calloc(1, sizeof(socks5_server_reply_t)); if (NULL == val) return NULL; - val->version = 1; + val->version = 5; return val; } /** Release all storage held inside 'obj', but do not free 'obj'. */ static void -tor_extended_socks_auth_response_clear(tor_extended_socks_auth_response_t *obj) +socks5_server_reply_clear(socks5_server_reply_t *obj) { (void) obj; - { - - unsigned idx; - for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->pairs); ++idx) { - tor_socksauth_keyval_free(TRUNNEL_DYNARRAY_GET(&obj->pairs, idx)); - } - } - TRUNNEL_DYNARRAY_WIPE(&obj->pairs); - TRUNNEL_DYNARRAY_CLEAR(&obj->pairs); + domainname_free(obj->bind_addr_domainname); + obj->bind_addr_domainname = NULL; } void -tor_extended_socks_auth_response_free(tor_extended_socks_auth_response_t *obj) +socks5_server_reply_free(socks5_server_reply_t *obj) { if (obj == NULL) return; - tor_extended_socks_auth_response_clear(obj); - trunnel_memwipe(obj, sizeof(tor_extended_socks_auth_response_t)); + socks5_server_reply_clear(obj); + trunnel_memwipe(obj, sizeof(socks5_server_reply_t)); trunnel_free_(obj); } uint8_t -tor_extended_socks_auth_response_get_version(const tor_extended_socks_auth_response_t *inp) +socks5_server_reply_get_version(const socks5_server_reply_t *inp) { return inp->version; } int -tor_extended_socks_auth_response_set_version(tor_extended_socks_auth_response_t *inp, uint8_t val) +socks5_server_reply_set_version(socks5_server_reply_t *inp, uint8_t val) { - if (! ((val == 1))) { + if (! ((val == 5))) { TRUNNEL_SET_ERROR_CODE(inp); return -1; } @@ -4751,212 +3553,305 @@ tor_extended_socks_auth_response_set_version(tor_extended_socks_auth_response_t return 0; } uint8_t -tor_extended_socks_auth_response_get_status(const tor_extended_socks_auth_response_t *inp) +socks5_server_reply_get_reply(const socks5_server_reply_t *inp) { - return inp->status; + return inp->reply; } int -tor_extended_socks_auth_response_set_status(tor_extended_socks_auth_response_t *inp, uint8_t val) +socks5_server_reply_set_reply(socks5_server_reply_t *inp, uint8_t val) { - inp->status = val; + inp->reply = val; + return 0; +} +uint8_t +socks5_server_reply_get_reserved(const socks5_server_reply_t *inp) +{ + return inp->reserved; +} +int +socks5_server_reply_set_reserved(socks5_server_reply_t *inp, uint8_t val) +{ + if (! ((val == 0))) { + TRUNNEL_SET_ERROR_CODE(inp); + return -1; + } + inp->reserved = val; + return 0; +} +uint8_t +socks5_server_reply_get_atype(const socks5_server_reply_t *inp) +{ + return inp->atype; +} +int +socks5_server_reply_set_atype(socks5_server_reply_t *inp, uint8_t val) +{ + inp->atype = val; return 0; } -uint16_t -tor_extended_socks_auth_response_get_npairs(const tor_extended_socks_auth_response_t *inp) +uint32_t +socks5_server_reply_get_bind_addr_ipv4(const socks5_server_reply_t *inp) { - return inp->npairs; + return inp->bind_addr_ipv4; } int -tor_extended_socks_auth_response_set_npairs(tor_extended_socks_auth_response_t *inp, uint16_t val) +socks5_server_reply_set_bind_addr_ipv4(socks5_server_reply_t *inp, uint32_t val) { - inp->npairs = val; + inp->bind_addr_ipv4 = val; return 0; } size_t -tor_extended_socks_auth_response_getlen_pairs(const tor_extended_socks_auth_response_t *inp) +socks5_server_reply_getlen_bind_addr_ipv6(const socks5_server_reply_t *inp) { - return TRUNNEL_DYNARRAY_LEN(&inp->pairs); + (void)inp; return 16; } -struct tor_socksauth_keyval_st * -tor_extended_socks_auth_response_get_pairs(tor_extended_socks_auth_response_t *inp, size_t idx) +uint8_t +socks5_server_reply_get_bind_addr_ipv6(socks5_server_reply_t *inp, size_t idx) { - return TRUNNEL_DYNARRAY_GET(&inp->pairs, idx); + trunnel_assert(idx < 16); + return inp->bind_addr_ipv6[idx]; } - const struct tor_socksauth_keyval_st * -tor_extended_socks_auth_response_getconst_pairs(const tor_extended_socks_auth_response_t *inp, size_t idx) +uint8_t +socks5_server_reply_getconst_bind_addr_ipv6(const socks5_server_reply_t *inp, size_t idx) { - return tor_extended_socks_auth_response_get_pairs((tor_extended_socks_auth_response_t*)inp, idx); + return socks5_server_reply_get_bind_addr_ipv6((socks5_server_reply_t*)inp, idx); } int -tor_extended_socks_auth_response_set_pairs(tor_extended_socks_auth_response_t *inp, size_t idx, struct tor_socksauth_keyval_st * elt) +socks5_server_reply_set_bind_addr_ipv6(socks5_server_reply_t *inp, size_t idx, uint8_t elt) { - tor_socksauth_keyval_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->pairs, idx); - if (oldval && oldval != elt) - tor_socksauth_keyval_free(oldval); - return tor_extended_socks_auth_response_set0_pairs(inp, idx, elt); + trunnel_assert(idx < 16); + inp->bind_addr_ipv6[idx] = elt; + return 0; } -int -tor_extended_socks_auth_response_set0_pairs(tor_extended_socks_auth_response_t *inp, size_t idx, struct tor_socksauth_keyval_st * elt) + +uint8_t * +socks5_server_reply_getarray_bind_addr_ipv6(socks5_server_reply_t *inp) { - TRUNNEL_DYNARRAY_SET(&inp->pairs, idx, elt); - return 0; + return inp->bind_addr_ipv6; +} +const uint8_t * +socks5_server_reply_getconstarray_bind_addr_ipv6(const socks5_server_reply_t *inp) +{ + return (const uint8_t *)socks5_server_reply_getarray_bind_addr_ipv6((socks5_server_reply_t*)inp); +} +struct domainname_st * +socks5_server_reply_get_bind_addr_domainname(socks5_server_reply_t *inp) +{ + return inp->bind_addr_domainname; +} +const struct domainname_st * +socks5_server_reply_getconst_bind_addr_domainname(const socks5_server_reply_t *inp) +{ + return socks5_server_reply_get_bind_addr_domainname((socks5_server_reply_t*) inp); } int -tor_extended_socks_auth_response_add_pairs(tor_extended_socks_auth_response_t *inp, struct tor_socksauth_keyval_st * elt) +socks5_server_reply_set_bind_addr_domainname(socks5_server_reply_t *inp, struct domainname_st *val) { -#if SIZE_MAX >= UINT16_MAX - if (inp->pairs.n_ == UINT16_MAX) - goto trunnel_alloc_failed; -#endif - TRUNNEL_DYNARRAY_ADD(struct tor_socksauth_keyval_st *, &inp->pairs, elt, {}); - return 0; - trunnel_alloc_failed: - TRUNNEL_SET_ERROR_CODE(inp); - return -1; + if (inp->bind_addr_domainname && inp->bind_addr_domainname != val) + domainname_free(inp->bind_addr_domainname); + return socks5_server_reply_set0_bind_addr_domainname(inp, val); } - -struct tor_socksauth_keyval_st * * -tor_extended_socks_auth_response_getarray_pairs(tor_extended_socks_auth_response_t *inp) +int +socks5_server_reply_set0_bind_addr_domainname(socks5_server_reply_t *inp, struct domainname_st *val) { - return inp->pairs.elts_; + inp->bind_addr_domainname = val; + return 0; } -const struct tor_socksauth_keyval_st * const * -tor_extended_socks_auth_response_getconstarray_pairs(const tor_extended_socks_auth_response_t *inp) +uint16_t +socks5_server_reply_get_bind_port(const socks5_server_reply_t *inp) { - return (const struct tor_socksauth_keyval_st * const *)tor_extended_socks_auth_response_getarray_pairs((tor_extended_socks_auth_response_t*)inp); + return inp->bind_port; } int -tor_extended_socks_auth_response_setlen_pairs(tor_extended_socks_auth_response_t *inp, size_t newlen) +socks5_server_reply_set_bind_port(socks5_server_reply_t *inp, uint16_t val) { - struct tor_socksauth_keyval_st * *newptr; -#if UINT16_MAX < SIZE_MAX - if (newlen > UINT16_MAX) - goto trunnel_alloc_failed; -#endif - newptr = trunnel_dynarray_setlen(&inp->pairs.allocated_, - &inp->pairs.n_, inp->pairs.elts_, newlen, - sizeof(inp->pairs.elts_[0]), (trunnel_free_fn_t) tor_socksauth_keyval_free, - &inp->trunnel_error_code_); - if (newlen != 0 && newptr == NULL) - goto trunnel_alloc_failed; - inp->pairs.elts_ = newptr; + inp->bind_port = val; return 0; - trunnel_alloc_failed: - TRUNNEL_SET_ERROR_CODE(inp); - return -1; } const char * -tor_extended_socks_auth_response_check(const tor_extended_socks_auth_response_t *obj) +socks5_server_reply_check(const socks5_server_reply_t *obj) { if (obj == NULL) return "Object was NULL"; if (obj->trunnel_error_code_) return "A set function failed on this object"; - if (! (obj->version == 1)) + if (! (obj->version == 5)) return "Integer out of bounds"; - { - const char *msg; + if (! (obj->reserved == 0)) + return "Integer out of bounds"; + switch (obj->atype) { + + case ATYPE_IPV4: + break; + + case ATYPE_IPV6: + break; + + case ATYPE_DOMAINNAME: + { + const char *msg; + if (NULL != (msg = domainname_check(obj->bind_addr_domainname))) + return msg; + } + break; - unsigned idx; - for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->pairs); ++idx) { - if (NULL != (msg = tor_socksauth_keyval_check(TRUNNEL_DYNARRAY_GET(&obj->pairs, idx)))) - return msg; - } + default: + return "Bad tag for union"; + break; } - if (TRUNNEL_DYNARRAY_LEN(&obj->pairs) != obj->npairs) - return "Length mismatch for pairs"; return NULL; } ssize_t -tor_extended_socks_auth_response_encoded_len(const tor_extended_socks_auth_response_t *obj) +socks5_server_reply_encoded_len(const socks5_server_reply_t *obj) { ssize_t result = 0; - if (NULL != tor_extended_socks_auth_response_check(obj)) + if (NULL != socks5_server_reply_check(obj)) return -1; - /* Length of u8 version IN [1] */ + /* Length of u8 version IN [5] */ result += 1; - /* Length of u8 status */ + /* Length of u8 reply */ result += 1; - /* Length of u16 npairs */ - result += 2; + /* Length of u8 reserved IN [0] */ + result += 1; - /* Length of struct tor_socksauth_keyval pairs[npairs] */ - { + /* Length of u8 atype */ + result += 1; + switch (obj->atype) { + + case ATYPE_IPV4: + + /* Length of u32 bind_addr_ipv4 */ + result += 4; + break; + + case ATYPE_IPV6: + + /* Length of u8 bind_addr_ipv6[16] */ + result += 16; + break; + + case ATYPE_DOMAINNAME: + + /* Length of struct domainname bind_addr_domainname */ + result += domainname_encoded_len(obj->bind_addr_domainname); + break; - unsigned idx; - for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->pairs); ++idx) { - result += tor_socksauth_keyval_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->pairs, idx)); - } + default: + trunnel_assert(0); + break; } + + /* Length of u16 bind_port */ + result += 2; return result; } int -tor_extended_socks_auth_response_clear_errors(tor_extended_socks_auth_response_t *obj) +socks5_server_reply_clear_errors(socks5_server_reply_t *obj) { int r = obj->trunnel_error_code_; obj->trunnel_error_code_ = 0; return r; } ssize_t -tor_extended_socks_auth_response_encode(uint8_t *output, const size_t avail, const tor_extended_socks_auth_response_t *obj) +socks5_server_reply_encode(uint8_t *output, const size_t avail, const socks5_server_reply_t *obj) { ssize_t result = 0; size_t written = 0; uint8_t *ptr = output; const char *msg; #ifdef TRUNNEL_CHECK_ENCODED_LEN - const ssize_t encoded_len = tor_extended_socks_auth_response_encoded_len(obj); + const ssize_t encoded_len = socks5_server_reply_encoded_len(obj); #endif - if (NULL != (msg = tor_extended_socks_auth_response_check(obj))) + if (NULL != (msg = socks5_server_reply_check(obj))) goto check_failed; #ifdef TRUNNEL_CHECK_ENCODED_LEN trunnel_assert(encoded_len >= 0); #endif - /* Encode u8 version IN [1] */ + /* Encode u8 version IN [5] */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->version)); written += 1; ptr += 1; - /* Encode u8 status */ + /* Encode u8 reply */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; - trunnel_set_uint8(ptr, (obj->status)); + trunnel_set_uint8(ptr, (obj->reply)); written += 1; ptr += 1; - /* Encode u16 npairs */ + /* Encode u8 reserved IN [0] */ trunnel_assert(written <= avail); - if (avail - written < 2) + if (avail - written < 1) goto truncated; - trunnel_set_uint16(ptr, trunnel_htons(obj->npairs)); - written += 2; ptr += 2; + trunnel_set_uint8(ptr, (obj->reserved)); + written += 1; ptr += 1; - /* Encode struct tor_socksauth_keyval pairs[npairs] */ - { + /* Encode u8 atype */ + trunnel_assert(written <= avail); + if (avail - written < 1) + goto truncated; + trunnel_set_uint8(ptr, (obj->atype)); + written += 1; ptr += 1; + + /* Encode union bind_addr[atype] */ + trunnel_assert(written <= avail); + switch (obj->atype) { + + case ATYPE_IPV4: + + /* Encode u32 bind_addr_ipv4 */ + trunnel_assert(written <= avail); + if (avail - written < 4) + goto truncated; + trunnel_set_uint32(ptr, trunnel_htonl(obj->bind_addr_ipv4)); + written += 4; ptr += 4; + break; + + case ATYPE_IPV6: + + /* Encode u8 bind_addr_ipv6[16] */ + trunnel_assert(written <= avail); + if (avail - written < 16) + goto truncated; + memcpy(ptr, obj->bind_addr_ipv6, 16); + written += 16; ptr += 16; + break; - unsigned idx; - for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->pairs); ++idx) { + case ATYPE_DOMAINNAME: + + /* Encode struct domainname bind_addr_domainname */ trunnel_assert(written <= avail); - result = tor_socksauth_keyval_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->pairs, idx)); + result = domainname_encode(ptr, avail - written, obj->bind_addr_domainname); if (result < 0) goto fail; /* XXXXXXX !*/ written += result; ptr += result; - } + break; + + default: + trunnel_assert(0); + break; } + /* Encode u16 bind_port */ + trunnel_assert(written <= avail); + if (avail - written < 2) + goto truncated; + trunnel_set_uint16(ptr, trunnel_htons(obj->bind_port)); + written += 2; ptr += 2; + trunnel_assert(ptr == output + written); #ifdef TRUNNEL_CHECK_ENCODED_LEN @@ -4981,48 +3876,79 @@ tor_extended_socks_auth_response_encode(uint8_t *output, const size_t avail, con return result; } -/** As tor_extended_socks_auth_response_parse(), but do not allocate - * the output object. +/** As socks5_server_reply_parse(), but do not allocate the output + * object. */ static ssize_t -tor_extended_socks_auth_response_parse_into(tor_extended_socks_auth_response_t *obj, const uint8_t *input, const size_t len_in) +socks5_server_reply_parse_into(socks5_server_reply_t *obj, const uint8_t *input, const size_t len_in) { const uint8_t *ptr = input; size_t remaining = len_in; ssize_t result = 0; (void)result; - /* Parse u8 version IN [1] */ + /* Parse u8 version IN [5] */ CHECK_REMAINING(1, truncated); obj->version = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; - if (! (obj->version == 1)) + if (! (obj->version == 5)) goto fail; - /* Parse u8 status */ + /* Parse u8 reply */ CHECK_REMAINING(1, truncated); - obj->status = (trunnel_get_uint8(ptr)); + obj->reply = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; - /* Parse u16 npairs */ - CHECK_REMAINING(2, truncated); - obj->npairs = trunnel_ntohs(trunnel_get_uint16(ptr)); - remaining -= 2; ptr += 2; + /* Parse u8 reserved IN [0] */ + CHECK_REMAINING(1, truncated); + obj->reserved = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + if (! (obj->reserved == 0)) + goto fail; - /* Parse struct tor_socksauth_keyval pairs[npairs] */ - TRUNNEL_DYNARRAY_EXPAND(tor_socksauth_keyval_t *, &obj->pairs, obj->npairs, {}); - { - tor_socksauth_keyval_t * elt; - unsigned idx; - for (idx = 0; idx < obj->npairs; ++idx) { - result = tor_socksauth_keyval_parse(&elt, ptr, remaining); + /* Parse u8 atype */ + CHECK_REMAINING(1, truncated); + obj->atype = (trunnel_get_uint8(ptr)); + remaining -= 1; ptr += 1; + + /* Parse union bind_addr[atype] */ + switch (obj->atype) { + + case ATYPE_IPV4: + + /* Parse u32 bind_addr_ipv4 */ + CHECK_REMAINING(4, truncated); + obj->bind_addr_ipv4 = trunnel_ntohl(trunnel_get_uint32(ptr)); + remaining -= 4; ptr += 4; + break; + + case ATYPE_IPV6: + + /* Parse u8 bind_addr_ipv6[16] */ + CHECK_REMAINING(16, truncated); + memcpy(obj->bind_addr_ipv6, ptr, 16); + remaining -= 16; ptr += 16; + break; + + case ATYPE_DOMAINNAME: + + /* Parse struct domainname bind_addr_domainname */ + result = domainname_parse(&obj->bind_addr_domainname, ptr, remaining); if (result < 0) goto relay_fail; trunnel_assert((size_t)result <= remaining); remaining -= result; ptr += result; - TRUNNEL_DYNARRAY_ADD(tor_socksauth_keyval_t *, &obj->pairs, elt, {tor_socksauth_keyval_free(elt);}); - } + break; + + default: + goto fail; + break; } + + /* Parse u16 bind_port */ + CHECK_REMAINING(2, truncated); + obj->bind_port = trunnel_ntohs(trunnel_get_uint16(ptr)); + remaining -= 2; ptr += 2; trunnel_assert(ptr + remaining == input + len_in); return len_in - remaining; @@ -5031,23 +3957,21 @@ tor_extended_socks_auth_response_parse_into(tor_extended_socks_auth_response_t * relay_fail: trunnel_assert(result < 0); return result; - trunnel_alloc_failed: - return -1; fail: result = -1; return result; } ssize_t -tor_extended_socks_auth_response_parse(tor_extended_socks_auth_response_t **output, const uint8_t *input, const size_t len_in) +socks5_server_reply_parse(socks5_server_reply_t **output, const uint8_t *input, const size_t len_in) { ssize_t result; - *output = tor_extended_socks_auth_response_new(); + *output = socks5_server_reply_new(); if (NULL == *output) return -1; - result = tor_extended_socks_auth_response_parse_into(*output, input, len_in); + result = socks5_server_reply_parse_into(*output, input, len_in); if (result < 0) { - tor_extended_socks_auth_response_free(*output); + socks5_server_reply_free(*output); *output = NULL; } return result; -- cgit v1.2.3-54-g00ecf