/** Add an entry to a GeoIP table, mapping all IP addresses between <b>low</b> * and <b>high</b>, inclusive, to the 2-letter country code <b>country</b>. */ static void geoip_add_entry(const tor_addr_t *low, const tor_addr_t *high, const char *country) { intptr_t idx; void *idxplus1_; if (tor_addr_family(low) != tor_addr_family(high)) return; if (tor_addr_compare(high, low, CMP_EXACT) < 0) return; idxplus1_ = strmap_get_lc(country_idxplus1_by_lc_code, country); if (!idxplus1_) { geoip_country_t *c = tor_malloc_zero(sizeof(geoip_country_t)); strlcpy(c->countrycode, country, sizeof(c->countrycode)); tor_strlower(c->countrycode); smartlist_add(geoip_countries, c); idx = smartlist_len(geoip_countries) - 1; strmap_set_lc(country_idxplus1_by_lc_code, country, (void*)(idx+1)); } else { idx = ((uintptr_t)idxplus1_)-1; } { geoip_country_t *c = smartlist_get(geoip_countries, idx); tor_assert(!strcasecmp(c->countrycode, country)); } if (tor_addr_family(low) == AF_INET) { geoip_ipv4_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv4_entry_t)); ent->ip_low = tor_addr_to_ipv4h(low); ent->ip_high = tor_addr_to_ipv4h(high); ent->country = idx; smartlist_add(geoip_ipv4_entries, ent); } else if (tor_addr_family(low) == AF_INET6) { geoip_ipv6_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv6_entry_t)); ent->ip_low = *tor_addr_to_in6(low); ent->ip_high = *tor_addr_to_in6(high); ent->country = idx; smartlist_add(geoip_ipv6_entries, ent); } }
/** Given an IP address, return a number representing the country to which * that address belongs, -1 for "No geoip information available", or 0 for * the 'unknown country'. The return value will always be less than * geoip_get_n_countries(). To decode it, call geoip_get_country_name(). */ int geoip_get_country_by_addr(const tor_addr_t *addr) { if (tor_addr_family(addr) == AF_INET) { return geoip_get_country_by_ipv4(tor_addr_to_ipv4h(addr)); } else if (tor_addr_family(addr) == AF_INET6) { return geoip_get_country_by_ipv6(tor_addr_to_in6(addr)); } else { return -1; } }
static void test_address_tor_addr_to_in6(void *ignored) { (void)ignored; tor_addr_t *a = tor_malloc_zero(sizeof(tor_addr_t)); const struct in6_addr *res; uint8_t expected[16] = {42, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; a->family = AF_INET; res = tor_addr_to_in6(a); tt_assert(!res); a->family = AF_INET6; memcpy(a->addr.in6_addr.s6_addr, expected, 16); res = tor_addr_to_in6(a); tt_assert(res); tt_mem_op(res->s6_addr, OP_EQ, expected, 16); done: tor_free(a); }
/** 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; } }