anonpenguin23 abcc23c4f3 refactor(monorepo): restructure repo with core, website, vault, os packages
- add monorepo Makefile delegating to sub-projects
- update CI workflows, GoReleaser, gitignore for new structure
- revise README, CONTRIBUTING.md for monorepo overview
- bump Go to 1.24
2026-03-26 18:21:55 +02:00

140 lines
3.2 KiB
Go

// Package wireguard manages the WireGuard interface for OramaOS.
//
// On OramaOS, the WireGuard kernel module is built-in (Linux 6.6+).
// Configuration is written during enrollment and persisted on the rootfs.
package wireguard
import (
"fmt"
"log"
"os"
"os/exec"
)
const (
// Interface is the WireGuard interface name.
Interface = "wg0"
// ConfigPath is the default WireGuard configuration file.
ConfigPath = "/etc/wireguard/wg0.conf"
// PrivateKeyPath stores the WG private key separately for identity derivation.
PrivateKeyPath = "/etc/wireguard/private.key"
)
// Manager handles WireGuard interface lifecycle.
type Manager struct {
iface string
}
// NewManager creates a new WireGuard manager.
func NewManager() *Manager {
return &Manager{iface: Interface}
}
// Configure writes the WireGuard configuration to disk.
// Called during enrollment with config received from the Gateway.
func (m *Manager) Configure(config string) error {
if err := os.MkdirAll("/etc/wireguard", 0700); err != nil {
return fmt.Errorf("failed to create wireguard dir: %w", err)
}
if err := os.WriteFile(ConfigPath, []byte(config), 0600); err != nil {
return fmt.Errorf("failed to write WG config: %w", err)
}
log.Println("WireGuard configuration written")
return nil
}
// Up brings the WireGuard interface up using wg-quick.
func (m *Manager) Up() error {
log.Println("bringing up WireGuard interface")
cmd := exec.Command("wg-quick", "up", m.iface)
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("wg-quick up failed: %w\n%s", err, string(output))
}
log.Println("WireGuard interface is up")
return nil
}
// Down takes the WireGuard interface down.
func (m *Manager) Down() error {
cmd := exec.Command("wg-quick", "down", m.iface)
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("wg-quick down failed: %w\n%s", err, string(output))
}
log.Println("WireGuard interface is down")
return nil
}
// GetPeers returns the current WireGuard peer list with their IPs.
func (m *Manager) GetPeers() ([]string, error) {
cmd := exec.Command("wg", "show", m.iface, "allowed-ips")
output, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("wg show failed: %w", err)
}
var ips []string
for _, line := range splitLines(string(output)) {
if line == "" {
continue
}
// Format: "<pubkey>\t<ip>/32\n"
parts := splitTabs(line)
if len(parts) >= 2 {
ip := parts[1]
// Strip /32 suffix
if idx := indexOf(ip, '/'); idx >= 0 {
ip = ip[:idx]
}
ips = append(ips, ip)
}
}
return ips, nil
}
func splitLines(s string) []string {
var lines []string
start := 0
for i := 0; i < len(s); i++ {
if s[i] == '\n' {
lines = append(lines, s[start:i])
start = i + 1
}
}
if start < len(s) {
lines = append(lines, s[start:])
}
return lines
}
func splitTabs(s string) []string {
var parts []string
start := 0
for i := 0; i < len(s); i++ {
if s[i] == '\t' {
parts = append(parts, s[start:i])
start = i + 1
}
}
if start < len(s) {
parts = append(parts, s[start:])
}
return parts
}
func indexOf(s string, c byte) int {
for i := 0; i < len(s); i++ {
if s[i] == c {
return i
}
}
return -1
}