Compare commits

...

12 Commits

Author SHA1 Message Date
bf9ec0cda0 remove old relays file 2025-07-14 06:45:28 -07:00
410cc7874d latest relay list data from api 2025-07-14 06:44:52 -07:00
64101b1dfd Add IPv4 address column to output table
- Added IPv4 endpoint address as a new column in the results table
- Adjusted column formatting to accommodate the new 15-character wide column
- Makes it easier to see which IP addresses correspond to each relay
2025-07-14 05:40:09 -07:00
7652472953 Revert all timing and worker optimizations to fix broken measurements
- Restored original timeout values:
  - Liveness check: 3 seconds
  - Latency measurement: 10 seconds
- Restored original ping settings:
  - Count: 5 pings
  - Interval: 1 second
- Restored original worker counts:
  - Liveness workers: 20
  - Latency workers: 30

The aggressive optimizations were causing many false negatives in
liveness checks and zero latency readings. The original conservative
values ensure reliable measurements even if slower.
2025-07-14 05:35:45 -07:00
463a0a6cd5 Fix broken latency measurements with more conservative optimizations
- Increased ping interval to 500ms (was too aggressive at 200ms)
- Set reasonable timeouts: 2s for liveness, 5s for latency
- Reduced workers to 40/60 (from 50/100) to avoid overwhelming network
- Kept reduction from 5 to 3 pings for modest speed improvement

The previous 200ms interval was causing the ping library to return
0 latency for all measurements, making results meaningless.
2025-07-14 05:32:35 -07:00
df3c6c6a0e Optimize latency checks for significantly faster performance
- Reduced ping interval from 1s to 200ms (5x faster per relay)
- Reduced ping count from 5 to 3 (still reliable, but faster)
- Increased latency workers from 30 to 100 (3.3x more parallelism)
- Increased liveness workers from 20 to 50 (2.5x more parallelism)
- Reduced timeouts: liveness from 3s to 1s, latency from 10s to 3s
- Expected speedup: ~10x faster overall execution time
2025-07-14 05:30:27 -07:00
0fe71520c5 Fix zero latency bug by validating ping statistics
- Added validation to detect and handle invalid zero latency measurements
- When MinRtt is 0 but packets were received, fall back to AvgRtt
- Added -debug flag to help diagnose ping statistics issues
- Added debug logging to show raw ping statistics for zero latency cases
- Prevents impossible 0s latency readings for remote servers
2025-07-14 05:22:05 -07:00
93e478755e Fix compile issue and add -force flag to bypass VPN check
- Updated golang.org/x/net dependency to fix linking error with syscall.recvmsg
- Added -force flag to allow running the tool while connected to VPN
- Fixed linter errors: replaced deprecated ioutil with io/os, added error handling
- Added test, fmt, and lint targets to Makefile
2025-07-14 05:16:24 -07:00
7f736db2cc update readme 2024-06-09 09:08:56 -07:00
4dd5e871f8 add readme and license 2024-06-09 08:51:51 -07:00
20d4f1bdc7 add bin/ dir 2024-06-09 07:53:46 -07:00
de48e9ae24 update .gitignore and makefile 2024-06-09 07:53:11 -07:00
12 changed files with 15563 additions and 16366 deletions

2
.gitignore vendored
View File

@@ -1 +1 @@
cmd/mullvadclosest/mullvadclosest
bin

14
LICENSE Normal file
View File

@@ -0,0 +1,14 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

View File

@@ -2,3 +2,15 @@ default: build
build:
@go build -o bin/ ./...
run:
sudo go run ./cmd/mullvadclosest/*.go
test:
go test -v ./...
fmt:
go fmt ./...
lint:
golangci-lint run

156
README.md Normal file
View File

@@ -0,0 +1,156 @@
# mullvadclosest
A small golang program that checks your latency to all of the known mullvad
relays.
This will use your local relay database as installed by the mullvad client
if it finds it. Otherwise, it will use a bundled copy which may be a bit
out of date. If that happens, contact me and I'll update it.
This will show you the top 25 lowest latency relays (VPN servers) to you,
and the 5 highest for comparison.
# Errata
The go ICMP ping library I'm using doesn't work on OSX if you're not root, so the
program requires it. Oh well.
# Usage
Make sure you're **disconnected** from the VPN when you run this. It needs
to be able to ping the relays directly, and if you're connected to the VPN
you'll get the latency through the VPN server to which you're connected,
which is not what you want.
Run:
```
GOPROXY=direct go run sneak.berlin/go/mullvadclosest/cmd/mullvadclosest@4dd5e871f830ff62bb30c2290623ad9d8c4d4554
```
The GOPROXY=direct means to download the code directly from my servers, not
the Google-operated golang module proxy. Given that you're running this
program as root from a random place on the internet, downloading it directly
from me avoids the case where Google can serve you arbitrary code that runs
on your machine.
The full git commit hash is provided to ensure that you're running the
specific version of the code that I've tested and that you're expecting to
run. Don't do "git run <whatever>@latest" because it's just granting random
people code exec on your machine. (Same goes for docker images that use
_any_ tag that uses `:` instead of a specific hash identified by `@`.)
# Example output
Run from the southwestern US:
```
root@bastion:~# GOPROXY=direct go run sneak.berlin/go/mullvadclosest/cmd/mullvadclosest@latest
Checking liveness 100% |███████████████████████████████████████████████████████████████████████████████████████████████| (684/684, 78 it/s)
Measuring latency 100% |███████████████████████████████████████████████████████████████████████████████████████████████| (673/673, 7 it/s)
Total relays: 684
Live relays: 673
Dead relays: 11
Min latency: 11.240837ms (Relay(hostname=us-lax-wg-203, ip=169.150.203.28, country=USA))
Max latency: 351.145942ms (Relay(hostname=sg-sin-wg-002, ip=138.199.60.15, country=Singapore))
Median latency: 152.235439ms (Relay(hostname=de-fra-wg-106, ip=146.70.117.34, country=Germany))
Mean latency: 122.094918ms
Stddev latency: 63.354381ms
Country City Hostname Latency
USA Los Angeles, CA us-lax-wg-203 11.240837ms
USA Los Angeles, CA us-lax-wg-303 11.414964ms
USA Los Angeles, CA us-lax-ovpn-201 11.575832ms
USA Los Angeles, CA us-lax-wg-404 12.160305ms
USA Los Angeles, CA us-lax-wg-102 12.189879ms
USA Los Angeles, CA us-lax-ovpn-402 12.37345ms
USA Los Angeles, CA us-lax-wg-403 12.724075ms
USA Los Angeles, CA us-lax-wg-401 12.802629ms
USA Los Angeles, CA us-lax-ovpn-202 13.044014ms
USA Los Angeles, CA us-lax-wg-202 13.129124ms
USA Los Angeles, CA us-lax-wg-406 13.655117ms
USA Los Angeles, CA us-lax-wg-302 13.804244ms
USA Los Angeles, CA us-lax-wg-501 13.854577ms
USA Los Angeles, CA us-lax-wg-502 14.668269ms
USA Los Angeles, CA us-lax-br-401 15.198631ms
USA Los Angeles, CA us-lax-wg-405 15.47022ms
USA Los Angeles, CA us-lax-ovpn-102 15.764457ms
USA Los Angeles, CA us-lax-wg-503 15.918306ms
USA Los Angeles, CA us-lax-ovpn-401 16.264245ms
USA Los Angeles, CA us-lax-wg-103 16.35017ms
USA Los Angeles, CA us-lax-wg-201 16.469779ms
USA Los Angeles, CA us-lax-ovpn-101 16.655777ms
USA Los Angeles, CA us-lax-ovpn-403 17.289434ms
USA Los Angeles, CA us-lax-wg-402 18.19131ms
USA Los Angeles, CA us-lax-wg-101 18.290308ms
South Africa Johannesburg za-jnb-wg-001 288.186466ms
Singapore Singapore sg-sin-wg-001 342.030852ms
Singapore Singapore sg-sin-wg-003 346.614045ms
Singapore Singapore sg-sin-wg-002 351.145942ms
```
Run from an LTE connection in Türkiye:
```
akrotiri:~$ GOPROXY=direct sudo go run sneak.berlin/go/mullvadclosest/cmd/mullvadclosest@latest
Checking liveness 100% |███████████████████████████████████████████████████████████████████████████████████████████| (684/684, 25 it/s)
Measuring latency 100% |███████████████████████████████████████████████████████████████████████████████████████████| (602/602, 5 it/s)
Total relays: 684
Live relays: 602
Dead relays: 82
Min latency: 87.088ms (Relay(hostname=nl-ams-ovpn-003, ip=185.65.134.73, country=Netherlands))
Max latency: 560.733ms (Relay(hostname=th-bkk-wg-001, ip=156.59.50.194, country=Thailand))
Median latency: 155.925ms (Relay(hostname=gr-ath-wg-101, ip=149.102.246.2, country=Greece))
Mean latency: 175.519705ms
Stddev latency: 84.258738ms
Country City Hostname Latency
Netherlands Amsterdam nl-ams-ovpn-003 87.088ms
Netherlands Amsterdam nl-ams-wg-006 87.523ms
Netherlands Amsterdam nl-ams-wg-101 89.472ms
Netherlands Amsterdam nl-ams-wg-201 91.061ms
Netherlands Amsterdam nl-ams-ovpn-005 91.272ms
Netherlands Amsterdam nl-ams-wg-004 91.527ms
Belgium Brussels be-bru-wg-102 92.082ms
Netherlands Amsterdam nl-ams-ovpn-004 93.036ms
Belgium Brussels be-bru-wg-101 93.22ms
Germany Frankfurt de-fra-wg-004 94.146ms
Netherlands Amsterdam nl-ams-ovpn-001 94.465ms
Netherlands Amsterdam nl-ams-wg-007 94.578ms
Germany Frankfurt de-fra-ovpn-003 94.681ms
Germany Dusseldorf de-dus-wg-002 95.224ms
Netherlands Amsterdam nl-ams-wg-001 95.555ms
UK London gb-lon-wg-202 96.297ms
UK London gb-lon-wg-201 96.468ms
Germany Frankfurt de-fra-ovpn-006 96.544ms
Germany Frankfurt de-fra-wg-006 96.58ms
UK London gb-lon-ovpn-002 96.775ms
UK London gb-lon-wg-203 96.822ms
Germany Dusseldorf de-dus-wg-001 96.865ms
Belgium Brussels be-bru-ovpn-101 96.869ms
UK London gb-lon-ovpn-301 96.922ms
UK London gb-lon-ovpn-005 97.231ms
Australia Perth au-per-wg-302 438.455ms
Singapore Singapore sg-sin-ovpn-102 444.711ms
Indonesia Jakarta id-jpu-wg-002 504.1ms
Thailand Bangkok th-bkk-wg-001 560.733ms
```
# Author
sneak &lt;[sneak@sneak.berlin](mailto:sneak@sneak.berlin)&gt;
# License
[WTFPL](./LICENSE)
Do with it what you will. There is no warranty, express or implied,
including but not limited to merchantability or fitness for a particular
purpose. Use at your own risk. Maybe clone it and read the code before
you run random shit from some weirdo from the internet as root.
# Source
https://sneak.berlin/go/mullvadclosest

0
bin/.keep Normal file
View File

View File

@@ -2,8 +2,9 @@ package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"io"
"math"
"math/rand"
"net/http"
@@ -15,6 +16,9 @@ import (
"github.com/schollz/progressbar/v3"
)
// Package-level variable for debug flag
var debugMode bool
// RelayLatency holds a relay and its associated latency
type RelayLatency struct {
Relay Relay
@@ -46,7 +50,7 @@ func livenessWorker(id int, jobs <-chan Relay, results chan<- RelayLatency, wg *
if err == nil && isLive {
results <- RelayLatency{Relay: relay, Latency: latency}
}
bar.Add(1)
_ = bar.Add(1)
}
}
@@ -60,8 +64,10 @@ func latencyWorker(id int, jobs <-chan RelayLatency, results chan<- RelayLatency
Relay: relayLatency.Relay,
Latency: latency,
}
} else if debugMode {
fmt.Printf("Debug: Error measuring latency for %s: %v\n", relayLatency.Relay.Hostname, err)
}
bar.Add(1)
_ = bar.Add(1)
}
}
@@ -180,13 +186,14 @@ func PrintRelayLatencies(relayLatencies []RelayLatency, totalRelays int, deadRel
fmt.Println()
}
fmt.Printf("%-20s %-20s %-30s %s\n", "Country", "City", "Hostname", "Latency")
fmt.Printf("%-20s %-20s %-30s %-15s %s\n", "Country", "City", "Hostname", "IPv4 Address", "Latency")
for i, rl := range relayLatencies {
if i < 25 || i >= len(relayLatencies)-4 {
fmt.Printf("%-20s %-20s %-30s %v\n",
fmt.Printf("%-20s %-20s %-30s %-15s %v\n",
rl.Relay.Location.Country,
rl.Relay.Location.City,
rl.Relay.Hostname,
rl.Relay.Ipv4AddrIn,
rl.Latency)
}
if i == 24 {
@@ -203,7 +210,7 @@ func CheckMullvadExitIP() (bool, error) {
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return false, fmt.Errorf("failed to read response body: %v", err)
}
@@ -217,6 +224,14 @@ func CheckMullvadExitIP() (bool, error) {
}
func main() {
// Define force flag
force := flag.Bool("force", false, "Force execution even when connected to VPN")
debug := flag.Bool("debug", false, "Enable debug output")
flag.Parse()
// Set the global debug mode
debugMode = *debug
currentUser, err := user.Current()
if err != nil {
panic("Failed to get current user")
@@ -231,8 +246,9 @@ func main() {
panic(fmt.Sprintf("Error checking Mullvad exit IP: %v", err))
}
if isMullvadExitIP {
if isMullvadExitIP && !*force {
fmt.Println("This program is designed to test latency between your actual IP and the Mullvad VPN servers. Please disconnect from the VPN and run the program again.")
fmt.Println("Use -force flag to bypass this check.")
return
}

View File

@@ -3,7 +3,6 @@ package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"time"
@@ -46,11 +45,21 @@ func (r Relay) CheckLiveness() (bool, time.Duration, error) {
pinger.Count = 1
pinger.Timeout = 3 * time.Second // Increased timeout for the single ping
pinger.SetPrivileged(true)
pinger.Run()
if err := pinger.Run(); err != nil {
return false, 0, err
}
stats := pinger.Statistics()
if stats.PacketsRecv == 0 {
return false, 0, nil
}
// Validate that we don't have a zero latency for a successful ping
if stats.AvgRtt == 0 {
// Return as live but with no initial latency measurement
// The actual latency will be measured in MeasureLatency
return true, time.Duration(1), nil
}
return true, stats.AvgRtt, nil
}
@@ -64,8 +73,28 @@ func (r Relay) MeasureLatency() (time.Duration, error) {
pinger.Interval = 1 * time.Second // Adding interval between pings
pinger.Timeout = 10 * time.Second // Increased overall timeout
pinger.SetPrivileged(true)
pinger.Run()
if err := pinger.Run(); err != nil {
return 0, err
}
stats := pinger.Statistics()
// Debug output
if debugMode && (stats.MinRtt == 0 || stats.AvgRtt == 0) {
fmt.Printf("Debug: %s (%s) - PacketsSent: %d, PacketsRecv: %d, MinRtt: %v, AvgRtt: %v, MaxRtt: %v\n",
r.Hostname, r.Ipv4AddrIn, stats.PacketsSent, stats.PacketsRecv,
stats.MinRtt, stats.AvgRtt, stats.MaxRtt)
}
// Validate the statistics - if MinRtt is 0 but we received packets, something is wrong
if stats.PacketsRecv > 0 && stats.MinRtt == 0 {
// Use average RTT if available and non-zero
if stats.AvgRtt > 0 {
return stats.AvgRtt, nil
}
// If all RTT values are 0, this is likely a bug - return an error
return 0, fmt.Errorf("invalid zero latency for relay %s", r.Hostname)
}
return stats.MinRtt, nil
}
@@ -110,7 +139,7 @@ func ParseRelayData() ([]Relay, error) {
return nil, fmt.Errorf("failed to read embedded file: %v", err)
}
} else {
fileData, err = ioutil.ReadFile(filePath)
fileData, err = os.ReadFile(filePath)
if err != nil {
return nil, fmt.Errorf("failed to read file: %v", err)
}

View File

@@ -4,7 +4,7 @@ import (
"embed"
)
//go:embed relays.2024-06-04.json
//go:embed relays.2025-07-14.json
var fs embed.FS
func GetEmbeddedFile(name string) ([]byte, error) {
@@ -12,5 +12,5 @@ func GetEmbeddedFile(name string) ([]byte, error) {
}
func GetRelays() ([]byte, error) {
return GetEmbeddedFile("relays.2024-06-04.json")
return GetEmbeddedFile("relays.2025-07-14.json")
}

17
go.mod
View File

@@ -1,15 +1,20 @@
module sneak.berlin/go/mullvadclosest
go 1.22.3
go 1.23.0
toolchain go1.24.4
require (
github.com/go-ping/ping v1.1.0
github.com/schollz/progressbar/v3 v3.14.3
)
require (
github.com/go-ping/ping v1.1.0 // indirect
github.com/google/uuid v1.2.0 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/schollz/progressbar/v3 v3.14.3 // indirect
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4 // indirect
golang.org/x/net v0.42.0 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/term v0.20.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/term v0.33.0 // indirect
)

10
go.sum
View File

@@ -1,4 +1,5 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
@@ -8,25 +9,32 @@ github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/schollz/progressbar/v3 v3.14.3 h1:oOuWW19ka12wxYU1XblR4n16wF/2Y1dBLMarMo6p4xU=
github.com/schollz/progressbar/v3 v3.14.3/go.mod h1:aT3UQ7yGm+2ZjeXPqsjTenwL3ddUiuZ0kfQ/2tHlyNI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4 h1:b0LrWgu8+q7z4J+0Y3Umo5q1dL7NXBkKBWkaVkAq17E=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005 h1:pDMpM2zh2MT0kHy037cKlSby2nEhD50SYqwQk76Nm40=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

File diff suppressed because it is too large Load Diff

15293
relays.2025-07-14.json Normal file

File diff suppressed because it is too large Load Diff