init
This commit is contained in:
		
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					dist/
 | 
				
			||||||
 | 
					.idea
 | 
				
			||||||
 | 
					*.iml
 | 
				
			||||||
 | 
					*.eml
 | 
				
			||||||
							
								
								
									
										33
									
								
								.goreleaser.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								.goreleaser.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					project_name: mullvad-best-server
 | 
				
			||||||
 | 
					# This is an example .goreleaser.yml file with some sensible defaults.
 | 
				
			||||||
 | 
					# Make sure to check the documentation at https://goreleaser.com
 | 
				
			||||||
 | 
					before:
 | 
				
			||||||
 | 
					  hooks:
 | 
				
			||||||
 | 
					    # You may remove this if you don't use go modules.
 | 
				
			||||||
 | 
					    - go mod tidy
 | 
				
			||||||
 | 
					    # you may remove this if you don't need go generate
 | 
				
			||||||
 | 
					    - go generate ./...
 | 
				
			||||||
 | 
					builds:
 | 
				
			||||||
 | 
					  - env:
 | 
				
			||||||
 | 
					      - CGO_ENABLED=0
 | 
				
			||||||
 | 
					    goos:
 | 
				
			||||||
 | 
					      - linux
 | 
				
			||||||
 | 
					      - windows
 | 
				
			||||||
 | 
					      - darwin
 | 
				
			||||||
 | 
					archives:
 | 
				
			||||||
 | 
					  - replacements:
 | 
				
			||||||
 | 
					      darwin: Darwin
 | 
				
			||||||
 | 
					      linux: Linux
 | 
				
			||||||
 | 
					      windows: Windows
 | 
				
			||||||
 | 
					      386: i386
 | 
				
			||||||
 | 
					      amd64: x86_64
 | 
				
			||||||
 | 
					checksum:
 | 
				
			||||||
 | 
					  name_template: 'checksums.txt'
 | 
				
			||||||
 | 
					snapshot:
 | 
				
			||||||
 | 
					  name_template: "{{ incpatch .Version }}-next"
 | 
				
			||||||
 | 
					changelog:
 | 
				
			||||||
 | 
					  sort: asc
 | 
				
			||||||
 | 
					  filters:
 | 
				
			||||||
 | 
					    exclude:
 | 
				
			||||||
 | 
					      - '^docs:'
 | 
				
			||||||
 | 
					      - '^test:'
 | 
				
			||||||
							
								
								
									
										15
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					module github.com/bastiandoetsch/mullvad-best-server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					go 1.17
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require (
 | 
				
			||||||
 | 
						github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534
 | 
				
			||||||
 | 
						github.com/rs/zerolog v1.26.1
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require (
 | 
				
			||||||
 | 
						github.com/google/uuid v1.2.0 // indirect
 | 
				
			||||||
 | 
						golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect
 | 
				
			||||||
 | 
						golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
 | 
				
			||||||
 | 
						golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										41
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 | 
				
			||||||
 | 
					github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 h1:dhy9OQKGBh4zVXbjwbxxHjRxMJtLXj3zfgpBYQaR4Q4=
 | 
				
			||||||
 | 
					github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
 | 
				
			||||||
 | 
					github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 | 
				
			||||||
 | 
					github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
 | 
				
			||||||
 | 
					github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
				
			||||||
 | 
					github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
				
			||||||
 | 
					github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
 | 
				
			||||||
 | 
					github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc=
 | 
				
			||||||
 | 
					github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc=
 | 
				
			||||||
 | 
					github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 | 
				
			||||||
 | 
					golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
				
			||||||
 | 
					golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
				
			||||||
 | 
					golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
 | 
				
			||||||
 | 
					golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI=
 | 
				
			||||||
 | 
					golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 | 
				
			||||||
 | 
					golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
				
			||||||
 | 
					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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
 | 
					golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
				
			||||||
 | 
					golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
				
			||||||
 | 
					golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
				
			||||||
 | 
					golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
				
			||||||
 | 
					golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
				
			||||||
 | 
					golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 | 
				
			||||||
 | 
					golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
 | 
				
			||||||
 | 
					golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
				
			||||||
 | 
					golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
				
			||||||
 | 
					golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 | 
				
			||||||
							
								
								
									
										94
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"github.com/go-ping/ping"
 | 
				
			||||||
 | 
						"github.com/rs/zerolog/log"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var pings = make(map[string]time.Duration)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						servers := getServers()
 | 
				
			||||||
 | 
						bestIndex := selectBestServerIndex(servers)
 | 
				
			||||||
 | 
						log.Info().Interface("best", servers[bestIndex]).Msg("Best Latency Server found.")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func selectBestServerIndex(servers []server) int {
 | 
				
			||||||
 | 
						best := servers[0].Hostname
 | 
				
			||||||
 | 
						bestIndex := 0
 | 
				
			||||||
 | 
						allowedCountries := map[string]string{}
 | 
				
			||||||
 | 
						allowedCountries["de"] = "1"
 | 
				
			||||||
 | 
						allowedCountries["ch"] = "1"
 | 
				
			||||||
 | 
						allowedCountries["at"] = "1"
 | 
				
			||||||
 | 
						for i, server := range servers {
 | 
				
			||||||
 | 
							if server.Active && allowedCountries[server.CountryCode] != "" {
 | 
				
			||||||
 | 
								duration, err := serverLatency(server)
 | 
				
			||||||
 | 
								if err == nil {
 | 
				
			||||||
 | 
									pings[server.Hostname] = duration
 | 
				
			||||||
 | 
									if best == "" || pings[best] > pings[server.Hostname] {
 | 
				
			||||||
 | 
										best = server.Hostname
 | 
				
			||||||
 | 
										bestIndex = i
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return bestIndex
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getServers() []server {
 | 
				
			||||||
 | 
						resp, err := http.Get("https://api.mullvad.net/www/relays/wireguard/")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal().Err(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						responseBody, err := ioutil.ReadAll(resp.Body)
 | 
				
			||||||
 | 
						defer func(Body io.ReadCloser) {
 | 
				
			||||||
 | 
							err := Body.Close()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Err(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}(resp.Body)
 | 
				
			||||||
 | 
						var servers []server
 | 
				
			||||||
 | 
						err = json.Unmarshal(responseBody, &servers)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal().Err(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return servers
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func serverLatency(s server) (time.Duration, error) {
 | 
				
			||||||
 | 
						pinger, err := ping.NewPinger(s.Ipv4AddrIn)
 | 
				
			||||||
 | 
						pinger.Count = 1
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return 0, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var duration time.Duration
 | 
				
			||||||
 | 
						pinger.OnRecv = func(pkt *ping.Packet) {
 | 
				
			||||||
 | 
							log.Info().Str("Server", s.Hostname).IPAddr("IP", pkt.IPAddr.IP).Dur("RTT", pkt.Rtt).Msg("Added server latency.")
 | 
				
			||||||
 | 
							duration = pkt.Rtt
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = pinger.Run()
 | 
				
			||||||
 | 
						return duration, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type server struct {
 | 
				
			||||||
 | 
						Hostname         string `json:"hostname"`
 | 
				
			||||||
 | 
						CountryCode      string `json:"country_code"`
 | 
				
			||||||
 | 
						CountryName      string `json:"country_name"`
 | 
				
			||||||
 | 
						CityCode         string `json:"city_code"`
 | 
				
			||||||
 | 
						CityName         string `json:"city_name"`
 | 
				
			||||||
 | 
						Active           bool   `json:"active"`
 | 
				
			||||||
 | 
						Owned            bool   `json:"owned"`
 | 
				
			||||||
 | 
						Provider         string `json:"provider"`
 | 
				
			||||||
 | 
						Ipv4AddrIn       string `json:"ipv4_addr_in"`
 | 
				
			||||||
 | 
						Ipv6AddrIn       string `json:"ipv6_addr_in"`
 | 
				
			||||||
 | 
						NetworkPortSpeed int    `json:"network_port_speed"`
 | 
				
			||||||
 | 
						Pubkey           string `json:"pubkey"`
 | 
				
			||||||
 | 
						MultihopPort     int    `json:"multihop_port"`
 | 
				
			||||||
 | 
						SocksName        string `json:"socks_name"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user