Skip to content

Instantly share code, notes, and snippets.

@takuan-osho
Last active December 13, 2024 05:35
Show Gist options
  • Save takuan-osho/068f4417d3652461f3f1b3d97fc4caf7 to your computer and use it in GitHub Desktop.
Save takuan-osho/068f4417d3652461f3f1b3d97fc4caf7 to your computer and use it in GitHub Desktop.
sample codes for generating OpenVPN config file
{
"domains": [
"sample.domain.example.com" # sample domain
]
}
package main
import (
"encoding/json"
"flag"
"fmt"
"html/template"
"log"
"net"
"os"
"sync"
"github.com/tailscale/hujson"
)
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 GetIPs(domain string, ipChan chan<- string, wg *sync.WaitGroup) {
defer wg.Done()
ips, err := net.LookupIP(domain)
if err != nil {
log.Printf("Failed to lookup IP for domain %s: %v", domain, err)
return // エラーの場合は処理を終了
}
for _, ip := range ips {
if ip.To4() != nil {
ipChan <- ip.String()
}
}
}
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))
var wg sync.WaitGroup
for _, domain := range domains {
wg.Add(1)
go GetIPs(domain, ipChan, &wg)
}
go func() {
wg.Wait()
close(ipChan)
}()
ipList := make([]string, 0, len(domains))
for ip := range ipChan {
ipList = append(ipList, ip)
}
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)
}
fmt.Printf("Generated OpenVPN configuration file: %s\n", outputFile)
}
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