{"id":30938207,"url":"https://github.com/fastcat/wirelink","last_synced_at":"2025-09-10T19:02:59.513Z","repository":{"id":36995063,"uuid":"211362152","full_name":"fastcat/wirelink","owner":"fastcat","description":"Experimental P2P configuration plane for Wireguard","archived":false,"fork":false,"pushed_at":"2025-09-08T13:23:47.000Z","size":1224,"stargazers_count":22,"open_issues_count":0,"forks_count":6,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-09-08T15:21:50.302Z","etag":null,"topics":["linux","networking","peer-to-peer","vpn","wireguard"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fastcat.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-09-27T16:40:24.000Z","updated_at":"2025-09-08T13:23:50.000Z","dependencies_parsed_at":"2023-02-12T18:15:55.032Z","dependency_job_id":"5a22a61c-99f8-43e6-a337-b1859571afc4","html_url":"https://github.com/fastcat/wirelink","commit_stats":null,"previous_names":[],"tags_count":46,"template":false,"template_full_name":null,"purl":"pkg:github/fastcat/wirelink","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastcat%2Fwirelink","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastcat%2Fwirelink/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastcat%2Fwirelink/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastcat%2Fwirelink/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fastcat","download_url":"https://codeload.github.com/fastcat/wirelink/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastcat%2Fwirelink/sbom","scorecard":{"id":393280,"data":{"date":"2025-08-11","repo":{"name":"github.com/fastcat/wirelink","commit":"e4804c1eaef17d4b5490ed1fb4f2dff6897d6931"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":5.9,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/22 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":10,"reason":"22 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/codeql-analysis.yml:1","Warn: no topLevel permission defined: .github/workflows/go-fuzz.yml:1","Warn: no topLevel permission defined: .github/workflows/go.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/fastcat/wirelink/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:37: update your workflow using https://app.stepsecurity.io/secureworkflow/fastcat/wirelink/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:48: update your workflow using https://app.stepsecurity.io/secureworkflow/fastcat/wirelink/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:72: update your workflow using https://app.stepsecurity.io/secureworkflow/fastcat/wirelink/codeql-analysis.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go-fuzz.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/fastcat/wirelink/go-fuzz.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go-fuzz.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/fastcat/wirelink/go-fuzz.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/fastcat/wirelink/go.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/fastcat/wirelink/go.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/go.yml:56: update your workflow using https://app.stepsecurity.io/secureworkflow/fastcat/wirelink/go.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/go.yml:72: update your workflow using https://app.stepsecurity.io/secureworkflow/fastcat/wirelink/go.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/go.yml:77: update your workflow using https://app.stepsecurity.io/secureworkflow/fastcat/wirelink/go.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:85: update your workflow using https://app.stepsecurity.io/secureworkflow/fastcat/wirelink/go.yml/main?enable=pin","Info:   0 out of   9 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU Affero General Public License v3.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":10,"reason":"project is fuzzed","details":["Info: GoBuiltInFuzzer integration found: fact/parse_test.go:316"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":-1,"reason":"internal error: internal error: Client.Checks.ListCheckRunsForRef: error during graphqlHandler.setupCheckRuns: non-200 OK status code: 502 Bad Gateway body: \"\u003chtml\u003e\\r\\n\u003chead\u003e\u003ctitle\u003e502 Bad Gateway\u003c/title\u003e\u003c/head\u003e\\r\\n\u003cbody\u003e\\r\\n\u003ccenter\u003e\u003ch1\u003e502 Bad Gateway\u003c/h1\u003e\u003c/center\u003e\\r\\n\u003chr\u003e\u003ccenter\u003enginx\u003c/center\u003e\\r\\n\u003c/body\u003e\\r\\n\u003c/html\u003e\\r\\n\"","details":null,"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T18:21:33.877Z","repository_id":36995063,"created_at":"2025-08-18T18:21:33.877Z","updated_at":"2025-08-18T18:21:33.877Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274407330,"owners_count":25279267,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-10T02:00:12.551Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["linux","networking","peer-to-peer","vpn","wireguard"],"created_at":"2025-09-10T19:00:58.352Z","updated_at":"2025-09-10T19:02:59.493Z","avatar_url":"https://github.com/fastcat.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# wirelink\n\n[![Actions Status](https://github.com/fastcat/wirelink/workflows/Go/badge.svg)](https://github.com/fastcat/wirelink/actions)\n[![codecov](https://codecov.io/gh/fastcat/wirelink/graph/badge.svg?token=RdvrbmY3R3)](https://codecov.io/gh/fastcat/wirelink)\n[![Go Report Card](https://goreportcard.com/badge/github.com/fastcat/wirelink)](https://goreportcard.com/report/github.com/fastcat/wirelink)\n\n## Concept\n\nThis is an experiment in implementing automatic peer-to-peer link setup in\nwireguard by:\n\n* Automatically configuring IPv6 link-local ips for each peer, derived by\n  hashing the peer's public key\n* Using that to automatically share information about available peers and their\n  endpoints\n* Using that to try to automatically setup direct connections between peers\n  (when possible) instead of routing through a central \"server\".\n\n## Configuration\n\n`wirelink` will read basic configuration from:\n\n* A config file `/etc/wireguard/wirelink.\u003cinterface\u003e.json`\n  * Some other extensions such as `.yaml` will be accepted too\n  * Some settings can _only_ be set in the config file for now\n* Environment variables of the form `WIRELINK_\u003csetting\u003e`\n* Command line args (see `--help`)\n\n### Systemd\n\nTwo systemd template units are provided:\n\n`wl-quick@.service`, when enabled for an interface, will bind tightly to\n`wg-quick@.service`. If you are using `wg-quick`, this is the recommended\nmethod. If you have `wg-quick@wg0` enabled, then to activate the wirelink pair,\nrun `systemctl enable wl-quick@wg0 \u0026\u0026 systemctl start wl-quick@wg0`. In the\nfuture, the `wirelink` instance will automatically start \u0026 stop along with the\n`wg-quick` instance.\n\n`wirelink@.service` is provided for more manual configurations, such as if you\nconfigure your wireguard interface in `/etc/network/interfaces`. Enable and\nstart it with e.g. `systemctl enable wirelink@wg0 \u0026\u0026 systemctl start\nwirelink@wg0` similar to how `wl-quick@` works. If the wireguard interface goes\ndown, the service will fail, but it is configured to auto-restart periodically\nuntil the link comes back up.\n\n## How It Works\n\nPeers produce a list of local \"facts\" based on information from the wireguard\ndevice and the local network interfaces. Facts have:\n\n* A subject\n  * Who is the fact about\n* An attribute\n  * What attribute of the subject does the fact describe\n* A value\n  * What is the value of that attribute\n* A TTL\n  * For how long should this fact be considered valid\n\nFor now subjects are always a peer's public key. Attributes are commonly the\npeer's allowed ip value(s) and possible endpoints. Peers share endpoints of\nother peers if they have a live connection to that peer. Peers also share all\ntheir local IP addresses and their listening port in case they are on a public\nIP or other peers are on the same LAN.\n\nPeers periodically send all their locally known facts to all the other peers,\nalong with a generic placeholder \"I'm here\" fact that is used to detect link\nhealth. What facts are sent when is filtered to avoid sending facts they think\nthe other peer already knows and is not going to forget before the next send\ntime comes around.\n\nPeers receive facts from other peers as they arrive, but filter them based on a\ntrust model. For now the default trust configuration is simple:\n\n* Peers are trusted to provide possible endpoints for themselves\n* Peers are trusted to provide possible endpoints for other peers\n* Peers that have an allowed ip value that implies they route packets for the\n  network are trusted to provide AllowedIP values for other peers\n* Nobody is trusted by default to provide information on new peers, i.e. all\n  peers must have an externally configured list of the other peer public keys\n  with which they are willing to communicate.\n* Peers may have their default trust level overridden in the config file,\n  including marking peers that are trusted to tell us which peers are valid to\n  have in the network (`Membership`). If no trusted source (including the\n  static config) says a peer should be a member, it gets removed.\n\nReceived facts are removed as they expire based on the given TTL value, or\nrenewed as fresh versions come in from trusted sources.\n\n## Connecting two peers\n\nTo connect two peers that aren't directly connected, each end (independently)\nconfigures the remote peer in the local wireguard interface with that peer's\nautomatic link local address. It then cycles through the known endpoints and\nattempts to contact the peer. This should work with simple NAT configurations,\nbut may fail for more complex ones where a full STUN/ICE system would succeed,\nesp. since there is no coordination on which endpoints are being tried when.\n\nIf contact is successful, then the peer's other allowed IPs are added and\ntraffic can start to flow directly (at least it can once both peers have\nreciprocated on this).\n\nOnce a live connection is established, it is monitored to see if it stays\nalive. If it goes down, and the local peer is not a router, then the allowed\nIPs other than the automatic link-local one are removed, so that traffic to\nthat peer will be routed through a central router peer, and attempts to connect\nto that peer directly will resume. The removal of allowed IPs is not done for\nrouter nodes since they are the source of that information, and removing them\nfrom the router node would cause the network to forget that, and also obstruct\nthat peer from reconnecting to the network.\n\n### Contact Detection\n\nDetermining when there is a live connection to a peer is based on two things:\n\n* Does the wireguard interface report a recent handshake?\n  * Recent is defined based on a combination of timeout values from the\n    wireguard go implementation.\n* Have we received an \"I'm here\" fact packet from the peer recently.\n\n## Inspiration\n\nA couple key items from upstream inspired this:\n\n* Automatic assigning of link-local IPv6 addresses:\n  \u003chttps://lists.zx2c4.com/pipermail/wireguard/2017-April/001177.html\u003e\n  (and following messages, about the `wg set wg0 llv6 on` proposal)\n* The NAT hole-punching example that ships with the wireguard source:\n  \u003chttps://git.zx2c4.com/WireGuard/tree/contrib/examples/nat-hole-punching\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastcat%2Fwirelink","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffastcat%2Fwirelink","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastcat%2Fwirelink/lists"}