diff --git a/Dockerfile b/Dockerfile index 046053f02..75097c1ed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,7 +42,7 @@ ENV VPNSP=pia \ UID=1000 \ GID=1000 \ IP_STATUS_FILE="/ip" \ - # PIA, Windscribe, Surfshark, Cyberghost, Vyprvpn, NordVPN only + # PIA, Windscribe, Surfshark, Cyberghost, Vyprvpn, NordVPN, PureVPN only USER= \ PASSWORD= \ REGION= \ @@ -50,9 +50,10 @@ ENV VPNSP=pia \ PIA_ENCRYPTION=strong \ PORT_FORWARDING=off \ PORT_FORWARDING_STATUS_FILE="/forwarded_port" \ - # Mullvad only + # Mullvad and PureVPN only COUNTRY= \ CITY= \ + # Mullvad only ISP= \ # Mullvad and Windscribe only PORT= \ @@ -100,7 +101,7 @@ ENTRYPOINT ["/entrypoint"] EXPOSE 8000/tcp 8888/tcp 8388/tcp 8388/udp HEALTHCHECK --interval=10m --timeout=10s --start-period=30s --retries=2 CMD /entrypoint healthcheck RUN apk add -q --progress --no-cache --update openvpn ca-certificates iptables ip6tables unbound tinyproxy tzdata && \ - echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \ + echo "http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \ apk add -q --progress --no-cache --update shadowsocks-libev && \ rm -rf /var/cache/apk/* /etc/unbound/* /usr/sbin/unbound-* /etc/tinyproxy/tinyproxy.conf && \ deluser openvpn && \ diff --git a/README.md b/README.md index 39bc9f98d..52847cdfe 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Gluetun VPN client *Lightweight swiss-knife-like VPN client to tunnel to Private Internet Access, -Mullvad, Windscribe, Surfshark Cyberghost, VyprVPN and NordVPN VPN servers, using Go, OpenVPN, +Mullvad, Windscribe, Surfshark Cyberghost, VyprVPN, NordVPN and PureVPN VPN servers, using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and Tinyproxy* **ANNOUNCEMENT**: *[Video of the Git history of Gluetun](https://youtu.be/khipOYJtGJ0)* @@ -35,7 +35,7 @@ iptables, DNS over TLS, ShadowSocks and Tinyproxy* ## Features - Based on Alpine 3.12 for a small Docker image of 52MB -- Supports **Private Internet Access**, **Mullvad**, **Windscribe**, **Surfshark**, **Cyberghost**, **Vyprvpn** and **NordVPN** servers +- Supports **Private Internet Access**, **Mullvad**, **Windscribe**, **Surfshark**, **Cyberghost**, **Vyprvpn**, **NordVPN** and **PureVPN** servers - 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 - Choose the vpn network protocol, `udp` or `tcp` @@ -55,6 +55,7 @@ iptables, DNS over TLS, ShadowSocks and Tinyproxy* - **Cyberghost**: Pick the [region](https://github.com/qdm12/private-internet-access-docker/wiki/Cyberghost) and server group. - **VyprVPN**: Pick the [region](https://www.vyprvpn.com/server-locations), port forwarding works by default (see `FIREWALL_VPN_INPUT_PORTS` though) - **NordVPN**: Pick the region and optionally the server number +- **PureVPN**: Pick the region, and optionally the country and city ### Extra niche features @@ -77,6 +78,7 @@ iptables, DNS over TLS, ShadowSocks and Tinyproxy* - Cyberghost: **username**, **password** and **device client key file** ([sign up](https://www.cyberghostvpn.com/en_US/buy/cyberghost-vpn-4)) - Vyprvpn: **username** and **password** - NordVPN: **username** and **password** + - PureVPN: **username** and **password** - If you have a host or router firewall, please refer [to the firewall documentation](https://github.com/qdm12/private-internet-access-docker/blob/master/doc/firewall.md) 1. On some devices you may need to setup your tunnel kernel module on your host with `insmod /lib/modules/tun.ko` or `modprobe tun` @@ -125,7 +127,7 @@ Want more testing? โ–ถ [see the Wiki](https://github.com/qdm12/private-internet- | Variable | Default | Choices | Description | | --- | --- | --- | --- | -| ๐Ÿ `VPNSP` | `private internet access` | `private internet access`, `mullvad`, `windscribe`, `surfshark`, `vyprvpn`, `nordvpn` | VPN Service Provider | +| ๐Ÿ `VPNSP` | `private internet access` | `private internet access`, `mullvad`, `windscribe`, `surfshark`, `vyprvpn`, `nordvpn`, `purevpn` | VPN Service Provider | | `IP_STATUS_FILE` | `/ip` | Any filepath | Filepath to store the public IP address assigned | | `PROTOCOL` | `udp` | `udp` or `tcp` | Network protocol to use | | `OPENVPN_VERBOSITY` | `1` | `0` to `6` | Openvpn verbosity level | @@ -212,6 +214,15 @@ Want more testing? โ–ถ [see the Wiki](https://github.com/qdm12/private-internet- | `REGION` | | One of the NordVPN server country, i.e. `Switzerland` | VPN server country | | `SERVER_NUMBER` | | Server integer number | Optional server number. For example `251` for `Italy #251` | +- PureVPN + + | Variable | Default | Choices | Description | + | --- | --- | --- | --- | + | ๐Ÿ `USER` | | | Your user ID | + | ๐Ÿ `REGION` | | One of the [PureVPN regions](https://support.purevpn.com/vpn-servers) | VPN server region | + | `COUNTRY` | | One of the [PureVPN countries](https://support.purevpn.com/vpn-servers) | VPN server country | + | `CITY` | | One of the [PureVPN cities](https://support.purevpn.com/vpn-servers) | VPN server city | + ### DNS over TLS None of the following values are required. diff --git a/cmd/locationToSubdomain/main.go b/cmd/locationToSubdomain/main.go new file mode 100644 index 000000000..addb323c6 --- /dev/null +++ b/cmd/locationToSubdomain/main.go @@ -0,0 +1,111 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "net/http" + "os" + "sort" + "strings" + "time" + + "github.com/qdm12/golibs/network" +) + +func main() { + os.Exit(_main()) +} + +func _main() int { + provider := flag.String("provider", "purevpn", "VPN provider to map location to subdomain, can be 'purevpn'") + flag.Parse() + + client := network.NewClient(5 * time.Second) + switch *provider { + case "purevpn": + servers, warnings, err := purevpn(client) + if err != nil { + fmt.Println(err) + return 1 + } + for _, server := range servers { + fmt.Printf( + "{subdomain: %q, region: %q, country: %q, city: %q},\n", + server.subdomain, server.region, server.country, server.city, + ) + } + fmt.Print("\n\n") + for _, warning := range warnings { + fmt.Println(warning) + } + default: + fmt.Printf("Provider %q is not supported\n", *provider) + return 1 + } + return 0 +} + +type purevpnServer struct { + region string + country string + city string + subdomain string // without -tcp or -udp suffix +} + +func purevpn(client network.Client) (servers []purevpnServer, warnings []string, err error) { + content, status, err := client.GetContent("https://support.purevpn.com/vpn-servers") + if err != nil { + return nil, nil, err + } else if status != http.StatusOK { + return nil, nil, fmt.Errorf("HTTP status %d from Purevpn", status) + } + const jsonPrefix = "" + s := string(content) + jsonPrefixIndex := strings.Index(s, jsonPrefix) + if jsonPrefixIndex == -1 { + return nil, nil, fmt.Errorf("cannot find prefix %s in html", jsonPrefix) + } + if len(s[jsonPrefixIndex:]) == len(jsonPrefix) { + return nil, nil, fmt.Errorf("no body after json prefix %s", jsonPrefix) + } + s = s[jsonPrefixIndex+len(jsonPrefix):] + endIndex := strings.Index(s, jsonSuffix) + s = s[:endIndex] + var data []struct { + Region string `json:"region_name"` + Country string `json:"country_name"` + City string `json:"city_name"` + TCP string `json:"tcp"` + UDP string `json:"udp"` + } + if err := json.Unmarshal([]byte(s), &data); err != nil { + return nil, nil, err + } + sort.Slice(data, func(i, j int) bool { + if data[i].Region == data[j].Region { + if data[i].Country == data[j].Country { + return data[i].City < data[j].City + } + return data[i].Country < data[j].Country + } + return data[i].Region < data[j].Region + }) + for i := range data { + if data[i].UDP == "" && data[i].TCP == "" { + warnings = append(warnings, fmt.Sprintf("server %s %s %s does not support TCP and UDP for openvpn", data[i].Region, data[i].Country, data[i].City)) + continue + } + if data[i].UDP == "" || data[i].TCP == "" { + warnings = append(warnings, fmt.Sprintf("server %s %s %s does not support TCP or udp for openvpn", data[i].Region, data[i].Country, data[i].City)) + } + servers = append(servers, purevpnServer{ + region: data[i].Region, + country: data[i].Country, + city: data[i].City, + subdomain: strings.TrimSuffix(data[i].TCP, "-tcp.pointtoserver.com"), + }) + } + return servers, warnings, nil +} diff --git a/cmd/resolver/main.go b/cmd/resolver/main.go index 2c3e9d9ee..6d9f30a04 100644 --- a/cmd/resolver/main.go +++ b/cmd/resolver/main.go @@ -18,7 +18,7 @@ func main() { func _main(ctx context.Context) int { resolverAddress := flag.String("resolver", "1.1.1.1", "DNS Resolver IP address to use") - provider := flag.String("provider", "pia", "VPN provider to resolve for, 'pia', 'windscribe', 'cyberghost' or 'vyprvpn'") + provider := flag.String("provider", "pia", "VPN provider to resolve for, 'pia', 'windscribe', 'cyberghost', 'vyprvpn' or 'purevpn'") region := flag.String("region", "all", "Comma separated list of VPN provider region names to resolve for, use 'all' to resolve all") flag.Parse() @@ -43,6 +43,9 @@ func _main(ctx context.Context) int { case "vyprvpn": domain = "vyprvpn.com" servers = vyprvpnServers() + case "purevpn": + domain = "pointtoserver.com" + servers = purevpnServers() default: fmt.Printf("Provider %q is not supported\n", *provider) return 1 @@ -135,6 +138,11 @@ func formatLine(provider string, s server, ips []net.IP) string { "{Region: %q, IPs: []net.IP{%s}},", s.region, ipString, ) + case "purevpn": + return fmt.Sprintf( + "{Region: %q, Country: %q, City: %q, IPs: []net.IP{%s}},", + s.region, s.country, s.city, ipString, + ) } return "" } @@ -197,6 +205,8 @@ type server struct { subdomain string region string group string // only for cyberghost + country string // only for purevpn + city string // only for purevpn } func piaServers() []server { @@ -747,3 +757,164 @@ func vyprvpnServers() []server { {subdomain: "vn1", region: "Vietnam"}, } } + +func purevpnServers() []server { + servers := []server{ + {subdomain: "vlus-dz1-ovpn", region: "Africa", country: "Algeria", city: "Algiers"}, + {subdomain: "vlus-ao1-ovpn", region: "Africa", country: "Angola", city: "Benguela"}, + {subdomain: "vleu-cv-ovpn", region: "Africa", country: "Cape Verde", city: "Praia"}, + {subdomain: "vlus-eg1-ovpn", region: "Africa", country: "Egypt", city: "Cairo"}, + {subdomain: "et1-ovpn", region: "Africa", country: "Ethiopia", city: "Addis Ababa"}, + {subdomain: "gh1-ovpn", region: "Africa", country: "Ghana", city: "Accra"}, + {subdomain: "ke1-ovpn", region: "Africa", country: "Kenya", city: "Mombasa"}, + {subdomain: "vlus-mg1-ovpn", region: "Africa", country: "Madagascar", city: "Antananarivo"}, + {subdomain: "vlus-mr1-ovpn", region: "Africa", country: "Mauritania", city: "Nouakchott"}, + {subdomain: "mu1-ovpn", region: "Africa", country: "Mauritius", city: "Port Louis"}, + {subdomain: "ma1-ovpn", region: "Africa", country: "Morocco", city: "Rabat"}, + {subdomain: "vlus-ne1-ovpn", region: "Africa", country: "Niger", city: "Niamey"}, + {subdomain: "ng1-ovpn", region: "Africa", country: "Nigeria", city: "Suleja"}, + {subdomain: "vlus-sn1-ovpn", region: "Africa", country: "Senegal", city: "Dakar"}, + {subdomain: "sc1-ovpn", region: "Africa", country: "Seychelles", city: "Victoria"}, + {subdomain: "za2-ovpn", region: "Africa", country: "South Africa", city: "Johannesburg"}, + {subdomain: "vlus-tz1-ovpn", region: "Africa", country: "Tanzania", city: "Dar Es Salaam"}, + {subdomain: "vlus-tn1-ovpn", region: "Africa", country: "Tunisia", city: "Tunis"}, + {subdomain: "vlus-af1-ovpn", region: "Asia", country: "Afghanistan", city: "Kabul"}, + {subdomain: "sg2-ovpn", region: "Asia", country: "Armenia", city: "Singapore"}, + {subdomain: "az1-ovpn", region: "Asia", country: "Azerbaijan", city: "Baku"}, + {subdomain: "vlus-bd1-ovpn", region: "Asia", country: "Bangladesh", city: "Dhaka"}, + {subdomain: "bn2-ovpn", region: "Asia", country: "Brunei Darussalam", city: "Bandar Seri Begawan"}, + {subdomain: "kh1-ovpn", region: "Asia", country: "Cambodia", city: "Phnom Penh"}, + {subdomain: "hk2-ovpn", region: "Asia", country: "Hong Kong (SAR)", city: "Hong Kong"}, + {subdomain: "in2-ovpn", region: "Asia", country: "India", city: "Chennai"}, + {subdomain: "idn1-ovpn", region: "Asia", country: "Indonesia", city: "Jakarta"}, + {subdomain: "jp-tk1-ovpn", region: "Asia", country: "Japan", city: "Tokyo"}, + {subdomain: "vlus-kz1-ovpn", region: "Asia", country: "Kazakhstan", city: "Almaty"}, + {subdomain: "kr2-ovpn", region: "Asia", country: "Korea, South", city: "Seoul"}, + {subdomain: "vlus-kg1-ovpn", region: "Asia", country: "Kyrgyzstan", city: "Bishkek"}, + {subdomain: "vlus-la1-ovpn", region: "Asia", country: "Laos", city: "Vientiane"}, + {subdomain: "mo1-ovpn", region: "Asia", country: "Macao", city: "Beyrouth"}, + {subdomain: "my2-ovpn", region: "Asia", country: "Malaysia", city: "Johor Baharu"}, + {subdomain: "my-kl2-ovpn", region: "Asia", country: "Malaysia", city: "Kuala Lumpur"}, + {subdomain: "vlus-mn1-ovpn", region: "Asia", country: "Mongolia", city: "Ulaanbaatar"}, + {subdomain: "pk1-ovpn", region: "Asia", country: "Pakistan", city: "Islamabad"}, + {subdomain: "vlus-pg1-ovpn", region: "Asia", country: "Papua New Guinea", city: "Port Moresby"}, + {subdomain: "vlap-ph2-ovpn", region: "Asia", country: "Philippines", city: "Manila"}, + {subdomain: "vlus-lk1-ovpn", region: "Asia", country: "Sri Lanka", city: "Colombo"}, + {subdomain: "tw2-ovpn", region: "Asia", country: "Taiwan", city: "Taipei"}, + {subdomain: "vlus-tj-ovpn", region: "Asia", country: "Tajikistan", city: "Dushanbe"}, + {subdomain: "vlap-th2-ovpn", region: "Asia", country: "Thailand", city: "Bangkok"}, + {subdomain: "tr2-ovpn", region: "Asia", country: "Turkey", city: "Istanbul"}, + {subdomain: "vlus-tm1-ovpn", region: "Asia", country: "Turkmenistan", city: "Ashgabat"}, + {subdomain: "vlus-uz-ovpn", region: "Asia", country: "Uzbekistan", city: "Tashkent"}, + {subdomain: "vlap-vn2-ovpn", region: "Asia", country: "Vietnam", city: "Hanoi"}, + {subdomain: "al1-ovpn", region: "Europe", country: "Albania", city: "Tirane"}, + {subdomain: "vleu-am1-ovpn", region: "Europe", country: "Armenia", city: "Yerevan"}, + {subdomain: "at2-ovpn", region: "Europe", country: "Austria", city: "Vienna"}, + {subdomain: "vleu-be2-ovpn", region: "Europe", country: "Belgium", city: "Brussels"}, + {subdomain: "ba1-ovpn", region: "Europe", country: "Bosnia and Herzegovina", city: "Sarajevo"}, + {subdomain: "bg2-ovpn", region: "Europe", country: "Bulgaria", city: "Sofia"}, + {subdomain: "vlus-hr1-ovpn", region: "Europe", country: "Croatia", city: "Zagreb"}, + {subdomain: "cy1-ovpn", region: "Europe", country: "Cyprus", city: "Nicosia"}, + {subdomain: "dk2-ovpn", region: "Europe", country: "Denmark", city: "Copenhagen"}, + {subdomain: "ee1-ovpn", region: "Europe", country: "Estonia", city: "Tallinn"}, + {subdomain: "fr2-ovpn", region: "Europe", country: "France", city: "Paris"}, + {subdomain: "vlus-ge1-ovpn", region: "Europe", country: "Georgia", city: "Tbilisi"}, + {subdomain: "de2-ovpn", region: "Europe", country: "Germany", city: "Frankfurt"}, + {subdomain: "de2-ovpn", region: "Europe", country: "Germany", city: "Munich"}, + {subdomain: "de-ao1-ovpn", region: "Europe", country: "Germany", city: "Nuremberg"}, + {subdomain: "gr2-ovpn", region: "Europe", country: "Greece", city: "Thessaloniki"}, + {subdomain: "hu2-ovpn", region: "Europe", country: "Hungary", city: "Budapest"}, + {subdomain: "is1-ovpn", region: "Europe", country: "Iceland", city: "Reykjavik"}, + {subdomain: "ie2-ovpn", region: "Europe", country: "Ireland", city: "Dublin"}, + {subdomain: "im1-ovpn", region: "Europe", country: "Isle of Man", city: "Onchan"}, + {subdomain: "vlus-it1-ovpn", region: "Europe", country: "Italy", city: "Milano"}, + {subdomain: "lv1-ovpn", region: "Europe", country: "Latvia", city: "RIGA"}, + {subdomain: "li1-ovpn", region: "Europe", country: "Liechtenstein", city: "Vaduz"}, + {subdomain: "lt1-ovpn", region: "Europe", country: "Lithuania", city: "Vilnius"}, + {subdomain: "lu2-ovpn", region: "Europe", country: "Luxembourg", city: "Luxembourg"}, + {subdomain: "mt1-ovpn", region: "Europe", country: "Malta", city: "Sliema"}, + {subdomain: "mn1-ovpn", region: "Europe", country: "Monaco", city: "Monaco"}, + {subdomain: "vleu-me1-ovpn", region: "Europe", country: "Montenegro", city: "Podgorica"}, + {subdomain: "nl2-ovpn", region: "Europe", country: "Netherlands", city: "Amsterdam"}, + {subdomain: "vleu-no2-ovpn", region: "Europe", country: "Norway", city: "Oslo"}, + {subdomain: "pl2-ovpn", region: "Europe", country: "Poland", city: "Warsaw"}, + {subdomain: "pt2-ovpn", region: "Europe", country: "Portugal", city: "Lisbon"}, + {subdomain: "ro2-ovpn", region: "Europe", country: "Romania", city: "Bucharest"}, + {subdomain: "rs2-ovpn", region: "Europe", country: "Serbia", city: "Niลก"}, + {subdomain: "sk1-ovpn", region: "Europe", country: "Slovakia", city: "Bratislava"}, + {subdomain: "si1-ovpn", region: "Europe", country: "Slovenia", city: "Ljubljana"}, + {subdomain: "es-ovpn", region: "Europe", country: "Spain", city: "Barcelona"}, + {subdomain: "vlus-se1-ovpn", region: "Europe", country: "Sweden", city: "Stockholm"}, + {subdomain: "ch2-ovpn", region: "Europe", country: "Switzerland", city: "Zurich"}, + {subdomain: "ukg2-ovpn", region: "Europe", country: "United Kingdom", city: "Gosport"}, + {subdomain: "ukl2-ovpn", region: "Europe", country: "United Kingdom", city: "London"}, + {subdomain: "ukm2-ovpn", region: "Europe", country: "United Kingdom", city: "Maidenhead"}, + {subdomain: "vlus-uk-man1-ovpn", region: "Europe", country: "United Kingdom", city: "Manchester"}, + {subdomain: "bh-ovpn", region: "Middle East", country: "Bahrain", city: "Manama"}, + {subdomain: "vlus-jo1-ovpn", region: "Middle East", country: "Jordan", city: "Amman"}, + {subdomain: "vlus-kw1-ovpn", region: "Middle East", country: "Kuwait", city: "Kuwait"}, + {subdomain: "om1-ovpn", region: "Middle East", country: "Oman", city: "Salalah"}, + {subdomain: "qa1-ovpn", region: "Middle East", country: "Qatar", city: "Doha"}, + {subdomain: "sa1-ovpn", region: "Middle East", country: "Saudi Arabia", city: "Jeddah"}, + {subdomain: "ae2-ovpn", region: "Middle East", country: "United Arab Emirates", city: "Dubai"}, + {subdomain: "aw1-ovpn", region: "North America", country: "Aruba", city: "Oranjestad"}, + {subdomain: "vleu-bb-ovpn", region: "North America", country: "Barbados", city: "Bridgetown"}, + {subdomain: "bz1-ovpn", region: "North America", country: "Belize", city: "Belmopan"}, + {subdomain: "vleu-bm-ovpn", region: "North America", country: "Bermuda", city: "Hamilton"}, + {subdomain: "caq1-ovpn", region: "North America", country: "Canada", city: "Montreal"}, + {subdomain: "cato-ovpn", region: "North America", country: "Canada", city: "Toronto"}, + {subdomain: "cav2-ovpn", region: "North America", country: "Canada", city: "Vancouver"}, + {subdomain: "vleu-ky-ovpn", region: "North America", country: "Cayman Islands", city: "George Town"}, + {subdomain: "vlus-cr1-ovpn", region: "North America", country: "Costa Rica", city: "San Jose"}, + {subdomain: "vleu-dm-ovpn", region: "North America", country: "Dominica", city: "Roseau"}, + {subdomain: "vleu-do-ovpn", region: "North America", country: "Dominican Republic", city: "Santo Domingo"}, + {subdomain: "vleu-sv-ovpn", region: "North America", country: "El Salvador", city: "San Salvador"}, + {subdomain: "vleu-gd-ovpn", region: "North America", country: "Grenada", city: "St George's"}, + {subdomain: "vleu-gt-ovpn", region: "North America", country: "Guatemala", city: "Guatemala"}, + {subdomain: "vleu-ht1-ovpn", region: "North America", country: "Haiti", city: "PORT-AU-PRINCE"}, + {subdomain: "vleu-hn-ovpn", region: "North America", country: "Honduras", city: "TEGUCIGALPA"}, + {subdomain: "jm1-ovpn", region: "North America", country: "Jamaica", city: "Kingston"}, + {subdomain: "vlus-mx2-ovpn", region: "North America", country: "Mexico", city: "Mexico City"}, + {subdomain: "vleu-ms-ovpn", region: "North America", country: "Montserrat", city: "plymouth"}, + {subdomain: "pr1-ovpn", region: "North America", country: "Puerto Rico", city: "San Juan"}, + {subdomain: "vleu-lc-ovpn", region: "North America", country: "Saint Lucia", city: "Castries"}, + {subdomain: "bs1-ovpn", region: "North America", country: "The Bahamas", city: "Freeport"}, + {subdomain: "vleu-tt-ovpn", region: "North America", country: "Trinidad and Tobago", city: "Port of Spain"}, + {subdomain: "vleu-tc-ovpn", region: "North America", country: "Turks and Caicos Islands", city: "Balfour Town"}, + {subdomain: "usva-ovpn", region: "North America", country: "United States", city: "Ashburn"}, + {subdomain: "usil2-ovpn", region: "North America", country: "United States", city: "Chicago"}, + {subdomain: "usoh1-ovpn", region: "North America", country: "United States", city: "Columbus"}, + {subdomain: "usga2-ovpn", region: "North America", country: "United States", city: "Georgia"}, + {subdomain: "ustx2-ovpn", region: "North America", country: "United States", city: "Houston"}, + {subdomain: "usla2-ovpn", region: "North America", country: "United States", city: "Los Angeles"}, + {subdomain: "usfl2-ovpn", region: "North America", country: "United States", city: "Miami"}, + {subdomain: "usnj2-ovpn", region: "North America", country: "United States", city: "New Jersey"}, + {subdomain: "usny2-ovpn", region: "North America", country: "United States", city: "New York"}, + {subdomain: "usphx2-ovpn", region: "North America", country: "United States", city: "Phoenix"}, + {subdomain: "usut2-ovpn", region: "North America", country: "United States", city: "Salt Lake City"}, + {subdomain: "ussf2-ovpn", region: "North America", country: "United States", city: "San Francisco"}, + {subdomain: "ussa-ovpn", region: "North America", country: "United States", city: "Seattle"}, + {subdomain: "uswdc2-ovpn", region: "North America", country: "United States", city: "Washington, D.C."}, + {subdomain: "au-bn-ovpn", region: "Oceania", country: "Australia", city: "Brisbane"}, + {subdomain: "au-me1-ovpn", region: "Oceania", country: "Australia", city: "Melbourne"}, + {subdomain: "au2-pe-ovpn", region: "Oceania", country: "Australia", city: "Perth"}, + {subdomain: "au-sd2-ovpn", region: "Oceania", country: "Australia", city: "Sydney"}, + {subdomain: "nz2-ovpn", region: "Oceania", country: "New Zealand", city: "Auckland"}, + {subdomain: "vlus-ar1-ovpn", region: "South America", country: "Argentina", city: "Buenos Aires"}, + {subdomain: "vleu-bo-ovpn", region: "South America", country: "Bolivia", city: "Sucre"}, + {subdomain: "br2-ovpn", region: "South America", country: "Brazil", city: "Sao Paulo"}, + {subdomain: "vg1-ovpn", region: "South America", country: "British Virgin Island", city: "Road Town"}, + {subdomain: "vlbr-cl-ovpn", region: "South America", country: "Chile", city: "Santiago"}, + {subdomain: "co1-ovpn", region: "South America", country: "Colombia", city: "Bogota"}, + {subdomain: "ec1-ovpn", region: "South America", country: "Ecuador", city: "Quito"}, + {subdomain: "vleu-gy-ovpn", region: "South America", country: "Guyana", city: "Georgetown"}, + {subdomain: "pa2-ovpn", region: "South America", country: "Panama", city: "Panama City"}, + {subdomain: "vleu-py-ovpn", region: "South America", country: "Paraguay", city: "Asuncion"}, + {subdomain: "pe1-ovpn", region: "South America", country: "Peru", city: "Lima"}, + {subdomain: "vleu-sr-ovpn", region: "South America", country: "Suriname", city: "Paramaribo"}, + } + for i := range servers { + servers[i].subdomain += "-udp" + } + return servers +} diff --git a/internal/constants/purevpn.go b/internal/constants/purevpn.go new file mode 100644 index 000000000..d64bb55ed --- /dev/null +++ b/internal/constants/purevpn.go @@ -0,0 +1,198 @@ +package constants + +import ( + "net" + + "github.com/qdm12/private-internet-access-docker/internal/models" +) + +const ( + PurevpnCertificateAuthority = "MIIE6DCCA9CgAwIBAgIJAMjXFoeo5uSlMA0GCSqGSIb3DQEBCwUAMIGoMQswCQYDVQQGEwJISzEQMA4GA1UECBMHQ2VudHJhbDELMAkGA1UEBxMCSEsxGDAWBgNVBAoTD1NlY3VyZS1TZXJ2ZXJDQTELMAkGA1UECxMCSVQxGDAWBgNVBAMTD1NlY3VyZS1TZXJ2ZXJDQTEYMBYGA1UEKRMPU2VjdXJlLVNlcnZlckNBMR8wHQYJKoZIhvcNAQkBFhBtYWlsQGhvc3QuZG9tYWluMB4XDTE2MDExNTE1MzQwOVoXDTI2MDExMjE1MzQwOVowgagxCzAJBgNVBAYTAkhLMRAwDgYDVQQIEwdDZW50cmFsMQswCQYDVQQHEwJISzEYMBYGA1UEChMPU2VjdXJlLVNlcnZlckNBMQswCQYDVQQLEwJJVDEYMBYGA1UEAxMPU2VjdXJlLVNlcnZlckNBMRgwFgYDVQQpEw9TZWN1cmUtU2VydmVyQ0ExHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDluufhyLlyvXzPUL16kAWAdivl1roQv3QHbuRshyKacf/1Er1JqEbtW3Mx9Fvr/u27qU2W8lQI6DaJhU2BfijPe/KHkib55mvHzIVvoexxya26nk79F2c+d9PnuuMdThWQO3El5a/i2AASnM7T7piIBT2WRZW2i8RbfJaTT7G7LP7OpMKIV1qyBg/cWoO7cIWQW4jmzqrNryIkF0AzStLN1DxvnQZwgXBGv0CwuAkfQuNSLu0PQgPp0PhdukNZFllv5D29IhPr0Z+kwPtrAgPQo+lHlOBHBMUpDT4XChTPeAvMaUSBsqmonAE8UUHEabWrqYN/kWNHCNkYXMkiVmK1AgMBAAGjggERMIIBDTAdBgNVHQ4EFgQU456ijsFrYnzHBShLAPpOUqQ+Z2cwgd0GA1UdIwSB1TCB0oAU456ijsFrYnzHBShLAPpOUqQ+Z2ehga6kgaswgagxCzAJBgNVBAYTAkhLMRAwDgYDVQQIEwdDZW50cmFsMQswCQYDVQQHEwJISzEYMBYGA1UEChMPU2VjdXJlLVNlcnZlckNBMQswCQYDVQQLEwJJVDEYMBYGA1UEAxMPU2VjdXJlLVNlcnZlckNBMRgwFgYDVQQpEw9TZWN1cmUtU2VydmVyQ0ExHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW6CCQDI1xaHqObkpTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCvga2HMwOtUxWH/inL2qk24KX2pxLg939JNhqoyNrUpbDHag5xPQYXUmUpKrNJZ0z+o/ZnNUPHydTSXE7Z7E45J0GDN5E7g4pakndKnDLSjp03NgGsCGW+cXnz6UBPM5FStFvGdDeModeSUyoS9fjk+mYROvmiy5EiVDP91sKGcPLR7Ym0M7zl2aaqV7bb98HmMoBOxpeZQinof67nKrCsgz/xjktWFgcmPl4/PQSsmqQD0fTtWxGuRX+FzwvF2OCMCAJgp1RqJNlk2g50/kBIoJVPPCfjDFeDU5zGaWGSQ9+z1L6/z7VXdjUiHL0ouOcHwbiS4ZjTr9nMn6WdAHU2" + PurevpnCertificate = "MIIEnzCCA4egAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBqDELMAkGA1UEBhMCSEsxEDAOBgNVBAgTB0NlbnRyYWwxCzAJBgNVBAcTAkhLMRgwFgYDVQQKEw9TZWN1cmUtU2VydmVyQ0ExCzAJBgNVBAsTAklUMRgwFgYDVQQDEw9TZWN1cmUtU2VydmVyQ0ExGDAWBgNVBCkTD1NlY3VyZS1TZXJ2ZXJDQTEfMB0GCSqGSIb3DQEJARYQbWFpbEBob3N0LmRvbWFpbjAeFw0xNjAxMTUxNjE1MzhaFw0yNjAxMTIxNjE1MzhaMIGdMQswCQYDVQQGEwJISzEQMA4GA1UECBMHQ2VudHJhbDELMAkGA1UEBxMCSEsxFjAUBgNVBAoTDVNlY3VyZS1DbGllbnQxCzAJBgNVBAsTAklUMRYwFAYDVQQDEw1TZWN1cmUtQ2xpZW50MREwDwYDVQQpEwhjaGFuZ2VtZTEfMB0GCSqGSIb3DQEJARYQbWFpbEBob3N0LmRvbWFpbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxsnyn4v6xxDPnuDaYS0b9M1N8nxgg7OBPBlK+FWRxdTQ8yxt5U5CZGm7riVp7fya2J2iPZIgmHQEv/KbxztsHAVlYSfYYlalrnhEL3bDP2tY+N43AwB1k5BrPq2s1pPLT2XG951drDKG4PUuFHUP1sHzW5oQlfVCmxgIMAP8OYkCAwEAAaOCAV8wggFbMAkGA1UdEwQCMAAwLQYJYIZIAYb4QgENBCAWHkVhc3ktUlNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU9MwUnUDbQKKZKjoeieD2OD5NlAEwgd0GA1UdIwSB1TCB0oAU456ijsFrYnzHBShLAPpOUqQ+Z2ehga6kgaswgagxCzAJBgNVBAYTAkhLMRAwDgYDVQQIEwdDZW50cmFsMQswCQYDVQQHEwJISzEYMBYGA1UEChMPU2VjdXJlLVNlcnZlckNBMQswCQYDVQQLEwJJVDEYMBYGA1UEAxMPU2VjdXJlLVNlcnZlckNBMRgwFgYDVQQpEw9TZWN1cmUtU2VydmVyQ0ExHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW6CCQDI1xaHqObkpTATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQELBQADggEBAFyFo2VUX/UFixsdPdK9/Yt6mkCWc+XS1xbapGXXb9U1d+h1iBCIV9odUHgNCXWpz1hR5Uu/OCzaZ0asLE4IFMZlQmJs8sMT0c1tfPPGW45vxbL0lhqnQ8PNcBH7huNK7VFjUh4szXRKmaQPaM4S91R3L4CaNfVeHfAg7mN2m9Zn5Gto1Q1/CFMGKu2hxwGEw5p+X1czBWEvg/O09ckx/ggkkI1NcZsNiYQ+6Pz8DdGGX3+05YwLZu94+O6iIMrzxl/il0eK83g3YPbsOrASARvw6w/8sOnJCK5eOacl21oww875KisnYdWjHB1FiI+VzQ1/gyoDsL5kPTJVuu2CoG8=" + PurevpnKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMbJ8p+L+scQz57g2mEtG/TNTfJ8YIOzgTwZSvhVkcXU0PMsbeVOQmRpu64lae38mtidoj2SIJh0BL/ym8c7bBwFZWEn2GJWpa54RC92wz9rWPjeNwMAdZOQaz6trNaTy09lxvedXawyhuD1LhR1D9bB81uaEJX1QpsYCDAD/DmJAgMBAAECgYEAvTHbDupE5U0krUvHzBEIuHblptGlcfNYHoDcD3oxYR3pOGeiuElBexv+mgHVzcFLBrsQfJUlHLPfCWi3xmjRvDQcr7N7U1u7NIzazy/PpRBaKolMRiM1KMYi2DG0i4ZONwFT8bvNHOIrZzCLY54KDrqOn55OzC70WYjWh4t5evkCQQDkkzZUAeskBC9+JP/zLps8jhwfoLBWGw/zbC9ePDmX0N8MTZdcUpg6KUTf1wbkLUyVtIRjS2ao6qu1jWG6K0x3AkEA3qPWyaWQWCynhNDqu2U1cPb2kh5AJip+gqxO3emikAdajsSxeoyEC2AfyBITbeB1tvCUZH17J4i/0+OFTEQp/wJAb/zEOGJ8PzghwK8GC7JA8mk51DEZVAaMSRovFv9wxDXcoh191AjPdmdzzCuAv9iF1i8MUc3GbWoUWK39PIYsPwJAWh63sqfx5b8tj/WBDpnJKBDPfhYAoXJSA1L8GZeY1fQkE+ZKcPCwAmrGcpXeh3t0Krj3WDXyw+32uC5Apr5wwQJAPZwOOReaC4YNfBPZN9BdHvVjOYGGUffpI+X+hWpLRnQFJteAi+eqwyk0Oi0SkJB+a7jcerK2d7q7xhec5WHlng==" + PurevpnOpenvpnStaticKeyV1 = "e30af995f56d07426d9ba1f824730521d4283db4b4d0cdda9c6e8759a3799dcb7939b6a5989160c9660de0f6125cbb1f585b41c074b2fe88ecfcf17eab9a33be1352379cdf74952b588fb161a93e13df9135b2b29038231e02d657a6225705e6868ccb0c384ed11614690a1894bfbeb274cebf1fe9c2329bdd5c8a40fe8820624d2ea7540cd79ab76892db51fc371a3ac5fc9573afecb3fffe3281e61d72e91579d9b03d8cbf7909b3aebf4d90850321ee6b7d0a7846d15c27d8290e031e951e19438a4654663cad975e138f5bc5af89c737ad822f27e19057731f41e1e254cc9c95b7175c622422cde9f1f2cfd3510add94498b4d7133d3729dd214a16b27fb" +) + +func PurevpnRegionChoices() (choices []string) { + servers := PurevpnServers() + choices = make([]string, len(servers)) + for i := range servers { + choices[i] = servers[i].Region + } + return choices +} + +func PurevpnCountryChoices() (choices []string) { + servers := PurevpnServers() + choices = make([]string, len(servers)) + for i := range servers { + choices[i] = servers[i].Country + } + return choices +} + +func PurevpnCityChoices() (choices []string) { + servers := PurevpnServers() + choices = make([]string, len(servers)) + for i := range servers { + choices[i] = servers[i].City + } + return choices +} + +func PurevpnServers() []models.PurevpnServer { + return []models.PurevpnServer{ + {Region: "Africa", Country: "Algeria", City: "Algiers", IPs: []net.IP{{172, 94, 64, 2}}}, + {Region: "Africa", Country: "Angola", City: "Benguela", IPs: []net.IP{{45, 115, 26, 2}}}, + {Region: "Africa", Country: "Cape Verde", City: "Praia", IPs: []net.IP{{45, 74, 25, 2}}}, + {Region: "Africa", Country: "Egypt", City: "Cairo", IPs: []net.IP{{192, 198, 120, 122}}}, + {Region: "Africa", Country: "Ethiopia", City: "Addis Ababa", IPs: []net.IP{{104, 250, 178, 4}}}, + {Region: "Africa", Country: "Ghana", City: "Accra", IPs: []net.IP{{196, 251, 67, 4}}}, + {Region: "Africa", Country: "Kenya", City: "Mombasa", IPs: []net.IP{{154, 127, 57, 151}}}, + {Region: "Africa", Country: "Madagascar", City: "Antananarivo", IPs: []net.IP{{206, 123, 156, 131}}}, + {Region: "Africa", Country: "Mauritania", City: "Nouakchott", IPs: []net.IP{{206, 123, 158, 63}}}, + {Region: "Africa", Country: "Mauritius", City: "Port Louis", IPs: []net.IP{{104, 250, 181, 4}}}, + {Region: "Africa", Country: "Morocco", City: "Rabat", IPs: []net.IP{{104, 243, 250, 126}}}, + {Region: "Africa", Country: "Niger", City: "Niamey", IPs: []net.IP{{206, 123, 157, 131}}}, + {Region: "Africa", Country: "Nigeria", City: "Suleja", IPs: []net.IP{{102, 165, 25, 38}}}, + {Region: "Africa", Country: "Senegal", City: "Dakar", IPs: []net.IP{{206, 123, 158, 131}}}, + {Region: "Africa", Country: "Seychelles", City: "Victoria", IPs: []net.IP{{172, 111, 128, 126}}}, + {Region: "Africa", Country: "South Africa", City: "Johannesburg", IPs: []net.IP{{102, 165, 3, 34}}}, + {Region: "Africa", Country: "Tanzania", City: "Dar Es Salaam", IPs: []net.IP{{102, 135, 0, 2}}}, + {Region: "Africa", Country: "Tunisia", City: "Tunis", IPs: []net.IP{{206, 123, 159, 4}}}, + {Region: "Asia", Country: "Afghanistan", City: "Kabul", IPs: []net.IP{{172, 111, 208, 2}}}, + {Region: "Asia", Country: "Armenia", City: "Singapore", IPs: []net.IP{{37, 120, 208, 147}}}, + {Region: "Asia", Country: "Azerbaijan", City: "Baku", IPs: []net.IP{{104, 250, 177, 4}}}, + {Region: "Asia", Country: "Bangladesh", City: "Dhaka", IPs: []net.IP{{206, 123, 154, 190}}}, + {Region: "Asia", Country: "Brunei Darussalam", City: "Bandar Seri Begawan", IPs: []net.IP{{119, 81, 75, 84}, {119, 81, 242, 8}}}, + {Region: "Asia", Country: "Cambodia", City: "Phnom Penh", IPs: []net.IP{{104, 250, 176, 122}}}, + {Region: "Asia", Country: "Hong Kong (SAR)", City: "Hong Kong", IPs: []net.IP{{46, 243, 250, 4}}}, + {Region: "Asia", Country: "India", City: "Chennai", IPs: []net.IP{{129, 227, 107, 242}}}, + {Region: "Asia", Country: "Indonesia", City: "Jakarta", IPs: []net.IP{{103, 55, 9, 2}}}, + {Region: "Asia", Country: "Japan", City: "Tokyo", IPs: []net.IP{{172, 94, 56, 2}}}, + {Region: "Asia", Country: "Kazakhstan", City: "Almaty", IPs: []net.IP{{206, 123, 152, 4}}}, + {Region: "Asia", Country: "Korea, South", City: "Seoul", IPs: []net.IP{{45, 115, 25, 2}}}, + {Region: "Asia", Country: "Kyrgyzstan", City: "Bishkek", IPs: []net.IP{{206, 123, 151, 131}}}, + {Region: "Asia", Country: "Laos", City: "Vientiane", IPs: []net.IP{{206, 123, 153, 4}}}, + {Region: "Asia", Country: "Macao", City: "Beyrouth", IPs: []net.IP{{104, 243, 240, 121}}}, + {Region: "Asia", Country: "Malaysia", City: "Johor Baharu", IPs: []net.IP{{43, 226, 230, 4}}}, + {Region: "Asia", Country: "Malaysia", City: "Kuala Lumpur", IPs: []net.IP{{104, 250, 160, 4}}}, + {Region: "Asia", Country: "Mongolia", City: "Ulaanbaatar", IPs: []net.IP{{206, 123, 153, 131}}}, + {Region: "Asia", Country: "Pakistan", City: "Islamabad", IPs: []net.IP{{104, 250, 187, 3}}}, + {Region: "Asia", Country: "Papua New Guinea", City: "Port Moresby", IPs: []net.IP{{206, 123, 155, 131}}}, + {Region: "Asia", Country: "Philippines", City: "Manila", IPs: []net.IP{{36, 255, 97, 3}}}, + {Region: "Asia", Country: "Sri Lanka", City: "Colombo", IPs: []net.IP{{206, 123, 154, 4}}}, + {Region: "Asia", Country: "Taiwan", City: "Taipei", IPs: []net.IP{{203, 69, 105, 5}}}, + {Region: "Asia", Country: "Tajikistan", City: "Dushanbe", IPs: []net.IP{{206, 123, 151, 4}}}, + {Region: "Asia", Country: "Thailand", City: "Bangkok", IPs: []net.IP{{104, 37, 6, 4}}}, + {Region: "Asia", Country: "Turkey", City: "Istanbul", IPs: []net.IP{{82, 102, 22, 212}}}, + {Region: "Asia", Country: "Turkmenistan", City: "Ashgabat", IPs: []net.IP{{206, 123, 152, 131}}}, + {Region: "Asia", Country: "Uzbekistan", City: "Tashkent", IPs: []net.IP{{206, 123, 150, 131}}}, + {Region: "Asia", Country: "Vietnam", City: "Hanoi", IPs: []net.IP{{192, 253, 249, 132}}}, + {Region: "Europe", Country: "Albania", City: "Tirane", IPs: []net.IP{{46, 243, 224, 2}}}, + {Region: "Europe", Country: "Armenia", City: "Yerevan", IPs: []net.IP{{172, 94, 35, 4}}}, + {Region: "Europe", Country: "Austria", City: "Vienna", IPs: []net.IP{{172, 94, 125, 4}}}, + {Region: "Europe", Country: "Belgium", City: "Brussels", IPs: []net.IP{{172, 111, 223, 4}, {172, 111, 244, 4}}}, + {Region: "Europe", Country: "Bosnia and Herzegovina", City: "Sarajevo", IPs: []net.IP{{104, 250, 169, 122}}}, + {Region: "Europe", Country: "Bulgaria", City: "Sofia", IPs: []net.IP{{37, 120, 152, 52}}}, + {Region: "Europe", Country: "Croatia", City: "Zagreb", IPs: []net.IP{{104, 250, 163, 2}}}, + {Region: "Europe", Country: "Cyprus", City: "Nicosia", IPs: []net.IP{{188, 72, 119, 4}}}, + {Region: "Europe", Country: "Denmark", City: "Copenhagen", IPs: []net.IP{{172, 111, 223, 4}}}, + {Region: "Europe", Country: "Estonia", City: "Tallinn", IPs: []net.IP{{185, 166, 87, 2}, {188, 72, 111, 4}}}, + {Region: "Europe", Country: "France", City: "Paris", IPs: []net.IP{{172, 111, 223, 4}}}, + {Region: "Europe", Country: "Georgia", City: "Tbilisi", IPs: []net.IP{{141, 101, 156, 2}}}, + {Region: "Europe", Country: "Germany", City: "Frankfurt", IPs: []net.IP{{82, 102, 16, 107}}}, + {Region: "Europe", Country: "Germany", City: "Munich", IPs: []net.IP{{82, 102, 16, 107}}}, + {Region: "Europe", Country: "Germany", City: "Nuremberg", IPs: []net.IP{{172, 94, 125, 2}}}, + {Region: "Europe", Country: "Greece", City: "Thessaloniki", IPs: []net.IP{{5, 172, 199, 2}}}, + {Region: "Europe", Country: "Hungary", City: "Budapest", IPs: []net.IP{{217, 138, 192, 136}}}, + {Region: "Europe", Country: "Iceland", City: "Reykjavik", IPs: []net.IP{{192, 253, 250, 1}}}, + {Region: "Europe", Country: "Ireland", City: "Dublin", IPs: []net.IP{{78, 153, 208, 173}}}, + {Region: "Europe", Country: "Isle of Man", City: "Onchan", IPs: []net.IP{{46, 243, 144, 2}}}, + {Region: "Europe", Country: "Italy", City: "Milano", IPs: []net.IP{{45, 9, 251, 2}}}, + {Region: "Europe", Country: "Latvia", City: "RIGA", IPs: []net.IP{{185, 118, 76, 5}}}, + {Region: "Europe", Country: "Liechtenstein", City: "Vaduz", IPs: []net.IP{{104, 250, 164, 4}}}, + {Region: "Europe", Country: "Lithuania", City: "Vilnius", IPs: []net.IP{{188, 72, 116, 3}}}, + {Region: "Europe", Country: "Luxembourg", City: "Luxembourg", IPs: []net.IP{{94, 242, 225, 132}}}, + {Region: "Europe", Country: "Malta", City: "Sliema", IPs: []net.IP{{46, 243, 241, 4}}}, + {Region: "Europe", Country: "Monaco", City: "Monaco", IPs: []net.IP{{104, 250, 168, 132}}}, + {Region: "Europe", Country: "Montenegro", City: "Podgorica", IPs: []net.IP{{104, 250, 165, 121}}}, + {Region: "Europe", Country: "Netherlands", City: "Amsterdam", IPs: []net.IP{{37, 120, 192, 212}}}, + {Region: "Europe", Country: "Norway", City: "Oslo", IPs: []net.IP{{82, 102, 22, 212}}}, + {Region: "Europe", Country: "Poland", City: "Warsaw", IPs: []net.IP{{5, 253, 206, 251}}}, + {Region: "Europe", Country: "Portugal", City: "Lisbon", IPs: []net.IP{{5, 154, 174, 3}}}, + {Region: "Europe", Country: "Romania", City: "Bucharest", IPs: []net.IP{{188, 240, 220, 35}}}, + {Region: "Europe", Country: "Serbia", City: "Niลก", IPs: []net.IP{{152, 89, 160, 201}}}, + {Region: "Europe", Country: "Slovakia", City: "Bratislava", IPs: []net.IP{{188, 72, 112, 3}}}, + {Region: "Europe", Country: "Slovenia", City: "Ljubljana", IPs: []net.IP{{104, 243, 246, 129}}}, + {Region: "Europe", Country: "Spain", City: "Barcelona", IPs: []net.IP{{185, 230, 124, 147}}}, + {Region: "Europe", Country: "Sweden", City: "Stockholm", IPs: []net.IP{{45, 74, 46, 2}}}, + {Region: "Europe", Country: "Switzerland", City: "Zurich", IPs: []net.IP{{45, 12, 222, 98}, {45, 12, 222, 99}}}, + {Region: "Europe", Country: "United Kingdom", City: "Gosport", IPs: []net.IP{{45, 141, 154, 70}}}, + {Region: "Europe", Country: "United Kingdom", City: "London", IPs: []net.IP{{193, 9, 113, 66}}}, + {Region: "Europe", Country: "United Kingdom", City: "Maidenhead", IPs: []net.IP{{188, 72, 89, 4}}}, + {Region: "Europe", Country: "United Kingdom", City: "Manchester", IPs: []net.IP{{172, 111, 183, 2}}}, + {Region: "Middle East", Country: "Bahrain", City: "Manama", IPs: []net.IP{{46, 243, 150, 4}}}, + {Region: "Middle East", Country: "Jordan", City: "Amman", IPs: []net.IP{{172, 111, 152, 3}}}, + {Region: "Middle East", Country: "Kuwait", City: "Kuwait", IPs: []net.IP{{206, 123, 146, 4}}}, + {Region: "Middle East", Country: "Oman", City: "Salalah", IPs: []net.IP{{46, 243, 148, 125}}}, + {Region: "Middle East", Country: "Qatar", City: "Doha", IPs: []net.IP{{46, 243, 147, 2}}}, + {Region: "Middle East", Country: "Saudi Arabia", City: "Jeddah", IPs: []net.IP{{45, 74, 1, 4}}}, + {Region: "Middle East", Country: "United Arab Emirates", City: "Dubai", IPs: []net.IP{{104, 37, 6, 4}}}, + {Region: "North America", Country: "Aruba", City: "Oranjestad", IPs: []net.IP{{104, 243, 246, 129}}}, + {Region: "North America", Country: "Barbados", City: "Bridgetown", IPs: []net.IP{{172, 94, 97, 2}}}, + {Region: "North America", Country: "Belize", City: "Belmopan", IPs: []net.IP{{104, 243, 241, 4}}}, + {Region: "North America", Country: "Bermuda", City: "Hamilton", IPs: []net.IP{{172, 94, 76, 2}}}, + {Region: "North America", Country: "Canada", City: "Montreal", IPs: []net.IP{{172, 94, 7, 2}}}, + {Region: "North America", Country: "Canada", City: "Toronto", IPs: []net.IP{{172, 94, 7, 2}}}, + {Region: "North America", Country: "Canada", City: "Vancouver", IPs: []net.IP{{172, 94, 34, 4}}}, + {Region: "North America", Country: "Cayman Islands", City: "George Town", IPs: []net.IP{{172, 94, 113, 2}}}, + {Region: "North America", Country: "Costa Rica", City: "San Jose", IPs: []net.IP{{104, 243, 245, 1}}}, + {Region: "North America", Country: "Dominica", City: "Roseau", IPs: []net.IP{{45, 74, 22, 2}}}, + {Region: "North America", Country: "Dominican Republic", City: "Santo Domingo", IPs: []net.IP{{45, 74, 23, 129}}}, + {Region: "North America", Country: "El Salvador", City: "San Salvador", IPs: []net.IP{{45, 74, 17, 129}}}, + {Region: "North America", Country: "Grenada", City: "St George's", IPs: []net.IP{{45, 74, 21, 129}}}, + {Region: "North America", Country: "Guatemala", City: "Guatemala", IPs: []net.IP{{45, 74, 17, 129}}}, + {Region: "North America", Country: "Haiti", City: "PORT-AU-PRINCE", IPs: []net.IP{{45, 74, 24, 2}}}, + {Region: "North America", Country: "Honduras", City: "TEGUCIGALPA", IPs: []net.IP{{45, 74, 18, 2}}}, + {Region: "North America", Country: "Jamaica", City: "Kingston", IPs: []net.IP{{104, 250, 182, 126}}}, + {Region: "North America", Country: "Mexico", City: "Mexico City", IPs: []net.IP{{104, 243, 243, 131}}}, + {Region: "North America", Country: "Montserrat", City: "plymouth", IPs: []net.IP{{45, 74, 26, 190}}}, + {Region: "North America", Country: "Puerto Rico", City: "San Juan", IPs: []net.IP{{104, 37, 2, 2}}}, + {Region: "North America", Country: "Saint Lucia", City: "Castries", IPs: []net.IP{{45, 74, 23, 2}}}, + {Region: "North America", Country: "The Bahamas", City: "Freeport", IPs: []net.IP{{104, 243, 242, 2}}}, + {Region: "North America", Country: "Trinidad and Tobago", City: "Port of Spain", IPs: []net.IP{{45, 74, 21, 2}}}, + {Region: "North America", Country: "Turks and Caicos Islands", City: "Balfour Town", IPs: []net.IP{{172, 94, 60, 4}}}, + {Region: "North America", Country: "United States", City: "Ashburn", IPs: []net.IP{{46, 243, 249, 2}}}, + {Region: "North America", Country: "United States", City: "Chicago", IPs: []net.IP{{37, 230, 169, 4}}}, + {Region: "North America", Country: "United States", City: "Columbus", IPs: []net.IP{{172, 94, 115, 2}}}, + {Region: "North America", Country: "United States", City: "Georgia", IPs: []net.IP{{141, 101, 168, 4}}}, + {Region: "North America", Country: "United States", City: "Houston", IPs: []net.IP{{172, 94, 1, 4}}}, + {Region: "North America", Country: "United States", City: "Los Angeles", IPs: []net.IP{{172, 111, 147, 4}}}, + {Region: "North America", Country: "United States", City: "Miami", IPs: []net.IP{{172, 94, 108, 4}}}, + {Region: "North America", Country: "United States", City: "New Jersey", IPs: []net.IP{{141, 101, 168, 4}}}, + {Region: "North America", Country: "United States", City: "New York", IPs: []net.IP{{172, 111, 147, 4}}}, + {Region: "North America", Country: "United States", City: "Phoenix", IPs: []net.IP{{172, 94, 26, 4}}}, + {Region: "North America", Country: "United States", City: "Salt Lake City", IPs: []net.IP{{141, 101, 168, 4}}}, + {Region: "North America", Country: "United States", City: "San Francisco", IPs: []net.IP{{172, 111, 147, 4}}}, + {Region: "North America", Country: "United States", City: "Seattle", IPs: []net.IP{{172, 94, 86, 2}}}, + {Region: "North America", Country: "United States", City: "Washington, D.C.", IPs: []net.IP{{37, 230, 169, 4}}}, + {Region: "Oceania", Country: "Australia", City: "Brisbane", IPs: []net.IP{{172, 111, 236, 2}}}, + {Region: "Oceania", Country: "Australia", City: "Melbourne", IPs: []net.IP{{118, 127, 62, 2}}}, + {Region: "Oceania", Country: "Australia", City: "Perth", IPs: []net.IP{{172, 94, 123, 4}}}, + {Region: "Oceania", Country: "Australia", City: "Sydney", IPs: []net.IP{{46, 243, 245, 4}}}, + {Region: "Oceania", Country: "New Zealand", City: "Auckland", IPs: []net.IP{{43, 228, 156, 4}}}, + {Region: "South America", Country: "Argentina", City: "Buenos Aires", IPs: []net.IP{{104, 243, 244, 1}}}, + {Region: "South America", Country: "Bolivia", City: "Sucre", IPs: []net.IP{{172, 94, 77, 2}}}, + {Region: "South America", Country: "Brazil", City: "Sao Paulo", IPs: []net.IP{{104, 243, 244, 2}}}, + {Region: "South America", Country: "British Virgin Island", City: "Road Town", IPs: []net.IP{{104, 250, 184, 130}}}, + {Region: "South America", Country: "Chile", City: "Santiago", IPs: []net.IP{{191, 96, 183, 251}}}, + {Region: "South America", Country: "Colombia", City: "Bogota", IPs: []net.IP{{172, 111, 132, 1}}}, + {Region: "South America", Country: "Ecuador", City: "Quito", IPs: []net.IP{{104, 250, 180, 126}}}, + {Region: "South America", Country: "Guyana", City: "Georgetown", IPs: []net.IP{{45, 74, 20, 129}}}, + {Region: "South America", Country: "Panama", City: "Panama City", IPs: []net.IP{{104, 243, 243, 131}}}, + {Region: "South America", Country: "Paraguay", City: "Asuncion", IPs: []net.IP{{45, 74, 19, 129}}}, + {Region: "South America", Country: "Peru", City: "Lima", IPs: []net.IP{{172, 111, 131, 1}}}, + {Region: "South America", Country: "Suriname", City: "Paramaribo", IPs: []net.IP{{45, 74, 20, 4}}}, + } +} diff --git a/internal/constants/vpn.go b/internal/constants/vpn.go index 4cb20ac81..e9a64c896 100644 --- a/internal/constants/vpn.go +++ b/internal/constants/vpn.go @@ -19,6 +19,8 @@ const ( Vyprvpn models.VPNProvider = "vyprvpn" // NordVPN is a VPN provider Nordvpn models.VPNProvider = "nordvpn" + // PureVPN is a VPN provider + Purevpn models.VPNProvider = "purevpn" ) const ( diff --git a/internal/models/selection.go b/internal/models/selection.go index 0fc54fdb8..b7732b65d 100644 --- a/internal/models/selection.go +++ b/internal/models/selection.go @@ -25,11 +25,13 @@ type ServerSelection struct { //nolint:maligned // Cyberghost Group string `json:"group"` - // Mullvad + // Mullvad, PureVPN Country string `json:"country"` City string `json:"city"` - ISP string `json:"isp"` - Owned bool `json:"owned"` + + // Mullvad + ISP string `json:"isp"` + Owned bool `json:"owned"` // Mullvad, Windscribe CustomPort uint16 `json:"customPort"` @@ -110,6 +112,12 @@ func (p *ProviderSettings) String() string { "Region: "+p.ServerSelection.Region, "Number: "+number, ) + case "purevpn": + settingsList = append(settingsList, + "Region: "+p.ServerSelection.Region, + "Country: "+p.ServerSelection.Country, + "City: "+p.ServerSelection.City, + ) default: settingsList = append(settingsList, "", diff --git a/internal/models/servers.go b/internal/models/servers.go index 8b3848da9..02e6c1e03 100644 --- a/internal/models/servers.go +++ b/internal/models/servers.go @@ -44,3 +44,10 @@ type NordvpnServer struct { //nolint:maligned TCP bool UDP bool } + +type PurevpnServer struct { + Region string + Country string + City string + IPs []net.IP +} diff --git a/internal/params/params.go b/internal/params/params.go index 85c1df036..5a6d9b57c 100644 --- a/internal/params/params.go +++ b/internal/params/params.go @@ -86,6 +86,11 @@ type Reader interface { GetNordvpnRegion() (region string, err error) GetNordvpnNumber() (number uint16, err error) + // PureVPN getters + GetPurevpnRegion() (region string, err error) + GetPurevpnCountry() (country string, err error) + GetPurevpnCity() (city string, err error) + // Shadowsocks getters GetShadowSocks() (activated bool, err error) GetShadowSocksLog() (activated bool, err error) @@ -131,7 +136,7 @@ func NewReader(logger logging.Logger, fileManager files.FileManager) Reader { // GetVPNSP obtains the VPN service provider to use from the environment variable VPNSP func (r *reader) GetVPNSP() (vpnServiceProvider models.VPNProvider, err error) { - s, err := r.envParams.GetValueIfInside("VPNSP", []string{"pia", "private internet access", "mullvad", "windscribe", "surfshark", "cyberghost", "vyprvpn", "nordvpn"}) + s, err := r.envParams.GetValueIfInside("VPNSP", []string{"pia", "private internet access", "mullvad", "windscribe", "surfshark", "cyberghost", "vyprvpn", "nordvpn", "purevpn"}) if s == "pia" { s = "private internet access" } diff --git a/internal/params/purevpn.go b/internal/params/purevpn.go new file mode 100644 index 000000000..2c30abad5 --- /dev/null +++ b/internal/params/purevpn.go @@ -0,0 +1,26 @@ +package params + +import ( + "github.com/qdm12/private-internet-access-docker/internal/constants" +) + +// GetPurevpnRegion obtains the region (continent) for the PureVPN server from the +// environment variable REGION +func (r *reader) GetPurevpnRegion() (region string, err error) { + choices := append(constants.PurevpnRegionChoices(), "") + return r.envParams.GetValueIfInside("REGION", choices) +} + +// GetPurevpnCountry obtains the country for the PureVPN server from the +// environment variable COUNTRY +func (r *reader) GetPurevpnCountry() (country string, err error) { + choices := append(constants.PurevpnCountryChoices(), "") + return r.envParams.GetValueIfInside("COUNTRY", choices) +} + +// GetPurevpnCity obtains the city for the PureVPN server from the +// environment variable CITY +func (r *reader) GetPurevpnCity() (city string, err error) { + choices := append(constants.PurevpnCityChoices(), "") + return r.envParams.GetValueIfInside("CITY", choices) +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index cd70ec3c4..e7b907557 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -29,6 +29,8 @@ func New(provider models.VPNProvider) Provider { return newVyprvpn() case constants.Nordvpn: return newNordvpn() + case constants.Purevpn: + return newPurevpn() default: return nil // should never occur } diff --git a/internal/provider/purevpn.go b/internal/provider/purevpn.go new file mode 100644 index 000000000..a90857b10 --- /dev/null +++ b/internal/provider/purevpn.go @@ -0,0 +1,159 @@ +package provider + +import ( + "fmt" + "strings" + + "github.com/qdm12/golibs/network" + "github.com/qdm12/private-internet-access-docker/internal/constants" + "github.com/qdm12/private-internet-access-docker/internal/models" +) + +type purevpn struct{} + +func newPurevpn() *purevpn { + return &purevpn{} +} + +func (p *purevpn) filterServers(region, country, city string) (servers []models.PurevpnServer) { + allServers := constants.PurevpnServers() + for i, server := range allServers { + if len(region) == 0 { + server.Region = "" + } + if len(country) == 0 { + server.Country = "" + } + if len(city) == 0 { + server.City = "" + } + if strings.EqualFold(server.Region, region) && + strings.EqualFold(server.Country, country) && + strings.EqualFold(server.City, city) { + servers = append(servers, allServers[i]) + } + } + return servers +} + +func (p *purevpn) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { //nolint:dupl + servers := p.filterServers(selection.Region, selection.Country, selection.City) + if len(servers) == 0 { + return nil, fmt.Errorf("no server found for region %q, country %q and city %q", selection.Region, selection.Country, selection.City) + } + + var port uint16 + switch { + case selection.Protocol == constants.UDP: + port = 53 + case selection.Protocol == constants.TCP: + port = 80 + default: + return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol) + } + + for _, server := range servers { + for _, IP := range server.IPs { + if selection.TargetIP != nil { + if IP.Equal(selection.TargetIP) { + return []models.OpenVPNConnection{{IP: IP, Port: port, Protocol: selection.Protocol}}, nil + } + } else { + connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol}) + } + } + } + + if selection.TargetIP != nil { + return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP) + } + + if len(connections) > 64 { + connections = connections[:64] + } + + return connections, nil +} + +func (p *purevpn) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) { //nolint:dupl + if len(cipher) == 0 { + cipher = aes256cbc + } + lines = []string{ + "client", + "dev tun", + "nobind", + "persist-key", + "remote-cert-tls server", + + // Purevpn specific + "key-direction 1", + "remote-cert-tls server", + "cipher AES-256-CBC", + "route-method exe", + "route-delay 0", + "route 0.0.0.0 0.0.0.0", + "script-security 2", + + // Added constant values + "auth-nocache", + "mute-replay-warnings", + "pull-filter ignore \"auth-token\"", // prevent auth failed loops + "auth-retry nointeract", + "remote-random", + "suppress-timestamps", + + // Modified variables + fmt.Sprintf("verb %d", verbosity), + fmt.Sprintf("auth-user-pass %s", constants.OpenVPNAuthConf), + fmt.Sprintf("proto %s", string(connections[0].Protocol)), + fmt.Sprintf("cipher %s", cipher), + } + if !root { + lines = append(lines, "user nonrootuser") + } + for _, connection := range connections { + lines = append(lines, fmt.Sprintf("remote %s %d", connection.IP.String(), connection.Port)) + } + lines = append(lines, []string{ + "", + "-----BEGIN CERTIFICATE-----", + constants.PurevpnCertificateAuthority, + "-----END CERTIFICATE-----", + "", + }...) + lines = append(lines, []string{ + "", + "-----BEGIN CERTIFICATE-----", + constants.PurevpnCertificate, + "-----END CERTIFICATE-----", + "", + }...) + lines = append(lines, []string{ + "", + "-----BEGIN PRIVATE KEY-----", + constants.PurevpnKey, + "-----END PRIVATE KEY-----", + "", + "", + }...) + lines = append(lines, []string{ + "", + "-----BEGIN OpenVPN Static key V1-----", + constants.PurevpnOpenvpnStaticKeyV1, + "-----END OpenVPN Static key V1-----", + "", + "", + }...) + if len(auth) > 0 { + lines = append(lines, "auth "+auth) + } + if connections[0].Protocol == constants.UDP { + lines = append(lines, "explicit-exit-notify") + } + return lines +} + +func (p *purevpn) GetPortForward(client network.Client) (port uint16, err error) { + panic("port forwarding is not supported for purevpn") +} diff --git a/internal/settings/openvpn.go b/internal/settings/openvpn.go index db61211d7..787fb463b 100644 --- a/internal/settings/openvpn.go +++ b/internal/settings/openvpn.go @@ -66,6 +66,8 @@ func GetOpenVPNSettings(paramsReader params.Reader, vpnProvider models.VPNProvid settings.Provider, err = GetVyprvpnSettings(paramsReader) case constants.Nordvpn: settings.Provider, err = GetNordvpnSettings(paramsReader) + case constants.Purevpn: + settings.Provider, err = GetPurevpnSettings(paramsReader) default: err = fmt.Errorf("VPN service provider %q is not valid", vpnProvider) } diff --git a/internal/settings/providers.go b/internal/settings/providers.go index 43d40313d..ecfe8acfe 100644 --- a/internal/settings/providers.go +++ b/internal/settings/providers.go @@ -175,3 +175,29 @@ func GetNordvpnSettings(paramsReader params.Reader) (settings models.ProviderSet } return settings, nil } + +// GetPurevpnSettings obtains Purevpn settings from environment variables using the params package. +func GetPurevpnSettings(paramsReader params.Reader) (settings models.ProviderSettings, err error) { + settings.Name = constants.Mullvad + settings.ServerSelection.Protocol, err = paramsReader.GetNetworkProtocol() + if err != nil { + return settings, err + } + settings.ServerSelection.TargetIP, err = paramsReader.GetTargetIP() + if err != nil { + return settings, err + } + settings.ServerSelection.Region, err = paramsReader.GetPurevpnRegion() + if err != nil { + return settings, err + } + settings.ServerSelection.Country, err = paramsReader.GetPurevpnCountry() + if err != nil { + return settings, err + } + settings.ServerSelection.City, err = paramsReader.GetPurevpnCity() + if err != nil { + return settings, err + } + return settings, nil +}