# Essential Networking on Debian

VirtualBox has multiple options when it comes to it's networking settings.
We've already used two different ones, *NAT* and *bridged*, but we'll now try to create our own *internal* network.
For this we'll need a few minimal Debian installations.
I invite you to install at the least two basic installations.

* One will become our router
* The other one our first client

## Static routing

The most basic way of setting your network settings in Debian can be found in the `/etc/network/interfaces` file.
When you open it you'll notice it mentions it sources a folder called `interfaces.d`.
The choice is up to you whether you set your networking settings in this file or create a new file in the folder but I advise you to go for the second way.
Don't just *copy/paste* the code below, check whether the interface names and ranges make sense!

```bash
auto eth0
iface eth0 inet static
	address 10.0.0.1
	netmask 255.255.255.0
	gateway 10.0.0.1
```

![overview](./assets/network_basic.png)

If you set both machines with addresses in the same range, you should be able to ping each other.
Have a go at this until you can make it work.
Which service do you have to restart of reload to apply your changes?

Restarting your network interfaces can be done in multiple ways.
The most complete restart of all the interfaces can be done by restarting the `networking.service` run by `systemd`.

```bash
sudo systemctl restart networking.service
```

If this does not bring back your network settings you probably forgot to add the `auto $INTERFACENAME` line in the `/etc/network/interfaces` file.

A less brutal and more advised way of bringing an interface down and up is done with the following commands.
It has the added advantage of giving a verbose output to STDOUT with what is happening which can be very handy for debugging purposes.

```bash
sudo ifdown $INTERFACENAME
sudo ifup $INTERFACENAME
```

## Forwarding traffic

One of our machines is supposed to be a router and the other a client.
Right now we can just ping between both machines but the outside world is completely invisible to us.
How can we tackle this?
Do we need more equipment?

An overview of what we would like to accomplish can be seen below.

![overview](./assets/network_large.png)

In VirtualBox we can add more than one network adapter.
On the router machine I would like you to add a second network interface and set it to *bridged mode*.
When you reboot you should notice you have two network cards.
Can you ping outside of your network now?

You could try and add a dhcp configuration to your `/etc/network/interfaces` file for this second interface.
Once this is done, how do you ask for an IP address from the dhcp server?
Have a look at the `dhclient` program to see how it works.

Now, if everything went OK your router should have two IP addresses, one in the 10.0.0.0/24 range and one in the 192.168.0.0/24 range.
Who gave you this second address?
Can the client ping both IP addresses?
Can the client now ping outside of the network?

The *easiest* way to achieve routing between your internal network and the outside world is to enable [NAT](https://en.wikipedia.org/wiki/Network_address_translation) on your router.
In order to do this, you need to do 2 things.
First enable the kernel to actually forward packages, secondly `iptables` needs to do masquerading.
You can do both these things with just to simple commands on you router.

1. IP forwarding needs to be setup on the router
2. NAT needs to be enabled

From here on out all your clients *should* have internet access but you won't be able to `ping` your clients from outside your network.
Your clients can ping each other and the internet at large but for clients **outside** of their mini network the router will **masquerade** the IP address.
This means that from outside your network, you'll never be able to ping a specific client, just the router itself.

```bash
sysctl net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -j MASQUERADE
```

These settings won't save themselves so next time you reboot they'll be missing.
For the kernel option you should have a look at `/etc/sysctl.conf`.
In this file you can enable, disable or set kernel values.
Changes to this file won't be automatically reloaded so we can execute `sudo sysctl -p /etc/sysctl.conf` to force a reload of that specific file.

To save `iptables` rules have a look online but [this](http://www.faqs.org/docs/iptables/iptables-save.html) and [this](https://zertrin.org/projects/iptables-persistent/).

### Extra Challenge

Your client machines are now behind a NAT.
Can you think of a way to ssh into them?
As you can only ping the router from outside of the network you'll have to setup [port forwarding](https://en.wikipedia.org/wiki/Port_forwarding).
On Debian this is done with [iptables](https://serverfault.com/questions/532569/how-to-do-port-forwarding-redirecting-on-debian#532575).

## DHCP

It gets real tiring real quick to fix the IP address for every new machine we add to the network.
A solution for this is to install a [DHCP](https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol) server onto our network.
It can be installed onto any machine or ever a new machine but I advise you to install the DHCP server onto the router.

As with most thing Linux there are multiple servers to choose from. 
The two most popular ones are:

* [isc-dhcp-server](https://wiki.debian.org/DHCP_Server)
* [dnsmasq](https://wiki.debian.org/dnsmasq)

We'll start with isc-dhcp-server because it's an industry standard for large scale networks.
The other one, dnsmasq, is lighter and easier to use but consequently it has less features.
It does however has the added benefit of being a [DNS](https://en.wikipedia.org/wiki/Domain_Name_System) server as well!
If you want to use isc-dhcp-server and add a DNS server to your network as well you'll have to install a secondary service.
Large scale networks often combine it with [bind9](https://wiki.debian.org/Bind9) which is a very powerful, but pretty complicated to configure, server.
For our long term purposes dnsmasq is a better option but we'll start with isc-dhcp-server non the less.

### isc-dhcp-server

Installing isc-dhcp-server is pretty straight forward.
An `sudo apt install isc-dhcp-server` should sort you out but you'll get a bunch of errors.
Don't panic, this is pretty normal because we haven't configured the server yet.
A handy new command you'll learn here is `journalctl`.
This is the main interface towards all logging done by all services `systemd` manages.
The `-x` option will 'Augment log lines with explanation texts from the message catalog.' so will be more verbose and the `-e` will jump to the end of the logs.

```bash
sudo journalctl -xe
```

We need to edit two files to successfully start the DHCP server.
First we need to specify which interface the server should listen on because by default it listens on no interface.
This first file can be found at `/etc/default/isc-dhcp-server`.
Have a read of this configuration file and you'll quickly understand *where* the second file we need to edit is located.

In this second file we need to add a subnet on which the server will distribute IP addresses.
Declaring the subnet is enough for the server to start however if we don't set a range, no IP address will be handed out.
A simple declaration with a corresponding range is expressed as follows:

```bash
subnet 10.0.1.0 netmask 255.255.255.0 {
	range 10.0.1.10 10.0.1.100;
}
```

This suffices to get the server up and running without any errors.
We can also use the DHCP server to push routes to all our clients.
This can be tremendously helpful for larger networks but can also be used to push a default route to your clients.
Additionally we can push a DNS server as well.

```bash
subnet 10.0.1.0 netmask 255.255.255.0 {
	range 10.0.1.10 10.0.1.100;
	option routers 10.0.1.1;
	option domain-name-servers 8.8.8.8, 1.1.1.1;
}
```

### dnsmasq

If want to resolve local domain names on our network we need DNS server.
As mentioned above the classic dns counterpart to isc-dhcp-server is bind9.
An easier to setup DNS server is dnsmasq and as an added benefit it does DHCP as well!
We can't run two DHCP servers on the same machine at the same time, because they will both try to bind to the same port, so we have to stop and disable isc-dhcp-server.
We already know how to stop the server with `systemctl` but disabling is new.
What is the difference?
Well, disabling will prevent the server from starting at boot time.
The counterpart to disable is enable.

```bash
sudo systemctl disable isc-dhcp-server
sudo systemctl stop isc-dhcp-server
```

Now we can install dnsmasq with `sudo apt install dnsmasq`.
The configuration is done by creating a new file at `/etc/dnsmasq.d/`.
You're free to name this file however you want and you can also create multiple files to spread out your configuration.
This can be very handy for larger setups.

#### DHCP

At the bare minimum, to replace isc-dhcp-server, we need the following:

```bash
dhcp-range=10.0.1.10,10.1.100,24h
```

The same 90 leases will be available for hand out and each lease is valid for 24 hours.
You restart the service in the same way you restart all other services we did up until now; `sudo systemctl restart dnsmasq.service`.

A slightly modified configuration can make things a bit clearer.
By default dnsmsq is smart enough to distribute on the right interfaces but we can specify this ourselves.
It won't change much to the operation, but will clear things up when we start offering different ranges on different interfaces.

```bash
dhcp-range=eth0,10.0.1.10,10.1.100,24h
```

#### DNS

The DNS aspect of dnsmsq requires a bit more configuration.
By just installing dnsmsq it already *is* a DNS server and you can test this with `nslookup`.
If you don't have that program installed you can install it with the `dnsutils` package.
We will need to add a few more lines of configuration though.
Again, don't just *copy/paste*, modify the lines to your need.

```bash
# specify the interfaces we will listen on to resolve DNS requests
interface=lo
interface=eth1
interface=eth2

# bind only to the interfaces we specify
bind-interfaces

# we can add out clients to our domain
domain=peperoni.lan
local=/peperoni.lan/

# we set which servers our dns uses to resolve
server=127.0.0.1
```

If we want to use our DNS server to [push routes](https://en.wikipedia.org/wiki/Routing) to our clients we need to add it to the configuration as well.
The syntax is as follows, `121,x.x.x.x/yy,z.z.z.z` where `x.x.x.x` is the IP range, `yy` the netmask and `z.z.z.z` is the via which IP address.
You can add as many as you want but there is a practical [limit](https://unix.stackexchange.com/questions/457572/use-dnsmasq-to-pushing-routes-to-my-clients-on-a-small-local-network).
Are you wondering what the `121` [means](http://help.sonicwall.com/help/sw/eng/6800/26/2/3/content/Network_DHCP_Server.042.12.htm)?

```bash
dhcp-option=121,10.0.4.0/24,192.168.0.117
```

## Group labo

The goal of this exercise is to create a small network of VM's on each of our workstations and interconnect all of them over the LAN in the classroom.
Your responsibility is to create a functioning mini network of VM's on your workstation.
Once this is operational you can add routes to the mini networks of the other students.
You have to add routes for each student so maybe a script can come in handy.
As I'm running the DHCP and DNS of our LAN I can push these routes to your routers but first you should create them yourself!

![big network](./assets/network_big.png)

## Solo labo

Try to go as far as you can with following the network layout below.
You'll have to create quite a few virtual machines machines so grouping them and having a consistent naming scheme is advised.

![solo labo layout](./assets/network_solo.png)

I would break it down as such:

* 1 VM to be the bridge between all your clients and the LAN of the class
	* 1 network interface in **bridged** mode (connects to my LAN)
	* 2 network interfaces in **internal network** mode (they should be named differently **LSN/RSN**)
* 1 VM on the left side with:
	* 4 network interfaces (**LSN/LSN1/LSN2/LSN3**)
	* can run the DHCP for all these subnets'
* 4 VM as clients per subnet (so 3 * 4 = 12)

The setup is mirrored on the right side so rinse and repeat.

### Set by step

#### The NAT router

![NAT router](./assets/network_solo_detail1.png)

First focus on the machine that will become your NAT router.
This part of the exercise is very similar to the static router we made before.
Looking at the diagram we can see that this machine will need three network interfaces:

* one in bridge mode (so you get an IP from the class DHCP)
* one in internal network mode for the 10.10.0.0/24 network
* one in internal network mode for the 172.20.0.0/24 network

The internal network can be a shared one as the networks are separated and we'll set static IP addresses for the two router clients but if it looks cleaner to you, make a named internal network for each of them.

#### The first router

![first router](./assets/network_solo_detail2.png)

Next up is the first router on the left hand side.
This is also a Debian VM but with four network cards attached!
All cards will have to be in internal mode where one is connected to the same network as the NAT router's 10.10.0.1 card and the other three will have to be three **new** internally named networks.
One for each of the ranges because we'll run a DHCP server on this router that will offer different addresses on each interface.
I advise you to write down which card does which network.
The IP addresses for the cards on this router have to be set statically because we won't run a DHCP on the 10.10.0.0/24 network.

* 10.10.1.0/24
* 10.10.2.0/24
* 10.10.3.0/24

#### The clients

This is easy!
Create a client, put their network card in the right internal network and they should be good to go!
