diff --git a/cmd/ovpnparser/main.go b/cmd/ovpnparser/main.go new file mode 100644 index 00000000..8a3eb14c --- /dev/null +++ b/cmd/ovpnparser/main.go @@ -0,0 +1,106 @@ +package main + +import ( + "archive/zip" + "bytes" + "flag" + "fmt" + "io/ioutil" + "net/http" + "os" + "sort" + "strings" + "time" + + "github.com/qdm12/golibs/network" +) + +func main() { + os.Exit(_main()) +} + +func _main() int { + provider := flag.String("provider", "surfshark", "VPN provider to parse openvpn files for, can be 'surfshark'") + flag.Parse() + + var url string + switch *provider { + case "surfshark": + url = "https://account.surfshark.com/api/v1/server/configurations" + default: + fmt.Printf("Provider %q is not supported\n", *provider) + return 1 + } + client := network.NewClient(time.Second) + zipBytes, status, err := client.GetContent(url) + if err != nil { + fmt.Println(err) + return 1 + } else if status != http.StatusOK { + fmt.Printf("Getting %s results in HTTP status code %d\n", url, status) + return 1 + } + contents, err := zipExtractAll(zipBytes) + if err != nil { + fmt.Println(err) + return 1 + } + uniqueSubdomains := make(map[string]struct{}) + for _, content := range contents { + subdomain, err := extractInformation(content) + if err != nil { + fmt.Println(err) + return 1 + } + uniqueSubdomains[subdomain] = struct{}{} + } + subdomains := make([]string, len(uniqueSubdomains)) + i := 0 + for subdomain := range uniqueSubdomains { + subdomains[i] = subdomain + i++ + } + sort.Slice(subdomains, func(i, j int) bool { + return subdomains[i] < subdomains[j] + }) + fmt.Println("Subdomains found are: ", strings.Join(subdomains, ",")) + return 0 +} + +func zipExtractAll(zipBytes []byte) (contents [][]byte, err error) { + r, err := zip.NewReader(bytes.NewReader(zipBytes), int64(len(zipBytes))) + if err != nil { + return nil, err + } + contents = make([][]byte, len(r.File)) + for i, zf := range r.File { + f, err := zf.Open() + if err != nil { + return nil, err + } + defer f.Close() + contents[i], err = ioutil.ReadAll(f) + if err != nil { + return nil, err + } + if err := f.Close(); err != nil { + return nil, err + } + } + return contents, nil +} + +func extractInformation(content []byte) (subdomain string, err error) { + lines := strings.Split(string(content), "\n") + for _, line := range lines { + if strings.HasPrefix(line, "remote ") { + words := strings.Fields(line) + if len(words) < 2 { + return "", fmt.Errorf("not enough words on line %q", line) + } + host := words[1] + return strings.TrimSuffix(host, ".prod.surfshark.com"), nil + } + } + return "", fmt.Errorf("could not find remote line") +}