/** Set the tor_addr_t in <b>a</b> to contain the socket address contained in * <b>sa</b>. */ int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa, uint16_t *port_out) { tor_assert(a); tor_assert(sa); if (sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *) sa; tor_addr_from_ipv4n(a, sin->sin_addr.s_addr); if (port_out) *port_out = ntohs(sin->sin_port); } else if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; tor_addr_from_in6(a, &sin6->sin6_addr); if (port_out) *port_out = ntohs(sin6->sin6_port); } else { tor_addr_make_unspec(a); return -1; } return 0; }
/** Add an entry to the GeoIP table indicated by <b>family</b>, * parsing it from <b>line</b>. The format is as for geoip_load_file(). */ /*private*/ int geoip_parse_entry(const char *line, sa_family_t family) { tor_addr_t low_addr, high_addr; char c[3]; char *country = NULL; if (!geoip_countries) init_geoip_countries(); if (family == AF_INET) { if (!geoip_ipv4_entries) geoip_ipv4_entries = smartlist_new(); } else if (family == AF_INET6) { if (!geoip_ipv6_entries) geoip_ipv6_entries = smartlist_new(); } else { log_warn(LD_GENERAL, "Unsupported family: %d", family); return -1; } while (TOR_ISSPACE(*line)) ++line; if (*line == '#') return 0; if (family == AF_INET) { unsigned int low, high; if (tor_sscanf(line,"%u,%u,%2s", &low, &high, c) == 3 || tor_sscanf(line,"\"%u\",\"%u\",\"%2s\",", &low, &high, c) == 3) { tor_addr_from_ipv4h(&low_addr, low); tor_addr_from_ipv4h(&high_addr, high); } else goto fail; country = c; } else { /* AF_INET6 */ char buf[512]; char *low_str, *high_str; struct in6_addr low, high; char *strtok_state; strlcpy(buf, line, sizeof(buf)); low_str = tor_strtok_r(buf, ",", &strtok_state); if (!low_str) goto fail; high_str = tor_strtok_r(NULL, ",", &strtok_state); if (!high_str) goto fail; country = tor_strtok_r(NULL, "\n", &strtok_state); if (!country) goto fail; if (strlen(country) != 2) goto fail; if (tor_inet_pton(AF_INET6, low_str, &low) <= 0) goto fail; tor_addr_from_in6(&low_addr, &low); if (tor_inet_pton(AF_INET6, high_str, &high) <= 0) goto fail; tor_addr_from_in6(&high_addr, &high); } geoip_add_entry(&low_addr, &high_addr, country); return 0; fail: log_warn(LD_GENERAL, "Unable to parse line from GEOIP %s file: %s", family == AF_INET ? "IPv4" : "IPv6", escaped(line)); return -1; }
/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set * *<b>addr</b> to the proper IP address and family. The <b>family</b> * argument (which must be AF_INET, AF_INET6, or AF_UNSPEC) declares a * <i>preferred</i> family, though another one may be returned if only one * family is implemented for this address. * * Return 0 on success, -1 on failure; 1 on transient failure. */ int tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr) { /* Perhaps eventually this should be replaced by a tor_getaddrinfo or * something. */ struct in_addr iaddr; struct in6_addr iaddr6; tor_assert(name); tor_assert(addr); tor_assert(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC); if (!*name) { /* Empty address is an error. */ return -1; } else if (tor_inet_pton(AF_INET, name, &iaddr)) { /* It's an IPv4 IP. */ if (family == AF_INET6) return -1; tor_addr_from_in(addr, &iaddr); return 0; } else if (tor_inet_pton(AF_INET6, name, &iaddr6)) { if (family == AF_INET) return -1; tor_addr_from_in6(addr, &iaddr6); return 0; } else { #ifdef HAVE_GETADDRINFO int err; struct addrinfo *res=NULL, *res_p; struct addrinfo *best=NULL; struct addrinfo hints; int result = -1; memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; err = sandbox_getaddrinfo(name, NULL, &hints, &res); /* The check for 'res' here shouldn't be necessary, but it makes static * analysis tools happy. */ if (!err && res) { best = NULL; for (res_p = res; res_p; res_p = res_p->ai_next) { if (family == AF_UNSPEC) { if (res_p->ai_family == AF_INET) { best = res_p; break; } else if (res_p->ai_family == AF_INET6 && !best) { best = res_p; } } else if (family == res_p->ai_family) { best = res_p; break; } } if (!best) best = res; if (best->ai_family == AF_INET) { tor_addr_from_in(addr, &((struct sockaddr_in*)best->ai_addr)->sin_addr); result = 0; } else if (best->ai_family == AF_INET6) { tor_addr_from_in6(addr, &((struct sockaddr_in6*)best->ai_addr)->sin6_addr); result = 0; } sandbox_freeaddrinfo(res); return result; } return (err == EAI_AGAIN) ? 1 : -1; #else struct hostent *ent; int err; #ifdef HAVE_GETHOSTBYNAME_R_6_ARG char buf[2048]; struct hostent hostent; int r; r = gethostbyname_r(name, &hostent, buf, sizeof(buf), &ent, &err); #elif defined(HAVE_GETHOSTBYNAME_R_5_ARG) char buf[2048]; struct hostent hostent; ent = gethostbyname_r(name, &hostent, buf, sizeof(buf), &err);