package main // get https://www.expressvpn.com/vpn-server // remove everyting starting with > // remove until "Not supported" and after What the green checks mean import ( "bufio" "errors" "fmt" "net" "net/http" "strings" "sync" "time" ) func (s *OpenVpnMgt) getServerList() error { var mux sync.Mutex requestCount := 0 VPNNames := map[string]bool{} // Create HTTP client with timeout client := &http.Client{ Timeout: 30 * time.Second, } // Make request resp, err := client.Get("https://www.expressvpn.com/vpn-server") if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != 200 { return errors.New(fmt.Sprintf("Server List URL is not valid (%d)\n", resp.StatusCode)) } buf := bufio.NewReader(bufio.NewReader(resp.Body)) start := false for { line, err := buf.ReadString('\n') if err != nil { break } line = strings.Trim(line, "\n\r ") if strings.HasPrefix(line, "<") { continue } if line == "Not supported" { start = true continue } if line == "What the green checks mean" { start = false } if !start { continue } if line == "" { continue } requestCount++ go func(line string) { line = strings.ToLower(line) line = strings.Replace(line, " & ", "", -1) line = strings.Replace(line, " ", "", -1) name := fmt.Sprintf("%s-ca-version-2.expressnetw.com", line) if _, err := net.ResolveIPAddr("ip4", name); err == nil { mux.Lock() VPNNames[name] = true mux.Unlock() } requestCount-- }(line) } // wait for all resolutions for requestCount > 0 { time.Sleep(100 * time.Millisecond) } if len(VPNNames) == 0 { return errors.New("Can't get a list of VPN endpoints") } // add the right values keys := make([]string, 0, len(VPNNames)) for k := range VPNNames { keys = append(keys, k) } s.Lock() s.VpnRemotes = keys s.Unlock() return nil }