Grabbing true client IP with UDP connect
I’ve been reading the Transmission source code and playing with writing my own BitTorrent client (just to learn about the protocols especially Kademlia). One detail that I think is common in peer to peer applications is the requirement to announce a client’s ability to join a swarm.
In BitTorrent, in the “Tracker Request”, a client connects to a tracker and can send a GET
request including the client’s ip address in the query string:
GET /announce?info_hash=XXX&ipv6=<ipv6 address>&<other_fields> HTTP/1.1
Transmission has an interesting snippet of code to support grabbing the clients “true IP address”.
Ref: https://github.com/transmission/transmission/blob/main/libtransmission/net.cc#L644
/*
get_source_address() and global_unicast_address() were written by
Juliusz Chroboczek, and are covered under the same license as dht.c.
Please feel free to copy them into your software if it can help
unbreaking the double-stack Internet. */
/* Get the source address used for a given destination address. Since
there is no official interface to get this information, we create
a connected UDP socket (connected UDP... hmm...) and check its source
address. */
static int get_source_address(struct sockaddr const* dst,
socklen_t dst_len,
struct sockaddr* src,
socklen _t* src_len)
{
tr_socket_t const s = socket(dst->sa_family, SOCK_DGRAM, 0);
if (s == TR_BAD_SOCKET) {
return -1;
}
// since it's a UDP socket, this doesn't actually send any packets
if (connect(s, dst, dst_len) == 0 &&
getsockname(s, src, src_len) == 0 {
evutil_closesocket(s);
return 0;
}
auto const save = errno;
evutil_closesocket(s);
errno = save;
return -1;
}
The only link I could find related to using UDP connect
to get a source IP was on StackOverflow.
Here’s a small standalone C program to do the same thing: https://github.com/tinselcity/experiments/blob/master/get_my_ip/get_my_ip.c
Building/Running:
~># Building...
~>gcc get_my_ip.c -o get_my_ip
...
~># Running...
~>./get_my_ip
: getting public ip address(es)
: trying IPv4...
: warning ipv4 appears to be private address (RFC4193)
: warning: error performing get_public_address (IPv4)
: trying IPv6...
: ipv6: XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
The common use-case of an application’s need to know its own source IP address could be why there’s a proliferation of sites/API’s like “What’s My IP Address”. Using UDP connect
+getsockname
could be an alternative approach if they’re available from the language/OS.
References:
- BitTorrent specification: https://wiki.theory.org/BitTorrentSpecification
- Code snippet from libtransmission
- StackOverflow Getting my own IP address by connect()ing using UDP socket?