keksvpn/pkg/wgfunc/wireguard.go

251 lines
4.6 KiB
Go

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
}