summaryrefslogtreecommitdiff
path: root/pkg/wgconf/wgconf.go
diff options
context:
space:
mode:
authorJames O'Doherty <james@theodohertyfamily.com>2026-05-22 16:17:55 -0400
committerJames O'Doherty <james@theodohertyfamily.com>2026-05-22 16:17:55 -0400
commit135f6edbd9389bc4783f13c26aed0a74d3c8aca0 (patch)
tree41a8e80b0dcf2c42b045bc91d9101deceb049f47 /pkg/wgconf/wgconf.go
parent2e3a1d07b43e6e942e51ba263c6fcdc2351afc0d (diff)
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
Diffstat (limited to 'pkg/wgconf/wgconf.go')
-rw-r--r--pkg/wgconf/wgconf.go97
1 files changed, 97 insertions, 0 deletions
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
+}