keksvpn/pkg/wgfunc/server.go

294 lines
5.3 KiB
Go

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
}