From be72f4a04653e2618b2404af535d59a400f81b3c Mon Sep 17 00:00:00 2001 From: Quentin McGaw Date: Fri, 5 Mar 2021 22:45:54 -0500 Subject: [PATCH] Feature: Hide My Ass VPN provider support (#401) --- .github/labels.yml | 3 + README.md | 4 +- internal/cli/update.go | 1 + internal/configuration/hidemyass.go | 61 +++++ internal/configuration/openvpn.go | 4 +- internal/configuration/provider.go | 2 + internal/configuration/provider_test.go | 18 ++ internal/configuration/selection.go | 6 +- internal/configuration/updater.go | 2 + internal/constants/hidemyass.go | 313 ++++++++++++++++++++++++ internal/constants/servers.go | 5 + internal/constants/servers_test.go | 10 + internal/constants/vpn.go | 2 + internal/models/server.go | 15 ++ internal/models/servers.go | 7 + internal/provider/errors.go | 5 + internal/provider/hidemyass.go | 169 +++++++++++++ internal/provider/provider.go | 2 + internal/storage/merge.go | 17 ++ internal/storage/sync.go | 1 + internal/updater/errors.go | 5 +- internal/updater/hma.go | 270 ++++++++++++++++++++ internal/updater/updater.go | 10 + 23 files changed, 924 insertions(+), 8 deletions(-) create mode 100644 internal/configuration/hidemyass.go create mode 100644 internal/constants/hidemyass.go create mode 100644 internal/provider/errors.go create mode 100644 internal/provider/hidemyass.go create mode 100644 internal/updater/hma.go diff --git a/.github/labels.yml b/.github/labels.yml index 7f677f70..5b2c3782 100644 --- a/.github/labels.yml +++ b/.github/labels.yml @@ -18,6 +18,9 @@ - name: ":cloud: Cyberghost" color: "cfe8d4" description: "" +- name: ":cloud: HideMyAss" + color: "cfe8d4" + description: "" - name: ":cloud: Mullvad" color: "cfe8d4" description: "" diff --git a/README.md b/README.md index b6ae854d..0ed14fee 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Gluetun VPN client *Lightweight swiss-knife-like VPN client to tunnel to Cyberghost, -Mullvad, NordVPN, Privado, Private Internet Access, PureVPN, +HideMyAss, Mullvad, NordVPN, Privado, Private Internet Access, PureVPN, Surfshark, TorGuard, VyprVPN and Windscribe VPN servers using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy* @@ -39,7 +39,7 @@ using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy* ## Features - Based on Alpine 3.12 for a small Docker image of 52MB -- Supports: **Cyberghost**, **Mullvad**, **NordVPN**, **Privado**, **Private Internet Access**, **PureVPN**, **Surfshark**, **TorGuard**, **Vyprvpn**, **Windscribe**, servers +- Supports: **Cyberghost**, **HideMyAss**, **Mullvad**, **NordVPN**, **Privado**, **Private Internet Access**, **PureVPN**, **Surfshark**, **TorGuard**, **Vyprvpn**, **Windscribe**, servers - Supports Openvpn only for now - DNS over TLS baked in with service provider(s) of your choice - DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours diff --git a/internal/cli/update.go b/internal/cli/update.go index 6496650e..4c01448b 100644 --- a/internal/cli/update.go +++ b/internal/cli/update.go @@ -23,6 +23,7 @@ func (c *cli) Update(ctx context.Context, args []string, os os.OS) error { flagSet.BoolVar(&options.Stdout, "stdout", false, "Write results to console to modify the program (for maintainers)") flagSet.StringVar(&options.DNSAddress, "dns", "8.8.8.8", "DNS resolver address to use") flagSet.BoolVar(&options.Cyberghost, "cyberghost", false, "Update Cyberghost servers") + flagSet.BoolVar(&options.HideMyAss, "hidemyass", false, "Update HideMyAss servers") flagSet.BoolVar(&options.Mullvad, "mullvad", false, "Update Mullvad servers") flagSet.BoolVar(&options.Nordvpn, "nordvpn", false, "Update Nordvpn servers") flagSet.BoolVar(&options.PIA, "pia", false, "Update Private Internet Access post-summer 2020 servers") diff --git a/internal/configuration/hidemyass.go b/internal/configuration/hidemyass.go new file mode 100644 index 00000000..f82b2504 --- /dev/null +++ b/internal/configuration/hidemyass.go @@ -0,0 +1,61 @@ +package configuration + +import ( + "github.com/qdm12/gluetun/internal/constants" +) + +func (settings *Provider) hideMyAssLines() (lines []string) { + if len(settings.ServerSelection.Countries) > 0 { + lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries)) + } + + if len(settings.ServerSelection.Regions) > 0 { + lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions)) + } + + if len(settings.ServerSelection.Cities) > 0 { + lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities)) + } + + if len(settings.ServerSelection.Hostnames) > 0 { + lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames)) + } + + return lines +} + +func (settings *Provider) readHideMyAss(r reader) (err error) { + settings.Name = constants.HideMyAss + + settings.ServerSelection.Protocol, err = readProtocol(r.env) + if err != nil { + return err + } + + settings.ServerSelection.TargetIP, err = readTargetIP(r.env) + if err != nil { + return err + } + + settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.HideMyAssCountryChoices()) + if err != nil { + return err + } + + settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.HideMyAssCountryChoices()) + if err != nil { + return err + } + + settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.HideMyAssCityChoices()) + if err != nil { + return err + } + + settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.TorguardHostnamesChoices()) + if err != nil { + return err + } + + return nil +} diff --git a/internal/configuration/openvpn.go b/internal/configuration/openvpn.go index dde8ac26..8c131368 100644 --- a/internal/configuration/openvpn.go +++ b/internal/configuration/openvpn.go @@ -56,7 +56,7 @@ var ( func (settings *OpenVPN) read(r reader) (err error) { vpnsp, err := r.env.Inside("VPNSP", []string{ - "cyberghost", "mullvad", "nordvpn", "privado", + "cyberghost", "hidemyass", "mullvad", "nordvpn", "privado", "pia", "private internet access", "purevpn", "surfshark", "torguard", "vyprvpn", "windscribe"}, params.Default("private internet access")) @@ -115,6 +115,8 @@ func (settings *OpenVPN) read(r reader) (err error) { switch settings.Provider.Name { case constants.Cyberghost: readProvider = settings.Provider.readCyberghost + case constants.HideMyAss: + readProvider = settings.Provider.readHideMyAss case constants.Mullvad: readProvider = settings.Provider.readMullvad case constants.Nordvpn: diff --git a/internal/configuration/provider.go b/internal/configuration/provider.go index 582d5c6d..d50c680e 100644 --- a/internal/configuration/provider.go +++ b/internal/configuration/provider.go @@ -31,6 +31,8 @@ func (settings *Provider) lines() (lines []string) { switch strings.ToLower(settings.Name) { case "cyberghost": providerLines = settings.cyberghostLines() + case "hidemyass": + providerLines = settings.hideMyAssLines() case "mullvad": providerLines = settings.mullvadLines() case "nordvpn": diff --git a/internal/configuration/provider_test.go b/internal/configuration/provider_test.go index 8622e989..04eeb328 100644 --- a/internal/configuration/provider_test.go +++ b/internal/configuration/provider_test.go @@ -42,6 +42,24 @@ func Test_Provider_lines(t *testing.T) { " |--Client certificate is set", }, }, + "hidemyass": { + settings: Provider{ + Name: constants.HideMyAss, + ServerSelection: ServerSelection{ + Protocol: constants.UDP, + Countries: []string{"a", "b"}, + Cities: []string{"c", "d"}, + Hostnames: []string{"e", "f"}, + }, + }, + lines: []string{ + "|--Hidemyass settings:", + " |--Network protocol: udp", + " |--Countries: a, b", + " |--Cities: c, d", + " |--Hostnames: e, f", + }, + }, "mullvad": { settings: Provider{ Name: constants.Mullvad, diff --git a/internal/configuration/selection.go b/internal/configuration/selection.go index 92e15976..261a4173 100644 --- a/internal/configuration/selection.go +++ b/internal/configuration/selection.go @@ -15,9 +15,9 @@ type ServerSelection struct { // Cyberghost Group string `json:"group"` - Countries []string `json:"countries"` // Mullvad, PureVPN - Cities []string `json:"cities"` // Mullvad, PureVPN, Windscribe - Hostnames []string `json:"hostnames"` // Windscribe, Privado + Countries []string `json:"countries"` // HideMyAss, Mullvad, PureVPN + Cities []string `json:"cities"` // HideMyAss, Mullvad, PureVPN, Windscribe + Hostnames []string `json:"hostnames"` // HideMyAss, Windscribe, Privado // Mullvad ISPs []string `json:"isps"` diff --git a/internal/configuration/updater.go b/internal/configuration/updater.go index 163ce9be..8ff7ad42 100644 --- a/internal/configuration/updater.go +++ b/internal/configuration/updater.go @@ -11,6 +11,7 @@ type Updater struct { Period time.Duration `json:"period"` DNSAddress string `json:"dns_address"` Cyberghost bool `json:"cyberghost"` + HideMyAss bool `json:"hidemyass"` Mullvad bool `json:"mullvad"` Nordvpn bool `json:"nordvpn"` PIA bool `json:"pia"` @@ -43,6 +44,7 @@ func (settings *Updater) lines() (lines []string) { func (settings *Updater) read(r reader) (err error) { settings.Cyberghost = true + settings.HideMyAss = true settings.Mullvad = true settings.Nordvpn = true settings.Privado = true diff --git a/internal/constants/hidemyass.go b/internal/constants/hidemyass.go new file mode 100644 index 00000000..64ae4d41 --- /dev/null +++ b/internal/constants/hidemyass.go @@ -0,0 +1,313 @@ +package constants + +import ( + "net" + + "github.com/qdm12/gluetun/internal/models" +) + +//nolint:lll +const ( + HideMyAssCA = "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" + HideMyAssCertificate = "MIIGMjCCBBqgAwIBAgICAQIwDQYJKoZIhvcNAQELBQAwgZIxCzAJBgNVBAYTAlVLMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjETMBEGA1UECgwKUHJpdmF4IEx0ZDEUMBIGA1UECwwLSE1BIFBybyBWUE4xFjAUBgNVBAMMDWhpZGVteWFzcy5jb20xHjAcBgkqhkiG9w0BCQEWD2luZm9AcHJpdmF4LmNvbTAeFw0xNjEwMTgxNDE4MThaFw0yNjEwMTUxNDE4MThaMIGNMQswCQYDVQQGEwJVSzEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xEzARBgNVBAoMClByaXZheCBMdGQxFDASBgNVBAsMC0hNQSBQcm8gVlBOMREwDwYDVQQDDAhobWF1c2VyMjEeMBwGCSqGSIb3DQEJARYPaW5mb0Bwcml2YXguY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5XY3ERJYWs/YIeBoybivNlu+M32rJs+CAZsh7BnnetTxytI4ngsMRoqXETuis8udp2hsqEHsglLR9tlk9C8yCuKhxbkpdrXFWdISmUq5sa7/wqg/zJF1AZm5Jy0oHNyTHfG6XW61I/h9IN5dmcR9YLir8DVDBNllbtt0z+DnvOhYJOqC30ENahWkTmNKl1cT7EBrR5slddiBJleAb08z77pwsD310e6jWTBySsBcPy+xu/Jj2QgVil/3mstZZDI+noFzs3SkTFBkha/lNTP7NODBQ6m39iaJxz6ZR1xE3v7XU0H5WnpZIcQ2+kmu5Krk2y1GYMKL+9oaotXFPz9v+QIDAQABo4IBkzCCAY8wCQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMCB4AwCwYDVR0PBAQDAgeAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU2LKFPHjFUzLfsHIMWi0VukhBgTEwgccGA1UdIwSBvzCBvIAU4MZR0iTa8SoTWOJeoOmtynuk8/ehgZikgZUwgZIxCzAJBgNVBAYTAlVLMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjETMBEGA1UECgwKUHJpdmF4IEx0ZDEUMBIGA1UECwwLSE1BIFBybyBWUE4xFjAUBgNVBAMMDWhpZGVteWFzcy5jb20xHjAcBgkqhkiG9w0BCQEWD2luZm9AcHJpdmF4LmNvbYIJAOmTY3hf1Bb6MBoGA1UdEQQTMBGBD2luZm9AcHJpdmF4LmNvbTAaBgNVHRIEEzARgQ9pbmZvQHByaXZheC5jb20wEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggIBAKeGVnbL3yu2fh1T0ATbgyHx9rnFGRW1o/xfF5ssfRInlopsGDejrk9goyJErVxuzSzLp8AhxSOrVZJp6Tlpssj3B4FbGB0BIH+LcrID9pb+r2LqrTeYfMwYo6zRLNQ5NmMyxQCf6XrdxihUTiZBV31LKlWNkhOLMlHr2eXwAEXjqYMXjYwN+WE8I7SlUm5WCwj7PTiF7BpdDP5Ut4y5Dj8A2m1zXt36rr5hxvbgo2JAeFwVEG4ch67PI+uM0G2GilxnjuK2wKgjBKFMAUfLs7tigzSgx8PEfYCc+bgWpPyfG5hYM9n94zd2VTDN4sam12Bxvhw8zn20L6eT+Skfa8BN7eesrV5opABt/IImZ4Q1HShKKc5EiBN8CKGDydojkNrXuFfsyv7S9VHch0e5cS+Annhr4ARaH0O5fPOD5PBVajdbV6/Rf7NzB5b/raJcUK5BD6KWWRCsmaNYzaabJjUpCmigrOMmkdAxeKCY/oEFpU3+7VeKfNyxBTIiGFt5RjNqTQXmMVjiRN97VN7fqAaFTQB2OF7E3hrtqU9jXkeN8Tvu/FF0LNyt87orewecC0Ujz7Hto9fchPH0roP+DVzoAEP8axD9RV5pM/kgubu3hMD6lLsbx4GOD11GQplvuygURxAYsyjbgFydbk1ZIpeE2OeGXXrfuQWFbNtjLJTu" + HideMyAssRSAPrivateKey = "MIIEpAIBAAKCAQEA5XY3ERJYWs/YIeBoybivNlu+M32rJs+CAZsh7BnnetTxytI4ngsMRoqXETuis8udp2hsqEHsglLR9tlk9C8yCuKhxbkpdrXFWdISmUq5sa7/wqg/zJF1AZm5Jy0oHNyTHfG6XW61I/h9IN5dmcR9YLir8DVDBNllbtt0z+DnvOhYJOqC30ENahWkTmNKl1cT7EBrR5slddiBJleAb08z77pwsD310e6jWTBySsBcPy+xu/Jj2QgVil/3mstZZDI+noFzs3SkTFBkha/lNTP7NODBQ6m39iaJxz6ZR1xE3v7XU0H5WnpZIcQ2+kmu5Krk2y1GYMKL+9oaotXFPz9v+QIDAQABAoIBAQCcMcssOMOiFWc3MC3EWo4SP4MKQ9n0Uj5Z34LI151FdJyehlj54+VYQ1Cv71tCbjED2sZUBoP69mtsT/EzcsjqtfiOwgrifrs2+BOm+0HKHKiGlcbP9peiHkT10PxEITWXpYtJvGlbcfOjIxqt6B28cBjCK09ShrVQL9ylAKBearRRUacszppntMNTMtN/uG48ZR9Wm+xAczImdG6CrG5sLI/++JwM5PDChLvn5JgMGyOfQZdjNe1oSOVLmqFeG5uu/FS4oMon9+HtfjHJr4ZgA1yQ2wQh3GvEjlP8zwHxEpRJYbxpj6ZbjHZJ2HLX/Gcd9/cXiN8+fQ2zPIYQyG9dAoGBAPUUmt2nJNvl7gj0GbZZ3XR9o+hvj7bJ74W2NhMrw6kjrrzHTAUQd1sBQS8szAQCLqf2ou1aw9AMMBdsLAHydXxvbH7IBAla7rKr23iethtSfjhTNSgQLJHVZlNHfp3hzNtCQZ7j0qVjrteNotrdVF7kKPHDXAK00ICy6SPNjvrXAoGBAO+vdnO15jLeZbbi3lQNS4r8oCadyqyX7ouKE6MtKNhiPsNPGqHKiGcKs/+QylVgYvSmm7TgpsCAiEYeLSPT+Yq3y7HtwVpULlpfAhEJXmvn/6hGpOizx1WNGWhw7nHPWPDzf+jqCGzHdhK0aEZR3MZZQ+U+uKfGiJ8vrvgB7eGvAoGAWxxp5nU48rcsIw/8bxpBhgkfYk33M5EnBqKSv9XJS5wEXhIJZOiWNrLktNEGl4boKXE7aNoRacreJhcE1UR6AOS7hPZ+6atwiePyF4mJUeb9HZtxa493wk9/Vv6BR9il++1Jz/QKX4oLef8hyBP4Rb60qgxirG7kBLR+j9zfhskCgYEAzA5y5xIeuIIU0H4XUDG9dcebxSSjbwsuYIgeLdb9pjMGQhsvjjyyoh8/nT20tLkJpkXN3FFCRjNnUWLRhWYrVkkh1wqWiYOPrwqh5MU4KN/sDWSPcznTY+drkTpMFoKzsvdrl2zf3VR3FneXKv742bkXj601Ykko+XWMHcLutisCgYBSq8IrsjzfaTQiTGI9a7WWsvzK92bq7Abnfq7swAXWcJd/bnjTQKLrrvt2bmwNvlWKAb3c69BFMn0X4t4PuN0iJQ39D6aQAEaM7HwWAmjf5TbodbmgbGxdsUB4xcCIQQ1mvTkigXWrCg0YAD2GZSoaslXAAVv6nR5qWEIa0Hx9GA==" +) + +func HideMyAssCountryChoices() (choices []string) { + servers := HideMyAssServers() + choices = make([]string, len(servers)) + for i := range servers { + choices[i] = servers[i].Country + } + return makeUnique(choices) +} + +func HideMyAssCityChoices() (choices []string) { + servers := HideMyAssServers() + choices = make([]string, len(servers)) + for i := range servers { + choices[i] = servers[i].City + } + return makeUnique(choices) +} + +func HideMyAssHostnameChoices() (choices []string) { + servers := HideMyAssServers() + choices = make([]string, len(servers)) + for i := range servers { + choices[i] = servers[i].Hostname + } + return makeUnique(choices) +} + +//nolint:lll +// HideMyAssServers returns a slice of all the server information for HideMyAss. +func HideMyAssServers() []models.HideMyAssServer { + return []models.HideMyAssServer{ + {Country: "Afghanistan", Region: "", City: "Kabul", Hostname: "af.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 236}, {5, 62, 63, 232}}}, + {Country: "Aland Islands", Region: "", City: "Mariehamn", Hostname: "ax.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 248}, {5, 62, 63, 244}}}, + {Country: "Albania", Region: "", City: "Tirana", Hostname: "al.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 240}, {5, 62, 63, 236}}}, + {Country: "Algeria", Region: "", City: "Annaba", Hostname: "dz.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 244}, {5, 62, 63, 240}}}, + {Country: "American Samoa", Region: "", City: "Pago Pago", Hostname: "as.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 4}, {5, 62, 58, 4}}}, + {Country: "Andorra", Region: "", City: "Andorrala Vella", Hostname: "ad.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 4}, {5, 62, 62, 4}}}, + {Country: "Angola", Region: "", City: "Luanda", Hostname: "ao.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 8}, {5, 62, 62, 8}}}, + {Country: "Anguilla", Region: "", City: "The Valley", Hostname: "ai.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 8}, {5, 62, 58, 8}}}, + {Country: "Antiguaand Barbuda", Region: "", City: "Saint John's", Hostname: "ag.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 12}, {5, 62, 58, 12}}}, + {Country: "Argentina", Region: "", City: "Buenos Aires", Hostname: "ar.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 16}, {5, 62, 58, 16}}}, + {Country: "Armenia", Region: "", City: "Tsaghkadzor", Hostname: "am.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 12}, {5, 62, 62, 12}}}, + {Country: "Aruba", Region: "", City: "Palm Beach", Hostname: "aw.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 20}, {5, 62, 58, 20}}}, + {Country: "Australia", Region: "New South Wales", City: "Sydney", Hostname: "au.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 23, 3}, {5, 62, 23, 18}}}, + {Country: "Austria", Region: "Carinthia", City: "Klagenfurt", Hostname: "at.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 253, 207, 3}, {91, 132, 139, 115}, {94, 198, 41, 126}, {94, 198, 41, 142}, {185, 9, 19, 126}, {185, 183, 107, 147}}}, + {Country: "Azerbaijan", Region: "", City: "Qusar", Hostname: "az.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 16}, {5, 62, 62, 16}}}, + {Country: "Bahamas", Region: "", City: "Freeport", Hostname: "bs.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 24}, {5, 62, 58, 24}}}, + {Country: "Bahrain", Region: "", City: "Manama", Hostname: "bh.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 20}, {5, 62, 62, 20}}}, + {Country: "Bangladesh", Region: "", City: "Dhaka", Hostname: "bd.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 24}, {5, 62, 62, 24}}}, + {Country: "Barbados", Region: "", City: "Worthing", Hostname: "bb.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 28}, {5, 62, 58, 28}}}, + {Country: "Belarus", Region: "", City: "Minsk", Hostname: "by.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 28}, {5, 62, 62, 28}}}, + {Country: "Belgium", Region: "", City: "Brussels", Hostname: "be.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 20, 24}, {5, 62, 20, 33}, {5, 62, 20, 34}, {5, 62, 20, 44}}}, + {Country: "Belize", Region: "", City: "Belize City", Hostname: "bz.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 32}, {5, 62, 58, 32}}}, + {Country: "Benin", Region: "", City: "Cotonou", Hostname: "bj.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 32}, {5, 62, 62, 32}}}, + {Country: "Bermuda", Region: "", City: "Hamilton", Hostname: "bm.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 36}, {5, 62, 58, 36}}}, + {Country: "Bhutan", Region: "", City: "Thimphu", Hostname: "bt.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 36}, {5, 62, 62, 36}}}, + {Country: "Bolivia", Region: "", City: "Santa Cruz", Hostname: "bo.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 40}, {5, 62, 58, 40}}}, + {Country: "Bosnia", Region: "", City: "Sarajevo", Hostname: "ba.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 40}, {5, 62, 62, 40}}}, + {Country: "Botswana", Region: "", City: "Gaborone", Hostname: "bw.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 44}, {5, 62, 62, 44}}}, + {Country: "Brazil", Region: "", City: "Joao Pessoa", Hostname: "br.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 51, 61}, {5, 62, 51, 101}, {5, 62, 51, 151}, {191, 96, 4, 167}, {191, 96, 5, 163}, {191, 96, 9, 143}}}, + {Country: "British Virgin Islands", Region: "", City: "Tortola", Hostname: "vg.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 44}, {5, 62, 58, 44}}}, + {Country: "Brunei", Region: "", City: "Jerudong", Hostname: "bn.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 48}, {5, 62, 62, 48}}}, + {Country: "Bulgaria", Region: "", City: "Sofia", Hostname: "bg.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 52}, {5, 62, 62, 52}}}, + {Country: "Burkina Faso", Region: "", City: "Ouagadougou", Hostname: "bf.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 56}, {5, 62, 62, 56}}}, + {Country: "Burundi", Region: "", City: "Bujumbura", Hostname: "bi.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 60}, {5, 62, 62, 60}}}, + {Country: "Cambodia", Region: "", City: "Phnom Penh", Hostname: "kh.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 64}, {5, 62, 62, 64}}}, + {Country: "Cameroon", Region: "", City: "Yaounde", Hostname: "cm.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 68}, {5, 62, 62, 68}}}, + {Country: "Canada", Region: "British Columbia", City: "Vancouver", Hostname: "ca.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{51, 161, 54, 15}, {51, 161, 66, 111}, {144, 217, 105, 207}, {192, 99, 89, 207}, {192, 99, 110, 143}, {198, 27, 103, 191}}}, + {Country: "Cape Verde", Region: "", City: "Cidade Velha", Hostname: "cv.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 72}, {5, 62, 62, 72}}}, + {Country: "Cayman Islands", Region: "", City: "Spot Bay", Hostname: "ky.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 48}, {5, 62, 58, 48}}}, + {Country: "Central African Republic", Region: "", City: "Bangassou", Hostname: "cf.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 76}, {5, 62, 62, 76}}}, + {Country: "Chad", Region: "", City: "N'Djamena", Hostname: "td.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 80}, {5, 62, 62, 80}}}, + {Country: "Chile", Region: "", City: "Santiago", Hostname: "cl.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 52}, {5, 62, 58, 52}}}, + {Country: "China", Region: "Sichuan Sheng", City: "Chengdu", Hostname: "cn.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 34, 40}, {5, 62, 34, 44}}}, + {Country: "Christmas Island", Region: "", City: "Flying Fish Cove", Hostname: "cx.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 88}, {5, 62, 62, 84}}}, + {Country: "Cocos Islands", Region: "", City: "West Island", Hostname: "cc.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 92}, {5, 62, 62, 88}}}, + {Country: "Colombia", Region: "", City: "San Andres", Hostname: "co.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 60}, {5, 62, 58, 56}}}, + {Country: "Comoros", Region: "", City: "Ouani", Hostname: "km.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 96}, {5, 62, 62, 92}}}, + {Country: "Congo", Region: "", City: "Kinshasa", Hostname: "cd.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 100}, {5, 62, 62, 96}}}, + {Country: "Cook Islands", Region: "", City: "Avarua", Hostname: "ck.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 64}, {5, 62, 58, 60}}}, + {Country: "Costa Rica", Region: "", City: "San Jose", Hostname: "cr.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 68}, {5, 62, 58, 64}}}, + {Country: "Coted`Ivoire", Region: "", City: "Yamoussoukro", Hostname: "ci.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 104}, {5, 62, 62, 100}}}, + {Country: "Croatia", Region: "", City: "Zagreb", Hostname: "hr.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 228}, {5, 62, 63, 224}}}, + {Country: "Cuba", Region: "", City: "Havana", Hostname: "cu.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 72}, {5, 62, 58, 68}}}, + {Country: "Cyprus", Region: "", City: "Limassol", Hostname: "cy.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 108}, {5, 62, 62, 104}}}, + {Country: "Czech Republic", Region: "", City: "Prague", Hostname: "cz.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{185, 246, 210, 130}, {185, 246, 210, 146}, {185, 246, 210, 162}, {185, 246, 210, 194}, {212, 102, 38, 186}}}, + {Country: "Denmark", Region: "", City: "Copenhagen", Hostname: "dk.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{2, 58, 46, 195}, {2, 58, 46, 211}, {95, 174, 65, 158}, {185, 212, 169, 190}, {185, 212, 169, 206}, {185, 212, 169, 222}}}, + {Country: "Dominica", Region: "", City: "Marigot", Hostname: "dm.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 76}, {5, 62, 58, 72}}}, + {Country: "Dominican Republic", Region: "", City: "Punta Cana", Hostname: "do.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 80}, {5, 62, 58, 76}}}, + {Country: "Ecuador", Region: "", City: "Quito", Hostname: "ec.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 84}, {5, 62, 58, 80}}}, + {Country: "Egypt", Region: "", City: "Cairo", Hostname: "eg.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 112}, {5, 62, 62, 108}}}, + {Country: "El Salvador", Region: "", City: "San Miguel", Hostname: "sv.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 88}, {5, 62, 58, 84}}}, + {Country: "Equatorial Guinea", Region: "", City: "Malabo", Hostname: "gq.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 116}, {5, 62, 62, 112}}}, + {Country: "Eritrea", Region: "", City: "Asmara", Hostname: "er.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 120}, {5, 62, 62, 116}}}, + {Country: "Estonia", Region: "", City: "Tallinn", Hostname: "ee.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 124}, {5, 62, 62, 120}}}, + {Country: "Ethiopia", Region: "", City: "Gondar", Hostname: "et.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 128}, {5, 62, 62, 124}}}, + {Country: "Falkland Islands", Region: "", City: "Stanley", Hostname: "fk.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 92}, {5, 62, 58, 88}}}, + {Country: "Faroe Islands", Region: "", City: "Torshavn", Hostname: "fo.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 132}, {5, 62, 62, 128}}}, + {Country: "Fiji", Region: "", City: "Nadi", Hostname: "fj.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 96}, {5, 62, 58, 92}}}, + {Country: "Finland", Region: "", City: "Helsinki", Hostname: "fi.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{185, 77, 217, 16}, {185, 77, 217, 46}, {185, 77, 217, 76}, {185, 77, 217, 91}, {185, 77, 217, 106}}}, + {Country: "France", Region: "", City: "Paris", Hostname: "fr.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{62, 210, 15, 189}, {84, 17, 43, 77}, {84, 17, 43, 116}, {163, 172, 122, 138}, {185, 93, 2, 82}, {212, 83, 167, 108}, {212, 129, 37, 89}, {212, 129, 49, 206}}}, + {Country: "Gabon", Region: "", City: "Libreville", Hostname: "ga.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 136}, {5, 62, 62, 132}}}, + {Country: "Gambia", Region: "", City: "Serekunda", Hostname: "gm.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 140}, {5, 62, 62, 136}}}, + {Country: "Georgia", Region: "", City: "Tbilisi", Hostname: "ge.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 144}, {5, 62, 62, 140}}}, + {Country: "Germany", Region: "Hesse", City: "Frankfurt", Hostname: "de.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 41, 121}, {5, 62, 41, 133}, {5, 62, 41, 145}, {5, 62, 41, 157}, {5, 62, 41, 169}, {5, 62, 41, 181}}}, + {Country: "Ghana", Region: "", City: "Accra", Hostname: "gh.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 148}, {5, 62, 62, 144}}}, + {Country: "Gibraltar", Region: "", City: "Catalan", Hostname: "gi.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 152}, {5, 62, 62, 148}}}, + {Country: "Greece", Region: "", City: "Patras", Hostname: "gr.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 156}, {5, 62, 62, 152}}}, + {Country: "Greenland", Region: "", City: "Ilulissat", Hostname: "gl.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 160}, {5, 62, 62, 156}}}, + {Country: "Grenada", Region: "", City: "Saint George", Hostname: "gd.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 100}, {5, 62, 58, 96}}}, + {Country: "Guadeloupe", Region: "", City: "Le Gosier", Hostname: "gp.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 104}, {5, 62, 58, 100}}}, + {Country: "Guam", Region: "", City: "Tamuning", Hostname: "gu.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 108}, {5, 62, 60, 164}}}, + {Country: "Guatemala", Region: "", City: "Guatemala City", Hostname: "gt.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 112}, {5, 62, 58, 104}}}, + {Country: "Guinea-Bissau", Region: "", City: "Bissau", Hostname: "gw.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 168}, {5, 62, 62, 160}}}, + {Country: "Guinea", Region: "", City: "Conakry", Hostname: "gn.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 172}, {5, 62, 62, 164}}}, + {Country: "Guyana", Region: "", City: "Barima-Waini", Hostname: "gy.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 116}, {5, 62, 58, 108}}}, + {Country: "Haiti", Region: "", City: "Cap-Haitien", Hostname: "ht.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 120}, {5, 62, 58, 112}}}, + {Country: "Honduras", Region: "", City: "Tegucigalpa", Hostname: "hn.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 124}, {5, 62, 58, 116}}}, + {Country: "Hungary", Region: "", City: "Budapest", Hostname: "hu.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{37, 120, 144, 78}, {37, 120, 144, 94}, {185, 128, 26, 113}, {185, 128, 26, 126}}}, + {Country: "Iceland", Region: "", City: "Reykjavik", Hostname: "is.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{82, 221, 112, 243}, {82, 221, 112, 244}}}, + {Country: "India", Region: "Maharashtra", City: "Mumbai", Hostname: "in.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 34, 8}, {5, 62, 34, 12}}}, + {Country: "Indonesia", Region: "", City: "Jakarta", Hostname: "id.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 34, 16}, {5, 62, 34, 20}}}, + {Country: "Iran", Region: "", City: "Isfahan", Hostname: "ir.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 176}, {5, 62, 62, 168}}}, + {Country: "Iraq", Region: "", City: "Baghdad", Hostname: "iq.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 180}, {5, 62, 62, 172}}}, + {Country: "Ireland", Region: "", City: "Dublin", Hostname: "ie.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{78, 153, 199, 5}, {78, 153, 199, 29}, {78, 153, 199, 243}, {78, 153, 199, 254}}}, + {Country: "Israel", Region: "", City: "Petah Tikva", Hostname: "il.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{185, 185, 132, 62}, {185, 185, 132, 110}, {185, 185, 133, 78}, {185, 185, 133, 190}}}, + {Country: "Italy", Region: "Pordenone", City: "Porcia", Hostname: "it.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{45, 87, 184, 15}, {45, 87, 184, 47}, {45, 87, 184, 63}, {45, 87, 184, 79}, {84, 17, 58, 168}, {84, 17, 58, 213}, {84, 17, 59, 45}, {84, 17, 59, 59}}}, + {Country: "Jamaica", Region: "", City: "Montego Bay", Hostname: "jm.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 128}, {5, 62, 58, 120}}}, + {Country: "Japan", Region: "", City: "Tokyo", Hostname: "jp.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{156, 146, 35, 162}, {156, 146, 35, 184}, {156, 146, 35, 185}, {212, 102, 51, 235}}}, + {Country: "Jordan", Region: "", City: "Amman", Hostname: "jo.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 188}, {5, 62, 62, 180}}}, + {Country: "Kazakhstan", Region: "", City: "Shymkent", Hostname: "kz.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 192}, {5, 62, 62, 184}}}, + {Country: "Kenya", Region: "", City: "Nairobi", Hostname: "ke.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 196}, {5, 62, 62, 188}}}, + {Country: "Kiribati", Region: "", City: "Umwa Village", Hostname: "ki.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 132}, {5, 62, 58, 124}}}, + {Country: "Kuwait", Region: "", City: "Kuwait City", Hostname: "kw.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 200}, {5, 62, 62, 192}}}, + {Country: "Kyrgyzstan", Region: "", City: "Bishkek", Hostname: "kg.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 204}, {5, 62, 62, 196}}}, + {Country: "Laos", Region: "", City: "Thakhek", Hostname: "la.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 208}, {5, 62, 62, 200}}}, + {Country: "Latvia", Region: "", City: "Riga", Hostname: "lv.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 212}, {5, 62, 62, 204}}}, + {Country: "Lebanon", Region: "", City: "Beirut", Hostname: "lb.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 216}, {5, 62, 62, 208}}}, + {Country: "Lesotho", Region: "", City: "Peka", Hostname: "ls.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 220}, {5, 62, 62, 212}}}, + {Country: "Liberia", Region: "", City: "Monrovia", Hostname: "lr.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 224}, {5, 62, 62, 216}}}, + {Country: "Libya", Region: "", City: "Ghadames", Hostname: "ly.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 228}, {5, 62, 62, 220}}}, + {Country: "Liechtenstein", Region: "", City: "Vaduz", Hostname: "li.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 232}, {5, 62, 62, 224}}}, + {Country: "Lithuania", Region: "", City: "Siauliai", Hostname: "lt.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 236}, {5, 62, 62, 228}}}, + {Country: "Luxembourg", Region: "", City: "", Hostname: "lu.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{92, 38, 162, 148}, {92, 38, 162, 151}, {92, 38, 172, 25}}}, + {Country: "Macau", Region: "", City: "Macau", Hostname: "mo.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 240}, {5, 62, 62, 232}}}, + {Country: "Macedonia", Region: "", City: "Skopje", Hostname: "mk.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 244}, {5, 62, 62, 236}}}, + {Country: "Madagascar", Region: "", City: "Antsiranana", Hostname: "mg.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 248}, {5, 62, 62, 240}}}, + {Country: "Malawi", Region: "", City: "Lilongwe", Hostname: "mw.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 60, 252}, {5, 62, 62, 244}}}, + {Country: "Malaysia", Region: "", City: "Kuala Lumpur", Hostname: "my.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{185, 54, 231, 26}, {185, 54, 231, 43}, {185, 54, 231, 60}, {185, 54, 231, 77}}}, + {Country: "Maldives", Region: "", City: "Male", Hostname: "mv.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 0}, {5, 62, 62, 248}}}, + {Country: "Mali", Region: "", City: "Bamako", Hostname: "ml.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 4}, {5, 62, 62, 252}}}, + {Country: "Malta", Region: "", City: "Cospicua", Hostname: "mt.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 8}, {5, 62, 63, 0}}}, + {Country: "Mauritius", Region: "", City: "Port Louis", Hostname: "mu.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 16}, {5, 62, 63, 8}}}, + {Country: "Mexico", Region: "Sinaloa", City: "Mazatlan", Hostname: "mx.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{31, 14, 72, 23}, {31, 14, 72, 30}, {31, 14, 72, 44}, {31, 14, 72, 51}}}, + {Country: "Moldova", Region: "", City: "Chisinau", Hostname: "md.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 20}, {5, 62, 63, 12}}}, + {Country: "Monaco", Region: "", City: "Monaco", Hostname: "mc.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 24}, {5, 62, 63, 16}}}, + {Country: "Mongolia", Region: "", City: "Suhbaatar", Hostname: "mn.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 28}, {5, 62, 63, 20}}}, + {Country: "Montenegro", Region: "", City: "Becici", Hostname: "me.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 32}, {5, 62, 63, 24}}}, + {Country: "Montserrat", Region: "", City: "Plymouth", Hostname: "ms.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 136}, {5, 62, 58, 128}}}, + {Country: "Morocco", Region: "", City: "Fes", Hostname: "ma.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 36}, {5, 62, 63, 28}}}, + {Country: "Mozambique", Region: "", City: "Pemba", Hostname: "mz.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 40}, {5, 62, 63, 32}}}, + {Country: "Myanmar", Region: "", City: "Yangon", Hostname: "mm.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 44}, {5, 62, 63, 36}}}, + {Country: "Namibia", Region: "", City: "Windhoek", Hostname: "na.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 48}, {5, 62, 63, 40}}}, + {Country: "Nauru", Region: "", City: "Anabar", Hostname: "nr.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 140}, {5, 62, 58, 132}}}, + {Country: "Nepal", Region: "", City: "Janakpur", Hostname: "np.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 52}, {5, 62, 63, 44}}}, + {Country: "Netherlands", Region: "", City: "Amsterdam", Hostname: "nl.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{84, 17, 46, 134}, {84, 17, 46, 158}, {84, 17, 46, 182}, {84, 17, 46, 251}}}, + {Country: "New Caledonia", Region: "", City: "Noumea", Hostname: "nc.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 144}, {5, 62, 58, 136}}}, + {Country: "New Zealand", Region: "", City: "Auckland", Hostname: "nz.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{103, 76, 164, 3}, {103, 76, 164, 19}, {103, 108, 94, 243}, {103, 231, 91, 131}}}, + {Country: "Nicaragua", Region: "", City: "Managua", Hostname: "ni.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 148}, {5, 62, 58, 140}}}, + {Country: "Niger", Region: "", City: "Niamey", Hostname: "ne.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 56}, {5, 62, 63, 48}}}, + {Country: "Nigeria", Region: "", City: "Lagos", Hostname: "ng.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 60}, {5, 62, 63, 52}}}, + {Country: "Niue", Region: "", City: "Alofi", Hostname: "nu.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 152}, {5, 62, 58, 144}}}, + {Country: "Norfolk Island", Region: "", City: "Kingston", Hostname: "nf.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 156}, {5, 62, 58, 148}}}, + {Country: "North Korea", Region: "", City: "Manpo", Hostname: "kp.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 160}, {5, 62, 61, 64}}}, + {Country: "Norway", Region: "", City: "Oslo", Hostname: "no.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{185, 101, 32, 16}, {185, 101, 32, 64}, {217, 170, 202, 112}, {217, 170, 204, 160}}}, + {Country: "Oman", Region: "", City: "Salalah", Hostname: "om.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 68}, {5, 62, 63, 56}}}, + {Country: "Pakistan", Region: "", City: "Karachi", Hostname: "pk.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 72}, {5, 62, 63, 60}}}, + {Country: "Palau", Region: "", City: "Melekeok", Hostname: "pw.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 164}, {5, 62, 61, 76}}}, + {Country: "Palestine", Region: "", City: "Bethlehem", Hostname: "ps.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 80}, {5, 62, 63, 64}}}, + {Country: "Panama", Region: "", City: "Panama City", Hostname: "pa.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 168}, {5, 62, 58, 152}}}, + {Country: "Papua New Guinea", Region: "", City: "Alotau", Hostname: "pg.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 172}, {5, 62, 61, 84}}}, + {Country: "Paraguay", Region: "", City: "Boqueron", Hostname: "py.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 176}, {5, 62, 58, 156}}}, + {Country: "Peru", Region: "", City: "Cusco", Hostname: "pe.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 180}}}, + {Country: "Philippines", Region: "", City: "Baguio", Hostname: "ph.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 184}, {5, 62, 61, 88}}}, + {Country: "Pitcairn Islands", Region: "", City: "Adamstown", Hostname: "pn.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 188}, {5, 62, 58, 164}}}, + {Country: "Poland", Region: "", City: "Warsaw", Hostname: "pl.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{185, 246, 208, 61}, {185, 246, 208, 130}, {185, 246, 208, 157}}}, + {Country: "Portugal", Region: "", City: "Leiria", Hostname: "pt.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{91, 205, 230, 239}, {91, 205, 230, 255}, {91, 250, 240, 193}, {91, 250, 240, 209}, {91, 250, 240, 225}, {195, 158, 248, 94}}}, + {Country: "Puerto Rico", Region: "", City: "San Juan", Hostname: "pr.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 192}, {5, 62, 58, 168}}}, + {Country: "Qatar", Region: "", City: "Doha", Hostname: "qa.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 92}, {5, 62, 63, 68}}}, + {Country: "Republicof Djibouti", Region: "", City: "Djibouti", Hostname: "dj.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 96}, {5, 62, 63, 72}}}, + {Country: "Republicof Singapore", Region: "", City: "Singapore", Hostname: "sg.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 35, 159}, {5, 62, 35, 175}, {89, 187, 163, 226}, {89, 187, 163, 250}, {92, 223, 85, 21}, {92, 223, 85, 22}}}, + {Country: "Republicofthe Congo", Region: "", City: "Brazzaville", Hostname: "cg.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 100}, {5, 62, 63, 76}}}, + {Country: "Romania", Region: "", City: "Bucharest", Hostname: "ro.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 104}, {5, 62, 63, 80}}}, + {Country: "Russia", Region: "", City: "Moscow", Hostname: "ru.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 19, 39}, {5, 62, 19, 47}, {5, 62, 19, 55}, {5, 62, 19, 63}, {5, 62, 19, 71}}}, + {Country: "Rwanda", Region: "", City: "Kigali", Hostname: "rw.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 108}, {5, 62, 63, 84}}}, + {Country: "Saint Helena", Region: "", City: "Tristan Da Cunha", Hostname: "sh.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 112}, {5, 62, 63, 88}}}, + {Country: "Saint Kittsand Nevis", Region: "", City: "Basseterre", Hostname: "kn.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 196}, {5, 62, 58, 172}}}, + {Country: "Saint Lucia", Region: "", City: "Gros Islet", Hostname: "lc.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 200}, {5, 62, 58, 176}}}, + {Country: "Saint Pierreand Miquelon", Region: "", City: "Saint-Pierre", Hostname: "pm.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 58, 180}, {5, 62, 63, 92}}}, + {Country: "Saint Vincentandthe Grenadines", Region: "", City: "Kingstown", Hostname: "vc.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 204}, {5, 62, 58, 184}}}, + {Country: "Samoa", Region: "", City: "Matatufu", Hostname: "ws.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 208}, {5, 62, 58, 188}}}, + {Country: "San Marino", Region: "", City: "San Marino", Hostname: "sm.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 116}, {5, 62, 63, 96}}}, + {Country: "Sao Tomeand Principe", Region: "", City: "Sao Tome", Hostname: "st.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 120}, {5, 62, 63, 100}}}, + {Country: "Saudi Arabia", Region: "", City: "Riyadh", Hostname: "sa.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 124}, {5, 62, 63, 104}}}, + {Country: "Senegal", Region: "", City: "Dakar", Hostname: "sn.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 128}, {5, 62, 63, 108}}}, + {Country: "Serbia", Region: "", City: "Belgrade", Hostname: "rs.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 132}, {5, 62, 63, 112}}}, + {Country: "Slovakia", Region: "", City: "Bratislava", Hostname: "sk.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 140}, {5, 62, 63, 120}}}, + {Country: "Slovenia", Region: "", City: "Vrhnika", Hostname: "si.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 144}, {5, 62, 63, 124}}}, + {Country: "Solomon Islands", Region: "", City: "Honiara", Hostname: "sb.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 212}, {5, 62, 58, 192}}}, + {Country: "Somalia", Region: "", City: "Afgooye", Hostname: "so.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 148}, {5, 62, 63, 128}}}, + {Country: "South Africa", Region: "", City: "Johannesburg", Hostname: "za.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{154, 127, 57, 21}, {154, 127, 57, 93}, {196, 251, 250, 39}, {196, 251, 250, 74}, {196, 251, 250, 92}, {196, 251, 250, 137}, {196, 251, 250, 206}}}, + {Country: "South Korea", Region: "", City: "Seoul", Hostname: "kr.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{92, 223, 73, 22}, {92, 223, 73, 71}, {92, 223, 73, 89}, {92, 223, 73, 93}, {92, 223, 73, 147}}}, + {Country: "Spain", Region: "", City: "Alicante", Hostname: "es.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{82, 102, 17, 126}, {82, 102, 17, 222}, {82, 102, 17, 254}, {185, 183, 106, 110}, {185, 183, 106, 126}}}, + {Country: "Sri Lanka", Region: "", City: "Moratuwa", Hostname: "lk.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 152}, {5, 62, 63, 132}}}, + {Country: "Sudan", Region: "", City: "Khartoum", Hostname: "sd.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 156}, {5, 62, 63, 136}}}, + {Country: "Suriname", Region: "", City: "Paramaribo", Hostname: "sr.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 216}, {5, 62, 58, 196}}}, + {Country: "Svalbardand Jan Mayen", Region: "", City: "Longyearbyen", Hostname: "sj.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 160}, {5, 62, 63, 140}}}, + {Country: "Swaziland", Region: "", City: "Manzini", Hostname: "sz.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 220}, {5, 62, 58, 200}}}, + {Country: "Sweden", Region: "Stockholm", City: "Nacka", Hostname: "se.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{31, 3, 152, 138}, {31, 3, 152, 170}, {31, 3, 152, 192}, {31, 3, 153, 140}, {37, 46, 121, 240}, {128, 127, 105, 164}}}, + {Country: "Switzerland", Region: "", City: "Zurich", Hostname: "ch.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{84, 17, 52, 141}, {84, 17, 52, 154}, {84, 17, 52, 167}, {84, 17, 52, 180}, {84, 17, 52, 253}, {89, 187, 165, 179}}}, + {Country: "Syria", Region: "", City: "Ad Darah", Hostname: "sy.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 164}, {5, 62, 63, 144}}}, + {Country: "Taiwan", Region: "", City: "Taipei", Hostname: "tw.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{172, 107, 246, 62}, {172, 107, 246, 110}, {172, 107, 246, 126}, {172, 107, 246, 142}, {172, 107, 246, 174}, {172, 107, 246, 190}, {172, 107, 246, 206}, {172, 107, 246, 222}}}, + {Country: "Tajikistan", Region: "", City: "Dushanbe", Hostname: "tj.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 168}, {5, 62, 63, 148}}}, + {Country: "Tanzania", Region: "", City: "Arusha", Hostname: "tz.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 172}, {5, 62, 63, 152}}}, + {Country: "Thailand", Region: "", City: "Bangkok", Hostname: "th.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 176}, {5, 62, 63, 156}}}, + {Country: "Togo", Region: "", City: "Lome", Hostname: "tg.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 180}, {5, 62, 63, 160}}}, + {Country: "Tokelau", Region: "", City: "Atafu", Hostname: "tk.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 224}, {5, 62, 58, 204}}}, + {Country: "Tonga", Region: "", City: "Nukualofa", Hostname: "to.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 228}, {5, 62, 58, 208}}}, + {Country: "Trinidadand Tobago", Region: "", City: "San Fernando", Hostname: "tt.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 232}, {5, 62, 58, 212}}}, + {Country: "Tunisia", Region: "", City: "Mahdia", Hostname: "tn.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 184}, {5, 62, 63, 164}}}, + {Country: "Turkey", Region: "", City: "Istanbul", Hostname: "tr.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{92, 38, 180, 63}, {92, 38, 180, 76}, {92, 38, 180, 86}}}, + {Country: "Turkmenistan", Region: "", City: "Ashgabat", Hostname: "tm.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 188}, {5, 62, 63, 168}}}, + {Country: "Turksand Caicos Islands", Region: "", City: "Balfour Town", Hostname: "tc.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 236}, {5, 62, 58, 216}}}, + {Country: "Tuvalu", Region: "", City: "Vaitupu", Hostname: "tv.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 240}, {5, 62, 58, 220}}}, + {Country: "UK", Region: "", City: "London", Hostname: "london.gb.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 43, 193}, {5, 62, 43, 202}, {5, 62, 43, 218}, {5, 62, 43, 229}, {77, 234, 43, 130}, {77, 234, 43, 166}, {77, 234, 43, 175}}}, + {Country: "UK", Region: "Scotland", City: "Glasgow", Hostname: "scotland.gb.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{62, 128, 207, 110}, {62, 128, 217, 112}, {80, 75, 64, 66}, {109, 169, 34, 23}, {109, 169, 34, 42}, {109, 169, 34, 62}}}, + {Country: "UK", Region: "", City: "", Hostname: "gb.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{62, 128, 207, 110}, {62, 128, 217, 69}, {62, 128, 217, 85}, {62, 128, 217, 112}, {80, 75, 64, 66}, {109, 169, 34, 23}, {109, 169, 34, 42}, {109, 169, 34, 62}}}, + {Country: "USA", Region: "Alabama", City: "Montgomery", Hostname: "al.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{95, 142, 127, 16}, {95, 142, 127, 25}}}, + {Country: "USA", Region: "Alaska", City: "Anchorage", Hostname: "ak.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 252}, {5, 62, 58, 232}}}, + {Country: "USA", Region: "Arizona", City: "Phoenix", Hostname: "az.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{23, 83, 130, 37}, {23, 83, 130, 187}, {23, 83, 131, 113}, {23, 83, 131, 215}, {23, 83, 185, 35}, {23, 83, 185, 50}}}, + {Country: "USA", Region: "Arkansas", City: "Magnolia", Hostname: "ar.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 0}, {5, 62, 58, 236}}}, + {Country: "USA", Region: "California", City: "Los Angeles", Hostname: "ca.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{67, 201, 33, 54}, {107, 181, 178, 97}, {162, 253, 68, 161}, {162, 253, 68, 177}, {162, 253, 68, 193}, {162, 253, 68, 209}, {162, 253, 68, 225}, {162, 253, 68, 241}, {192, 252, 220, 17}}}, + {Country: "USA", Region: "Connecticut", City: "Trumbull", Hostname: "ct.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 16, 16}, {5, 62, 16, 25}}}, + {Country: "USA", Region: "Delaware", City: "Wilmington", Hostname: "de.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 4}, {5, 62, 58, 240}}}, + {Country: "USA", Region: "Florida", City: "Miami", Hostname: "fl.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{171, 22, 76, 15}, {171, 22, 76, 31}, {171, 22, 76, 47}, {171, 22, 76, 63}, {171, 22, 76, 79}, {171, 22, 76, 95}}}, + {Country: "USA", Region: "Georgia", City: "Atlanta", Hostname: "ga.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 24, 15}, {5, 62, 24, 31}, {5, 62, 24, 46}, {5, 62, 24, 61}, {66, 115, 181, 145}}}, + {Country: "USA", Region: "Hawaii", City: "Honolulu", Hostname: "hi.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{131, 100, 2, 51}, {131, 100, 2, 99}, {131, 100, 2, 121}, {131, 100, 2, 222}}}, + {Country: "USA", Region: "Idaho", City: "Idaho Falls", Hostname: "id.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 12}, {5, 62, 58, 248}}}, + {Country: "USA", Region: "Illinois", City: "Chicago", Hostname: "il.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{154, 16, 241, 127}, {181, 214, 61, 64}, {181, 214, 102, 159}, {181, 214, 107, 31}, {181, 214, 107, 63}}}, + {Country: "USA", Region: "Indiana", City: "South Bend", Hostname: "in.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{198, 134, 108, 67}, {198, 134, 109, 131}}}, + {Country: "USA", Region: "Iowa", City: "Des Moines", Hostname: "ia.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 104}, {5, 62, 59, 84}}}, + {Country: "USA", Region: "Kansas", City: "Wichita", Hostname: "ks.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 16}, {5, 62, 58, 252}}}, + {Country: "USA", Region: "Kentucky", City: "Louisville", Hostname: "ky.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 20}, {5, 62, 59, 0}}}, + {Country: "USA", Region: "Louisiana", City: "New Orleans", Hostname: "la.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 24}, {5, 62, 59, 4}}}, + {Country: "USA", Region: "Maine", City: "Bath", Hostname: "me.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 28}, {5, 62, 59, 8}}}, + {Country: "USA", Region: "Maryland", City: "Baltimore", Hostname: "md.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 32}, {5, 62, 59, 12}}}, + {Country: "USA", Region: "Massachusetts", City: "Boston", Hostname: "ma.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{38, 146, 52, 205}, {38, 146, 57, 205}, {38, 146, 57, 253}, {38, 242, 7, 243}, {154, 3, 129, 29}, {154, 3, 222, 163}}}, + {Country: "USA", Region: "Michigan", City: "Lansing", Hostname: "mi.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 36}, {5, 62, 59, 16}}}, + {Country: "USA", Region: "Minnesota", City: "Saint Paul", Hostname: "mn.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 108}, {5, 62, 59, 88}}}, + {Country: "USA", Region: "Mississippi", City: "Louisville", Hostname: "ms.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 40}, {5, 62, 59, 20}}}, + {Country: "USA", Region: "Missouri", City: "Kansas City", Hostname: "mo.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{209, 239, 115, 164}, {209, 239, 115, 186}}}, + {Country: "USA", Region: "Montana", City: "Billings", Hostname: "mt.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 116}, {5, 62, 59, 92}}}, + {Country: "USA", Region: "Nebraska", City: "Omaha", Hostname: "ne.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 44}, {5, 62, 59, 24}}}, + {Country: "USA", Region: "Nevada", City: "Las Vegas", Hostname: "nv.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{76, 164, 192, 254}, {76, 164, 193, 82}, {76, 164, 200, 114}, {76, 164, 205, 194}, {76, 164, 224, 211}, {76, 164, 225, 75}}}, + {Country: "USA", Region: "New Hampshire", City: "Bedford", Hostname: "nh.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 48}, {5, 62, 59, 28}}}, + {Country: "USA", Region: "New York", City: "Manhattan", Hostname: "ny.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{156, 146, 36, 77}, {156, 146, 36, 103}, {195, 181, 168, 187}, {212, 102, 33, 50}, {212, 102, 33, 77}, {212, 102, 33, 90}, {212, 102, 33, 176}, {212, 102, 33, 224}, {212, 102, 33, 251}}}, + {Country: "USA", Region: "North Carolina", City: "Asheville", Hostname: "nc.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{104, 247, 208, 78}, {104, 247, 208, 94}, {104, 247, 208, 126}, {104, 247, 208, 142}, {104, 247, 208, 158}, {104, 247, 208, 174}}}, + {Country: "USA", Region: "North Dakota", City: "Grand Forks", Hostname: "nd.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 60}, {5, 62, 59, 40}}}, + {Country: "USA", Region: "Ohio", City: "Columbus", Hostname: "oh.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{199, 114, 218, 99}, {199, 114, 218, 115}}}, + {Country: "USA", Region: "Oklahoma", City: "Oklahoma City", Hostname: "ok.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{209, 54, 43, 201}, {209, 54, 47, 200}}}, + {Country: "USA", Region: "Pennsylvania", City: "Wilkes-Barre", Hostname: "pa.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 64}, {5, 62, 59, 44}}}, + {Country: "USA", Region: "Rhode Island", City: "Providence", Hostname: "ri.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 68}, {5, 62, 59, 48}}}, + {Country: "USA", Region: "South Carolina", City: "Columbia", Hostname: "sc.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 72}, {5, 62, 59, 52}}}, + {Country: "USA", Region: "South Dakota", City: "Sioux Falls", Hostname: "sd.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 76}, {5, 62, 59, 56}}}, + {Country: "USA", Region: "Tennessee", City: "Nashville", Hostname: "tn.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 80}, {5, 62, 59, 60}}}, + {Country: "USA", Region: "Texas", City: "Dallas", Hostname: "tx.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{89, 187, 164, 144}, {89, 187, 164, 160}, {89, 187, 164, 176}, {156, 146, 38, 141}, {156, 146, 38, 154}, {212, 102, 40, 13}, {212, 102, 40, 26}, {212, 102, 40, 141}, {212, 102, 40, 154}}}, + {Country: "USA", Region: "Utah", City: "Salt Lake City", Hostname: "ut.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{69, 36, 169, 129}, {199, 189, 106, 235}, {199, 189, 106, 239}, {199, 189, 106, 251}, {209, 95, 34, 73}, {209, 95, 56, 199}}}, + {Country: "USA", Region: "Vermont", City: "Rutland", Hostname: "vt.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 84}, {5, 62, 59, 64}}}, + {Country: "USA", Region: "Virginia", City: "Ashburn", Hostname: "va.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{198, 98, 183, 37}, {198, 98, 183, 133}, {198, 98, 183, 152}}}, + {Country: "USA", Region: "Washington", City: "Seattle", Hostname: "wa.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{66, 115, 149, 17}, {66, 115, 149, 97}, {66, 115, 149, 123}, {199, 187, 211, 172}, {199, 187, 211, 217}, {199, 187, 211, 232}, {199, 187, 211, 247}, {199, 229, 250, 241}}}, + {Country: "USA", Region: "West Virginia", City: "Philippi", Hostname: "wv.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 88}, {5, 62, 59, 68}}}, + {Country: "USA", Region: "Wisconsin", City: "Madison", Hostname: "wi.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{204, 15, 110, 131}, {204, 15, 110, 163}}}, + {Country: "USA", Region: "Wyoming", City: "Cheyenne", Hostname: "wy.us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 92}, {5, 62, 59, 72}}}, + {Country: "USA", Region: "", City: "", Hostname: "us.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 84}, {5, 62, 59, 64}}}, + {Country: "Uganda", Region: "", City: "Kampala", Hostname: "ug.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 192}, {5, 62, 63, 172}}}, + {Country: "Ukraine", Region: "", City: "Odessa", Hostname: "ua.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{31, 28, 162, 3}, {31, 28, 162, 35}, {62, 149, 29, 158}, {62, 149, 29, 190}}}, + {Country: "United Arab Emirates", Region: "", City: "Dubai", Hostname: "ae.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 200}, {5, 62, 63, 188}}}, + {Country: "Uruguay", Region: "", City: "Montevideo", Hostname: "uy.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 56, 244}, {5, 62, 58, 224}}}, + {Country: "Uzbekistan", Region: "", City: "Samarkand", Hostname: "uz.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 204}, {5, 62, 63, 192}}}, + {Country: "Vanuatu", Region: "", City: "Loltong", Hostname: "vu.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 96}, {5, 62, 59, 76}}}, + {Country: "Vatican", Region: "", City: "Vatican City", Hostname: "va.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 208}, {5, 62, 63, 196}}}, + {Country: "Venezuela", Region: "", City: "Caracas", Hostname: "ve.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 57, 100}, {5, 62, 59, 80}}}, + {Country: "Vietnam", Region: "", City: "Ho Chi Minh City", Hostname: "vn.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 212}, {5, 62, 63, 200}}}, + {Country: "Yemen", Region: "", City: "Sanaa", Hostname: "ye.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 216}, {5, 62, 63, 204}}}, + {Country: "Zambia", Region: "", City: "Lusaka", Hostname: "zm.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 220}, {5, 62, 63, 208}}}, + {Country: "Zimbabwe", Region: "", City: "Harare", Hostname: "zw.hma.rocks", TCP: true, UDP: true, IPs: []net.IP{{5, 62, 61, 224}, {5, 62, 63, 212}}}, + } +} diff --git a/internal/constants/servers.go b/internal/constants/servers.go index 2452987f..12b37711 100644 --- a/internal/constants/servers.go +++ b/internal/constants/servers.go @@ -11,6 +11,11 @@ func GetAllServers() (allServers models.AllServers) { Timestamp: 1612031135, // latest takes precedence Servers: CyberghostServers(), }, + HideMyAss: models.HideMyAssServers{ + Version: 1, + Timestamp: 1614562368, + Servers: HideMyAssServers(), + }, Mullvad: models.MullvadServers{ Version: 1, Timestamp: 1612031135, diff --git a/internal/constants/servers_test.go b/internal/constants/servers_test.go index 0c73e62e..3fe38932 100644 --- a/internal/constants/servers_test.go +++ b/internal/constants/servers_test.go @@ -39,6 +39,11 @@ func Test_versions(t *testing.T) { version: allServers.Cyberghost.Version, digest: "fd6242bb", }, + "HideMyAss": { + model: models.HideMyAssServer{}, + version: allServers.HideMyAss.Version, + digest: "a93b4057", + }, "Mullvad": { model: models.MullvadServer{}, version: allServers.Mullvad.Version, @@ -125,6 +130,11 @@ func Test_timestamps(t *testing.T) { timestamp: allServers.Cyberghost.Timestamp, digest: "5d3a8cbf", }, + "HideMyAss": { + servers: allServers.HideMyAss.Servers, + timestamp: allServers.HideMyAss.Timestamp, + digest: "38c71676", + }, "Mullvad": { servers: allServers.Mullvad.Servers, timestamp: allServers.Mullvad.Timestamp, diff --git a/internal/constants/vpn.go b/internal/constants/vpn.go index a03112a5..3b9109a9 100644 --- a/internal/constants/vpn.go +++ b/internal/constants/vpn.go @@ -3,6 +3,8 @@ package constants const ( // Cyberghost is a VPN provider. Cyberghost = "cyberghost" + // HideMyAss is a VPN provider. + HideMyAss = "hidemyass" // Mullvad is a VPN provider. Mullvad = "mullvad" // NordVPN is a VPN provider. diff --git a/internal/models/server.go b/internal/models/server.go index 129b54a5..bd2b2c80 100644 --- a/internal/models/server.go +++ b/internal/models/server.go @@ -17,6 +17,21 @@ func (s *CyberghostServer) String() string { return fmt.Sprintf("{Region: %q, Group: %q, IPs: %s}", s.Region, s.Group, goStringifyIPs(s.IPs)) } +type HideMyAssServer struct { + Country string `json:"country"` + Region string `json:"region"` + City string `json:"city"` + Hostname string `json:"hostname"` + TCP bool `json:"tcp"` + UDP bool `json:"udp"` + IPs []net.IP `json:"ips"` +} + +func (s *HideMyAssServer) String() string { + return fmt.Sprintf("{Country: %q, Region: %q, City: %q, Hostname: %q, TCP: %t, UDP: %t, IPs: %s}", + s.Country, s.Region, s.City, s.Hostname, s.TCP, s.UDP, goStringifyIPs(s.IPs)) +} + type MullvadServer struct { IPs []net.IP `json:"ips"` IPsV6 []net.IP `json:"ipsv6"` diff --git a/internal/models/servers.go b/internal/models/servers.go index ec6f5e1d..61d2f3d1 100644 --- a/internal/models/servers.go +++ b/internal/models/servers.go @@ -3,6 +3,7 @@ package models type AllServers struct { Version uint16 `json:"version"` Cyberghost CyberghostServers `json:"cyberghost"` + HideMyAss HideMyAssServers `json:"hidemyass"` Mullvad MullvadServers `json:"mullvad"` Nordvpn NordvpnServers `json:"nordvpn"` Privado PrivadoServers `json:"privado"` @@ -16,6 +17,7 @@ type AllServers struct { func (a *AllServers) Count() int { return len(a.Cyberghost.Servers) + + len(a.HideMyAss.Servers) + len(a.Mullvad.Servers) + len(a.Nordvpn.Servers) + len(a.Privado.Servers) + @@ -32,6 +34,11 @@ type CyberghostServers struct { Timestamp int64 `json:"timestamp"` Servers []CyberghostServer `json:"servers"` } +type HideMyAssServers struct { + Version uint16 `json:"version"` + Timestamp int64 `json:"timestamp"` + Servers []HideMyAssServer `json:"servers"` +} type MullvadServers struct { Version uint16 `json:"version"` Timestamp int64 `json:"timestamp"` diff --git a/internal/provider/errors.go b/internal/provider/errors.go new file mode 100644 index 00000000..dc24db52 --- /dev/null +++ b/internal/provider/errors.go @@ -0,0 +1,5 @@ +package provider + +import "errors" + +var ErrNoServerFound = errors.New("no server found") diff --git a/internal/provider/hidemyass.go b/internal/provider/hidemyass.go new file mode 100644 index 00000000..22fc961e --- /dev/null +++ b/internal/provider/hidemyass.go @@ -0,0 +1,169 @@ +package provider + +import ( + "context" + "fmt" + "math/rand" + "net" + "net/http" + "strconv" + "strings" + + "github.com/qdm12/gluetun/internal/configuration" + "github.com/qdm12/gluetun/internal/constants" + "github.com/qdm12/gluetun/internal/firewall" + "github.com/qdm12/gluetun/internal/models" + "github.com/qdm12/golibs/logging" + "github.com/qdm12/golibs/os" +) + +type hideMyAss struct { + servers []models.HideMyAssServer + randSource rand.Source +} + +func newHideMyAss(servers []models.HideMyAssServer, timeNow timeNowFunc) *hideMyAss { + return &hideMyAss{ + servers: servers, + randSource: rand.NewSource(timeNow().UnixNano()), + } +} + +func (h *hideMyAss) filterServers(countries, cities, hostnames []string, + protocol string) (servers []models.HideMyAssServer) { + for _, server := range h.servers { + switch { + case + filterByPossibilities(server.Country, countries), + filterByPossibilities(server.City, cities), + filterByPossibilities(server.Hostname, hostnames), + protocol == constants.TCP && !server.TCP, + protocol == constants.UDP && !server.UDP: + default: + servers = append(servers, server) + } + } + return servers +} + +func (h *hideMyAss) notFoundErr(selection configuration.ServerSelection) error { + var filters []string + + if len(selection.Countries) > 0 { + filters = append(filters, "countries "+commaJoin(selection.Countries)) + } + + if len(selection.Cities) > 0 { + filters = append(filters, "countries "+commaJoin(selection.Cities)) + } + + if len(selection.Hostnames) > 0 { + filters = append(filters, "countries "+commaJoin(selection.Hostnames)) + } + + return fmt.Errorf("%w for %s", ErrNoServerFound, strings.Join(filters, " + ")) +} + +func (h *hideMyAss) GetOpenVPNConnection(selection configuration.ServerSelection) ( + connection models.OpenVPNConnection, err error) { + var defaultPort uint16 = 553 + if selection.Protocol == constants.TCP { + defaultPort = 8080 + } + port := defaultPort + if selection.CustomPort > 0 { + port = selection.CustomPort + } + + if selection.TargetIP != nil { + return models.OpenVPNConnection{IP: selection.TargetIP, Port: port, Protocol: selection.Protocol}, nil + } + + servers := h.filterServers(selection.Countries, selection.Cities, selection.Hostnames, selection.Protocol) + if len(servers) == 0 { + return models.OpenVPNConnection{}, h.notFoundErr(selection) + } + + var connections []models.OpenVPNConnection + for _, server := range servers { + for _, IP := range server.IPs { + connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol}) + } + } + + return pickRandomConnection(connections, h.randSource), nil +} + +func (h *hideMyAss) BuildConf(connection models.OpenVPNConnection, + username string, settings configuration.OpenVPN) (lines []string) { + if len(settings.Cipher) == 0 { + settings.Cipher = aes256cbc + } + + lines = []string{ + "client", + "dev tun", + "nobind", + "persist-key", + "ping 5", + "ping-exit 30", + "ping-timer-rem", + "tls-exit", + + // HideMyAss specific + "remote-cert-tls server", // updated name of ns-cert-type + // "route-metric 1", + "comp-lzo yes", + "comp-noadapt", + + // Added constant values + "mute-replay-warnings", + "auth-nocache", + "pull-filter ignore \"auth-token\"", // prevent auth failed loops + `pull-filter ignore "ping-restart"`, + "auth-retry nointeract", + "suppress-timestamps", + + // Modified variables + "verb " + strconv.Itoa(settings.Verbosity), + "auth-user-pass " + constants.OpenVPNAuthConf, + "proto " + connection.Protocol, + "remote " + connection.IP.String() + strconv.Itoa(int(connection.Port)), + "cipher " + settings.Cipher, + } + + if !settings.Root { + lines = append(lines, "user "+username) + } + + if settings.MSSFix > 0 { + lines = append(lines, "mssfix "+strconv.Itoa(int(settings.MSSFix))) + } + + lines = append(lines, []string{ + "", + "-----BEGIN CERTIFICATE-----", + constants.HideMyAssCA, + "-----END CERTIFICATE-----", + "", + "", + "-----BEGIN CERTIFICATE-----", + constants.HideMyAssCertificate, + "-----END CERTIFICATE-----", + "", + "", + "-----BEGIN RSA PRIVATE KEY-----", + constants.HideMyAssRSAPrivateKey, + "-----END RSA PRIVATE KEY-----", + "", + "", + }...) + + return lines +} + +func (h *hideMyAss) PortForward(ctx context.Context, client *http.Client, + openFile os.OpenFileFunc, pfLogger logging.Logger, gateway net.IP, fw firewall.Configurator, + syncState func(port uint16) (pfFilepath string)) { + panic("port forwarding is not supported for hideMyAss") +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 15cf9d5e..960eef04 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -27,6 +27,8 @@ func New(provider string, allServers models.AllServers, timeNow timeNowFunc) Pro switch provider { case constants.Cyberghost: return newCyberghost(allServers.Cyberghost.Servers, timeNow) + case constants.HideMyAss: + return newHideMyAss(allServers.HideMyAss.Servers, timeNow) case constants.Mullvad: return newMullvad(allServers.Mullvad.Servers, timeNow) case constants.Nordvpn: diff --git a/internal/storage/merge.go b/internal/storage/merge.go index ec884332..6468eeea 100644 --- a/internal/storage/merge.go +++ b/internal/storage/merge.go @@ -18,6 +18,7 @@ func (s *storage) mergeServers(hardcoded, persisted models.AllServers) models.Al return models.AllServers{ Version: hardcoded.Version, Cyberghost: s.mergeCyberghost(hardcoded.Cyberghost, persisted.Cyberghost), + HideMyAss: s.mergeHideMyAss(hardcoded.HideMyAss, persisted.HideMyAss), Mullvad: s.mergeMullvad(hardcoded.Mullvad, persisted.Mullvad), Nordvpn: s.mergeNordVPN(hardcoded.Nordvpn, persisted.Nordvpn), Privado: s.mergePrivado(hardcoded.Privado, persisted.Privado), @@ -39,6 +40,22 @@ func (s *storage) mergeCyberghost(hardcoded, persisted models.CyberghostServers) return persisted } +func (s *storage) mergeHideMyAss(hardcoded, persisted models.HideMyAssServers) models.HideMyAssServers { + if persisted.Timestamp <= hardcoded.Timestamp { + return hardcoded + } + versionDiff := hardcoded.Version - persisted.Version + if versionDiff > 0 { + s.logger.Info( + "HideMyAss servers from file discarded because they are %d versions behind", + versionDiff) + return hardcoded + } + s.logger.Info("Using HideMyAss servers from file (%s more recent)", + getUnixTimeDifference(persisted.Timestamp, hardcoded.Timestamp)) + return persisted +} + func (s *storage) mergeMullvad(hardcoded, persisted models.MullvadServers) models.MullvadServers { if persisted.Timestamp <= hardcoded.Timestamp { return hardcoded diff --git a/internal/storage/sync.go b/internal/storage/sync.go index 6fa7d87e..bb479931 100644 --- a/internal/storage/sync.go +++ b/internal/storage/sync.go @@ -18,6 +18,7 @@ var ( func countServers(allServers models.AllServers) int { return len(allServers.Cyberghost.Servers) + + len(allServers.HideMyAss.Servers) + len(allServers.Mullvad.Servers) + len(allServers.Nordvpn.Servers) + len(allServers.Privado.Servers) + diff --git a/internal/updater/errors.go b/internal/updater/errors.go index 761e5c94..a716dec0 100644 --- a/internal/updater/errors.go +++ b/internal/updater/errors.go @@ -3,6 +3,7 @@ package updater import "errors" var ( - ErrHTTPStatusCodeNotOK = errors.New("HTTP status code not OK") - ErrUnmarshalResponseBody = errors.New("cannot unmarshal response body") + ErrHTTPStatusCodeNotOK = errors.New("HTTP status code not OK") + ErrUnmarshalResponseBody = errors.New("cannot unmarshal response body") + ErrUpdateServerInformation = errors.New("failed updating server information") ) diff --git a/internal/updater/hma.go b/internal/updater/hma.go new file mode 100644 index 00000000..62e633ce --- /dev/null +++ b/internal/updater/hma.go @@ -0,0 +1,270 @@ +package updater + +import ( + "context" + "fmt" + "io" + "net/http" + "regexp" + "sort" + "strings" + "time" + "unicode" + + "github.com/qdm12/gluetun/internal/models" +) + +func (u *updater) updateHideMyAss(ctx context.Context) (err error) { + servers, warnings, err := findHideMyAssServers(ctx, u.client, u.lookupIP) + if u.options.CLI { + for _, warning := range warnings { + u.logger.Warn("HideMyAss: %s", warning) + } + } + if err != nil { + return fmt.Errorf("%w: HideMyAss: %s", ErrUpdateServerInformation, err) + } + if u.options.Stdout { + u.println(stringifyHideMyAssServers(servers)) + } + u.servers.HideMyAss.Timestamp = u.timeNow().Unix() + u.servers.HideMyAss.Servers = servers + return nil +} + +func findHideMyAssServers(ctx context.Context, client *http.Client, lookupIP lookupIPFunc) ( + servers []models.HideMyAssServer, warnings []string, err error) { + TCPhostToURL, err := findHideMyAssHostToURLForProto(ctx, client, "TCP") + if err != nil { + return nil, nil, err + } + + UDPhostToURL, err := findHideMyAssHostToURLForProto(ctx, client, "UDP") + if err != nil { + return nil, nil, err + } + + uniqueHosts := make(map[string]struct{}, len(TCPhostToURL)) + for host := range TCPhostToURL { + uniqueHosts[host] = struct{}{} + } + for host := range UDPhostToURL { + uniqueHosts[host] = struct{}{} + } + + hosts := make([]string, len(uniqueHosts)) + i := 0 + for host := range uniqueHosts { + hosts[i] = host + i++ + } + + const failOnErr = false + const resolveRepetition = 5 + const timeBetween = 2 * time.Second + hostToIPs, warnings, _ := parallelResolve(ctx, lookupIP, hosts, resolveRepetition, timeBetween, failOnErr) + + servers = make([]models.HideMyAssServer, 0, len(hostToIPs)) + for host, IPs := range hostToIPs { + tcpURL, tcp := TCPhostToURL[host] + udpURL, udp := UDPhostToURL[host] + + var url, protocol string + if tcp { + url = tcpURL + protocol = "TCP" + } else if udp { + url = udpURL + protocol = "UDP" + } + country, region, city := parseHideMyAssURL(url, protocol) + + server := models.HideMyAssServer{ + Country: country, + Region: region, + City: city, + Hostname: host, + IPs: IPs, + TCP: tcp, + UDP: udp, + } + servers = append(servers, server) + } + + sort.Slice(servers, func(i, j int) bool { + return servers[i].Country+servers[i].Region+servers[i].City+servers[i].Hostname < + servers[j].Country+servers[j].Region+servers[j].City+servers[j].Hostname + }) + + return servers, warnings, nil +} + +func findHideMyAssHostToURLForProto(ctx context.Context, client *http.Client, protocol string) ( + hostToURL map[string]string, err error) { + indexURL := "https://vpn.hidemyass.com/vpn-config/" + strings.ToUpper(protocol) + "/" + + urls, err := fetchHideMyAssHTTPIndex(ctx, client, indexURL) + if err != nil { + return nil, err + } + + return fetchMultiOvpnFiles(ctx, client, urls) +} + +func parseHideMyAssURL(url, protocol string) (country, region, city string) { + lastSlashIndex := strings.LastIndex(url, "/") + url = url[lastSlashIndex+1:] + + suffix := "." + strings.ToUpper(protocol) + ".ovpn" + url = strings.TrimSuffix(url, suffix) + + parts := strings.Split(url, ".") + + switch len(parts) { + case 1: + country = parts[0] + return country, "", "" + case 2: //nolint:gomnd + country = parts[0] + city = parts[1] + default: + country = parts[0] + region = parts[1] + city = parts[2] + } + + return camelCaseToWords(country), camelCaseToWords(region), camelCaseToWords(city) +} + +func camelCaseToWords(camelCase string) (words string) { + wasLowerCase := false + for _, r := range camelCase { + if wasLowerCase && unicode.IsUpper(r) { + words += " " + } + wasLowerCase = unicode.IsLower(r) + words += string(r) + } + return words +} + +var hideMyAssIndexRegex = regexp.MustCompile(`.+\.ovpn`) + +func fetchHideMyAssHTTPIndex(ctx context.Context, client *http.Client, indexURL string) (urls []string, err error) { + htmlCode, err := fetchFile(ctx, client, indexURL) + if err != nil { + return nil, err + } + + if !strings.HasSuffix(indexURL, "/") { + indexURL += "/" + } + + lines := strings.Split(string(htmlCode), "\n") + for _, line := range lines { + found := hideMyAssIndexRegex.FindString(line) + if len(found) == 0 { + continue + } + const prefix = `.ovpn">` + const suffix = `` + startIndex := strings.Index(found, prefix) + len(prefix) + endIndex := strings.Index(found, suffix) + filename := found[startIndex:endIndex] + url := indexURL + filename + if !strings.HasSuffix(url, ".ovpn") { + continue + } + urls = append(urls, url) + } + + return urls, nil +} + +func fetchMultiOvpnFiles(ctx context.Context, client *http.Client, urls []string) ( + hostToURL map[string]string, err error) { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + hostToURL = make(map[string]string, len(urls)) + + type Result struct { + url string + host string + } + results := make(chan Result) + errors := make(chan error) + for _, url := range urls { + go func(url string) { + host, err := fetchOvpnFile(ctx, client, url) + if err != nil { + errors <- fmt.Errorf("%w: for %s", err, url) + return + } + results <- Result{ + url: url, + host: host, + } + }(url) + } + + for range urls { + select { + case newErr := <-errors: + if err == nil { // only assign to the first error + err = newErr + cancel() // stop other operations, this will trigger other errors we ignore + } + case result := <-results: + hostToURL[result.host] = result.url + } + } + + if err != nil { + return nil, err + } + + return hostToURL, nil +} + +func fetchOvpnFile(ctx context.Context, client *http.Client, url string) (hostname string, err error) { + b, err := fetchFile(ctx, client, url) + if err != nil { + return "", err + } + + const rejectIP = true + const rejectDomain = false + hosts := extractRemoteHostsFromOpenvpn(b, rejectIP, rejectDomain) + if len(hosts) == 0 { + return "", errRemoteHostNotFound + } + + return hosts[0], nil +} + +func fetchFile(ctx context.Context, client *http.Client, url string) (b []byte, err error) { + request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return nil, err + } + + response, err := client.Do(request) + if err != nil { + return nil, err + } + defer response.Body.Close() + + return io.ReadAll(response.Body) +} + +func stringifyHideMyAssServers(servers []models.HideMyAssServer) (s string) { + s = "func HideMyAssServers() []models.HideMyAssServer {\n" + s += " return []models.HideMyAssServer{\n" + for _, server := range servers { + s += " " + server.String() + ",\n" + } + s += " }\n" + s += "}" + return s +} diff --git a/internal/updater/updater.go b/internal/updater/updater.go index 2f5acfdd..49d68fe8 100644 --- a/internal/updater/updater.go +++ b/internal/updater/updater.go @@ -60,6 +60,16 @@ func (u *updater) UpdateServers(ctx context.Context) (allServers models.AllServe } } + if u.options.HideMyAss { + u.logger.Info("updating HideMyAss servers...") + if err := u.updateHideMyAss(ctx); err != nil { + u.logger.Error(err) + } + if err := ctx.Err(); err != nil { + return allServers, err + } + } + if u.options.Mullvad { u.logger.Info("updating Mullvad servers...") if err := u.updateMullvad(ctx); err != nil {