package wgfunc import ( "errors" "fmt" "golang.zx2c4.com/wireguard/wgctrl" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "net" "strconv" "strings" "sync" "time" ) type WireGuard struct { Device wgConfig wgtypes.Config wgClient *wgctrl.Client wgUpdate sync.Mutex port int //Wireguard WireGuard Port privateKey string //Wireguard WireGuard Private Key } type WireGuardConfig struct{ Name string IPRanges []string Port int //Wireguard WireGuard Port PrivateKey string //Wireguard WireGuard Private Key } func NewWireGuard(config WireGuardConfig) (WireGuard, error){ wireguard := WireGuard{ port: config.Port, privateKey: config.PrivateKey, } wireguard.name = config.Name wireguard.iPRanges = config.IPRanges return wireguard, nil } type PeerConfig struct { PublicKey string PreSharedKey string AllowedIPs []string Endpoint string } func (s *WireGuard) Down() (error) { return s.removeNetworkDevice() } func (s *WireGuard) Up() (error) { err := s.createNetworkDevice() if err != nil { return err } err = s.addIPToNetwork() if err != nil{ err2 := s.removeNetworkDevice() if err2 != nil { return fmt.Errorf("Error deleting Network Device %w because of IP range error %s.", err2, err) } return err } err = s.wgSetup() if err != nil{ err2 := s.removeNetworkDevice() if err2 != nil { return fmt.Errorf("Error deleting Network Device %w because of Wiregaurd error %s.", err2, err) } return err } err = s.upNetworkDevice() if err != nil{ //todo: test err2 := s.removeNetworkDevice() if err2 != nil { return fmt.Errorf("Error deleting Network Device %w because of Wiregaurd error %s.", err2, err) } return err } return nil } func (s *WireGuard) AddPeer(config PeerConfig) (error) { s.wgUpdate.Lock() defer s.wgUpdate.Unlock() if s.wgConfig.PrivateKey == nil { return errors.New("server not up") } client, err := wgctrl.New() if err != nil { return err } pubKey, err := wgtypes.ParseKey(config.PublicKey) if err != nil { return err } var ipList []net.IPNet for _, ip := range config.AllowedIPs { _, net, err := net.ParseCIDR(ip) if err != nil { return err } ipList = append(ipList, *net) } d := 30 * time.Second var endpoint *net.UDPAddr if config.Endpoint != "" { //todo: allow hostnames details := strings.Split(config.Endpoint, ":") ip := net.ParseIP(details[0]) if ip == nil{ return errors.New("Invalide endpoint ip") } port, err := strconv.Atoi(details[1]) if err != nil { return fmt.Errorf("Cant convert port to int: %w", err) } udpaddr := net.UDPAddr{ IP: ip, Port: port, } endpoint = &udpaddr } var preKey *wgtypes.Key if config.PreSharedKey != "" { presharedKey, err := wgtypes.ParseKey(config.PreSharedKey ) if err != nil { return err } preKey = &presharedKey } peerConfig := wgtypes.PeerConfig{ PublicKey: pubKey, Remove: false, UpdateOnly: false, PresharedKey: preKey, Endpoint: endpoint, PersistentKeepaliveInterval: &d, ReplaceAllowedIPs: true, AllowedIPs: ipList, } s.wgConfig.Peers = append(s.wgConfig.Peers, peerConfig) err = client.ConfigureDevice(s.name, s.wgConfig) if err != nil { return err } return nil } func (s *WireGuard) RemovePeer(publicKey string) (error) { s.wgUpdate.Lock() defer s.wgUpdate.Unlock() if s.wgConfig.PrivateKey == nil { return errors.New("server not up") } client, err := wgctrl.New() if err != nil { return err } var newlist []wgtypes.PeerConfig for _ , peer := range s.wgConfig.Peers { if peer.PublicKey.String() != publicKey { newlist = append(newlist, peer) } } s.wgConfig.Peers = newlist err = client.ConfigureDevice(s.name, s.wgConfig) if err != nil { return err } return nil } func (s *WireGuard) wgSetup() (error) { if s.wgConfig.PrivateKey != nil { return errors.New("Wireguard already setedup") } client, err := wgctrl.New() if err != nil { return err } s.wgClient = client privkey, err := wgtypes.ParseKey(s.privateKey) if err != nil { return err } var port *int if s.port > 0 { port = &s.port } s.wgConfig = wgtypes.Config{ PrivateKey: &privkey, ListenPort: port, FirewallMark: nil, ReplacePeers: true, Peers: nil, } s.wgClient.ConfigureDevice(s.name, s.wgConfig) return nil } func GenerateKeyPair() (pubkey string, privkey string, error error) { key, err := wgtypes.GeneratePrivateKey() if err != nil { return "", "", err } privkey = key.String() pubkey = key.PublicKey().String() return }