8.6 KiB
title | description | updateDate |
---|---|---|
Networking from Scratch | Setup your own simple network on Linux | Apr 22 2024 |
Why learn Low-Level Networking?
Networking is one of the most complicated and practical standards 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, making it hard to pick up network debugging skills.
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.
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:
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
:
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