Skip to content
Lesson 7 of 10

Step 1 of 5 · Reading · ~3 min

Read

Tunneling & Routing

Peer Configuration and Cryptokey Routing

After this lesson your program reads a real WireGuard config file, rejects a broken one, and answers the question WireGuard asks for every packet: which peer is this destination routed to, and is this peer allowed to use that source address.

The config file

A WireGuard config is an INI file of key = value lines in two kinds of section. A client that sends everything through the server:

[Interface]
PrivateKey = IqbXAZCn8Irm9vJH9B91bmAHmTd6iFz2DyfQlvgwn7E=
ListenPort = 51820
Address = 10.0.0.2/32

[Peer]
PublicKey = xfDRZWTLHNvi5xKmZ3n9Ys2n80HZ7hJ/guTx/IoXWjM=
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0   # full tunnel
PersistentKeepalive = 25

Parsing rules that matter:

  • Everything after # is a comment, blank lines are skipped, and files written on Windows end lines with CRLF.
  • Section names and key names are case-insensitive.
  • Split each line at the first =. Base64 keys end in =, so the value itself contains one.
  • A key is 32 bytes as base64: exactly 44 characters, ending in =, the first 43 from the base64 alphabet.
  • AllowedIPs takes a comma separated list, may appear several times in one peer (the entries add up), and may name IPv6 blocks such as ::/0. This stage routes IPv4 only, so skip IPv6 entries. A bare address means /32.
  • Keys we do not use (Address, DNS, PostUp, PresharedKey) are ignored. A line with no =, a line before any section, or an unknown section name is an error, and so is a missing or malformed key. The config needs exactly one [Interface].

PersistentKeepalive is a number of seconds, or 0 or off for none. ListenPort is optional and WireGuard picks a random port without it. Endpoint is optional; a server learns it from incoming packets.

Cryptokey routing

AllowedIPs is WireGuard's most unusual idea. It is the routing table and the firewall in one, and it is tied to a public key:

  • Sending: the destination address of an outgoing packet is looked up with longest-prefix match (the previous lesson). The peer that owns the best block is the one the packet is encrypted for.
  • Receiving: a packet that arrives and decrypts correctly from peer P carries a source address. It is accepted only if looking that source up in the same table gives P again.

Example with alice = 10.0.0.0/24 and bob = 10.0.0.128/25. A packet to 10.0.0.200 goes to bob, because /25 beats /24. A packet from alice with source 10.0.0.200 is dropped even though her /24 covers it: the table says that address belongs to bob, and one key may not speak for another's address. This is what stops a peer from spoofing anyone but itself, and why you need no separate firewall rules.

If two peers claim exactly the same block, the later one takes it over.

Common mistakes

  • Splitting on every = and cutting the key short.
  • Case-sensitive names. allowedips, ALLOWEDIPS and AllowedIPs are the same key.
  • Accepting by "inside the sender's blocks" only. The lookup of the source must return the sender, otherwise a /24 holder can claim a more specific /25 of someone else.
  • Letting the last AllowedIPs line replace the first instead of adding to it.
  • A Windows line ending left in the value. 25\r is not a number and ...=\r is not a key.

Your exercise

The starter reads stdin, separates the config from the queries and prints INVALID for you. You parse the file and answer the queries. The most likely mistake is checking that the source belongs to the sender instead of that the source's best match is the sender.

Up nextNAT Traversal and EndpointsTunneling & Routing

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…