One ip tool to rule them all

Play by the Rules

Since version 2.x, Linux has supported multiple routing tables – around 2^31 of them (which is quite a few), although table numbers 0 and 253-255 are reserved. By default, routes end up in table 254, which is also called main (see /etc/iproute2/rt_tables). Table 255 (local) contains routes to local and broadcast addresses. The kernel maintains this table automatically (Listing 5).

Listing 5

Local Table 255

 

Note how you tell ip the table you want to use. A special value, all, lists all route entries. Other ip route commands, such as add or del, support this syntax as well.

Multiple tables are used for policy-based routing, in which the criteria could be pretty much anything: a source address, ingress (incoming) or egress (outgoing) interface, TCP or UDP ports, or even the package payload.

Linux implements policy-based routing via a set of rules, also known as the Routing Policy Database (RPDB), and rule is an object in ip. The following is the default ruleset on a system with only classical routing configured:

$ ip rule show
0:      from all lookup local
32766:  from all lookup main
32767:  from all lookup default

You see that each rule comprises a priority (32766), a selector (from all), and an action (lookup main). The kernel traverses rules from smaller to larger priority values, so the local table comes into play first. The from all selector matches any source address. Selectors may also include destination addresses (to), ingress and egress interface names (iif and oif, respectively), and firewall marks (fwmark). You may assign this mark in your iptables rules with MARK/CONNMARK targets. Iptables implements sophisticated packet matches (LV017), including Deep Packet Inspection (DPI), and, with fwmark, you can route traffic according to these matches. This opens a whole new set of possibilities. A how-to [1] provides some useful hints.

Action is usually a table lookup. By now, you probably get the idea behind policy-based routing. Just mark traffic the way you want, create a routing table per traffic type, and add a rule to look up these tables. Do you want a separate ISP connection for your online gaming needs? No problem!

Building Private Networks

As you see now, ip can cope with a wide range of network configuration tasks. Beyond what you've already seen, ip can handle multicast, create network tunnels, and manage TUN/TAP devices. In fact, ip is sophisticated enough to pave the foundation for a full-featured VPN solution.

Perhaps the most popular VPN technology in Linux is OpenVPN [2], which creates a pair of TUN or TAP virtual adapters, depending on the settings, and wraps all packets coming through these interfaces in encrypted UDP datagrams. OpenVPN does all network-related heavy lifting itself, and there is nothing wrong with this approach, except it opens the way for simplification.

A recent Linux VPN solution called WireGuard [3] offloads networking to ip and focuses on the cryptography. This helps keep its codebase small and clear. WireGuard is under heavy development, so it might not have made its way into your distribution's repositories yet. If this is the case, you can compile it yourself: The homepage has a step-by-step guide.

To set up a tunnel, use ip to create wireguard-type devices on both peers and assign them IP addresses. This is similar to the Veth example:

# ip link add dev wg0 type wireguard
# ip address add dev wg0 192.168.200.1 peer 192.168.200.2

Note that ip addr specifies a peer, because the WireGuard tunnel is a point-to-point link.

Now you generate keys to encrypt the traffic. Although you have several options, for simplicity, you can follow the recipe in the wg(8) man page,

$ umask 077
$ wg genkey | tee private.key | wg pubkey > public.key

where wg is the WireGuard userspace tool. Run it on both peers, and create configuration files – for example:

[Interface]
PrivateKey = ...
ListenPort = 41414
[Peer]
PublicKey = ...
Endpoint = 192.168.101.149:41414
AllowedIPs = 192.168.200.0/24

Set PrivateKey to this host's private.key contents, and PublicKey to the peer's public.key. Assign Endpoint to the peer's IP address, and apply the configuration with

wg setconf wg0 sample.conf

on both ends.

To activate the link, you use ip once again. Peers negotiate the connection when you bring the link up:

# ip link set up dev wg0

If everything is fine, running wg show should bring the result, as shown in Figure 2.

Figure 2: WireGuard's wg tool reporting successful tunnel negotiation. Colorful output is a bonus.

Splitting cryptography and network-related tasks between wg and ip helped WireGuard focus on security rather than reinventing the networking wheel. One day the program will reach a 1.0 milestone, and I'll probably allot it a Core Tech article of its own.

Command of the Month: ip netns

This month, the whole Core Tech is devoted to a single command. It would be weird to nominate a different command as the Command of the Month, so instead, I'll honor one of the ip objects that is powerful enough to have a tool of its own.

The name of this object is netns, and it stands for "network namespaces." The Linux namespaces isolation technique is one of the standing pillars behind containerization tools like Docker. However, you can use network namespaces on their own without a fancy tool like Docker. Network namespaces come in handy whenever you need a separate network stack for some task, even if complete isolation is not a goal.

To create a namespace, use:

ip netns add <name>

Now, you can configure networking as usual, provided you add -netns <name> (or just -n <name>) to each ip command invocation. In fact, ip can execute arbitrary commands (e.g., ping) within the namespace with:

ip netns exec <name> <command>

and -netns is just a shortcut for:

ip netns exec <name> ip [args]

Each namespace comes with its own set of network interfaces, and you can assign a link to the namespace with:

ip link set netns <name>

The ip monitor command reports namespace creation and deletion events, and ip netns list shows namespaces defined in the system. If you no longer need a namespace, use ip netns del to delete it. Note the namespace might stay alive if it has users other than you. When the last user deletes the namespace, its physical devices are reassigned back to the default.

Linux Voice Pro Tip

Most ip objects understand save and restore commands to serialize and deserialize the configuration. Should you want some persistence, they are the way to go.

Infos

  1. The Linux Advanced Routing & Traffic Control HOWTO: http://lartc.org/howto/
  2. OpenVPN: http://www.openvpn.net
  3. WireGuard: http://www.wireguard.io

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus

Direct Download

Read full article as PDF:

Price $2.95

News