Skip to content

Networking

The Linux kernel supports several packet-filtering mechanisms.

  • Netfilter using the venerable iptables utility
  • nftables subsystem, introduced with kernel 3.13 (2014), had been commonly assumed to eventually take the place of iptables. Firewall rules are implemented in an in-kernel VM.
  • bpfilter

Netfilter is a software firewall and packet filtering framework introduced with Linux 2.4.0 (2001) and controlled by the iptables command.

Netfilter rules are stored in tables and in chains, and tables are associated with various chains.

By convention, table names are specified in lowercase and chain names in uppercase. Every packet starts at the top of a chain and is matched rule by rule. When a match is found the specified action, called the target, is triggered: i.e. "DROP" or "ACCEPT".

Tables INPUT OUTPUT FORWARD PREROUTING POSTROUTING
filter ✔️ ✔️ ✔️
nat ✔️ ✔️ ✔️
mangle ✔️ ✔️ ✔️ ✔️ ✔️
raw ✔️ ✔️

There are five builtin netfilter chains, though user-defined chains are also possible:

  • INPUT used for filtering incoming packets where the host itself is the destination packet.
  • OUTPUT for outgoing packets, where the host is the source of the packet.
  • FORWARD for filtering routed packets, where the host is router.
  • PREROUTING used for DNAT or port forwarding
  • POSTROUTING used for SNAT

Netfilter tables:

  • filter default
  • nat for SNAT and DNAT
  • mangle for packet alteration
  • raw used only to mark packets that should not be handled by the connection tracking system using the NOTRACK target

NetworkManager

NetworkManager provides a high-level interface for the configuration of network interfaces. It was developed by Red Hat and released in late 2004.

The config file format native to NetworkManager is the ini-format keyfile stored in /etc/NetworkManager/system-connections. These files define network interfaces, or connection profiles in NetworkManager's terminology.

nmcli

Control NetworkManager and report network status

Display devices and statuses

nmcli device status

Display information on interfaces as well as status Including other network connections not managed by network manager ("unmanaged") or not connected ("unavailable")

nmcli dev status

Display what connections are enabled

nmcli general status

Display UUIDs associated with network connections

nmcli connection show --active

Display much more information on network devices

nmcli device show

Configure settings for network interface {ens01} via interactive shell

nmcli connection edit ens01

List all connections NetworkManager has

nmcli connection show

Show settings for network interface {ens01}

nmcli device show ens01

Show status for all devices

nmcli device status

Display currently configured hostname

nmcli general hostname

Set hostname to {hostname}

nmcli general hostname hostname

Show overall status of NetworkManager

nmcli general status

Migrate a connection profile
nmcli connection migrate eth0

nmtui

dnf install NetworkManager-tui
nmtui is a curses-based TUI for control of NetworkManager.

Netplan

netplan is a utility for network configuration using YAML files that is the default network management tool used by recent versions of Ubuntu (since Ubuntu 17.10). Netplan is used as the default network management tool (previously ifconfig and its config at /etc/network/interfaces was used).

Netplan supports two renderers or backends: NetworkManager and networkd.

Netplan configs are YAML format and placed in /etc/netplan. Ubuntu installations usually come with a single config in this location named 01-network-manage-all-yaml, but many configs can be created in subdirectories. These are processed in lexicographical order regardless of subdirectory (unless there are multiple files with the same name). If a boolean or scalar parameter is defined in more than one config, the last value is assumed. Values that are sequences are concatenated.

Default config
# Let NetworkManager manage all devices on this system
network:
    version: 2
    renderer: NetworkManager # (1)
  1. This may require the python3-networkmanager package to be installed first.
Static IP configuration
network:
  version: 2
  ethernets:
    eth0:
      addresses:
      - 192.168.2.100/24
      gateway4: 192.168.2.1
      nameservers:
        addresses:
        - 192.168.1.1
        search: []

netplan

The netplan utility can be used to load the on-disk configuration.

Reload configuration temporarily
netplan try

Tasks

Bridge

A bridge is used to unite two or more network segments, typically used to establish communication channels between VMs, containers, and the host.

Unlike the virtual bridge that Windows uses for WSL2 distributions, the bridge in Linux is strictly L2. That is, VMs connecting to the bridge are assigned IPs by the same DHCP server (i.e. the router) in the same subnet as that of the physical hosts. In Windows, the virtual bridge assigns an internal IP in a private range (usually 172.16.0.0/12), and connectivity to the host or the Internet has to be accomplished via NAT.

ip link add virbr0 type bridge # (1)
ip link set virbr0 up
  1. The link can be deleted thus:
    ip link delete virbr0
    

Adding an interface to the bridge is done by setting its master.

ip link set enp2s0f0 master virbr0 # (1)

  1. This can be undone as follows:
    ip link set enp2s0f0 nomaster
    

The iproute2 bridge utility can be used to verify the command has taken effect:

bridge link

This may interrupt network connectivity. In this case, the IP address must be removed from the linked interface and assigned to the bridge

ip address delete 192.168.1.3 dev enp2s0f0
ip address add 192.168.1.3 dev virbr0

The default route in the routing table must also be amended. Note this is not the IP address of the interface but rather that of the gateway. Also note that this gateway must already have its own network segment defined. That is, in order for a default route to be defined at least one static route must also be defined, which is the gateway's own local subnet.

ip route delete default
ip route add default via 192.168.1.1

Downloading files

Wget defaults to file operations in a way that is more natural for downloading.

wget $url

Curl depends on piping and defaults to STDOUT in a manner similar to cat.

curl -O $url 

Wireguard tunnel

dnf install wireguard-tools
apt install wireguard

Successful installation can be confirmed by running the following, which should produce no output (and no error) on success.

sudo modprobe wireguard

The first step in creating a Wireguard tunnel is to create a private key on each endpoint of the tunnel. The genkey subcommand creates a 44-character base64 encoded key ending in = which can be redirected to a file. If the file will be world-readable, the utility will ask you to change the umask.

wg genkey # ▓▓░░░▓░▒▓▒▓▒░▓░▒░▓░▒▒░▓░▓░▒░▒▓▒▒▒░░▒▒░░░▒▒▓▓=

The public key can be generated by piping the private key from STDIN or from the file.

wg pubkey private > public
wg genkey | tee private | wg pubkey > public

Then a Wireguard interface is created, typically named wg0, using network management utilities.

ip link add wg0 type wireguard

An IP address is assigned to that interface, to be used within the tunnel:

ip addr add 10.0.0.1/24 dev wg0

Now the private key is associated with the interface:

wg set wg0 private-key ~/.config/wireguard/private

Finally, the interface is brought up:

ip link set wg0 up

The public key of the peer is now associated with the Wireguard interface and the public IP and port of the other endpoint are specified.

wg set wg0 peer $PUBKEY allowed-ips 10.0.0.2/32 endpoint $IP

The tunnel is dismantled by removing the interface.

ip link delete wg0

Alternatively, many of these steps can be consolidated into creating a config for the Wireguard interface at /etc/wireguard/wg0.conf with the following contents:

[Interface]
    PrivateKey = ▓▓░░░▓░▒▓▒▓▒░▓░▒░▓░▒▒░▓░▓░▒░▒▓▒▒▒░░▒▒░░░▒▒▓▓=
    Address = 10.0.0.1/24
    PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
    ListenPort = 51820

[Peer]
    PublicKey = ▓▒▓▒▓▓░▓▒▒░░▒▒▒▓▒░▒▓▒░▒▒▓▒░▒░░░░▒░▒▒▒░░▒▒▓░▒=
    AllowedIps = 10.0.0.2/32
    Endpoint = 123.45.67.89:51820

Then to bring it up quickly:

wg-quick up wg0

The same utility can be used to teardown the tunnel

wg-quick down wg0

Static IP

Static IP configuration varies by the network management toolset and backend presenton a system. Ubuntu systems use Netplan whereas other distributions most commonly use Network Manager.

network:
  version: 2
  ethernets:
    eth0:
      addresses:
      - 192.168.2.100/24
      gateway4: 192.168.2.1
      nameservers:
        addresses:
        - 192.168.1.1
        search: []
[connection]
id=Ethernet
uuid=abcdef01-2345-6789-0abc-def012345678
type=ethernet
interface-name=eth0

[ethernet]

[ipv4]
address1=192.168.2.100/24,192.168.2.1
dns=10.40.7.2
method=manual

[ipv6]
addr-gen-mode=stable-privacy
method=auto

Setting a static IP address on Red Hat distributions could involve multiple methods:

Commands

curl

Accept a self-signed certificate by skipping verification

curl -k https://192.168.1.10

Use the dict network protocol to retrieve the definition of a word. ref

curl dict://dict.org/d:<word>
Sending a POST method to a FastAPI app (src)
curl -X POST "http://127.0.0.1:8000/purchase/item/" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"name\":\"sample item\",\"info\":\"This is info for the item\",\"price\":40,\"qty\":2}"

firewall-cmd

Frontend to Netfilter in Red Hat distributions.

firewall-cmd --state # "running"

Firewalld has a runtime configuration and a saved, persistent configuration. Only the runtime configuration will be consulted for any command, unless the persistent configuration is specified with --permanent.

The runtime configuration can be saved with this command, which obviates the need to execute every change twice.

firewall-cmd --runtime-to-permanent

Alternatively, the persistent configuration can be loaded into memory:

firewall-cmd --reload

Display firewall rules
firewall-cmd --list-all --permanent

Firewalld uses zones to define the level of trust for network connections. A connection can only be part of one zone, but a zone can be used for many network connections. Builtin zones have XML-format configs found in /usr/lib/firewalld/zones.

firewall-cmd --get-active-zones     # Display active zones along with interfaces
firewall-cmd --info-zone=public     # Inspect zone
firewall-cmd --new-zone=testlab     # Create new zone

Firewalld rules are generally managed through builtin services. These bundle network settings together for well-known applications like SSH, etc. Builtin services are also XML-format configs found in /usr/lib/firewalld/services.

Services
firewall-cmd --list-services
firewall-cmd --add-service=http
firewall-cmd --remove-service=http

Firewalld's config file is at /etc/firewalld/firewalld.conf

/etc/firewalld/firewalld.conf
AllowZoneDrifting=no

Since RHEL 8, firewalld's backend has been changed to nftables.

/etc/firewalld/firewalld.conf
FirewallBackend=nftables

ip

ip address
ip address add 192.168.2.2 dev eth0
ip route
# Add static route (this is sometimes done automatically by the system after adding an address)
ip route add 192.168.2.0/24 dev eth0

# Add default route
ip route add default via 192.168.2.1 dev eth0
ip link
# Create new links
ip link add virbr0 type bridge
ip link add wg0 type wireguard

# Listen for netlink messages
ip monitor 

# Change the default gateway to 192.168.1.1 on eth0
ip route change default via 192.168.1.1 dev eth0

# Bring interface up"
ip link set wlp2s0 up
ip neighbor
# Display ARP cache
ip neighbor show

# Delete ARP entry
ip neighbor delete $IP_ADDR dev eth0 
ip netns
ip netns # (1)

# We can create a network namespace then add two virtual Ethernet interfaces.
# These are **peers**, meaning they are linked together as if connected to the same switch.
ip netns add netns0
ip link add veth0 type veth peer name veth1 netns netns0

# We can then run a command in the **context** of a namespace. Without providing a context, 
# the default namespace is used and we can display veth0 but not veth1. If there are no other
# links in the namespace (which there shouldn't be) then the **number** of the interface's 
# peer appears in the link's name. By running a command in the context of the new namespace 
# we can display veth1. The interface number of the link it's paired with in the 
# default namespace also appears in this link's name.
ip link show                        # "veth0@if2"
ip netns exec netns0 ip link show   # "veth1@if4"

# Now we assign an address to the namespaced link and bring it up
ip netns exec netns0 ip addr add 10.0.0.1/24 dev veth1
ip netns exec netns0 ip link set dev veth1 up

# Pinging this IP from outside the namespace will not work because there is no route.
# Adding an IP in the same subnet to veth0 creates the route.
ip addr add 10.0.0.2/24 dev veth0

# The interface must be brought up, which automatically adds a route to the routing table.
ip link set dev veth0 up
  1. Network namespaces are mounted to /var/run/netns

iptables

A frontend for the kernel-level netfilter service, similar to firewalld.

Rules are saved in a rulesfile which once may have been found at /etc/sysconfig/iptables, but this file does not exist on recent Fedora installations.

Display rules as written on disk

iptables --list-rules

Reload configuration file

iptables -F

Accept SSH traffic from a particular IP

iptables -A INPUT -p ssh -s 10.0.222.222 -j ACCEPT

Accept incoming TCP traffic to port 80

iptables -A INPUT -p tcp --dport 80 -j ACCEPT

Change FORWARD chain policy

iptables -P FORWARD ACCEPT # (1)

  1. By default, the INPUT chain accepts incoming packets. However, this policy can be changed by specifying a DROP rule specification.

Allow incoming SSH connections only from a single IP address

iptables -A INPUT -p tcp --dport 22 -j DROP
iptables -A INPUT -p tcp --dport 22 -s 1.2.3.4 -j ACCEPT

Do not respond to pings

iptables -t filter -A INPUT -p icmp -j DROP

netcat

The netcat utility allows testing of a host's ports, similar to ping, but more versatile because ping only uses the portless ICMP protocol. GNU and OpenBSD versions available

Connect to host on port 80

nc example.com 80
Scan ports

nc -v -w 2 z 192.168.56.1 22
nc -v -w 2 z 192.168.56.1 22 80
nc -v -w 2 z 192.168.56.1 22-25

Transfer files between servers This example uses the pv utility to monitor progress.

# Run `nc` in listening mode (`-l` option) on port 3000
tar -zcf - debian-10.0.0-amd64-xfce-CD-1.iso | pv | nc -l -p 3000 -q 5

# On the receiving client, to obtain the file:
nc 192.168.1.4 3000 | pv | tar -zxf -
Create a command-line chat server
# Create chat server listening on port 5000
nc -l -vv -p 5000

# Launch a chat session on the other system
nc 192.168.56.1 5000
Find a service running on port Obtain port banners (-n disables DNS lookup)
nc -v -n 192.168.56.110 80
Create stream sockets Create and listen on a UNIX-domain stream socket
nc -lU /var/tmp/mysocket &
ss -lpn | grep "/var/tmp/"
Create a backdoor Netcat needs to listen on a chosen port (here 3001): -d disables reading from stdin; -e specifies the command to run on the target system
nc -L -p 3001 -d -e cmd.exe
Connect to {port} at {host}
nc host port
Netcat command that retrieves a webpage
nc host port get

nft

nft list ruleset
nft list tables
nft list table ip filter # display just the filter table
nft flush ruleset

nmap

Scan hosts from a text file
nmap -iL hosts.txt
Identify a host's operating system
nmap -A localhost.example.com
Determine whether a host has a firewall enabled
nmap -sA localhost.example.com
Scan a specified range of ports
nmap -p 10-300 localhost.example.com
Perform a SYN TCP scan, stealthier than the TCP connect scan
nmap -sT localhost.example.com
Aggressive scan
nmap -A 192.168.1.0/24
Ping scan home network (not bothering with ports)
nmap -sn 192.168.1.0/24
Fast port scan using SYN packets
nmap -sS -F 192.168.1.0/24
Port scan using SYN ("synchronize") packet, first element of TCP handshake
nmap -sS 192.168.1.0/24
Port scan using normal TCP
nmap -sT 192.168.1.0/24
Port scan using UDP
nmap -sU 192.168.1.0/24
Xmas scan
nmap -sX
Scan a range of IPs [ref][Sec+ Lab]
nmap 192.168.27.0/24 > hosts.txt
Identify operating system and scan ports using TCP SYN packets [ref][Sec+ Lab]
nmap -O -sS 192.168.27.0/24 > hosts.txt

tcpdump

Inspect actual IP packets

Display all network data

tcpdump -i eth0   
Set snapshot length of capture (default: 65,535B)
tcpdump -s

ufw

Program for managing a Netfilter firewall.

Allow traffic associated with various services

ufw allow ssh
ufw allow http
ufw allow https

wg

This is the main CLI frontend for Wireguard, the UDP-based tunneling protocol and application that was introduced with kernel 5.6.

dnf install wireguard-tools
apt install wireguard

wget

Accept a self-signed certificate by skipping verification
wget --no-check-certificate $URL

Glossary

eBPF

eBPF is an extended version of the Berkeley Packet Filter (BPF). It is a sandboxed environment that allows code to be inserted into the running kernel. Kernel functionality must normally be extended by building an entirely new kernel with custom modules or upstream patching of the Linux kernel.

eBPF's architecture includes a JIT compiler that compiles the program's generic bytecode, which means eBPF programs run as efficiently as natively compiled kernel code.

eBPF programs can be bound to kernel events, such as receipt of a packet from the NIC.

bpftool is a core eBPF CLI tool.

bpftool prog     # Display running eBPF programs
bpftool map show # Display maps

ifcfg

Historically, ifcfg (interface configuration) files were ini-format files found in /etc/sysconfig/network-scripts/ in Red Hat distributions. They were used to control network interfaces on the legacy "network" service, now part of the network-scripts package, which included the sysconfig.txt file which documents the ifcfg file format.

After the introduction of NetworkManager, this format survived and was expanded with new directives specific to NetworkManager.

By convention, the string value of the DEVICE directive was the suffix of the filename itself.

ifcfg-eth0
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
TYPE=Ethernet

The nmcli utility exposes a command that can change the configuration backend from ifcfg to a NetworkManager keyfile.

Migrate a connection profile
nmcli connection migrate eth0

Ifcfg file support was finally removed in RHEL 9 and Fedora 36. If no ifcfg files are present, the configuration backend that supports them can be removed.

dnf remove NetworkManager-initscripts-ifcfg-rh

Netfilter

Netfilter is a software firewall and packet filtering framework introduced with Linux 2.4.0 (2001) and controlled by the iptables command.