package wgconf import ( "bufio" "fmt" "os" "strings" ) // Config represents a parsed WireGuard configuration file. type Config struct { PrivateKey string Address string DNS string Peers []Peer } // Peer represents a WireGuard peer. type Peer struct { PublicKey string Endpoint string AllowedIPs []string } // Parse reads a WireGuard .conf file and returns a Config struct. func Parse(path string) (*Config, error) { file, err := os.Open(path) if err != nil { return nil, fmt.Errorf("failed to open config file: %w", err) } defer func() { if err := file.Close(); err != nil { // We use a simple print here because we are in a defer fmt.Printf("warning: failed to close config file %s: %v\n", path, err) } }() cfg := &Config{} var currentPeer *Peer scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, "#") { continue } if strings.HasPrefix(line, "[") { section := strings.Trim(line, "[]") if section == "Peer" { if currentPeer != nil { cfg.Peers = append(cfg.Peers, *currentPeer) } currentPeer = &Peer{} } continue } parts := strings.SplitN(line, "=", 2) if len(parts) != 2 { return nil, fmt.Errorf("invalid line format: %s", line) } key := strings.TrimSpace(parts[0]) val := strings.TrimSpace(parts[1]) if currentPeer != nil { switch key { case "PublicKey": currentPeer.PublicKey = val case "Endpoint": currentPeer.Endpoint = val case "AllowedIPs": currentPeer.AllowedIPs = strings.Split(val, ",") } } else { switch key { case "PrivateKey": cfg.PrivateKey = val case "Address": cfg.Address = val case "DNS": cfg.DNS = val } } } if currentPeer != nil { cfg.Peers = append(cfg.Peers, *currentPeer) } if err := scanner.Err(); err != nil { return nil, fmt.Errorf("error reading config file: %w", err) } return cfg, nil }