At times I have wanted to demo the development version of a server that is running on my FreeBSD virtual machine. This is not a problem if the person I want to show it to is withing walking distance. The net being what it is, sometimes the other party is halfway around the world.

I figured tor would be a neat way to demo a server running on my laptop. This post covers serving content via tor on a FreeBSD machine. This does not cover securing a hidden service because it is non-trivial and that is not my use case.

Software Versions

$ date
February  6, 2016 at 08:59:26 AM JST
$ uname -vm
FreeBSD 11.0-CURRENT #0 r287598: Thu Sep 10 14:45:48 JST 2015     root@:/usr/obj/usr/src/sys/MIRAGE_KERNEL  amd64
$ tor --version
Tor version 0.2.7.6.
$ curl --version
curl 7.47.0 (amd64-portbld-freebsd11.0) libcurl/7.47.0 OpenSSL/1.0.2e zlib/1.2.8
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp 
Features: AsynchDNS IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets 

Instructions

First, install security/tor. Consider enabling TOR2WEB if your service does not really need to be hidden.

portmaster security/tor

Serve content to a port on localhost. For example, add the following to server.sh for a simple date server that serves content to port 8080. This is not a robust server, but it is good enough for configuration testing.

#/bin/sh

HOST=127.0.0.1
PORT=8080

while true; do
BODY=$(cat <<EOF
{
  "Date": "$(date)"
}
EOF
)
RESPONSE=$(cat <<EOF
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: $((${#BODY}+1))
Connection: close

${BODY}
EOF
)
echo "---$((X=X+1))---"
echo "$RESPONSE" | nc -N -l $HOST $PORT
done

If using the above, make the server script executable and run it.

chmod +x server.sh
./server.sh

Read the tor configuration instructions. Open /usr/local/etc/tor/torrc (see torrc instructions). Add the following lines to the section titled This section is just for location-hidden services

HiddenServiceDir /usr/home/tor/hidden_service/
HiddenServicePort 80 127.0.0.1:8080

The following commands can be used to test the above server.

curl -v 127.0.0.1:8080
# log request date on the server and send EOF
date | nc 127.0.0.1 8080

Enable tor in /etc/rc.conf

tor_enable="YES"

Start tor.

service tor start

Get the hostname for your hidden service with the following command. Do not share the private_key, found in the same directory.

cat /usr/home/tor/hidden_service/hostname

The following command can be used to test the above nc server by supplying the tor proxy with -x and proxy protocol with -X. The -w 1 specifies a timeout. This is necessary because the nc server does not close the connection. The -v flag gives verbose output.

nc -w 1 -v -X5 -x localhost:9050 "$(cat /usr/home/tor/hidden_service/hostname)" 80

Test your hidden service with curl by supplying the tor proxy with the -x option.

curl -x socks5h://127.0.0.1:9050 -v "http://$(cat /usr/home/tor/hidden_service/hostname)/"

You alo can test your hidden service with Tor2web. For example, if your hidden service has a hostname of ABCDEFGHIJKLMNOP.onion, go to https://ABCDEFGHIJKLMNOP.onion.to to view it in a web browser. The nc server listed above might be a little flakey because it expects the client to close the connection.. You may need to restart the script if the server stops responding.

Test the hidden service with Tor2web from the command line with the following command. Note that Tor2web blocks the curl user agent, so the user agent is set to test instead.

curl -A test "https://$(cat /usr/home/tor/hidden_service/hostname).to"

To disable tor when you no longer need to use it, stop it with the service command.

service tor stop

Then disable it in /etc/rc.conf.

tor_enable="NO"

References: