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:

Written on May 30, 2022