240 lines
4.4 KiB
Go
240 lines
4.4 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
|
|
}
|
|
|