Files
gluetun/cmd/ovpnparser/main.go

153 lines
3.8 KiB
Go
Raw Normal View History

2020-05-29 10:13:42 +00:00
package main
import (
"archive/zip"
"bytes"
"flag"
"fmt"
"io/ioutil"
"net"
2020-05-29 10:13:42 +00:00
"net/http"
"os"
2020-07-13 08:04:35 -04:00
"path/filepath"
2020-05-29 10:13:42 +00:00
"sort"
"strings"
"time"
"github.com/qdm12/golibs/network"
)
func main() {
os.Exit(_main())
}
2020-07-13 08:04:35 -04:00
// Find subdomains from .ovpn files contained in a .zip file
2020-05-29 10:13:42 +00:00
func _main() int {
2020-07-13 08:04:35 -04:00
provider := flag.String("provider", "surfshark", "VPN provider to parse openvpn files for, can be 'surfshark' or 'vyprvpn")
2020-05-29 10:13:42 +00:00
flag.Parse()
var urls []string
var suffix string
2020-05-29 10:13:42 +00:00
switch *provider {
case "surfshark":
urls = []string{
"https://account.surfshark.com/api/v1/server/configurations",
"https://v2uploads.zopim.io/p/2/L/p2LbwLkvfQoSdzOl6VEltzQA6StiZqrs/12500634259669c77012765139bcfe4f4c90db1e.zip",
}
suffix = ".prod.surfshark.com"
2020-07-13 08:04:35 -04:00
case "vyprvpn":
urls = []string{
"https://support.vyprvpn.com/hc/article_attachments/360052617332/Vypr_OpenVPN_20200320.zip",
}
suffix = ".vyprvpn.com"
2020-05-29 10:13:42 +00:00
default:
fmt.Printf("Provider %q is not supported\n", *provider)
return 1
}
contents, err := fetchAndExtractFiles(urls...)
2020-05-29 10:13:42 +00:00
if err != nil {
fmt.Println(err)
return 1
}
2020-07-13 08:04:35 -04:00
uniqueSubdomainsToFilename := make(map[string]string)
for fileName, content := range contents {
subdomain, err := extractInformation(content, suffix)
2020-05-29 10:13:42 +00:00
if err != nil {
fmt.Println(err)
return 1
} else if len(subdomain) > 0 {
2020-07-13 08:04:35 -04:00
fileName = strings.TrimSuffix(fileName, ".ovpn")
fileName = strings.ReplaceAll(fileName, " - ", " ")
uniqueSubdomainsToFilename[subdomain] = fileName
2020-05-29 10:13:42 +00:00
}
}
2020-07-13 08:04:35 -04:00
type subdomainFilename struct {
subdomain string
fileName string
}
subdomains := make([]subdomainFilename, len(uniqueSubdomainsToFilename))
2020-05-29 10:13:42 +00:00
i := 0
2020-07-13 08:04:35 -04:00
for subdomain, fileName := range uniqueSubdomainsToFilename {
subdomains[i] = subdomainFilename{
subdomain: subdomain,
fileName: fileName,
}
2020-05-29 10:13:42 +00:00
i++
}
sort.Slice(subdomains, func(i, j int) bool {
2020-07-13 08:04:35 -04:00
return subdomains[i].subdomain < subdomains[j].subdomain
2020-05-29 10:13:42 +00:00
})
2020-07-13 08:04:35 -04:00
fmt.Println("Subdomain Filename")
for i := range subdomains {
fmt.Printf("%s %s\n", subdomains[i].subdomain, subdomains[i].fileName)
}
2020-05-29 10:13:42 +00:00
return 0
}
2020-07-13 08:04:35 -04:00
func fetchAndExtractFiles(urls ...string) (contents map[string][]byte, err error) {
client := network.NewClient(10 * time.Second)
2020-07-13 08:04:35 -04:00
contents = make(map[string][]byte)
for _, url := range urls {
zipBytes, status, err := client.GetContent(url)
if err != nil {
return nil, err
} else if status != http.StatusOK {
return nil, fmt.Errorf("Getting %s results in HTTP status code %d", url, status)
}
newContents, err := zipExtractAll(zipBytes)
if err != nil {
return nil, err
}
2020-07-13 08:04:35 -04:00
for fileName, content := range newContents {
contents[fileName] = content
}
}
return contents, nil
}
2020-07-13 08:04:35 -04:00
func zipExtractAll(zipBytes []byte) (contents map[string][]byte, err error) {
2020-05-29 10:13:42 +00:00
r, err := zip.NewReader(bytes.NewReader(zipBytes), int64(len(zipBytes)))
if err != nil {
return nil, err
}
2020-07-13 08:04:35 -04:00
contents = map[string][]byte{}
for _, zf := range r.File {
fileName := filepath.Base(zf.Name)
if !strings.HasSuffix(fileName, ".ovpn") {
continue
}
2020-05-29 10:13:42 +00:00
f, err := zf.Open()
if err != nil {
return nil, err
}
defer f.Close()
2020-07-13 08:04:35 -04:00
contents[fileName], err = ioutil.ReadAll(f)
2020-05-29 10:13:42 +00:00
if err != nil {
return nil, err
}
if err := f.Close(); err != nil {
return nil, err
}
}
return contents, nil
}
func extractInformation(content []byte, suffix string) (subdomain string, err error) {
2020-05-29 10:13:42 +00:00
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]
if net.ParseIP(host) != nil {
return "", nil // ignore IP addresses
}
return strings.TrimSuffix(host, suffix), nil
2020-05-29 10:13:42 +00:00
}
}
2020-07-13 08:04:35 -04:00
return "", fmt.Errorf("could not find remote line in: %s", string(content))
2020-05-29 10:13:42 +00:00
}