/** Given a <b>len</b>-byte SOCKS4a response in <b>response</b>, set * *<b>addr_out</b> to the address it contains (in host order). * Return 0 on success, -1 on error. */ static int parse_socks4a_resolve_response(const char *hostname, const char *response, size_t len, tor_addr_t *addr_out) { uint8_t status; tor_assert(response); tor_assert(addr_out); if (len < RESPONSE_LEN_4) { log_warn(LD_PROTOCOL,"Truncated socks response."); return -1; } if (((uint8_t)response[0])!=0) { /* version: 0 */ log_warn(LD_PROTOCOL,"Nonzero version in socks response: bad format."); return -1; } status = (uint8_t)response[1]; if (get_uint16(response+2)!=0) { /* port: 0 */ log_warn(LD_PROTOCOL,"Nonzero port in socks response: bad format."); return -1; } if (status != 90) { log_warn(LD_NET,"Got status response '%d': socks request failed.", status); if (!strcasecmpend(hostname, ".onion")) { onion_warning(hostname); return -1; } return -1; } tor_addr_from_ipv4n(addr_out, get_uint32(response+4)); return 0; }
int store_pool_entry(dead_pool *pool, char *hostname, struct in_addr *addr) { int position = pool->write_pos; int oldpos; int rc; uint32_t intaddr; char *result_hostname; show_msg(MSGDEBUG, "store_pool_entry: storing '%s'\n", hostname); show_msg(MSGDEBUG, "store_pool_entry: write pos is: %d\n", pool->write_pos); /* Check to see if name already exists in pool */ oldpos = search_pool_for_name(pool, hostname); if(oldpos != -1){ show_msg(MSGDEBUG, "store_pool_entry: not storing (entry exists)\n"); addr->s_addr = pool->entries[oldpos].ip; return oldpos; } /* If this is a .onion host, then we return a bogus ip from our deadpool, otherwise we try to resolve it and store the 'real' IP */ if(strcasecmpend(hostname, ".onion") == 0) { get_next_dead_address(pool, &pool->entries[position].ip); } else { rc = do_resolve(hostname, pool->sockshost, pool->socksport, &intaddr, 0, 4 /*SOCKS5*/, 0 /*Reverse*/, &result_hostname); if(rc != 0) { show_msg(MSGWARN, "failed to resolve: %s\n", hostname); return -1; } if(is_dead_address(pool, intaddr)) { show_msg(MSGERR, "resolved %s -> %d (deadpool address) IGNORED\n"); return -1; } pool->entries[position].ip = intaddr; } strncpy(pool->entries[position].name, hostname, 255); pool->entries[position].name[255] = '\0'; pool->write_pos++; if(pool->write_pos >= pool->n_entries) { pool->write_pos = 0; } addr->s_addr = pool->entries[position].ip; show_msg(MSGDEBUG, "store_pool_entry: stored entry in slot '%d'\n", position); return position; }
/** Given a <b>len</b>-byte SOCKS4a response in <b>response</b>, set * *<b>addr_out</b> to the address it contains (in host order). * Return 0 on success, -1 on error. */ static int parse_socks4a_resolve_response(const char *hostname, const char *response, size_t len, uint32_t *addr_out) { uint8_t status; tor_assert(response); tor_assert(addr_out); if (len < RESPONSE_LEN_4) { log_warn(LD_PROTOCOL,"Truncated socks response."); return -1; } if (((uint8_t)response[0])!=0) { /* version: 0 */ log_warn(LD_PROTOCOL,"Nonzero version in socks response: bad format."); return -1; } status = (uint8_t)response[1]; if (get_uint16(response+2)!=0) { /* port: 0 */ log_warn(LD_PROTOCOL,"Nonzero port in socks response: bad format."); return -1; } if (status != 90) { log_warn(LD_NET,"Got status response '%d': socks request failed.", status); if (!strcasecmpend(hostname, ".onion")) { log_warn(LD_NET, "%s is a hidden service; those don't have IP addresses. " "To connect to a hidden service, you need to send the hostname " "to Tor; we suggest an application that uses SOCKS 4a.",hostname); return -1; } return -1; } *addr_out = ntohl(get_uint32(response+4)); return 0; }
/** Entry point to tor-resolve */ int main(int argc, char **argv) { uint32_t sockshost; uint16_t socksport; int isSocks4 = 0, isVerbose = 0, isReverse = 0, force = 0; char **arg; int n_args; struct in_addr a; uint32_t result = 0; char *result_hostname = NULL; char buf[INET_NTOA_BUF_LEN]; init_logging(); arg = &argv[1]; n_args = argc-1; if (!n_args) usage(); if (!strcmp(arg[0],"--version")) { printf("Tor version %s.\n",VERSION); return 0; } while (n_args && *arg[0] == '-') { if (!strcmp("-v", arg[0])) isVerbose = 1; else if (!strcmp("-4", arg[0])) isSocks4 = 1; else if (!strcmp("-5", arg[0])) isSocks4 = 0; else if (!strcmp("-x", arg[0])) isReverse = 1; else if (!strcmp("-F", arg[0])) force = 1; else { fprintf(stderr, "Unrecognized flag '%s'\n", arg[0]); usage(); } ++arg; --n_args; } if (isSocks4 && isReverse) { fprintf(stderr, "Reverse lookups not supported with SOCKS4a\n"); usage(); } if (isVerbose) { add_stream_log(LOG_DEBUG, LOG_ERR, "<stderr>", stderr); } else { add_stream_log(LOG_WARN, LOG_ERR, "<stderr>", stderr); } if (n_args == 1) { log_debug(LD_CONFIG, "defaulting to localhost:9050"); sockshost = 0x7f000001u; /* localhost */ socksport = 9050; /* 9050 */ } else if (n_args == 2) { if (parse_addr_port(LOG_WARN, arg[1], NULL, &sockshost, &socksport)<0) { fprintf(stderr, "Couldn't parse/resolve address %s", arg[1]); return 1; } if (socksport == 0) { log_debug(LD_CONFIG, "defaulting to port 9050"); socksport = 9050; } } else { usage(); } if (!strcasecmpend(arg[0], ".onion") && !force) { fprintf(stderr, "%s is a hidden service; those don't have IP addresses.\n\n" "To connect to a hidden service, you need to send the hostname\n" "to Tor; we suggest an application that uses SOCKS 4a.\n", arg[0]); return 1; } if (network_init()<0) { log_err(LD_BUG,"Error initializing network; exiting."); return 1; } if (do_resolve(arg[0], sockshost, socksport, isReverse, isSocks4 ? 4 : 5, &result, &result_hostname)) return 1; if (result_hostname) { printf("%s\n", result_hostname); } else { a.s_addr = htonl(result); tor_inet_ntoa(&a, buf, sizeof(buf)); printf("%s\n", buf); } return 0; }
/** Send a resolve request for <b>hostname</b> to the Tor listening on * <b>sockshost</b>:<b>socksport</b>. Store the resulting IPv4 * address (in host order) into *<b>result_addr</b>. */ static int do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport, int reverse, int version, uint32_t *result_addr, char **result_hostname) { int s; struct sockaddr_in socksaddr; char *req = NULL; ssize_t len = 0; tor_assert(hostname); tor_assert(result_addr); tor_assert(version == 4 || version == 5); *result_addr = 0; *result_hostname = NULL; s = tor_open_socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); if (s<0) { log_sock_error("creating_socket", -1); return -1; } memset(&socksaddr, 0, sizeof(socksaddr)); socksaddr.sin_family = AF_INET; socksaddr.sin_port = htons(socksport); socksaddr.sin_addr.s_addr = htonl(sockshost); if (connect(s, (struct sockaddr*)&socksaddr, sizeof(socksaddr))) { log_sock_error("connecting to SOCKS host", s); return -1; } if (version == 5) { char method_buf[2]; if (write_all(s, "\x05\x01\x00", 3, 1) != 3) { log_err(LD_NET, "Error sending SOCKS5 method list."); return -1; } if (read_all(s, method_buf, 2, 1) != 2) { log_err(LD_NET, "Error reading SOCKS5 methods."); return -1; } if (method_buf[0] != '\x05') { log_err(LD_NET, "Unrecognized socks version: %u", (unsigned)method_buf[0]); return -1; } if (method_buf[1] != '\x00') { log_err(LD_NET, "Unrecognized socks authentication method: %u", (unsigned)method_buf[1]); return -1; } } if ((len = build_socks_resolve_request(&req, "", hostname, reverse, version))<0) { log_err(LD_BUG,"Error generating SOCKS request"); tor_assert(!req); return -1; } if (write_all(s, req, len, 1) != len) { log_sock_error("sending SOCKS request", s); tor_free(req); return -1; } tor_free(req); if (version == 4) { char reply_buf[RESPONSE_LEN_4]; if (read_all(s, reply_buf, RESPONSE_LEN_4, 1) != RESPONSE_LEN_4) { log_err(LD_NET, "Error reading SOCKS4 response."); return -1; } if (parse_socks4a_resolve_response(hostname, reply_buf, RESPONSE_LEN_4, result_addr)<0){ return -1; } } else { char reply_buf[4]; if (read_all(s, reply_buf, 4, 1) != 4) { log_err(LD_NET, "Error reading SOCKS5 response."); return -1; } if (reply_buf[0] != 5) { log_err(LD_NET, "Bad SOCKS5 reply version."); return -1; } /* Give a user some useful feedback about SOCKS5 errors */ if (reply_buf[1] != 0) { log_warn(LD_NET,"Got SOCKS5 status response '%u': %s", (unsigned)reply_buf[1], socks5_reason_to_string(reply_buf[1])); if (reply_buf[1] == 4 && !strcasecmpend(hostname, ".onion")) { log_warn(LD_NET, "%s is a hidden service; those don't have IP addresses. " "To connect to a hidden service, you need to send the hostname " "to Tor; we suggest an application that uses SOCKS 4a.", hostname); } return -1; } if (reply_buf[3] == 1) { /* IPv4 address */ if (read_all(s, reply_buf, 4, 1) != 4) { log_err(LD_NET, "Error reading address in socks5 response."); return -1; } *result_addr = ntohl(get_uint32(reply_buf)); } else if (reply_buf[3] == 3) { size_t result_len; if (read_all(s, reply_buf, 1, 1) != 1) { log_err(LD_NET, "Error reading address_length in socks5 response."); return -1; } result_len = *(uint8_t*)(reply_buf); *result_hostname = tor_malloc(result_len+1); if (read_all(s, *result_hostname, result_len, 1) != (int) result_len) { log_err(LD_NET, "Error reading hostname in socks5 response."); return -1; } (*result_hostname)[result_len] = '\0'; } } return 0; }