258 lines
8.6 KiB
Markdown
258 lines
8.6 KiB
Markdown
|
---
|
||
|
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
|
||
|
```
|