💾 Archived View for the-brannons.com › rclocal captured on 2024-08-25 at 00:21:27. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

Configuring Networking in rc.local

Much of my Linux setup is totally bespoke and manual. GRUB config? I write it by hand, or I generate it from a template using a tiny program I wrote in CHICKEN Scheme named bootconf-update. The underlying principle is that if some part of the system shits the bed, I am better able to debug things because I can reason about my setup. Today I'm writing about how I do static network configuration.

Network Configuration on Linux

There are numerous network configuration and management tools on Linux. Here's a short list I came up with the other day:

The Network-managing Daemons

Declarative Interface Configurators

I have no interest in the first three on that list. systemd-networkd, in particular, has bitten me on the ass at least once. Of the network managing daemons, I find dhcpcd to be the most compelling. I like it. You can manage static addresses and dynamic DHCP addresses from one file and in one daemon.

The ifupdown family is great. /etc/network/interfaces is as old as the hills, easy to write, and easy to read.

I haven't looked at ifstate, but it seems to be a promising tool in the spirit of ifupdown. The config is yaml, which one may or may not consider to be a good thing. In its defense, there are lots of tools for working with yaml, and we do not have yet another of Unixes unending little languages to contend with.

ifupdown-ng and ifstate both have support for wireguard, amongst other exotic setups. On at least one of my public facing VMs, I use ifupdown-ng to configure all of my host interfaces, including the wireguard interface.

The Un-solution

Sometimes all you really have is a bunch of static network config. If you know iproute2 or net-tools, the easiest and most stable thing to do is just to plop a bunch of commands down in /etc/rc.local. You can guarantee that nothing is going to mess with your config behind your back.

A Fully Worked and Commented Example

Here's /etc/rc.local on my home server, complete with commentary.

# Default rc.local for void; add your custom commands here.
#
# This is run by runit in stage 2 before the services are executed
# (see /etc/runit/2).
nft -f /etc/nftables.conf  # Apply firewall rules before bringing up interfaces.

# Logical network interface names, like modem0 and lan0, are established
# using udev rules.  Or alternatively,
# I've used mdev and ifrename on Alpine systems.
# modem0 is an ethernet port connected to a DSL modem.
# We're going to use macvtap to pass modem0 down to a qemu VM.
ip link add link modem0 name macvtap0 type macvtap mode bridge
# Give macvtap0 a permanent mac address.  The "aa:00:" MAC address space
# is usable for this kind of stuff.
ip link set macvtap0 address aa:00:03:19:79:89
ip link set macvtap0 up

# The LAN is served by a bridge.  There are multiple ethernet ports connected
# to that bridge, including one for Chris's frontend machine
# and another for a wireless access point.
ip link add brlan type bridge

# Manually assign a MAC address to the bridge.  In this case, the address
# is one of the connected ports.
# If you do not set an address on the bridge, the bridge will have a
# somewhat nondeterministic MAC address.
# Specifically, it uses the lowest-numbered MAC address of all the
# interfaces added to it, and its MAC address can change over time.
# This will bite you, and you will be forced to debug it at the most
# inopportune time possible.
# When I say lowest numbered, keep in mind that MAC addresses are just
# 48-bit integer numbers.

ip link set brlan address 3c:ec:ef:d8:65:1b
ip link set brlan up

# Up the ethernet ports, add them to the bridge.
ip link set dev lan0 up promisc on
ip link set dev lan0 master brlan
ip link set dev lan1 up promisc on
ip link set dev lan1 master brlan

# Up modem0, so it will pass traffic once our qemu VM comes up later.
ip link set modem0 up

# Put some addresses and default routes on the bridge:
ip addr add 10.4.20.2/24 dev brlan
ip route add dev brlan via 10.4.20.1 default
ip -6 addr add '2001:db8::2/64' dev brlan
ip -6 route add dev brlan via '2001:db8::1' default
dmesg -n 1
# Some cargo-culted setting of the wireless regulatory domain.  I needed
# this when I was using hostapd.
iw reg set us

I can probably get everything I need with ifupdown-ng, and the configuration would be far more readable, especially for people unfamiliar with the host in question. Maybe I'll do that someday, but for now, this works, and it has one clear advantage over everything else. I know iproute2, because I spent some cycles gaining proficiency with it.