noway.moe/src/content/unix/networking-from-scratch.md

258 lines
8.6 KiB
Markdown
Raw Normal View History

2024-04-22 20:05:29 -06:00
---
title: 'Networking from Scratch'
description: 'Setup your own simple network on Linux'
updateDate: 'Apr 22 2024'
---
# Why learn Low-Level Networking?
Networking is one of the most complicated and practical standards for ever
created for digital communication. This unfortunately means that when we connect
to a network, it's quite hard to understand what's actually happening and
knowing this is very helpful for debugging.
In this article we'll go through setting up a simple wired network using the
`ip` tool on Linux. We'll also do a quick overview of next steps.
You only need one Linux computer, but it's much more fun if you have two. You'll
also want an Ethernet cable connecting the two Linux machines.
## Setting Up
By default, your Linux computer almost certainly uses a network manager. This is
a program that does what we're about to do automatically. You should never have
more than one network manager running at a time, so if we're acting as one,
you'll need to turn yours off.
```bash
systemctl disable NetworkManager.service
systemctl disable systemd-networkd.service
```
It's okay if one of those errors. Next, to clear the configuration those network
manager provided, you'll need to reboot with `systemctl reboot`.
Further, put the following alias in your `~/.bashrc` or whichever file your
shell uses:
```bash
alias ip='ip -c' # Makes output colorful
```
# Background of Networking
## IP Addresses
A computer can have multiple network interfaces. Most often these will be one
of:
- A WIFI card
- An Ethernet port
- A USB to Ethernet adapter
Each interface can be assigned IP addresses. These addresses come in one of two
flavours: IPv4 and IPv6. Version 4 is the old standard that's used almost
universally. Version 6 came out in 1996 and improves on IPv4 by adding more
addresses (IPv4 only has about 4.3 billion... these ran out in 2010).
Unfortunately, IPv6 adoption is one of the slowest updates in the history of
computing, so IPv4 remains more commonly used, with many home networks not even
offering IPv6.
An IPv4 address is 32bits, represented by decimal numbers in groups of 8bits,
with dots in between. This means each of the four numbers range from 0-255
inclusive. Here are some examples:
```
127.0.0.1
10.0.0.0
10.42.43.250
```
An IPv6 address is 128bits, represented by hexadecimal numbers, in groups of
16bits, with colons in between. Two consecutive colons can be used to indicate
filler zeros. Here are some examples:
```
fd00:1bac:c0ca:12a2:1a7e:b9ff:fe07:d7a2
2001:0db8:85a3:0000:0000:8a2e:0370:7334
2001:0db8:85a3:0:0:8a2e:0370:7334
2001:0db8:85a3::8a2e:0370:7334
```
We will use IPv4 for the convenience, but the concepts transfer quite directly
to IPv6.
## Subnet Masks
A network mask is used to figure out which IP addresses belong to a network.
This is specified as the number of bits in a slash after the IP address.
For example `192.168.1.7/24` means the netmask is the first 24 bits of this IPv4
address. Remember, that each number represents 8 bits, so we can convert this
address to:
```
192 . 168 . 1 . 7
11000000 10101000 00000001 00000111
└─────────────┬────────────┘
First 24 bits
```
In this case, that means the last of the four numbers can be anything, and the
IP address will be considered as part of this network. Some examples:
- `192.168.1.0`
- `192.168.1.255`
- `192.168.1.127`
- `192.168.1.100`
In total, there are 256 addresses on this network. The largest "block" reserved
for private use is `10.0.0.0/8`. This network has about 16.7 million addresses!
```
10 . 0 . 0 . 0
00001010 00000000 00000000 00000000
└────┬───┘
First 8 bits
```
# The Address Table
## Parsing the Address Table
Use `ip address` or `ip addr` or `ip a` to display your address table. It should
look something like:
```
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 18:7e:a9:47:e2:c7 brd ff:ff:ff:ff:ff:ff
3: wlan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 3c:22:ff:b8:27:a1 brd ff:ff:ff:ff:ff:ff
```
Let's go through this output. Firstly, we see there are three interfaces on this
computer. Their names are `lo`, `eth0`, and `wlan0`. Typically, interfaces
starting with an `e` are wired and those starting with `w` are wireless (WIFI).
`lo` is the loopback interface. This isn't a real interface, but your computer
uses it to send network messages to itself. We can see its IPv4 address in the
`inet` line is `127.0.0.1` with a subnet mask of `8`. In the `inet6` line, we
see it has an IPv6 of `::1` with subnet mask `128`. This is true for all Linux
computers, so you should see the same thing.
`eth0` is an Ethernet port on my computer. The lack of an `UP` in the
`<BROADCAST,MULTICAST>` means that the interface isn't currently communicating
with anything. On the `link/ether` line, we see the MAC address of this
interface. `eth0` currently doesn't have any IP addresses assigned to it, so the
`inet` and `inet6` lines are missing.
`wlan0` has a similar situation with `eth0`, in that it doesn't have any
addresses yet.
## Adding an Address
You will need `sudo` for any `ip` commands which modify the network tables. I
will omit the `sudo` from here on.
Let's add an IP address of `10.42.43.20/24` and `10.42.43.100/24` to `eth0`:
```bash
ip a add 10.42.43.20/24 dev eth0
ip a add 10.42.43.100/24 dev eth0
```
Now the address table should show these addresses:
```
...
2: eth0: <BROADCAST,UP,MULTICAST> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 18:7e:a9:47:e2:c7 brd ff:ff:ff:ff:ff:ff
inet 10.42.43.20/24 brd 10.42.43.255 scope global eth0
valid_lft forever preferred_lft forever
inet 10.42.43.100/24 brd 10.42.43.255 scope global eth0
valid_lft forever preferred_lft forever
...
```
As a challenge, try adding an IPv6 address!
# The Routing Table
Routing tables determine where your computer will send network messages (known
as packets). This is very important in determining which interface to send a
packet over and using the loopback when possible.
Say we have two interfaces with the following addresses:
- `eth0`: `10.42.43.20/24`
- `wlan0`: `192.168.0.4/24`
If we want to send the packet to IP address `10.42.43.30`, the computer will
make sure to use `eth0`.
In a more complicated case, consider:
- `eth0`: `10.42.43.20/24`
- `wlan0`: `10.42.43.21/8`
Sending to IP `10.42.40.1` clearly must go through interface `wlan0`, but what
about a packet to `10.42.43.1`? Both interfaces can legally send this packet, as
their subnetworks both contain the address `10.42.43.1`. To determine which one
to use, your computer will check the routing table.
## Parsing the Routing Table
You can view your routing table with `ip route` or `ip r`. Your routing table
might look like the this right now:
```
10.42.43.0/24 dev eth0 kernel scope link src 10.42.43.100
10.42.43.0/24 dev eth0 kernel scope link src 10.42.43.20
```
According to the routing table above, any packets sent to `10.42.43.0/24` will
have the `10.42.43.100` IP address in their header, when sent from `eth0`.
That's since it appears higher in the routing table.
## Setting routes
Adding a route is very similar to typing exactly what you want to see in the
routing table:
```
ip r add 10.42.43.0/24 dev eth0
```
You can also remove routes, which is helpful if you don't want a certain
interface sending packets:
```
ip r del 10.42.43.0/24 dev eth0
```
The last important route is the "default" route. Often this is called the
"default gateway" in network managers. This is the route used when the IP you're
trying to reach isn't on one of the subnetworks you're connected to. It's really
the "internet".
```
ip r add default via 10.42.42.1 dev eth0
```
This means that when your computer can't find a matching subnetwork in the
routing table, it'll send the packet over to `10.42.43.1` using interface
`eth0`. Assuming `10.42.43.1` is setup for packet forwarding and has internet
access, this will give your computer internet access as well!
Default routes are confusingly listed at the top of the routing table, but
they're used in order (top to bottom) only after all the subnets have been
checked.
```
default via 10.42.43.1 dev eth0
10.42.43.0/24 dev eth0 kernel scope link src 10.42.43.100
10.42.43.0/24 dev eth0 kernel scope link src 10.42.43.20
```