/* socks5.c -- generated by Trunnel v1.5.2. * https://gitweb.torproject.org/trunnel.git * You probably shouldn't edit this file. */ #include #include "trunnel-impl.h" #include "socks5.h" #define TRUNNEL_SET_ERROR_CODE(obj) \ do { \ (obj)->trunnel_error_code_ = 1; \ } while (0) #if defined(__COVERITY__) || defined(__clang_analyzer__) /* If we're running a static analysis tool, we don't want it to complain * that some of our remaining-bytes checks are dead-code. */ int socks_deadcode_dummy__ = 0; #define OR_DEADCODE_DUMMY || socks_deadcode_dummy__ #else #define OR_DEADCODE_DUMMY #endif #define CHECK_REMAINING(nbytes, label) \ do { \ if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \ goto label; \ } \ } while (0) domainname_t * domainname_new(void) { domainname_t *val = trunnel_calloc(1, sizeof(domainname_t)); if (NULL == val) return NULL; return val; } /** Release all storage held inside 'obj', but do not free 'obj'. */ static void domainname_clear(domainname_t *obj) { (void) obj; TRUNNEL_DYNARRAY_WIPE(&obj->name); TRUNNEL_DYNARRAY_CLEAR(&obj->name); } void domainname_free(domainname_t *obj) { if (obj == NULL) return; domainname_clear(obj); trunnel_memwipe(obj, sizeof(domainname_t)); trunnel_free_(obj); } uint8_t domainname_get_len(const domainname_t *inp) { return inp->len; } int domainname_set_len(domainname_t *inp, uint8_t val) { inp->len = val; return 0; } size_t domainname_getlen_name(const domainname_t *inp) { return TRUNNEL_DYNARRAY_LEN(&inp->name); } char domainname_get_name(domainname_t *inp, size_t idx) { return TRUNNEL_DYNARRAY_GET(&inp->name, idx); } char domainname_getconst_name(const domainname_t *inp, size_t idx) { return domainname_get_name((domainname_t*)inp, idx); } int domainname_set_name(domainname_t *inp, size_t idx, char elt) { TRUNNEL_DYNARRAY_SET(&inp->name, idx, elt); return 0; } int domainname_add_name(domainname_t *inp, char elt) { #if SIZE_MAX >= UINT8_MAX if (inp->name.n_ == UINT8_MAX) goto trunnel_alloc_failed; #endif TRUNNEL_DYNARRAY_ADD(char, &inp->name, elt, {}); return 0; trunnel_alloc_failed: TRUNNEL_SET_ERROR_CODE(inp); return -1; } char * domainname_getarray_name(domainname_t *inp) { return inp->name.elts_; } const char * domainname_getconstarray_name(const domainname_t *inp) { return (const char *)domainname_getarray_name((domainname_t*)inp); } int domainname_setlen_name(domainname_t *inp, size_t newlen) { #if UINT8_MAX < SIZE_MAX if (newlen > UINT8_MAX) goto trunnel_alloc_failed; #endif return trunnel_string_setlen(&inp->name, newlen, &inp->trunnel_error_code_); trunnel_alloc_failed: TRUNNEL_SET_ERROR_CODE(inp); return -1; } const char * domainname_getstr_name(domainname_t *inp) { return trunnel_string_getstr(&inp->name); } int domainname_setstr0_name(domainname_t *inp, const char *val, size_t len) { #if UINT8_MAX < SIZE_MAX if (len > UINT8_MAX) { TRUNNEL_SET_ERROR_CODE(inp); return -1; } #endif return trunnel_string_setstr0(&inp->name, val, len, &inp->trunnel_error_code_); } int domainname_setstr_name(domainname_t *inp, const char *val) { return domainname_setstr0_name(inp, val, strlen(val)); } const char * domainname_check(const domainname_t *obj) { 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->name) != obj->len) return "Length mismatch for name"; return NULL; } ssize_t domainname_encoded_len(const domainname_t *obj) { ssize_t result = 0; if (NULL != domainname_check(obj)) return -1; /* Length of u8 len */ result += 1; /* Length of char name[len] */ result += TRUNNEL_DYNARRAY_LEN(&obj->name); return result; } int domainname_clear_errors(domainname_t *obj) { int r = obj->trunnel_error_code_; obj->trunnel_error_code_ = 0; return r; } ssize_t domainname_encode(uint8_t *output, const size_t avail, const domainname_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 = domainname_encoded_len(obj); #endif if (NULL != (msg = domainname_check(obj))) goto check_failed; #ifdef TRUNNEL_CHECK_ENCODED_LEN trunnel_assert(encoded_len >= 0); #endif /* Encode u8 len */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->len)); written += 1; ptr += 1; /* Encode char name[len] */ { size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->name); trunnel_assert(obj->len == elt_len); trunnel_assert(written <= avail); if (avail - written < elt_len) goto truncated; if (elt_len) memcpy(ptr, obj->name.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 domainname_parse(), but do not allocate the output object. */ static ssize_t domainname_parse_into(domainname_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 len */ CHECK_REMAINING(1, truncated); obj->len = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; /* Parse char name[len] */ CHECK_REMAINING(obj->len, truncated); if (domainname_setstr0_name(obj, (const char*)ptr, obj->len)) goto fail; ptr += obj->len; remaining -= obj->len; trunnel_assert(ptr + remaining == input + len_in); return len_in - remaining; truncated: return -2; fail: result = -1; return result; } ssize_t domainname_parse(domainname_t **output, const uint8_t *input, const size_t len_in) { ssize_t result; *output = domainname_new(); if (NULL == *output) return -1; result = domainname_parse_into(*output, input, len_in); if (result < 0) { domainname_free(*output); *output = NULL; } return result; } socks4_client_request_t * socks4_client_request_new(void) { socks4_client_request_t *val = trunnel_calloc(1, sizeof(socks4_client_request_t)); if (NULL == val) return NULL; val->version = 4; val->command = CMD_BIND; return val; } /** Release all storage held inside 'obj', but do not free 'obj'. */ static void socks4_client_request_clear(socks4_client_request_t *obj) { (void) obj; trunnel_wipestr(obj->username); trunnel_free(obj->username); trunnel_wipestr(obj->socks4a_addr_hostname); trunnel_free(obj->socks4a_addr_hostname); } void socks4_client_request_free(socks4_client_request_t *obj) { if (obj == NULL) return; socks4_client_request_clear(obj); trunnel_memwipe(obj, sizeof(socks4_client_request_t)); trunnel_free_(obj); } uint8_t socks4_client_request_get_version(const socks4_client_request_t *inp) { return inp->version; } int socks4_client_request_set_version(socks4_client_request_t *inp, uint8_t val) { if (! ((val == 4))) { TRUNNEL_SET_ERROR_CODE(inp); return -1; } inp->version = val; return 0; } uint8_t socks4_client_request_get_command(const socks4_client_request_t *inp) { return inp->command; } int socks4_client_request_set_command(socks4_client_request_t *inp, uint8_t val) { if (! ((val == CMD_BIND || val == CMD_CONNECT || val == CMD_RESOLVE || val == CMD_RESOLVE_PTR))) { TRUNNEL_SET_ERROR_CODE(inp); return -1; } inp->command = val; return 0; } uint16_t socks4_client_request_get_port(const socks4_client_request_t *inp) { return inp->port; } int socks4_client_request_set_port(socks4_client_request_t *inp, uint16_t val) { inp->port = val; return 0; } uint32_t socks4_client_request_get_addr(const socks4_client_request_t *inp) { return inp->addr; } int socks4_client_request_set_addr(socks4_client_request_t *inp, uint32_t val) { inp->addr = val; return 0; } const char * socks4_client_request_get_username(const socks4_client_request_t *inp) { return inp->username; } int socks4_client_request_set_username(socks4_client_request_t *inp, const char *val) { trunnel_free(inp->username); if (NULL == (inp->username = trunnel_strdup(val))) { TRUNNEL_SET_ERROR_CODE(inp); return -1; } return 0; } const char * socks4_client_request_get_socks4a_addr_hostname(const socks4_client_request_t *inp) { return inp->socks4a_addr_hostname; } int socks4_client_request_set_socks4a_addr_hostname(socks4_client_request_t *inp, const char *val) { trunnel_free(inp->socks4a_addr_hostname); if (NULL == (inp->socks4a_addr_hostname = trunnel_strdup(val))) { TRUNNEL_SET_ERROR_CODE(inp); return -1; } return 0; } const char * socks4_client_request_check(const socks4_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 == 4)) return "Integer out of bounds"; if (! (obj->command == CMD_BIND || obj->command == CMD_CONNECT || obj->command == CMD_RESOLVE || obj->command == CMD_RESOLVE_PTR)) return "Integer out of bounds"; if (NULL == obj->username) return "Missing username"; switch (obj->addr) { case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127: case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: case 240: case 241: case 242: case 243: case 244: case 245: case 246: case 247: case 248: case 249: case 250: case 251: case 252: case 253: case 254: case 255: if (NULL == obj->socks4a_addr_hostname) return "Missing socks4a_addr_hostname"; break; default: break; } return NULL; } ssize_t socks4_client_request_encoded_len(const socks4_client_request_t *obj) { ssize_t result = 0; if (NULL != socks4_client_request_check(obj)) return -1; /* Length of u8 version IN [4] */ result += 1; /* Length of u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR] */ result += 1; /* Length of u16 port */ result += 2; /* Length of u32 addr */ result += 4; /* Length of nulterm username */ result += strlen(obj->username) + 1; switch (obj->addr) { case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127: case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: case 240: case 241: case 242: case 243: case 244: case 245: case 246: case 247: case 248: case 249: case 250: case 251: case 252: case 253: case 254: case 255: /* Length of nulterm socks4a_addr_hostname */ result += strlen(obj->socks4a_addr_hostname) + 1; break; default: break; } return result; } int socks4_client_request_clear_errors(socks4_client_request_t *obj) { int r = obj->trunnel_error_code_; obj->trunnel_error_code_ = 0; return r; } ssize_t socks4_client_request_encode(uint8_t *output, const size_t avail, const socks4_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 = socks4_client_request_encoded_len(obj); #endif if (NULL != (msg = socks4_client_request_check(obj))) goto check_failed; #ifdef TRUNNEL_CHECK_ENCODED_LEN trunnel_assert(encoded_len >= 0); #endif /* Encode u8 version IN [4] */ 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] */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->command)); written += 1; ptr += 1; /* Encode u16 port */ trunnel_assert(written <= avail); if (avail - written < 2) goto truncated; trunnel_set_uint16(ptr, trunnel_htons(obj->port)); written += 2; ptr += 2; /* Encode u32 addr */ trunnel_assert(written <= avail); if (avail - written < 4) goto truncated; trunnel_set_uint32(ptr, trunnel_htonl(obj->addr)); written += 4; ptr += 4; /* Encode nulterm username */ { size_t len = strlen(obj->username); trunnel_assert(written <= avail); if (avail - written < len + 1) goto truncated; memcpy(ptr, obj->username, len + 1); ptr += len + 1; written += len + 1; } /* Encode union socks4a_addr[addr] */ trunnel_assert(written <= avail); switch (obj->addr) { case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127: case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: case 240: case 241: case 242: case 243: case 244: case 245: case 246: case 247: case 248: case 249: case 250: case 251: case 252: case 253: case 254: case 255: /* Encode nulterm socks4a_addr_hostname */ { size_t len = strlen(obj->socks4a_addr_hostname); trunnel_assert(written <= avail); if (avail - written < len + 1) goto truncated; memcpy(ptr, obj->socks4a_addr_hostname, len + 1); ptr += len + 1; written += len + 1; } break; default: break; } 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 socks4_client_request_parse(), but do not allocate the output * object. */ static ssize_t socks4_client_request_parse_into(socks4_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 [4] */ CHECK_REMAINING(1, truncated); obj->version = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; if (! (obj->version == 4)) goto fail; /* Parse u8 command IN [CMD_BIND, CMD_CONNECT, CMD_RESOLVE, CMD_RESOLVE_PTR] */ 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)) goto fail; /* Parse u16 port */ CHECK_REMAINING(2, truncated); obj->port = trunnel_ntohs(trunnel_get_uint16(ptr)); remaining -= 2; ptr += 2; /* Parse u32 addr */ CHECK_REMAINING(4, truncated); obj->addr = trunnel_ntohl(trunnel_get_uint32(ptr)); remaining -= 4; ptr += 4; /* Parse nulterm username */ { uint8_t *eos = (uint8_t*)memchr(ptr, 0, remaining); size_t memlen; if (eos == NULL) goto truncated; trunnel_assert(eos >= ptr); trunnel_assert((size_t)(eos - ptr) < SIZE_MAX - 1); memlen = ((size_t)(eos - ptr)) + 1; if (!(obj->username = trunnel_malloc(memlen))) goto fail; memcpy(obj->username, ptr, memlen); remaining -= memlen; ptr += memlen; } /* Parse union socks4a_addr[addr] */ switch (obj->addr) { case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127: case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: case 240: case 241: case 242: case 243: case 244: case 245: case 246: case 247: case 248: case 249: case 250: case 251: case 252: case 253: case 254: case 255: /* Parse nulterm socks4a_addr_hostname */ { uint8_t *eos = (uint8_t*)memchr(ptr, 0, remaining); size_t memlen; if (eos == NULL) goto truncated; trunnel_assert(eos >= ptr); trunnel_assert((size_t)(eos - ptr) < SIZE_MAX - 1); memlen = ((size_t)(eos - ptr)) + 1; if (!(obj->socks4a_addr_hostname = trunnel_malloc(memlen))) goto fail; memcpy(obj->socks4a_addr_hostname, ptr, memlen); remaining -= memlen; ptr += memlen; } break; default: break; } trunnel_assert(ptr + remaining == input + len_in); return len_in - remaining; truncated: return -2; fail: result = -1; return result; } ssize_t socks4_client_request_parse(socks4_client_request_t **output, const uint8_t *input, const size_t len_in) { ssize_t result; *output = socks4_client_request_new(); if (NULL == *output) return -1; result = socks4_client_request_parse_into(*output, input, len_in); if (result < 0) { socks4_client_request_free(*output); *output = NULL; } return result; } socks4_server_reply_t * socks4_server_reply_new(void) { socks4_server_reply_t *val = trunnel_calloc(1, sizeof(socks4_server_reply_t)); if (NULL == val) return NULL; val->version = 4; return val; } /** Release all storage held inside 'obj', but do not free 'obj'. */ static void socks4_server_reply_clear(socks4_server_reply_t *obj) { (void) obj; } void socks4_server_reply_free(socks4_server_reply_t *obj) { if (obj == NULL) return; socks4_server_reply_clear(obj); trunnel_memwipe(obj, sizeof(socks4_server_reply_t)); trunnel_free_(obj); } uint8_t socks4_server_reply_get_version(const socks4_server_reply_t *inp) { return inp->version; } int socks4_server_reply_set_version(socks4_server_reply_t *inp, uint8_t val) { if (! ((val == 4))) { TRUNNEL_SET_ERROR_CODE(inp); return -1; } inp->version = val; return 0; } uint8_t socks4_server_reply_get_status(const socks4_server_reply_t *inp) { return inp->status; } int socks4_server_reply_set_status(socks4_server_reply_t *inp, uint8_t val) { inp->status = val; return 0; } uint16_t socks4_server_reply_get_port(const socks4_server_reply_t *inp) { return inp->port; } int socks4_server_reply_set_port(socks4_server_reply_t *inp, uint16_t val) { inp->port = val; return 0; } uint32_t socks4_server_reply_get_addr(const socks4_server_reply_t *inp) { return inp->addr; } int socks4_server_reply_set_addr(socks4_server_reply_t *inp, uint32_t val) { inp->addr = val; return 0; } const char * socks4_server_reply_check(const socks4_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 == 4)) return "Integer out of bounds"; return NULL; } ssize_t socks4_server_reply_encoded_len(const socks4_server_reply_t *obj) { ssize_t result = 0; if (NULL != socks4_server_reply_check(obj)) return -1; /* Length of u8 version IN [4] */ result += 1; /* Length of u8 status */ result += 1; /* Length of u16 port */ result += 2; /* Length of u32 addr */ result += 4; return result; } int socks4_server_reply_clear_errors(socks4_server_reply_t *obj) { int r = obj->trunnel_error_code_; obj->trunnel_error_code_ = 0; return r; } ssize_t socks4_server_reply_encode(uint8_t *output, const size_t avail, const socks4_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 = socks4_server_reply_encoded_len(obj); #endif if (NULL != (msg = socks4_server_reply_check(obj))) goto check_failed; #ifdef TRUNNEL_CHECK_ENCODED_LEN trunnel_assert(encoded_len >= 0); #endif /* Encode u8 version IN [4] */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->version)); written += 1; ptr += 1; /* Encode u8 status */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->status)); written += 1; ptr += 1; /* Encode u16 port */ trunnel_assert(written <= avail); if (avail - written < 2) goto truncated; trunnel_set_uint16(ptr, trunnel_htons(obj->port)); written += 2; ptr += 2; /* Encode u32 addr */ trunnel_assert(written <= avail); if (avail - written < 4) goto truncated; trunnel_set_uint32(ptr, trunnel_htonl(obj->addr)); written += 4; ptr += 4; 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 socks4_server_reply_parse(), but do not allocate the output * object. */ static ssize_t socks4_server_reply_parse_into(socks4_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 [4] */ CHECK_REMAINING(1, truncated); obj->version = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; if (! (obj->version == 4)) goto fail; /* Parse u8 status */ CHECK_REMAINING(1, truncated); obj->status = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; /* Parse u16 port */ CHECK_REMAINING(2, truncated); obj->port = trunnel_ntohs(trunnel_get_uint16(ptr)); remaining -= 2; ptr += 2; /* Parse u32 addr */ CHECK_REMAINING(4, truncated); obj->addr = trunnel_ntohl(trunnel_get_uint32(ptr)); remaining -= 4; ptr += 4; trunnel_assert(ptr + remaining == input + len_in); return len_in - remaining; truncated: return -2; fail: result = -1; return result; } ssize_t socks4_server_reply_parse(socks4_server_reply_t **output, const uint8_t *input, const size_t len_in) { ssize_t result; *output = socks4_server_reply_new(); if (NULL == *output) return -1; result = socks4_server_reply_parse_into(*output, input, len_in); if (result < 0) { socks4_server_reply_free(*output); *output = NULL; } return result; } socks5_client_userpass_auth_t * socks5_client_userpass_auth_new(void) { socks5_client_userpass_auth_t *val = trunnel_calloc(1, sizeof(socks5_client_userpass_auth_t)); if (NULL == val) return NULL; val->version = 1; return val; } /** Release all storage held inside 'obj', but do not free 'obj'. */ static void socks5_client_userpass_auth_clear(socks5_client_userpass_auth_t *obj) { (void) obj; TRUNNEL_DYNARRAY_WIPE(&obj->username); TRUNNEL_DYNARRAY_CLEAR(&obj->username); TRUNNEL_DYNARRAY_WIPE(&obj->passwd); TRUNNEL_DYNARRAY_CLEAR(&obj->passwd); } void socks5_client_userpass_auth_free(socks5_client_userpass_auth_t *obj) { if (obj == NULL) return; socks5_client_userpass_auth_clear(obj); trunnel_memwipe(obj, sizeof(socks5_client_userpass_auth_t)); trunnel_free_(obj); } uint8_t socks5_client_userpass_auth_get_version(const socks5_client_userpass_auth_t *inp) { return inp->version; } int socks5_client_userpass_auth_set_version(socks5_client_userpass_auth_t *inp, uint8_t val) { if (! ((val == 1))) { TRUNNEL_SET_ERROR_CODE(inp); return -1; } inp->version = val; return 0; } uint8_t socks5_client_userpass_auth_get_username_len(const socks5_client_userpass_auth_t *inp) { return inp->username_len; } int socks5_client_userpass_auth_set_username_len(socks5_client_userpass_auth_t *inp, uint8_t val) { inp->username_len = val; return 0; } size_t socks5_client_userpass_auth_getlen_username(const socks5_client_userpass_auth_t *inp) { return TRUNNEL_DYNARRAY_LEN(&inp->username); } char socks5_client_userpass_auth_get_username(socks5_client_userpass_auth_t *inp, size_t idx) { return TRUNNEL_DYNARRAY_GET(&inp->username, idx); } char socks5_client_userpass_auth_getconst_username(const socks5_client_userpass_auth_t *inp, size_t idx) { return socks5_client_userpass_auth_get_username((socks5_client_userpass_auth_t*)inp, idx); } int socks5_client_userpass_auth_set_username(socks5_client_userpass_auth_t *inp, size_t idx, char elt) { TRUNNEL_DYNARRAY_SET(&inp->username, idx, elt); return 0; } int socks5_client_userpass_auth_add_username(socks5_client_userpass_auth_t *inp, char elt) { #if SIZE_MAX >= UINT8_MAX if (inp->username.n_ == UINT8_MAX) goto trunnel_alloc_failed; #endif TRUNNEL_DYNARRAY_ADD(char, &inp->username, elt, {}); return 0; trunnel_alloc_failed: TRUNNEL_SET_ERROR_CODE(inp); return -1; } char * socks5_client_userpass_auth_getarray_username(socks5_client_userpass_auth_t *inp) { return inp->username.elts_; } const char * socks5_client_userpass_auth_getconstarray_username(const socks5_client_userpass_auth_t *inp) { return (const char *)socks5_client_userpass_auth_getarray_username((socks5_client_userpass_auth_t*)inp); } int socks5_client_userpass_auth_setlen_username(socks5_client_userpass_auth_t *inp, size_t newlen) { #if UINT8_MAX < SIZE_MAX if (newlen > UINT8_MAX) goto trunnel_alloc_failed; #endif return trunnel_string_setlen(&inp->username, newlen, &inp->trunnel_error_code_); trunnel_alloc_failed: TRUNNEL_SET_ERROR_CODE(inp); return -1; } const char * socks5_client_userpass_auth_getstr_username(socks5_client_userpass_auth_t *inp) { return trunnel_string_getstr(&inp->username); } int socks5_client_userpass_auth_setstr0_username(socks5_client_userpass_auth_t *inp, const char *val, size_t len) { #if UINT8_MAX < SIZE_MAX if (len > UINT8_MAX) { TRUNNEL_SET_ERROR_CODE(inp); return -1; } #endif return trunnel_string_setstr0(&inp->username, val, len, &inp->trunnel_error_code_); } int socks5_client_userpass_auth_setstr_username(socks5_client_userpass_auth_t *inp, const char *val) { return socks5_client_userpass_auth_setstr0_username(inp, val, strlen(val)); } uint8_t socks5_client_userpass_auth_get_passwd_len(const socks5_client_userpass_auth_t *inp) { return inp->passwd_len; } int socks5_client_userpass_auth_set_passwd_len(socks5_client_userpass_auth_t *inp, uint8_t val) { inp->passwd_len = val; return 0; } size_t socks5_client_userpass_auth_getlen_passwd(const socks5_client_userpass_auth_t *inp) { return TRUNNEL_DYNARRAY_LEN(&inp->passwd); } char socks5_client_userpass_auth_get_passwd(socks5_client_userpass_auth_t *inp, size_t idx) { return TRUNNEL_DYNARRAY_GET(&inp->passwd, idx); } char socks5_client_userpass_auth_getconst_passwd(const socks5_client_userpass_auth_t *inp, size_t idx) { return socks5_client_userpass_auth_get_passwd((socks5_client_userpass_auth_t*)inp, idx); } int socks5_client_userpass_auth_set_passwd(socks5_client_userpass_auth_t *inp, size_t idx, char elt) { TRUNNEL_DYNARRAY_SET(&inp->passwd, idx, elt); return 0; } int socks5_client_userpass_auth_add_passwd(socks5_client_userpass_auth_t *inp, char elt) { #if SIZE_MAX >= UINT8_MAX if (inp->passwd.n_ == UINT8_MAX) goto trunnel_alloc_failed; #endif TRUNNEL_DYNARRAY_ADD(char, &inp->passwd, elt, {}); return 0; trunnel_alloc_failed: TRUNNEL_SET_ERROR_CODE(inp); return -1; } char * socks5_client_userpass_auth_getarray_passwd(socks5_client_userpass_auth_t *inp) { return inp->passwd.elts_; } const char * socks5_client_userpass_auth_getconstarray_passwd(const socks5_client_userpass_auth_t *inp) { return (const char *)socks5_client_userpass_auth_getarray_passwd((socks5_client_userpass_auth_t*)inp); } int socks5_client_userpass_auth_setlen_passwd(socks5_client_userpass_auth_t *inp, size_t newlen) { #if UINT8_MAX < SIZE_MAX if (newlen > UINT8_MAX) goto trunnel_alloc_failed; #endif return trunnel_string_setlen(&inp->passwd, newlen, &inp->trunnel_error_code_); trunnel_alloc_failed: TRUNNEL_SET_ERROR_CODE(inp); return -1; } const char * socks5_client_userpass_auth_getstr_passwd(socks5_client_userpass_auth_t *inp) { return trunnel_string_getstr(&inp->passwd); } int socks5_client_userpass_auth_setstr0_passwd(socks5_client_userpass_auth_t *inp, const char *val, size_t len) { #if UINT8_MAX < SIZE_MAX if (len > UINT8_MAX) { TRUNNEL_SET_ERROR_CODE(inp); return -1; } #endif return trunnel_string_setstr0(&inp->passwd, val, len, &inp->trunnel_error_code_); } int socks5_client_userpass_auth_setstr_passwd(socks5_client_userpass_auth_t *inp, const char *val) { return socks5_client_userpass_auth_setstr0_passwd(inp, val, strlen(val)); } const char * socks5_client_userpass_auth_check(const socks5_client_userpass_auth_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)) return "Integer out of bounds"; if (TRUNNEL_DYNARRAY_LEN(&obj->username) != obj->username_len) return "Length mismatch for username"; if (TRUNNEL_DYNARRAY_LEN(&obj->passwd) != obj->passwd_len) return "Length mismatch for passwd"; return NULL; } ssize_t socks5_client_userpass_auth_encoded_len(const socks5_client_userpass_auth_t *obj) { ssize_t result = 0; if (NULL != socks5_client_userpass_auth_check(obj)) return -1; /* Length of u8 version IN [1] */ result += 1; /* Length of u8 username_len */ result += 1; /* Length of char username[username_len] */ result += TRUNNEL_DYNARRAY_LEN(&obj->username); /* Length of u8 passwd_len */ result += 1; /* Length of char passwd[passwd_len] */ result += TRUNNEL_DYNARRAY_LEN(&obj->passwd); return result; } int socks5_client_userpass_auth_clear_errors(socks5_client_userpass_auth_t *obj) { int r = obj->trunnel_error_code_; obj->trunnel_error_code_ = 0; return r; } ssize_t socks5_client_userpass_auth_encode(uint8_t *output, const size_t avail, const socks5_client_userpass_auth_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_userpass_auth_encoded_len(obj); #endif if (NULL != (msg = socks5_client_userpass_auth_check(obj))) goto check_failed; #ifdef TRUNNEL_CHECK_ENCODED_LEN trunnel_assert(encoded_len >= 0); #endif /* Encode u8 version IN [1] */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->version)); written += 1; ptr += 1; /* Encode u8 username_len */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->username_len)); written += 1; ptr += 1; /* Encode char username[username_len] */ { size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->username); trunnel_assert(obj->username_len == elt_len); trunnel_assert(written <= avail); if (avail - written < elt_len) goto truncated; if (elt_len) memcpy(ptr, obj->username.elts_, elt_len); written += elt_len; ptr += elt_len; } /* Encode u8 passwd_len */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->passwd_len)); written += 1; ptr += 1; /* Encode char passwd[passwd_len] */ { size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->passwd); trunnel_assert(obj->passwd_len == elt_len); trunnel_assert(written <= avail); if (avail - written < elt_len) goto truncated; if (elt_len) memcpy(ptr, obj->passwd.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 socks5_client_userpass_auth_parse(), but do not allocate the * output object. */ static ssize_t socks5_client_userpass_auth_parse_into(socks5_client_userpass_auth_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] */ CHECK_REMAINING(1, truncated); obj->version = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; if (! (obj->version == 1)) goto fail; /* Parse u8 username_len */ CHECK_REMAINING(1, truncated); obj->username_len = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; /* Parse char username[username_len] */ CHECK_REMAINING(obj->username_len, truncated); if (socks5_client_userpass_auth_setstr0_username(obj, (const char*)ptr, obj->username_len)) goto fail; ptr += obj->username_len; remaining -= obj->username_len; /* Parse u8 passwd_len */ CHECK_REMAINING(1, truncated); obj->passwd_len = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; /* Parse char passwd[passwd_len] */ CHECK_REMAINING(obj->passwd_len, truncated); if (socks5_client_userpass_auth_setstr0_passwd(obj, (const char*)ptr, obj->passwd_len)) goto fail; ptr += obj->passwd_len; remaining -= obj->passwd_len; trunnel_assert(ptr + remaining == input + len_in); return len_in - remaining; truncated: return -2; fail: result = -1; return result; } ssize_t socks5_client_userpass_auth_parse(socks5_client_userpass_auth_t **output, const uint8_t *input, const size_t len_in) { ssize_t result; *output = socks5_client_userpass_auth_new(); if (NULL == *output) return -1; result = socks5_client_userpass_auth_parse_into(*output, input, len_in); if (result < 0) { socks5_client_userpass_auth_free(*output); *output = NULL; } return result; } socks5_client_version_t * socks5_client_version_new(void) { socks5_client_version_t *val = trunnel_calloc(1, sizeof(socks5_client_version_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_client_version_clear(socks5_client_version_t *obj) { (void) obj; TRUNNEL_DYNARRAY_WIPE(&obj->methods); TRUNNEL_DYNARRAY_CLEAR(&obj->methods); } void socks5_client_version_free(socks5_client_version_t *obj) { if (obj == NULL) return; socks5_client_version_clear(obj); trunnel_memwipe(obj, sizeof(socks5_client_version_t)); trunnel_free_(obj); } uint8_t socks5_client_version_get_version(const socks5_client_version_t *inp) { return inp->version; } int socks5_client_version_set_version(socks5_client_version_t *inp, uint8_t val) { if (! ((val == 5))) { TRUNNEL_SET_ERROR_CODE(inp); return -1; } inp->version = val; return 0; } uint8_t socks5_client_version_get_n_methods(const socks5_client_version_t *inp) { return inp->n_methods; } int socks5_client_version_set_n_methods(socks5_client_version_t *inp, uint8_t val) { inp->n_methods = val; return 0; } size_t socks5_client_version_getlen_methods(const socks5_client_version_t *inp) { return TRUNNEL_DYNARRAY_LEN(&inp->methods); } uint8_t socks5_client_version_get_methods(socks5_client_version_t *inp, size_t idx) { return TRUNNEL_DYNARRAY_GET(&inp->methods, idx); } uint8_t socks5_client_version_getconst_methods(const socks5_client_version_t *inp, size_t idx) { return socks5_client_version_get_methods((socks5_client_version_t*)inp, idx); } int socks5_client_version_set_methods(socks5_client_version_t *inp, size_t idx, uint8_t elt) { TRUNNEL_DYNARRAY_SET(&inp->methods, idx, elt); return 0; } int socks5_client_version_add_methods(socks5_client_version_t *inp, uint8_t elt) { #if SIZE_MAX >= UINT8_MAX if (inp->methods.n_ == UINT8_MAX) goto trunnel_alloc_failed; #endif TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->methods, elt, {}); return 0; trunnel_alloc_failed: TRUNNEL_SET_ERROR_CODE(inp); return -1; } uint8_t * socks5_client_version_getarray_methods(socks5_client_version_t *inp) { return inp->methods.elts_; } const uint8_t * socks5_client_version_getconstarray_methods(const socks5_client_version_t *inp) { return (const uint8_t *)socks5_client_version_getarray_methods((socks5_client_version_t*)inp); } int socks5_client_version_setlen_methods(socks5_client_version_t *inp, size_t newlen) { uint8_t *newptr; #if UINT8_MAX < SIZE_MAX if (newlen > UINT8_MAX) goto trunnel_alloc_failed; #endif newptr = trunnel_dynarray_setlen(&inp->methods.allocated_, &inp->methods.n_, inp->methods.elts_, newlen, sizeof(inp->methods.elts_[0]), (trunnel_free_fn_t) NULL, &inp->trunnel_error_code_); if (newlen != 0 && newptr == NULL) goto trunnel_alloc_failed; inp->methods.elts_ = newptr; return 0; trunnel_alloc_failed: TRUNNEL_SET_ERROR_CODE(inp); return -1; } const char * socks5_client_version_check(const socks5_client_version_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 (TRUNNEL_DYNARRAY_LEN(&obj->methods) != obj->n_methods) return "Length mismatch for methods"; return NULL; } ssize_t socks5_client_version_encoded_len(const socks5_client_version_t *obj) { ssize_t result = 0; if (NULL != socks5_client_version_check(obj)) return -1; /* Length of u8 version IN [5] */ result += 1; /* Length of u8 n_methods */ result += 1; /* Length of u8 methods[n_methods] */ result += TRUNNEL_DYNARRAY_LEN(&obj->methods); return result; } int socks5_client_version_clear_errors(socks5_client_version_t *obj) { int r = obj->trunnel_error_code_; obj->trunnel_error_code_ = 0; return r; } ssize_t socks5_client_version_encode(uint8_t *output, const size_t avail, const socks5_client_version_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_version_encoded_len(obj); #endif if (NULL != (msg = socks5_client_version_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 n_methods */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->n_methods)); written += 1; ptr += 1; /* Encode u8 methods[n_methods] */ { size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->methods); trunnel_assert(obj->n_methods == elt_len); trunnel_assert(written <= avail); if (avail - written < elt_len) goto truncated; if (elt_len) memcpy(ptr, obj->methods.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 socks5_client_version_parse(), but do not allocate the output * object. */ static ssize_t socks5_client_version_parse_into(socks5_client_version_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 n_methods */ CHECK_REMAINING(1, truncated); obj->n_methods = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; /* Parse u8 methods[n_methods] */ CHECK_REMAINING(obj->n_methods, truncated); TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->methods, obj->n_methods, {}); obj->methods.n_ = obj->n_methods; if (obj->n_methods) memcpy(obj->methods.elts_, ptr, obj->n_methods); ptr += obj->n_methods; remaining -= obj->n_methods; trunnel_assert(ptr + remaining == input + len_in); return len_in - remaining; truncated: return -2; trunnel_alloc_failed: return -1; fail: result = -1; return result; } ssize_t socks5_client_version_parse(socks5_client_version_t **output, const uint8_t *input, const size_t len_in) { ssize_t result; *output = socks5_client_version_new(); if (NULL == *output) return -1; result = socks5_client_version_parse_into(*output, input, len_in); if (result < 0) { socks5_client_version_free(*output); *output = NULL; } return result; } socks5_server_method_t * socks5_server_method_new(void) { socks5_server_method_t *val = trunnel_calloc(1, sizeof(socks5_server_method_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_method_clear(socks5_server_method_t *obj) { (void) obj; } void socks5_server_method_free(socks5_server_method_t *obj) { if (obj == NULL) return; socks5_server_method_clear(obj); trunnel_memwipe(obj, sizeof(socks5_server_method_t)); trunnel_free_(obj); } uint8_t socks5_server_method_get_version(const socks5_server_method_t *inp) { return inp->version; } int socks5_server_method_set_version(socks5_server_method_t *inp, uint8_t val) { if (! ((val == 5))) { TRUNNEL_SET_ERROR_CODE(inp); return -1; } inp->version = val; return 0; } uint8_t socks5_server_method_get_method(const socks5_server_method_t *inp) { return inp->method; } int socks5_server_method_set_method(socks5_server_method_t *inp, uint8_t val) { inp->method = val; return 0; } const char * socks5_server_method_check(const socks5_server_method_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"; return NULL; } ssize_t socks5_server_method_encoded_len(const socks5_server_method_t *obj) { ssize_t result = 0; if (NULL != socks5_server_method_check(obj)) return -1; /* Length of u8 version IN [5] */ result += 1; /* Length of u8 method */ result += 1; return result; } int socks5_server_method_clear_errors(socks5_server_method_t *obj) { int r = obj->trunnel_error_code_; obj->trunnel_error_code_ = 0; return r; } ssize_t socks5_server_method_encode(uint8_t *output, const size_t avail, const socks5_server_method_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_method_encoded_len(obj); #endif if (NULL != (msg = socks5_server_method_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 method */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->method)); written += 1; ptr += 1; 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_method_parse(), but do not allocate the output * object. */ static ssize_t socks5_server_method_parse_into(socks5_server_method_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 method */ CHECK_REMAINING(1, truncated); obj->method = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; trunnel_assert(ptr + remaining == input + len_in); return len_in - remaining; truncated: return -2; fail: result = -1; return result; } ssize_t socks5_server_method_parse(socks5_server_method_t **output, const uint8_t *input, const size_t len_in) { ssize_t result; *output = socks5_server_method_new(); if (NULL == *output) return -1; result = socks5_server_method_parse_into(*output, input, len_in); if (result < 0) { socks5_server_method_free(*output); *output = NULL; } return result; } socks5_server_userpass_auth_t * socks5_server_userpass_auth_new(void) { socks5_server_userpass_auth_t *val = trunnel_calloc(1, sizeof(socks5_server_userpass_auth_t)); if (NULL == val) return NULL; val->version = 1; return val; } /** Release all storage held inside 'obj', but do not free 'obj'. */ static void socks5_server_userpass_auth_clear(socks5_server_userpass_auth_t *obj) { (void) obj; } void socks5_server_userpass_auth_free(socks5_server_userpass_auth_t *obj) { if (obj == NULL) return; socks5_server_userpass_auth_clear(obj); trunnel_memwipe(obj, sizeof(socks5_server_userpass_auth_t)); trunnel_free_(obj); } uint8_t socks5_server_userpass_auth_get_version(const socks5_server_userpass_auth_t *inp) { return inp->version; } int socks5_server_userpass_auth_set_version(socks5_server_userpass_auth_t *inp, uint8_t val) { if (! ((val == 1))) { TRUNNEL_SET_ERROR_CODE(inp); return -1; } inp->version = val; return 0; } uint8_t socks5_server_userpass_auth_get_status(const socks5_server_userpass_auth_t *inp) { return inp->status; } int socks5_server_userpass_auth_set_status(socks5_server_userpass_auth_t *inp, uint8_t val) { inp->status = val; return 0; } const char * socks5_server_userpass_auth_check(const socks5_server_userpass_auth_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)) return "Integer out of bounds"; return NULL; } ssize_t socks5_server_userpass_auth_encoded_len(const socks5_server_userpass_auth_t *obj) { ssize_t result = 0; if (NULL != socks5_server_userpass_auth_check(obj)) return -1; /* Length of u8 version IN [1] */ result += 1; /* Length of u8 status */ result += 1; return result; } int socks5_server_userpass_auth_clear_errors(socks5_server_userpass_auth_t *obj) { int r = obj->trunnel_error_code_; obj->trunnel_error_code_ = 0; return r; } ssize_t socks5_server_userpass_auth_encode(uint8_t *output, const size_t avail, const socks5_server_userpass_auth_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_userpass_auth_encoded_len(obj); #endif if (NULL != (msg = socks5_server_userpass_auth_check(obj))) goto check_failed; #ifdef TRUNNEL_CHECK_ENCODED_LEN trunnel_assert(encoded_len >= 0); #endif /* Encode u8 version IN [1] */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->version)); written += 1; ptr += 1; /* Encode u8 status */ trunnel_assert(written <= avail); if (avail - written < 1) goto truncated; trunnel_set_uint8(ptr, (obj->status)); written += 1; ptr += 1; 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_userpass_auth_parse(), but do not allocate the * output object. */ static ssize_t socks5_server_userpass_auth_parse_into(socks5_server_userpass_auth_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] */ CHECK_REMAINING(1, truncated); obj->version = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; if (! (obj->version == 1)) goto fail; /* Parse u8 status */ CHECK_REMAINING(1, truncated); obj->status = (trunnel_get_uint8(ptr)); remaining -= 1; ptr += 1; trunnel_assert(ptr + remaining == input + len_in); return len_in - remaining; truncated: return -2; fail: result = -1; return result; } ssize_t socks5_server_userpass_auth_parse(socks5_server_userpass_auth_t **output, const uint8_t *input, const size_t len_in) { ssize_t result; *output = socks5_server_userpass_auth_new(); if (NULL == *output) return -1; result = socks5_server_userpass_auth_parse_into(*output, input, len_in); if (result < 0) { socks5_server_userpass_auth_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; } 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; }