Last active
January 7, 2024 05:09
-
-
Save takuan-osho/068f4417d3652461f3f1b3d97fc4caf7 to your computer and use it in GitHub Desktop.
sample codes for generating OpenVPN config file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
{ | |
"domains": [ | |
"sample.domain.example.com" # sample domain | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"encoding/json" | |
"flag" | |
"html/template" | |
"log" | |
"net" | |
"os" | |
"github.com/tailscale/hujson" | |
"golang.org/x/sync/errgroup" | |
) | |
type Data struct { | |
IPs []string | |
} | |
type Config struct { | |
Domains []string `json:"domains"` | |
} | |
func readDomains(filename string) ([]string, error) { | |
fileBytes, err := os.ReadFile(filename) | |
if err != nil { | |
return nil, err | |
} | |
var cfg Config | |
b, err := hujson.Standardize(fileBytes) | |
if err != nil { | |
return nil, err | |
} | |
err = json.Unmarshal(b, &cfg) | |
if err != nil { | |
return nil, err | |
} | |
return cfg.Domains, nil | |
} | |
func readTemplate(filename string) (string, error) { | |
fileBytes, err := os.ReadFile(filename) | |
if err != nil { | |
return "", err | |
} | |
return string(fileBytes), nil | |
} | |
func main() { | |
var domainListFile string | |
var templateFile string | |
var outputFile string | |
flag.StringVar(&domainListFile, "file", "domains.jsonc", "file containing a list of domains") | |
flag.StringVar(&templateFile, "template", "profile.ovpn.tmpl", "OVPN template file written in go template format") | |
flag.StringVar(&outputFile, "output", "downloaded-client-config-programmed.ovpn", "output file") | |
flag.Parse() | |
domains, err := readDomains(domainListFile) | |
if err != nil { | |
log.Fatalf("Failed to read domains: %v", err) | |
} | |
ipChan := make(chan string, len(domains)) | |
eg, ctx := errgroup.WithContext(context.Background()) | |
for _, domain := range domains { | |
domain := domain // https://golang.org/doc/faq#closures_and_goroutines | |
eg.Go(func() error { | |
ips, err := net.LookupIP(domain) | |
if err != nil { | |
return err | |
} | |
for _, ip := range ips { | |
if ip.To4() != nil { | |
select { | |
case ipChan <- ip.String(): | |
case <-ctx.Done(): | |
return ctx.Err() | |
} | |
} | |
} | |
return nil | |
}) | |
} | |
go func() { | |
eg.Wait() | |
close(ipChan) | |
}() | |
ipList := make([]string, 0, len(domains)) | |
for ip := range ipChan { | |
ipList = append(ipList, ip) | |
} | |
if err := eg.Wait(); err != nil { | |
// If IP lookup fails, it is not a fatal problem and we can still generate the config file | |
log.Printf("Failed to lookup IPs: %v", err) | |
} | |
data := Data{IPs: ipList} | |
templateText, err := readTemplate(templateFile) | |
if err != nil { | |
log.Fatalf("Failed to read template: %v", err) | |
} | |
tmpl, err := template.New("config").Parse(templateText) | |
if err != nil { | |
log.Fatalf("Failed to parse template: %s", err) | |
} | |
file, err := os.Create(outputFile) | |
if err != nil { | |
log.Fatalf("Failed to create file: %s", err) | |
} | |
defer file.Close() | |
err = tmpl.Execute(file, data) | |
if err != nil { | |
log.Fatalf("Failed to execute template: %s", err) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
client | |
dev tun | |
proto udp | |
remote clientvpn.example.com 443 | |
remote-random-hostname | |
resolv-retry infinite | |
nobind | |
persist-key | |
persist-tun | |
remote-cert-tls server | |
cipher AES-256-GCM | |
verb 3 | |
route-nopull | |
{{range .IPs}} | |
route {{.}} 255.255.255.255 | |
{{- end }} | |
<ca> | |
-----BEGIN CERTIFICATE----- | |
<sensitive> | |
-----END CERTIFICATE----- | |
</ca> | |
<cert> | |
-----BEGIN CERTIFICATE----- | |
<sensitive> | |
-----END CERTIFICATE----- | |
</cert> | |
<key> | |
-----BEGIN PRIVATE KEY----- | |
<sensitive> | |
-----END PRIVATE KEY----- | |
</key> | |
auth-user-pass | |
reneg-sec 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment