From 135f6edbd9389bc4783f13c26aed0a74d3c8aca0 Mon Sep 17 00:00:00 2001 From: James O'Doherty Date: Fri, 22 May 2026 16:17:55 -0400 Subject: refactor: unify path management and complete profile management system - Create internal/paths package for unified config and runtime directory resolution - Implement robust WireGuard config parsing in pkg/wgconf - Implement profile management subcommands: list, import, configure, delete, stop - Fix namespace pinning path collisions (separating .ns files from pids directories) - Implement and verify namespace unpinning logic - Fix linting errors and improve error handling across the project --- pkg/wgconf/wgconf.go | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 pkg/wgconf/wgconf.go (limited to 'pkg/wgconf/wgconf.go') diff --git a/pkg/wgconf/wgconf.go b/pkg/wgconf/wgconf.go new file mode 100644 index 0000000..2615892 --- /dev/null +++ b/pkg/wgconf/wgconf.go @@ -0,0 +1,97 @@ +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 +} -- cgit v1.2.3