pages tagged networkyakkinghttp://yakking.branchable.com/tags/network/yakkingikiwiki2015-09-09T11:00:12ZNetworking - Namespaceshttp://yakking.branchable.com/posts/networking-4-namespaces-and-multi-host-routing/Richard Maw2015-09-09T11:00:12Z2015-09-09T11:00:06Z
<h1>What are network namespaces</h1>
<p>Network Namespaces are a Linux feature,
that allows different processes to have different views of the network.</p>
<p>Aspects of networking that can be isolated between processes include:</p>
<ul>
<li><p>Interfaces</p>
<p>Different processes can connect to addresses on different interfaces.</p></li>
<li><p>Routes</p>
<p>Since processes can see different addresses from different namespaces,
they also need different routes to connect to networks on those interfaces.</p></li>
<li><p>Firewall rules</p>
<p>Firewalls are mostly out of scope for this article,
but since firewall rules are dependant on the source or target interfaces,
you need different firewall rules in different network namespaces.</p></li>
</ul>
<h1>How do you manage network namespaces</h1>
<ul>
<li><p>When a network namespace is created with the <a href="http://man7.org/linux/man-pages/man2/unshare.2.html">unshare(2)</a> or <a href="http://man7.org/linux/man-pages/man2/clone.2.html">clone(2)</a> system calls,
it is bound to the life of the current process,
so if your process exits,
the network namespace is removed.</p>
<p>This is ideal for sandboxing processes,
so that they have restricted access to the network,
as the network namespaces are automatically cleaned up
when the process they were isolating the network for
no longer exists.</p></li>
<li><p>A privileged process can make their network namespace persistent,
which is useful for if the network namespace needs to exist when there are no processes in it.</p>
<p>This is what the <a href="http://man7.org/linux/man-pages/man8/ip.8.html">ip(8)</a> command does when you run <code>ip netns add NAME</code>.</p></li>
<li><p>The <code>ip netns delete NAME</code> command undoes this,
and allows the namespace to be removed
when the last process using it leaves the namespace.</p></li>
<li><p><code>ip netns list</code> shows current namespaces.</p>
<pre><code>$ sudo ip netns add testns
$ ip netns list
testns
$ sudo ip netns delete testns
$ ip netns list
</code></pre></li>
<li><p>A network namespace is of no use if it has no interfaces,
so we can move an existing interface into it with the
<code>ip link set dev DEVICE netns NAME</code> command.</p>
<pre><code>$ ip link show dev usb0
5: usb0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
link/ether 02:5e:37:61:60:66 brd ff:ff:ff:ff:ff:ff
$ sudo ip link set dev usb0 netns testns
$ ip link show dev usb0
Device "usb0" does not exist.
</code></pre></li>
<li><p>Network namespaces would be of limited use if we can't run a command in them.</p>
<p>We can run a command in a namespace with the <code>ip netns exec NAME COMMAND</code> command.</p>
<pre><code>$ sudo ip netns exec testns ip link show dev usb0
5: usb0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 02:5e:37:61:60:66 brd ff:ff:ff:ff:ff:ff5: usb0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 02:5e:37:61:60:66 brd ff:ff:ff:ff:ff:ff
</code></pre></li>
<li><p>There is no standard daemon to start persistent network namespaces on-boot,
however, the <a href="http://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateNetwork=">PrivateNetwork=</a> option to systemd service files can be used
to start a process in a network namespace on boot.</p></li>
</ul>
<h1>Uses of network namespaces</h1>
<p>Network namespaces can be used to sandbox processes,
so that they can only connect through the interfaces provided.</p>
<p>You could have a machine with two network interfaces,
one which connects out to the internet,
the other connected to your internal network.
You could set up network namespaces
such that you can run the ssh server on your internal network,
and run a web server in a network namespace that has the internet-facing interface,
so if your web server is compromised,
it can't connect to your internal network.</p>
<p><a href="https://www.docker.com/">docker</a> and <a href="http://www.freedesktop.org/software/systemd/man/systemd-nspawn.html">systemd-nspawn</a> combine network namespaces
with other namespaces to provide containers.
<a href="https://www.docker.com/">docker</a> is primarily interested in application containers,
while <a href="http://www.freedesktop.org/software/systemd/man/systemd-nspawn.html">systemd-nspawn</a> is more interested in system containers,
though both technologies can be used for either.</p>
<p>A more novel use of network namespaces is virtual routers,
as implemented in <a href="https://wiki.openstack.org/wiki/Neutron">OpenStack Neutron</a>.</p>
<h2>Network namespaced routing</h2>
<p>We previously mentioned that routes were a property of network namespaces,
that virtual ethernet devices have a pair of ends,
and that we can move a network interface into another network namespace.</p>
<p>By combining these features,
we can construct a series of virtual computers and experiment with routing.</p>
<h2>Two node networking</h2>
<p>To start with we're going to add another virtual computer,
start a simple echo server on it,
and configure the network such that we can connect to it from our host computer.</p>
<p>As we've done in previous articles,
we're going to make the <code>left</code> and <code>right</code> virtual ethernet pair.</p>
<pre><code>$ sudo ip link add left type veth peer name right
</code></pre>
<p>But to demonstrate routing to another machine we need to create one,
so we're making another network namespace,
as we only care about its networking.</p>
<pre><code>$ sudo ip netns add testns
</code></pre>
<p>We're going to move one half of the virtual ethernet device pair
into another namespace,
to simulate a physical link between the two virtual computers.</p>
<pre><code>$ sudo ip link set dev right netns testns
</code></pre>
<p>We're going to say that we connect to interfaces in the <code>testns</code> namespace
by connecting to addresses in the <code>10.248.179.1/24</code> subnet.</p>
<pre><code>$ sudo ip address add 10.248.179.1/24 dev left
$ sudo ip netns exec testns ip address add 10.248.179.2/24 dev right
</code></pre>
<p>We're also going to say that there's another network in there
on the <code>10.248.180.1/24</code> subnet.</p>
<p>Rather than having any more complicated network interfaces,
we assigning it to the loopback interface.</p>
<pre><code>$ sudo ip netns exec testns ip address add 10.248.180.1/24 dev lo
</code></pre>
<p>Now that we've assigned addresses,
we need to bring the interfaces up.</p>
<pre><code>$ sudo ip link set dev left up
$ sudo ip netns exec testns ip link set dev right up
$ sudo ip netns exec testns ip link set dev lo up
</code></pre>
<p>This has created a chain of interfaces linking <code>left</code> → <code>right</code> → <code>lo</code>.
Where <code>left</code> is in your namespace,
and <code>right</code> is in <code>testns</code> with its own private <code>lo</code>.</p>
<p>Now we can demonstrate sending messages through the network namespaces,
by creating a server on the <code>lo</code> interface inside <code>testns</code>.</p>
<p>Start an echo server in the test namespace by running this command in a new
terminal.</p>
<p>It is <em>important</em> to run this in another terminal,
as if you background the process,
netcat may decide it doesn't need to actively output data as it recieves it.</p>
<pre><code>$ sudo ip netns exec testns nc -l 10.248.180.1 12345
</code></pre>
<p>If we were to try to connect to it,
we would not be able to send messages.</p>
<pre><code>$ nc -v 10.248.180.1 12345
nc: connect to 10.248.180.1 port 12345 (tcp) failed: Network is unreachable
</code></pre>
<p>This is because your host namespace does not understand how to reach that address,
since it is not an address in your network namespace,
nor is it an address on any of the subnets in the namespace,
and there are no defined rules for how to reach it.</p>
<p>So let's add a rule!</p>
<pre><code>$ sudo ip route add 10.248.180.0/24 dev left via 10.248.179.2
</code></pre>
<p>This says that you can find the <code>10.248.180.0/24</code> subnet
by sending packets to the <code>10.248.179.2</code> address
through the <code>left</code> interface.</p>
<p>You should now be able to type messages into the following netcat command,
and see the result in your other terminal.</p>
<pre><code>$ nc -v 10.248.180.1 12345
Connection to 10.248.180.1 12345 port [tcp/*] succeeded!
</code></pre>
<h2>3 namespaces</h2>
<p>This works fine,
but in the wider internet you need to connect through long chains of computers
before you reach your final destination,
so we're going to use 3 network namespaces to represent a longer chain.</p>
<p>We are going to have two extra network namespaces, called <code>near</code> and <code>far</code>.</p>
<pre><code>$ sudo ip netns add near
$ sudo ip netns add far
</code></pre>
<p>We are going to create a chain of network interfaces called <code>one</code>, <code>two</code>, <code>three</code> and <code>four</code>.</p>
<pre><code>$ sudo ip link add one type veth peer name two
$ sudo ip link add three type veth peer name four
</code></pre>
<p><code>one</code> will be in our network namespace, connecting to <code>two</code> in the <code>near</code>
namespace, and <code>three</code> will connect to <code>four</code> in the <code>far</code> namespace.</p>
<pre><code>$ sudo ip link set dev two netns near
$ sudo ip link set dev three netns near
$ sudo ip link set dev four netns far
</code></pre>
<p>This produces a chain <code>one</code> → <code>two</code> → <code>three</code> → <code>four</code>.</p>
<p>To speak to these interfaces, we need to assign address ranges, so for our
host to <code>near</code> link we will use <code>10.248.1.0/24</code>,
for our <code>near</code> to <code>far</code> link we will use <code>10.248.2.0/24</code>,
and for our destination address we will use <code>10.248.3.1/24</code>.</p>
<pre><code>$ sudo ip address add 10.248.1.1/24 dev one
$ sudo ip netns exec near ip address add 10.248.1.2/24 dev two
$ sudo ip netns exec near ip address add 10.248.2.1/24 dev three
$ sudo ip netns exec far ip address add 10.248.2.2/24 dev four
$ sudo ip netns exec far ip address add 10.248.3.1/24 dev lo
</code></pre>
<p>We need to bring these interfaces up.</p>
<pre><code>$ sudo ip link set dev one up
$ sudo ip netns exec near ip link set dev two up
$ sudo ip netns exec near ip link set dev three up
$ sudo ip netns exec far ip link set dev four up
$ sudo ip netns exec far ip link set dev lo up
</code></pre>
<p>Now let's this time start our server in the <code>far</code> namespace,
so we can be sure that we can't connect to it directly from our namespace.</p>
<p>As before, start this echo server in a new terminal.</p>
<pre><code>$ sudo ip netns exec far nc -l 10.248.3.1 12345
</code></pre>
<p>Now let's try to connect to it from our namespace.</p>
<pre><code>$ nc -v 10.248.3.1 12345
nc: connect to 10.248.3.1 port 12345 (tcp) failed: Network is unreachable
</code></pre>
<p>If you try to send a message, it won't arrive.
If you inspect the routing table with <code>ip route</code>,
you will see that there is no match.</p>
<p>The relevant routing rules are:</p>
<pre><code>$ ip route
default via 192.168.1.1 dev wlan0 proto static
10.248.1.0/24 dev one proto kernel scope link src 10.248.1.1
</code></pre>
<p>This says that if you're broadcasting from <code>10.248.1.1</code> and going to
anything in <code>10.248.1.0/24</code> then it goes to the <code>one</code> interface. However
this doesn't match because we want to go to the <code>four</code> interface which
has address <code>10.248.3.1</code>.</p>
<p>We can make this route to our <code>near</code> interface by adding a new rule.</p>
<pre><code>$ sudo ip route add 10.248.2.0/24 dev one via 10.248.1.2
</code></pre>
<p>We can prove this hop works by starting a server in the <code>near</code> namespace
(again, in a separate terminal).</p>
<pre><code>$ sudo ip netns exec near nc -l 10.248.2.1 12345
</code></pre>
<p>We can try to talk to it:</p>
<pre><code>$ nc -v 10.248.2.2 12345
</code></pre>
<p>This doesn't yet work, because it's a bidirectional protocol,
so the return route needs to work too.</p>
<pre><code>$ sudo ip netns exec near ip route change 10.248.1.0/24 dev two via 10.248.1.1
</code></pre>
<p>This still doesn't work,
since while there's now routing rules,
they aren't for any addresses which have desinations in the near network namespace,
so by default they get dropped.</p>
<p>To change this we can turn on ip forwarding with:</p>
<pre><code>sudo dd of=/proc/sys/net/ipv4/ip_forward <<<1
</code></pre>
<p>Now we can talk to the <code>near</code> namespace, but we can't yet talk to the <code>far</code> namespace.
We need to add another routing rule for that.</p>
<pre><code>$ sudo ip route add 10.248.3.0/24 dev one via 10.248.1.2
</code></pre>
<p>As before, this means you can route to the <code>near</code> namespace.
However, it doesn't know how to reach the <code>far</code> namespace from there,
so we need to add another routing rule.</p>
<pre><code>$ sudo ip netns exec near ip route add 10.248.3.0/24 dev three via 10.248.2.2
</code></pre>
<p>Now you can reach the <code>far</code> namespace, but it's still not working.
This is because tcp is a bidirectional communication protocol,
and it doesn't know how to send the response to a message from <code>10.248.1.1</code>,
so we need to add another rule.</p>
<pre><code>$ sudo ip netns exec far ip route add 10.248.1.0/24 dev four via 10.248.2.1
</code></pre>
<h2>Conclusion</h2>
<p>I think you will agree that it's far too much faff
to set up this routing just to talk to a machine on another network.</p>
<p>You are likely thinking that there must be a better way,
and you are correct, there's a couple of ways,
but we will cover those in later articles.</p>
Networking - Addresses and Routeshttp://yakking.branchable.com/posts/networking-3-addresses-and-routes/Richard Maw2015-08-19T11:00:13Z2015-08-19T11:00:07Z
<p>In the previous article on interfaces, we added a virtual ethernet pair
with the following command.</p>
<pre><code>$ sudo ip link add left type veth peer name right
</code></pre>
<p>We can inspect the addresses owned by these interfaces with the <code>ip address</code> command.</p>
<pre><code>$ ip address show dev left
6: left: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 56:9e:e6:2d:34:e6 brd ff:ff:ff:ff:ff:ff
inet6 fe80::549e:e6ff:fe2d:34e6/64 scope link
valid_lft forever preferred_lft forever
</code></pre>
<p>This shows that we currently don't have an inet (IPv4) address,
but we have the default inet6 (IPv6) link-local address.</p>
<p>We can add any address we want to this interface,
but first we need to invent a subnet for the virtual ethernet device.</p>
<h1>Subnets</h1>
<p>The IPv4 address space is sub-divided
by saying that every address that starts with a specified prefix
belongs to that subnet.</p>
<p>So the subnet <code>127.0.0.0/8</code>
says that every address starting with <code>127.</code>
is in that subnet.
The <code>/8</code> says how long the prefix is,
so that you can have a <code>0</code> component in a prefix
without it being ambiguous as to whether it's not part of the prefix,
or whether the prefix has a <code>0</code> byte in it.</p>
<p>The number after the <code>/</code> is how many <em>bits</em> long the prefix is,
starting from the left.</p>
<p>So the network <code>127.0.0.0/8</code> has 2<sup>24</sup> addresses in it,
from <code>127.0.0.0</code> to <code>127.255.255.255</code>.</p>
<p>It just happens that usually only <code>127.0.0.1</code> is allocated,
and only on the loopback interface,
but you can configure more addresses for your loopback interface
than you will feasibly ever need.</p>
<p>You should <em>only</em> ever see the <code>127.0.0.0/8</code> subnet on your loopback interface,
as it is reserved for this purpose,
so that you can't confuse a global address for a local-only loopback address.</p>
<p>There are other such reserved ranges,
such as the private subnet only ranges:</p>
<ol>
<li><code>192.168.0.0/16</code></li>
<li><code>10.0.0.0/8</code></li>
<li><code>172.16.0.0/12</code></li>
</ol>
<p>These ranges are reserved
so that you can have private addresses for machines reachable only on your subnet.</p>
<p>These ranges can be subdivided as much as you want,
to provide further subnetting.</p>
<p>For the rest of the examples
here we are going to use the subnet <code>10.248.179.0/24</code>.
<strong>Please note that this address was selected randomly,
please check if addresses in this subnet are allocated to your local network</strong>.</p>
<p>For a more detailed explanation of subnets please read this <a href="https://en.wikipedia.org/wiki/Subnetwork">article on subnets</a>.</p>
<h1>Assigning addresses</h1>
<p>When you assign an address to an interface,
you assign a given address in a given subnet.
So <code>10.248.179.1</code> is not sufficient information to configure the address.
You also need the prefix length,
so if we want to assign <code>10.248.179.1</code> to the <code>left</code> virtual interface,
we can use this command:</p>
<pre><code>$ sudo ip address add 10.248.179.1/24 dev left
</code></pre>
<p>Now we can see that our <code>left</code> interface has this address.</p>
<pre><code>$ ip address show dev left
6: left: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 56:9e:e6:2d:34:e6 brd ff:ff:ff:ff:ff:ff
inet 10.248.179.1/24 scope global left
valid_lft forever preferred_lft forever
inet6 fe80::549e:e6ff:fe2d:34e6/64 scope link
valid_lft forever preferred_lft forever
</code></pre>
<p>We can prove this address works with a pair of netcat commands.</p>
<pre><code>$ nc -l 10.248.179.1 1234 >out.txt &
$ echo hello | nc 10.248.179.1 1234
$ cat out.txt
hello
</code></pre>
<p>Because <code>left</code> is paired with <code>right</code>,
if we configure an address for the <code>right</code> end,
we can send messages through the virtual ethernet link.</p>
<pre><code>$ sudo ip address add 10.248.179.2/24 dev right
$ nc -l 10.248.179.1 1234 >out.txt &
$ echo hello | nc -s 10.248.179.2 10.248.179.1 1234
</code></pre>
<p>To make these addresses persist across a reboot, you can use <a href="http://www.freedesktop.org/software/systemd/man/systemd-networkd.html">networkd</a> <a href="http://www.freedesktop.org/software/systemd/man/systemd.network.html">.network file</a>s.</p>
<pre><code>$ sudo install -m644 /dev/stdin /etc/systemd/network/left.network <<'EOF'
[Match]
Name=left
[Network]
Address=10.248.179.1/24
EOF
$ sudo install -m644 /dev/stdin /etc/systemd/network/right.network <<'EOF'
[Match]
Name=right
[Network]
Address=10.248.179.2/24
EOF
</code></pre>
<h1>Routes</h1>
<p>Because we configured this new address with an address prefix,
we now have a route configured.</p>
<pre><code>$ ip route
default via 192.168.1.254 dev wlan0 proto static
10.248.179.0/24 dev right proto kernel scope link src 10.248.179.2
10.248.179.0/24 dev left proto kernel scope link src 10.248.179.1
192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.94 metric 9
</code></pre>
<p>The first and last lines were added earlier by <a href="https://wiki.gnome.org/Projects/NetworkManager">NetworkManager</a>,
but the <code>ip address add</code> commands added the two rules in the middle.</p>
<p>These routing rules are consulted when you need to make an IPv4 connection.
Routing rules are selected most-specific first.</p>
<p>For our earlier call to <code>nc -s 10.248.179.2 10.248.179.1 1234</code>
we said we want to connect to <code>10.248.179.1</code> from <code>10.248.179.2</code>.</p>
<p>While there's a default rule for connecting everything through wlan0,
there is a more specific rule for connections coming from <code>10.248.179.2</code>,
and connecting to an address in the <code>10.248.179.0/24</code> subnet,
so the following rule matched:</p>
<pre><code>10.248.179.0/24 dev right proto kernel scope link src 10.248.179.2
</code></pre>
<p>Which means that the connections must go through the <code>right</code> interface.</p>
<p>Since we bound a service to port <code>1234</code> at address <code>10.248.179.1</code>,
which is assigned to the <code>left</code> interface,
the connection succeeded, as there was a service waiting for connections.</p>
<p>We can make this matching rule more generic by running:</p>
<pre><code>$ sudo ip route change 10.248.179.0/24 dev right
</code></pre>
<p>So now all connections to addresses in <code>10.248.179.0/24</code>
will go through the <code>right</code> interface.</p>
<p>We can make this configuration persist across reboots by replacing the
<a href="http://www.freedesktop.org/software/systemd/man/systemd.network.html">.network file</a> for our interface with this one:</p>
<pre><code>$ sudo install -m644 /dev/stdin /etc/systemd/network/right.network <<'EOF'
[Match]
Name=right
[Network]
Address=10.248.179.2/24
[Route]
Destination=10.248.179.0/24
EOF
</code></pre>
<p>as we could connect to <code>10.248.179.1</code> without going through <code>right</code>,
because it is one of our own addresses.</p>
<p>However if this were a real interface,
this would allow us to connect to other machines on the network,
that had chosen addresses in the <code>10.248.179.0/24</code> subnet.</p>
<h1>Homework</h1>
<ol>
<li>Find two computers not connected to any networks.</li>
<li>Plug them into each others' ethernet ports.</li>
<li>Configure the ethernet interfaces to addresses on the same subnet
so that they can talk to each other.</li>
</ol>
<!-- TODO: Next article, add Homework to set up a box as a gateway,
as by that point we should have described how to do routing. -->
Networking - Interfaceshttp://yakking.branchable.com/posts/networking-2-interfaces/Richard Maw2015-07-29T11:00:13Z2015-07-29T11:00:06Z
<p>We previously touched on some addresses and ports.
For many circumstances you don't need to know any more than this,
as your operating system will have sufficient tooling
that everything just works out of the box.</p>
<p>However this stops being true when your computer is connected to multiple networks,
as it then needs to manage multiple interfaces.</p>
<h1>Inspecting Interfaces</h1>
<p>You can run the ip link command to see which interfaces your computer has.</p>
<pre><code>$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether b8:88:e3:e1:3a:00 brd ff:ff:ff:ff:ff:ff
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DORMANT group default qlen 1000
link/ether 60:36:dd:13:98:22 brd ff:ff:ff:ff:ff:ff
4: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether e6:a6:ad:95:9f:27 brd ff:ff:ff:ff:ff:ff
</code></pre>
<p>The first column is the numeric ID of the interface, the second its name, and
the rest is various configuration.</p>
<p><code>lo</code> is the local only virtual interface,
this is always available so that networking is always possible,
even on machines that do not have external network ports,
as you may want to use networking for <a href="http://en.wikipedia.org/wiki/Inter-process_communication">IPC</a>.</p>
<p>Names starting <code>en</code> or <code>eth</code> are generated by Linux for physical ethernet links.
There is usually one of these per ethernet port on your computer.</p>
<p>Names starting <code>wl</code> are wireless interfaces.</p>
<p>Bridge interfaces have many names, usually with <code>br</code> in it.
These allow physical devices to be virtually connected,
which is useful to share a connection on one link to machines connected on another,
or virtual connections to a physical one,
which is what my <code>virbr0</code> interface does.</p>
<p><code>veth</code> interfaces are a virtual link pair.
They can take any name, but the ones systemd manages are named <code>ve-*</code>, <code>vb-*</code> and <code>host*</code>.
This is useful for network testing, and network isolation,
so some processes only have access through the virtual link,
and the other end of the link can decide to conditionally forward it on
to its destination or block it.</p>
<p><code>macvlan</code> or <code>ipvlan</code> virtual interfaces share a physical interface.
This is useful for containers
so you can host another network connected machine
and let it manage its own address while sharing your interfaces.</p>
<p><code>*.[0-9]</code> - <a href="http://en.wikipedia.org/wiki/Virtual_LAN#IEEE_802.1Q">vlan</a>, layered on top of any of the others such that packets are
tagged to only be visible to interfaces with the same vlan number.</p>
<p>A more complete list can be seen by running <code>ip link help</code>.</p>
<h1>Configuring Interfaces</h1>
<p>Virtual interfaces can be removed with the <code>ip link del $NAME</code> command,
or added with the <code>ip link add $NAME type $TYPE</code> command.</p>
<p>We can safely make a virtual ethernet link pair
without confusing your operating system's network configuration too much.</p>
<pre><code>$ sudo ip link add left type veth peer name right
</code></pre>
<p>This left and right pair will be used in further examples
rather than using one of the interfaces managed by your operating system.</p>
<p>There's no point making these interfaces if we can't prove they work,
so let's demonstrate.</p>
<p>First we need to get the ip addresses of those interfaces.
All interfaces have an ipv6 <a href="http://en.wikipedia.org/wiki/Link-local_address">link-local address</a> we can use.</p>
<pre><code>$ getip(){ ip -o addr | grep "$1" | tr -s ' ' '\n' | sed -ne '/inet6/{n;p}'; }
$ leftip="$(getip left)"
$ leftip="${leftip%/*}"
$ rightip="$(getip right)"
$ rightip="${rightip%/*}"
</code></pre>
<p>Netcat has a few implementations with differing behaviour.
IPv6 support is not guaranteed, so we're going to use <a href="http://linux.die.net/man/1/socat">socat</a>,
which is not shipped as standard in many Linux distributions,
but has a consistent interface.</p>
<p>We can then start a simple echo service on the left.</p>
<pre><code>$ socat "TCP6-LISTEN:12345,bind=${leftip}%left" - &
</code></pre>
<p>The number after the colon specifies to listen on port 12345,
the <code>bind=</code> option specifies to bind the socket
to the link local address by passing that address,
and only on the left interface with the <code>%left</code> suffix.</p>
<p>The <code>-</code> just says to feed the socket input from your terminal
and write output from the socket to your terminal.</p>
<p>We can then connect to this service from the right.</p>
<pre><code>$ socat - "TCP6:[${leftip}%right]:12345,sourceport=${rightip}%right"
</code></pre>
<p>This says to connect the input from your terminal,
to a tcp socket,
connecting to the address of the left end of the <code>veth</code> link,
by connecting to the right end,
coming from the left end with the <code>sourceport</code> option.</p>
<p>Now by entering text in one terminal,
it will also appear on the other.</p>
<h2>Permanent network interface configuration with networkd</h2>
<p>If you find this left-right <code>veth</code> link useful,
you can make its configuration permanent,
by running the following command,
to add <a href="http://www.freedesktop.org/software/systemd/man/systemd-networkd.service.html">systemd-networkd</a> <a href="http://www.freedesktop.org/software/systemd/man/systemd.netdev.html">netdev</a> configuration.</p>
<pre><code>$ sudo tee /etc/systemd/network/veth-pair.netdev >/dev/null <<EOF
[NetDev]
Name=left
Kind=veth
[Peer]
Name=right
EOF
</code></pre>
<h2>Further reading</h2>
<p>I could not find many resources on this topic,
hence why I felt it would be useful to write about it.
I found these and would happily take suggestions to extend this list.</p>
<ul>
<li><a href="https://www.kernel.org/doc/Documentation/networking/">Linux Kernel networking documentation</a></li>
<li><a href="http://en.wikibooks.org/wiki/Linux_Networking">Linux Networking wikibook</a></li>
</ul>
Networking - Sockets and Portshttp://yakking.branchable.com/posts/networking-1-sockets-and-ports/Richard Maw2015-07-08T11:00:14Z2015-07-08T11:00:08Z
<p>We previously wrote a brief <a href="http://yakking.branchable.com/posts/basic-networking/">introduction to networking</a>,
however networking is a larger topic than that,
so we've decided to produce a larger series
to try and do the subject justice.</p>
<h1>Binding services to sockets</h1>
<p>We're going to illustrate binding this service from Python
since shell is not appropriate,
and C is too verbose.</p>
<p>However we're going to use the low-level Python bindings
rather than the <a href="https://docs.python.org/2/library/socketserver.html">socketserver</a> class,
to show how it works beneath the layers of abstraction.</p>
<p>As with <a href="http://yakking.branchable.com/posts/cool-bits-of-python/">some</a> <a href="http://yakking.branchable.com/posts/data-processing-commands/">previous</a> <a href="http://yakking.branchable.com/posts/temporary-file-handling/">articles</a>,
we are going to describe how it works
in the form of a script with commentary.
You can download the full script <a href="http://yakking.branchable.com/posts/networking-1-sockets-and-ports/chuckle.py">here</a>.</p>
<pre><code>#!/usr/bin/python
#chuckle.py
</code></pre>
<p>Python's bindings are in the socket module,
we're doing a qualified import to resemble the API from C.</p>
<pre><code>from socket import socket, AF_INET, SOCK_STREAM
</code></pre>
<p>There's lots of setup stages involved in making a connection available,
following the general builder pattern, rather than having a single syscall that
takes a huge number of options, as it is more extensible.</p>
<p>The <a href="http://linux.die.net/man/2/socket"><code>socket()</code></a> syscall takes the parameters family, socket type and
protocol. This describes exactly what kind of socket to create. This will be
explained in greater detail later, but here we create a socket with an IP
address which acts as a stream.</p>
<pre><code>s = socket(AF_INET, SOCK_STREAM, 0)
</code></pre>
<p>One side of the connection needs to bind to a port, so that the
other can connect to it.
The <a href="http://en.wikipedia.org/wiki/IP_address">address</a> specifies which address your machine has,
that the service should be served on.
'<em>0.0.0.0</em>' means "all my addresses",
but we're going to use '<em>127.0.0.1</em>'
which means "only my internal address"
so that we can't have anything on the network connect to it:</p>
<pre><code>addr = '127.0.0.1'
</code></pre>
<p>A <a href="http://en.wikipedia.org/wiki/Port_%28computer_networking%29">port</a> number also needs to be chosen to provide the service.
The address denotes how to find the service,
while the port represents which of the potential services available
should be connected to.</p>
<pre><code>port = 12345
s.bind((addr, port))
</code></pre>
<p>The call to <a href="http://linux.die.net/man/2/listen">listen()</a> is further configuration,
of how many connections to buffer before refusing new connections.</p>
<pre><code>s.listen(0)
while True:
</code></pre>
<p>The <a href="http://linux.die.net/man/2/accept">accept()</a> call blocks
until there are available connections to service
and returns some information about where the connection was from.</p>
<pre><code> conn, hostaddr = s.accept()
</code></pre>
<p>The python connection object wraps a file descriptor
that can be used as any normal file,
so we do some conversion so we can use it as one.</p>
<pre><code> f = conn.makefile('rw')
while True:
f.write('> ')
f.flush()
line = f.readline()
if not line:
break
if line == 'to me\n':
print('to you')
elif line == 'oh dear\n':
print('oh dear oh dear')
break
conn.close()
</code></pre>
<p>We can demonstrate that this works with the <a href="http://linux.die.net/man/1/nc">netcat</a> command.</p>
<pre><code>$ python chuckle.py &
$ nc 127.0.0.1 12345
> to me
to you
> oh dear
oh dear oh dear
^C
$
</code></pre>
<p>We can make this service start on boot by creating and enabling a systemd unit
like this:</p>
<pre><code>$ sudo install -D -m755 chuckle.py /usr/local/libexec/chuckle.py
$ sudo tee /etc/systemd/system/chuckle.service >/dev/null <<'EOF'
[Unit]
Description=Chuckle server
[Service]
ExecStart=/usr/local/libexec/chuckle.py
[Install]
WantedBy=multi-user.target
EOF
$ sudo systemctl daemon-reload
$ sudo systemctl enable chuckle.service
</code></pre>
<h1>Connecting to services</h1>
<p>We glossed over how connecting works and just used <a href="http://linux.die.net/man/1/nc">netcat</a>,
so let's see what's involved by writing our own program.
You can download this script <a href="http://yakking.branchable.com/posts/networking-1-sockets-and-ports/connect.py">here</a>.</p>
<pre><code>#!/usr/bin/python
#connect.py
import sys
</code></pre>
<p>As before we need the same socket definitions to make a socket.</p>
<pre><code>from socket import socket, AF_INET, SOCK_STREAM
s = socket(AF_INET, SOCK_STREAM, 0)
</code></pre>
<p>Now instead of binding and listening we call <a href="http://linux.die.net/man/2/connect">connect()</a>.</p>
<pre><code>s.connect(('127.0.0.1', 12345))
</code></pre>
<p>The rest is just copying input from your terminal to the socket.
Note that this is unidirectional and line based,
while <a href="http://linux.die.net/man/1/nc">netcat</a> is bidirectional and asynchronous.</p>
<pre><code>f = s.makefile('w')
while True:
line = sys.stdin.readline()
if not line:
break
f.write(line)
f.flush()
</code></pre>
<p>It is simpler to create connections than bind services, but the address
conventions are the same.</p>
<p>Our existing service should still be running, so we can connect to it just like
we did before with <a href="http://linux.die.net/man/1/nc">netcat</a>.</p>
<pre><code>$ python connect.py
> to me
to you
> oh dear
oh dear oh dear
^C
$
</code></pre>
systemd for the uninformed - networkinghttp://yakking.branchable.com/posts/systemd-6-networkd/Richard Maw2015-07-01T11:00:13Z2015-07-01T11:00:07Z
<p>Networking is one of the most important things a computer can do, since
it's no so useful on its own.</p>
<h1>systemd-networkd</h1>
<p>Networking under Linux is powerful, but managed by a set of wildly
different tools, with different capabilities and with very different
interfaces.</p>
<p>To handle this, <a href="http://www.freedesktop.org/wiki/Software/systemd/">systemd</a> introduced <a href="http://www.freedesktop.org/software/systemd/man/systemd-networkd.html">networkd(8)</a> to provide a
common interface to all the network configuration, and is becoming a
standard way of doing this across the different distributions.</p>
<p>At the time of writing, <a href="http://www.freedesktop.org/software/systemd/man/systemd-networkd.html">networkd(8)</a> is intended to be
a replacement for static network config in the form of the
Debian-derived <a href="http://manpages.ubuntu.com/manpages/utopic/man5/interfaces.5.html">interfaces(5)</a> file, or the Red Hat-derived
<a href="http://www.linuxcertif.com/man/5/ifcfg/">ifcfg(5)</a>, rather than the dynamic network config managed by
<a href="https://wiki.gnome.org/Projects/NetworkManager">NetworkManager</a> or <a href="https://01.org/connman">connman</a>.</p>
<p>However, you can do some form of dynamic network configuration by
putting files in <code>/etc/systemd/network</code> and restarting <a href="http://www.freedesktop.org/software/systemd/man/systemd-networkd.html">networkd(8)</a>
by running <code>systemctl restart systemd-networkd.service</code>.</p>
<p>You can configure networks by adding a <a href="http://www.freedesktop.org/software/systemd/man/systemd.network.html">systemd.network(5)</a>
file, or create virtual network devices (such as bridges) with a
<a href="http://www.freedesktop.org/software/systemd/man/systemd.netdev.html">systemd.netdev(5)</a> file.</p>
<p>This is normally the domain of the system administrator, but <a href="http://www.freedesktop.org/wiki/Software/systemd/">systemd</a>
ships a few default rules to make networking with containers launched with
[systemd-networkd(1)][] work better.</p>
<p><a href="http://www.freedesktop.org/wiki/Software/systemd/">systemd</a> ships a rule for containers to use <a href="http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol">DHCP</a> on network
interfaces named <code>hostN</code>, to get their IP address. And ships a rule
such that the other end of these host-only interfaces provide a <a href="http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol">DHCP</a>
server, and use <a href="http://en.wikipedia.org/wiki/Network_address_translation">NAT</a> to allow containers to speak to the internet.</p>
<h1>systemd-resolved</h1>
<p><a href="http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol">DHCP</a> isn't the whole story though, as you need names to usefully
access the internet, so <a href="http://www.freedesktop.org/wiki/Software/systemd/">systemd</a> has some support for <a href="http://en.wikipedia.org/wiki/Domain_Name_System">DNS</a>.</p>
<p><a href="http://www.freedesktop.org/software/systemd/man/systemd-resolved.html">resolved(8)</a> provides per-interface <a href="http://en.wikipedia.org/wiki/Hostname">DNS hostname</a> resolution. This
is an improtant improvement over the current state of Linux networking,
because network interfaces are a lot more dynamic than they used to be.</p>
<p>It is not unusual to be connected to multiple networks, especially if
you need to use a <a href="http://en.wikipedia.org/wiki/Virtual_private_network">VPN</a> to talk to machines that are not allowed to
connect to the internet.</p>
<p>If name resolution is not handled per-interface, then you need to flush
the <a href="http://en.wikipedia.org/wiki/Domain_Name_System">DNS</a> cache to avoid having entries that are only relevant to
networks you are no longer connected to.</p>
<p><a href="http://www.freedesktop.org/software/systemd/man/systemd-resolved.html">resolved(8)</a> is only indirectly used, via the standard name lookup
procedure specified in the "hosts" line in the <a href="http://man7.org/linux/man-pages/man5/nsswitch.conf.5.html">nsswitch.conf(5)</a>
file, by adding "resolve".</p>
<p><a href="http://www.freedesktop.org/software/systemd/man/systemd-resolved.html">resolved(8)</a> doesn't normally need further configuration, as name
resolution is typically per-network configuration, and this network
configuration is usually shared by a <a href="http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol">DHCP</a> server.</p>
<p>However, if this is not reliable, then the name servers can be configured
per-interface in a <a href="http://www.freedesktop.org/software/systemd/man/systemd.network.html">systemd.network(5)</a> file, or system-wide in the
[resolved.conf(5)][] configuration file.</p>
Uses of SSHhttp://yakking.branchable.com/posts/uses-of-ssh/Richard Maw2015-02-18T11:00:17Z2015-02-18T11:00:12Z
<p><a href="http://www.openssh.com/">OpenSSH</a> is a handy tool for logging into other machines to run
a remote shell, but it's handy for other things too, giving the same
authentication mechanism and encryption.</p>
<h1>Passwordless logins</h1>
<p>Instead of requiring the entry of a password every time you want to log
in, you can use a local password manager, or key based authentication.</p>
<p>I prefer key based authentication. Keys can be generated by running
<code>ssh-keygen</code>, then future ssh connections can be made connection-less
by running <code>ssh copy-id USER@HOST</code>.</p>
<h1>File transfer</h1>
<p>The <a href="http://man7.org/linux/man-pages/man1/scp.1.html">scp</a> command can be used to securely copy files between two
machines, or even the same machine if it's a shared computing resource,
and sensitive data needs to be transferred between users.</p>
<p>For a less ad-hoc file server, OpenSSH includes an <a href="http://man7.org/linux/man-pages/man8/sftp-server.8.html">sftp-server</a>,
though you generally don't invoke it directly, but via <a href="http://man7.org/linux/man-pages/man5/sshd_config.5.html">sshd_config</a>.</p>
<p>It's very flexible, you can convert the SSH service into an SFTP server
by adding the following to <code>/etc/ssh/sshd_config</code>:</p>
<pre><code>ForceCommand internal-sftp
</code></pre>
<p>You can then view files in your home directory with the <a href="http://man7.org/linux/man-pages/man1/sftp.1.html">sftp</a> client,
or mount it with <a href="http://fuse.sourceforge.net/sshfs.html">sshfs</a>.</p>
<h1>Git server</h1>
<p>Git supports the ssh protocol. If you have a machine you can ssh to,
you can run <code>git init --bare reponame.git</code> to create a repository,
then clone it with <code>git clone ssh://USER@HOST/path/to/reponame.git</code>.</p>
<p>However for a shared git server this is cumbersome, as it requires every
git user to have an associated login account.</p>
<p>Instead, git servers like <a href="http://gitolite.com/">gitolite</a> and <a href="https://www.gitano.org.uk/">gitano</a> use one "git"
user, and handle authentication by assigning ssh keys to users.</p>
<h1>Port forwarding</h1>
<p>The <code>-R</code> option to ssh can be used to layer encryption and authentication
on top of an existing protocol that supports neither.</p>
<p>Supposing HOST has a service that isn't secure, it can instead bind to
a local only port, using the host address 127.0.0.1, and a port such
as 1234.</p>
<p>This port could be made available to your local machine on port 4321 by
running <code>ssh -R 127.0.0.1:1234:127.0.0.1:4321 USER@HOST</code>.</p>
<p>This service can then be connected to by connecting to the address
127.0.0.1:4312 locally.</p>
<h1>Advanced</h1>
<h2>sslh</h2>
<p>Corporate firewalls often block all ports not related to web browsing,
which limits it to plain HTTP on port 80, and HTTPS on 443.</p>
<p>One way around this is to use <a href="http://www.rutschle.net/tech/sslh.shtml">sslh</a>, which lets you run both HTTPS
and SSH on the same port. To make use of such services, add <code>-p 443</code>
to your ssh command-line.</p>
<p>If you regularly make use of such connections, it may be worthwhile to
add something like the following to your <code>~/.ssh/config</code> file.</p>
<pre><code>Host HOST
Port 443
</code></pre>
<h2>Using different keys for different machines</h2>
<p>I mentioned earlier that it is possible to do passwordless logins by
creating ssh keys.</p>
<p>By default this results in using your one key for authentication to every
host. You can generate extra keys by running <code>ssh-keygen -f KEYFILE</code>, and
use them instead of the default key by running ssh with <code>ssh -i KEYFILE</code>.</p>
<p>You can specify in your ssh config file to use a different key per host
with something like:</p>
<pre><code>Host HOST
IdentityFile KEYFILE
</code></pre>
<p>You might want to do this to avoid the association of a given key to a
person, by using different keys per service, and potentially to mitigate
the damage of future ssh key reverse engineering attacks, as only the
service for the reverse-engineered key is compromised.</p>
<h2>Making local resources available remotely</h2>
<p>I'm often annoyed that my local configuration is not available on remote
machines, so I wrote a script called <a href="http://richard.maw.name/blog/posts/2015-02-10-homely-ssh/">homely-ssh</a>, which makes the
home directory of my local machine available on the remote machine.</p>
<p>I would not recommend its use on shared machines, as it allows other
users to access your local machine.</p>