/** Set *<b>out</b> to a newly allocated SOCKS4a resolve request with * <b>username</b> and <b>hostname</b> as provided. Return the number * of bytes in the request. */ static ssize_t build_socks_resolve_request(char **out, const char *username, const char *hostname, int reverse, int version) { size_t len = 0; tor_assert(out); tor_assert(username); tor_assert(hostname); if (version == 4) { len = 8 + strlen(username) + 1 + strlen(hostname) + 1; *out = tor_malloc(len); (*out)[0] = 4; /* SOCKS version 4 */ (*out)[1] = '\xF0'; /* Command: resolve. */ set_uint16((*out)+2, htons(0)); /* port: 0. */ set_uint32((*out)+4, htonl(0x00000001u)); /* addr: 0.0.0.1 */ memcpy((*out)+8, username, strlen(username)+1); memcpy((*out)+8+strlen(username)+1, hostname, strlen(hostname)+1); } else if (version == 5) { int is_ip_address; tor_addr_t addr; size_t addrlen; int ipv6; is_ip_address = tor_addr_parse(&addr, hostname) != -1; if (!is_ip_address && reverse) { log_err(LD_GENERAL, "Tried to do a reverse lookup on a non-IP!"); return -1; } ipv6 = reverse && tor_addr_family(&addr) == AF_INET6; addrlen = reverse ? (ipv6 ? 16 : 4) : 1 + strlen(hostname); len = 6 + addrlen; *out = tor_malloc(len); (*out)[0] = 5; /* SOCKS version 5 */ (*out)[1] = reverse ? '\xF1' : '\xF0'; /* RESOLVE_PTR or RESOLVE */ (*out)[2] = 0; /* reserved. */ if (reverse) { (*out)[3] = ipv6 ? 4 : 1; if (ipv6) memcpy((*out)+4, tor_addr_to_in6_addr8(&addr), 16); else set_uint32((*out)+4, tor_addr_to_ipv4n(&addr)); } else { (*out)[3] = 3; (*out)[4] = (char)(uint8_t)(addrlen - 1); memcpy((*out)+5, hostname, addrlen - 1); } set_uint16((*out)+4+addrlen, 0); /* port */ } else { tor_assert(0); } return len; }
static void test_address_tor_addr_to_ipv4n(void *ignored) { (void)ignored; tor_addr_t *a = tor_malloc_zero(sizeof(tor_addr_t)); uint32_t res; a->family = AF_INET6; res = tor_addr_to_ipv4n(a); tt_assert(!res); a->family = AF_INET; a->addr.in_addr.s_addr = 43; res = tor_addr_to_ipv4n(a); tt_assert(res); tt_int_op(res, OP_EQ, 43); done: tor_free(a); }
static void update_difference(int ipv6, uint8_t *d, const tor_addr_t *a, const tor_addr_t *b) { const int n_bytes = ipv6 ? 16 : 4; uint8_t a_tmp[4], b_tmp[4]; const uint8_t *ba, *bb; int i; if (ipv6) { ba = tor_addr_to_in6_addr8(a); bb = tor_addr_to_in6_addr8(b); } else { set_uint32(a_tmp, tor_addr_to_ipv4n(a)); set_uint32(b_tmp, tor_addr_to_ipv4n(b)); ba = a_tmp; bb = b_tmp; } for (i = 0; i < n_bytes; ++i) { d[i] |= ba[i] ^ bb[i]; } }
/** Convert the tor_addr_t in <b>a</b>, with port in <b>port</b>, into a * sockaddr object in *<b>sa_out</b> of object size <b>len</b>. If not enough * room is available in sa_out, or on error, return 0. On success, return * the length of the sockaddr. * * Interface note: ordinarily, we return -1 for error. We can't do that here, * since socklen_t is unsigned on some platforms. **/ socklen_t tor_addr_to_sockaddr(const tor_addr_t *a, uint16_t port, struct sockaddr *sa_out, socklen_t len) { sa_family_t family = tor_addr_family(a); if (family == AF_INET) { struct sockaddr_in *sin; if (len < (int)sizeof(struct sockaddr_in)) return 0; sin = (struct sockaddr_in *)sa_out; memset(sin, 0, sizeof(struct sockaddr_in)); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin->sin_len = sizeof(struct sockaddr_in); #endif sin->sin_family = AF_INET; sin->sin_port = htons(port); sin->sin_addr.s_addr = tor_addr_to_ipv4n(a); return sizeof(struct sockaddr_in); } else if (family == AF_INET6) { struct sockaddr_in6 *sin6; if (len < (int)sizeof(struct sockaddr_in6)) return 0; sin6 = (struct sockaddr_in6 *)sa_out; memset(sin6, 0, sizeof(struct sockaddr_in6)); #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6->sin6_len = sizeof(struct sockaddr_in6); #endif sin6->sin6_family = AF_INET6; sin6->sin6_port = htons(port); memcpy(&sin6->sin6_addr, tor_addr_to_in6(a), sizeof(struct in6_addr)); return sizeof(struct sockaddr_in6); } else { return 0; } }
/** Format the EXTEND{,2} cell in <b>cell_in</b>, storing its relay payload in * <b>payload_out</b>, the number of bytes used in *<b>len_out</b>, and the * relay command in *<b>command_out</b>. The <b>payload_out</b> must have * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */ int extend_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extend_cell_t *cell_in) { uint8_t *p, *eop; if (check_extend_cell(cell_in) < 0) return -1; p = payload_out; eop = payload_out + RELAY_PAYLOAD_SIZE; memset(p, 0, RELAY_PAYLOAD_SIZE); switch (cell_in->cell_type) { case RELAY_COMMAND_EXTEND: { *command_out = RELAY_COMMAND_EXTEND; *len_out = 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN; set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr)); set_uint16(p+4, ntohs(cell_in->orport_ipv4.port)); if (cell_in->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_NTOR) { memcpy(p+6, NTOR_CREATE_MAGIC, 16); memcpy(p+22, cell_in->create_cell.onionskin, NTOR_ONIONSKIN_LEN); } else { memcpy(p+6, cell_in->create_cell.onionskin, TAP_ONIONSKIN_CHALLENGE_LEN); } memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->node_id, DIGEST_LEN); } break; case RELAY_COMMAND_EXTEND2: { uint8_t n = 2; *command_out = RELAY_COMMAND_EXTEND2; *p++ = n; /* 2 identifiers */ *p++ = SPECTYPE_IPV4; /* First is IPV4. */ *p++ = 6; /* It's 6 bytes long. */ set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr)); set_uint16(p+4, htons(cell_in->orport_ipv4.port)); p += 6; *p++ = SPECTYPE_LEGACY_ID; /* Next is an identity digest. */ *p++ = 20; /* It's 20 bytes long */ memcpy(p, cell_in->node_id, DIGEST_LEN); p += 20; /* Now we can send the handshake */ set_uint16(p, htons(cell_in->create_cell.handshake_type)); set_uint16(p+2, htons(cell_in->create_cell.handshake_len)); p += 4; if (cell_in->create_cell.handshake_len > eop - p) return -1; memcpy(p, cell_in->create_cell.onionskin, cell_in->create_cell.handshake_len); p += cell_in->create_cell.handshake_len; *len_out = p - payload_out; } break; default: return -1; } return 0; }
/** Format the EXTEND{,2} cell in <b>cell_in</b>, storing its relay payload in * <b>payload_out</b>, the number of bytes used in *<b>len_out</b>, and the * relay command in *<b>command_out</b>. The <b>payload_out</b> must have * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */ int extend_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extend_cell_t *cell_in) { uint8_t *p; if (check_extend_cell(cell_in) < 0) return -1; p = payload_out; memset(p, 0, RELAY_PAYLOAD_SIZE); switch (cell_in->cell_type) { case RELAY_COMMAND_EXTEND: { *command_out = RELAY_COMMAND_EXTEND; *len_out = 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN; set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr)); set_uint16(p+4, htons(cell_in->orport_ipv4.port)); if (cell_in->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_NTOR) { memcpy(p+6, NTOR_CREATE_MAGIC, 16); memcpy(p+22, cell_in->create_cell.onionskin, NTOR_ONIONSKIN_LEN); } else { memcpy(p+6, cell_in->create_cell.onionskin, TAP_ONIONSKIN_CHALLENGE_LEN); } memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->node_id, DIGEST_LEN); } break; case RELAY_COMMAND_EXTEND2: { uint8_t n_specifiers = 2; *command_out = RELAY_COMMAND_EXTEND2; extend2_cell_body_t *cell = extend2_cell_body_new(); link_specifier_t *ls; { /* IPv4 specifier first. */ ls = link_specifier_new(); extend2_cell_body_add_ls(cell, ls); ls->ls_type = LS_IPV4; ls->ls_len = 6; ls->un_ipv4_addr = tor_addr_to_ipv4h(&cell_in->orport_ipv4.addr); ls->un_ipv4_port = cell_in->orport_ipv4.port; } { /* Then RSA id */ ls = link_specifier_new(); extend2_cell_body_add_ls(cell, ls); ls->ls_type = LS_LEGACY_ID; ls->ls_len = DIGEST_LEN; memcpy(ls->un_legacy_id, cell_in->node_id, DIGEST_LEN); } if (should_include_ed25519_id_extend_cells(NULL, get_options()) && !ed25519_public_key_is_zero(&cell_in->ed_pubkey)) { /* Then, maybe, the ed25519 id! */ ++n_specifiers; ls = link_specifier_new(); extend2_cell_body_add_ls(cell, ls); ls->ls_type = LS_ED25519_ID; ls->ls_len = 32; memcpy(ls->un_ed25519_id, cell_in->ed_pubkey.pubkey, 32); } cell->n_spec = n_specifiers; /* Now, the handshake */ cell->create2 = create2_cell_body_new(); cell->create2->handshake_type = cell_in->create_cell.handshake_type; cell->create2->handshake_len = cell_in->create_cell.handshake_len; create2_cell_body_setlen_handshake_data(cell->create2, cell_in->create_cell.handshake_len); memcpy(create2_cell_body_getarray_handshake_data(cell->create2), cell_in->create_cell.onionskin, cell_in->create_cell.handshake_len); ssize_t len_encoded = extend2_cell_body_encode( payload_out, RELAY_PAYLOAD_SIZE, cell); extend2_cell_body_free(cell); if (len_encoded < 0 || len_encoded > UINT16_MAX) return -1; *len_out = (uint16_t) len_encoded; } break; default: return -1; } return 0; }