package wgfunc import ( "errors" "fmt" "github.com/vishvananda/netlink" "golang.zx2c4.com/wireguard/wgctrl" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "net" "strconv" "strings" "sync" "time" ) type Server struct { name string iPRanges []string wgDev *netlink.GenericLink wgConfig wgtypes.Config wgClient *wgctrl.Client wgUpdate sync.Mutex port int //Wireguard Server Port privateKey string //Wireguard Server Private Key } type ServerConfig struct{ Name string IPRanges []string Port int //Wireguard Server Port PrivateKey string //Wireguard Server Private Key } func NewServer(config ServerConfig) (Server, error){ server := Server{ name: config.Name, iPRanges: config.IPRanges, port: config.Port, privateKey: config.PrivateKey, } return server, nil } type PeerConfig struct { PublicKey string PreSharedKey string AllowedIPs []string Endpoint string } func (s *Server) Down() (error) { return s.removeNetworkDevice() } func (s *Server) 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 *Server) 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 *Server) 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 *Server) createNetworkDevice() (error) { la := netlink.NewLinkAttrs() la.Name = s.name wgDev := &netlink.GenericLink{ LinkAttrs: la, LinkType: "wireguard", } err := netlink.LinkAdd(wgDev) if err != nil { return err } s.wgDev = wgDev return nil } func (s *Server) upNetworkDevice() (error) { err := netlink.LinkSetUp(s.wgDev) //todo: test if err != nil { return err } return nil } func (s *Server) removeNetworkDevice() (error) { la := netlink.NewLinkAttrs() la.Name = s.name wgDev := &netlink.GenericLink{ LinkAttrs: la, LinkType: "wireguard", } err := netlink.LinkDel(wgDev) return err } func (s *Server) addIPToNetwork() (error) { var ips []*netlink.Addr for _, iprange := range s.iPRanges { ip, err := netlink.ParseAddr(iprange) if err != nil { return err } ips = append(ips, ip) } for _, ip := range ips { err := netlink.AddrAdd(s.wgDev, ip) if err != nil { //ToDo: Check how to test this case return err } } return nil } func (s *Server) 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 } s.wgConfig = wgtypes.Config{ PrivateKey: &privkey, ListenPort: &s.port, FirewallMark: nil, ReplacePeers: true, Peers: nil, } s.wgClient.ConfigureDevice(s.name, s.wgConfig) return nil }