Ephemeral IPv6 server addresses (part 4)

Very address. So IPv6. Such random. Wow.

For those of you who've just joined us: I'm trying to hide my IPv6 server among the 4 billion IPv6 addresses allocated to it.

So far I've suggested a couple of variations on a theme: a pseudo-random IP address is calculated using a secret known to both client and server plus a publicly available value. In Part 1 the public value was the time and in Part 2 it was a random value published by the server itself. There's a lot of information out there on the internet but only some of it has the necessary characteristics to be used as a public value: it has to change from time to time and it has to be reliable.

One possible source is the blockchains used by some of the cryptocurrencies that are floating about. The most prominent of these is Bitcoin, but there are others, such as Litecoin and Dogecoin. These latter are based on the Bitcoin code but with slightly different rules. The basic idea is:

The whole system is carefully crafted to keep all particpants honest despite their competing interests. The difficulty of the Very Hard Problem is continually adjusted so that the average time to find a solution is approximately constant. For Bitcoin the average time is 10 minutes; it's 2.5 minutes for Litecoin and 1 minute for Dogecoin.

By tapping into the blockchain we can obtain a stream of constantly changing values: the block hashes. These are used in another variant of the client script:

   #!/bin/sh

   # display the current Dogecoin-based IPv6 address

   confirms=10
   skip=60

   height=`wget -q -O - https://chain.so/api/v2/get_info/DOGE | \
      sed -e 's/"//g' -e 's/,//' | awk '$1 == "blocks" {print $NF}'`

   if [ -z "$height" ]
   then
      echo "No height"
      exit 1
   fi

   confirmed_height=`expr $height - $confirms`
   rem=`expr $confirmed_height % $skip`
   use_height=`expr $confirmed_height - $rem`

   hash=`wget -q -O - https://chain.so/api/v2/get_blockhash/DOGE/${use_height} | \
      sed -e 's/"//g' -e 's/,//' | awk '$1 == "blockhash" {print $3}'`

   if [ -z "$hash" ]
   then
      echo "No hash"
      exit 1
   fi

   secret="Beeblebrox"
   prefix="2001:db8:1:2:3:4"

   suffix1="fade"
   suffix2="deed"
   for salt in "Agrajag" "Zem" "Lintilla"
   do
      message="${secret}${hash}${salt}"
      sum=`echo "$message" | md5sum`

      # reserve a /124 for static addresses
      somesum=`echo "$sum" | cut -c1-7`
      if [ "$somesum" != "0000000" ]
      then
         suffix1=`echo "$sum" | cut -c1-4`
         suffix2=`echo "$sum" | cut -c5-8`
         break
      fi
   done
   echo "${prefix}:${suffix1}:${suffix2}"

Here I've used Dogecoin. Dogecoin blocks are generated about once a minute on average so, to have the IP address change about once an hour (like the previous scripts), only block numbers divisible by 60 are used. The very latest blocks aren't used because there's a slight chance that (due to propagation delays) different parts of the peer-to-peer network accept different solutions. Such a situation won't persist for long and it's generally considered that a block is immutable after six confirmations. I'm using slightly more than that on the client to allow the server a few blocks of leeway to get its act together.

As is now traditional, I've implemented a mirror of the frippery.org website on an ephemeral Dogecoin-based IPv6 address. There are no sample server-side scripts this time because the solution I've had to adopt is embarrassingly sub-optimal.

The best approach is probably to have the server run a full node on the peer-to-peer network, but my VPS is too feeble for that. Instead I've resorted to polling third-party blockchain APIs to get the data. These APIs are only available on IPv4 (how quaint) but fortunately my server has NAT64. All-in-all this is not ideal and likely to be flaky. Be assured, though, the IP address does change with the Dogecoin blockchain.

Note:


Ron Yorston
24th August 2015 (updated 13th December 2016)