Scope is an easy-to-setup WireGuard meshing utility that serves WireGuard peer information via WebSockets (for connectivity checking) and web APIs, inspired by the now poorly-maintained wgsd
. This allows use cases like:
- Building a mesh of WireGuard peers from a central registry
- Dynamic discovery of WireGuard endpoints
- Announce IP changes whenever possible
- UDP hole punching if under full cone NAT
The name "Scope" is a reference to Scope Lens in Shifting Melodies, a changeling with impressive hivemind abilities.
- A registry server is set up on the root WireGuard server.
- An edge client connects to the registry server, then requests peer information.
- Upon receiving peer information, the edge client tries to connect to the root WireGuard server, and adds all peers as available for connection.
- After 10 seconds, the edge client then broadcasts a peer update towards all peers, and waits all other peers to connect.
- When the edge receives a peer update, it'll try to connect to said peer.
- Install Deno.
- Download the respective script from either
/dist
or releases.
registry.js
- Scope server for serving peer information.edge.js
- Scope client for automatically managing edge configurations.browser.js
- Allows debugging directly from the browser.
- Configure the root server and the edge clients respectively. See
/examples
for examples. - If the current user can modify WireGuard settings, execute the scripts via
deno run --allow-read --allow-net --allow-run
.
browser.js
doesn't require any configuration file.
{
"listen": "127.0.0.1",
"listenPort": 8080,
"networks": [
"interface-1"
],
"self": {
"interface-1": {
"heartbeat": 20,
"end": "192.0.2.1:51820",
"range": "10.0.0.254/32"
}
}
}
[{
"registry": "https://example.com/pathPrefix",
"network": "local-interface-1",
"netreg": "interface-1",
"pubKey": "ThisIsAVeryAwesomeWireGuardPublicKey"
}]
Sends and receives WebSocket messages.
{
"t": "<type>",
"d": "<data>"
}
Used to initiate observable pings. Data can either be "SYN" for outgoing messages, or "ACK" for incoming messages.
Used to notify the edges about peer updates.
Gets all of the available interfaces.
["interface-1", "interface-2", ...]
Gets the registry. Will only reply config data if the provided pubKey
is listed in the registry. Registry only.
{
"ifname": "<network>",
"heartbeat": 20, // Global PersistentKeepalive
"self": {
"type": "self",
"pub": "JeZl...",
"end": "192.0.2.1:51820",
"range": "10.0.0.254/32"
},
"peer": [{
"type": "edge",
"pub": "xScV...",
"end": "192.0.2.2:10362",
"range": "10.0.0.1/32"
}, {
"type": "edge",
"pub": "syKB...",
"end": "192.0.2.3:51496",
"range": "10.0.0.2/32"
}, ...]
}
Send a peer update message to the rest of the network.
Fetches peer network information to the server. Not implemented.
Uploads peer network information to the server. Not implemented.
{
"ifname": "<network>",
"heartbeat": 20, // Global PersistentKeepalive
"self": {
"pub": "JeZl...",
"end": "192.0.2.1:51820",
"range": "10.0.0.254/32"
},
"peer": [{
"type": "edge",
"pub": "xScV...",
"end": "192.0.2.2:10362",
"range": "10.0.0.1/32",
"sum": 200, // observable average latency
"mode": "direct", // or leastSum
"leastSource": "" // public key of the upstream
}, {
"type": "edge",
"pub": "syKB...",
"end": "192.0.2.3:51496",
"range": "10.0.0.2/32",
"sum": 200,
"mode": "leastSum",
"leastSource": "xScV..."
}, ...]
}