wirelink

command module
v0.14.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 9, 2024 License: AGPL-3.0 Imports: 6 Imported by: 0

README

Actions Status codecov Go Report Card

Concept

This is an experiment in implementing automatic peer-to-peer link setup in wireguard by:

  • Automatically configuring IPv6 link-local ips for each peer, derived by hashing the peer's public key
  • Using that to automatically share information about available peers and their endpoints
  • Using that to try to automatically setup direct connections between peers (when possible) instead of routing through a central "server".

Configuration

wirelink will read basic configuration from:

  • A config file /etc/wireguard/wirelink.<interface>.json
    • Some other extensions such as .yaml will be accepted too
    • Some settings can only be set in the config file for now
  • Environment variables of the form WIRELINK_<setting>
  • Command line args (see --help)
Systemd

Two systemd template units are provided:

wl-quick@.service, when enabled for an interface, will bind tightly to wg-quick@.service. If you are using wg-quick, this is the recommended method. If you have wg-quick@wg0 enabled, then to activate the wirelink pair, run systemctl enable wl-quick@wg0 && systemctl start wl-quick@wg0. In the future, the wirelink instance will automatically start & stop along with the wg-quick instance.

wirelink@.service is provided for more manual configurations, such as if you configure your wireguard interface in /etc/network/interfaces. Enable and start it with e.g. systemctl enable wirelink@wg0 && systemctl start wirelink@wg0 similar to how wl-quick@ works. If the wireguard interface goes down, the service will fail, but it is configured to auto-restart periodically until the link comes back up.

How It Works

Peers produce a list of local "facts" based on information from the wireguard device and the local network interfaces. Facts have:

  • A subject
    • Who is the fact about
  • An attribute
    • What attribute of the subject does the fact describe
  • A value
    • What is the value of that attribute
  • A TTL
    • For how long should this fact be considered valid

For now subjects are always a peer's public key. Attributes are commonly the peer's allowed ip value(s) and possible endpoints. Peers share endpoints of other peers if they have a live connection to that peer. Peers also share all their local IP addresses and their listening port in case they are on a public IP or other peers are on the same LAN.

Peers periodically send all their locally known facts to all the other peers, along with a generic placeholder "I'm here" fact that is used to detect link health. What facts are sent when is filtered to avoid sending facts they think the other peer already knows and is not going to forget before the next send time comes around.

Peers receive facts from other peers as they arrive, but filter them based on a trust model. For now the default trust configuration is simple:

  • Peers are trusted to provide possible endpoints for themselves
  • Peers are trusted to provide possible endpoints for other peers
  • Peers that have an allowed ip value that implies they route packets for the network are trusted to provide AllowedIP values for other peers
  • Nobody is trusted by default to provide information on new peers, i.e. all peers must have an externally configured list of the other peer public keys with which they are willing to communicate.
  • Peers may have their default trust level overridden in the config file, including marking peers that are trusted to tell us which peers are valid to have in the network (Membership). If no trusted source (including the static config) says a peer should be a member, it gets removed.

Received facts are removed as they expire based on the given TTL value, or renewed as fresh versions come in from trusted sources.

Connecting two peers

To connect two peers that aren't directly connected, each end (independently) configures the remote peer in the local wireguard interface with that peer's automatic link local address. It then cycles through the known endpoints and attempts to contact the peer. This should work with simple NAT configurations, but may fail for more complex ones where a full STUN/ICE system would succeed, esp. since there is no coordination on which endpoints are being tried when.

If contact is successful, then the peer's other allowed IPs are added and traffic can start to flow directly (at least it can once both peers have reciprocated on this).

Once a live connection is established, it is monitored to see if it stays alive. If it goes down, and the local peer is not a router, then the allowed IPs other than the automatic link-local one are removed, so that traffic to that peer will be routed through a central router peer, and attempts to connect to that peer directly will resume. The removal of allowed IPs is not done for router nodes since they are the source of that information, and removing them from the router node would cause the network to forget that, and also obstruct that peer from reconnecting to the network.

Contact Detection

Determining when there is a live connection to a peer is based on two things:

  • Does the wireguard interface report a recent handshake?
    • Recent is defined based on a combination of timeout values from the wireguard go implementation.
  • Have we received an "I'm here" fact packet from the peer recently.

Inspiration

A couple key items from upstream inspired this:

Documentation

Overview

The wirelink command is the main entrypoint.

Directories

Path Synopsis
Package apply contains code for applying changes to network interfaces and wireguard configurations.
Package apply contains code for applying changes to network interfaces and wireguard configurations.
Package autopeer provides code to compute a peer's automatic IPv6-LL address derived from its public key.
Package autopeer provides code to compute a peer's automatic IPv6-LL address derived from its public key.
Package cmd provides the main implementation of the wirelink command line.
Package cmd provides the main implementation of the wirelink command line.
Package config provides code for working with both the wirelink command line arguments and its configuration file.
Package config provides code for working with both the wirelink command line arguments and its configuration file.
Package detect provides utilities to detect if the local system is a router, or if some remote peer is one.
Package detect provides utilities to detect if the local system is a router, or if some remote peer is one.
Package device wraps the wgctrl library with concurrency safety and dirty tracking to simplify interactions from the wirelink server.
Package device wraps the wgctrl library with concurrency safety and dirty tracking to simplify interactions from the wirelink server.
Package fact provides the core code for representing facts, and their serialization and deserialization.
Package fact provides the core code for representing facts, and their serialization and deserialization.
Package internal has bits and bobs for the internal implementation details of wirelink, esp.
Package internal has bits and bobs for the internal implementation details of wirelink, esp.
channels
Package channels contains various generic helpers for working with channels
Package channels contains various generic helpers for working with channels
mocks
Package mocks has just test files for use by other packages' tests
Package mocks has just test files for use by other packages' tests
networking
Package networking provides abstraction layers for accessing networking resources both across platform specific details, and for virtual / mock configurations for testing
Package networking provides abstraction layers for accessing networking resources both across platform specific details, and for virtual / mock configurations for testing
networking/darwin
Package darwin provides an implementation of networking.Environment for the host darwin (macOS) system, leveraging the Go native package, and then filling in the gaps by exececuting command line tools such as ifconfig.
Package darwin provides an implementation of networking.Environment for the host darwin (macOS) system, leveraging the Go native package, and then filling in the gaps by exececuting command line tools such as ifconfig.
networking/host
Package host provides a generic accessor factory to create the appropriate platform-specific interface to the host networking APIs.
Package host provides a generic accessor factory to create the appropriate platform-specific interface to the host networking APIs.
networking/linux
Package linux provides an implementation of networking.Environment for the host Linux system, leveraging the Go native package, and then filling in the gaps using netlink APIs.
Package linux provides an implementation of networking.Environment for the host Linux system, leveraging the Go native package, and then filling in the gaps using netlink APIs.
networking/mocks
Package mocks provides mock implementations of the networking apis, for the testify mock library, generated via go generate and mockery.
Package mocks provides mock implementations of the networking apis, for the testify mock library, generated via go generate and mockery.
networking/native
Package native provdies common base implementations of the networking.Environment and related interfaces, or at least the portions that can be implemented using common native Go APIs.
Package native provdies common base implementations of the networking.Environment and related interfaces, or at least the portions that can be implemented using common native Go APIs.
networking/vnet
Package vnet provides a virtual (as opposed to mocked) implementation of the abstracted UDP networking stack.
Package vnet provides a virtual (as opposed to mocked) implementation of the abstracted UDP networking stack.
testutils
Package testutils provides utility code needed by multiple packages' test suites, but which should not be referenced in any non-test code.
Package testutils provides utility code needed by multiple packages' test suites, but which should not be referenced in any non-test code.
testutils/facts
Package facts provides helper code for generating facts for use in unit tests.
Package facts provides helper code for generating facts for use in unit tests.
Package log is a bit of a ridiculous package to have, but the built in `log` package always writes to stderr, and fancy structured logging isn't what this tool needs
Package log is a bit of a ridiculous package to have, but the built in `log` package always writes to stderr, and fancy structured logging isn't what this tool needs
Package peerfacts provides functions to extract facts from the local network interfaces and the wireguard interface config.
Package peerfacts provides functions to extract facts from the local network interfaces and the wireguard interface config.
Package server provides the core class that implements the wirelink server, exchanging UDP packets with other peers on the same wireguard network.
Package server provides the core class that implements the wirelink server, exchanging UDP packets with other peers on the same wireguard network.
Package signing provides code for signing and verifying signatures using the XChaCha20-Poly1305-Curve25519 construction.
Package signing provides code for signing and verifying signatures using the XChaCha20-Poly1305-Curve25519 construction.
Package trust provides types and code for representing and evaluating trust levels of facts.
Package trust provides types and code for representing and evaluating trust levels of facts.
Package util provides common utility functions used by multiple portions of wirelink, primarily providing wrappers and helpers for core go libraries and constructs.
Package util provides common utility functions used by multiple portions of wirelink, primarily providing wrappers and helpers for core go libraries and constructs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL