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 = "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"
+ 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 {