mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
145 lines
3.1 KiB
Go
145 lines
3.1 KiB
Go
|
package wireguard
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"net"
|
||
|
"os"
|
||
|
"time"
|
||
|
|
||
|
"github.com/edgelesssys/constellation/coordinator/util"
|
||
|
"github.com/vishvananda/netlink"
|
||
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
netInterface = "wg0"
|
||
|
port = 51820
|
||
|
)
|
||
|
|
||
|
type Wireguard struct{}
|
||
|
|
||
|
func New() *Wireguard {
|
||
|
return &Wireguard{}
|
||
|
}
|
||
|
|
||
|
func (w *Wireguard) Setup(privKey []byte) ([]byte, error) {
|
||
|
client, err := wgctrl.New()
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("failed to open wgctrl: %w", err)
|
||
|
}
|
||
|
defer client.Close()
|
||
|
|
||
|
var key wgtypes.Key
|
||
|
if len(privKey) == 0 {
|
||
|
key, err = wgtypes.GeneratePrivateKey()
|
||
|
} else {
|
||
|
key, err = wgtypes.NewKey(privKey)
|
||
|
}
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
listenPort := port
|
||
|
if err := client.ConfigureDevice(netInterface, wgtypes.Config{PrivateKey: &key, ListenPort: &listenPort}); err != nil {
|
||
|
return nil, prettyWgError(err)
|
||
|
}
|
||
|
|
||
|
return key[:], nil
|
||
|
}
|
||
|
|
||
|
func (w *Wireguard) GetPublicKey(privKey []byte) ([]byte, error) {
|
||
|
key, err := wgtypes.NewKey(privKey)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
pubkey := key.PublicKey()
|
||
|
return pubkey[:], nil
|
||
|
}
|
||
|
|
||
|
func (w *Wireguard) GetInterfaceIP() (string, error) {
|
||
|
return util.GetInterfaceIP(netInterface)
|
||
|
}
|
||
|
|
||
|
// SetInterfaceIP sets the ip interface ip.
|
||
|
func (w *Wireguard) SetInterfaceIP(ip string) error {
|
||
|
addr, err := netlink.ParseAddr(ip + "/16")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
link, err := netlink.LinkByName(netInterface)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if err := netlink.AddrAdd(link, addr); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return netlink.LinkSetUp(link)
|
||
|
}
|
||
|
|
||
|
// AddPeer adds a new peer to a wireguard interface.
|
||
|
func (w *Wireguard) AddPeer(pubKey []byte, publicIP string, vpnIP string) error {
|
||
|
client, err := wgctrl.New()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to open wgctrl: %w", err)
|
||
|
}
|
||
|
defer client.Close()
|
||
|
|
||
|
_, allowedIPs, err := net.ParseCIDR(vpnIP + "/32")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
key, err := wgtypes.NewKey(pubKey)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
var endpoint *net.UDPAddr
|
||
|
if ip := net.ParseIP(publicIP); ip != nil {
|
||
|
endpoint = &net.UDPAddr{IP: ip, Port: port}
|
||
|
}
|
||
|
|
||
|
keepAlive := 10 * time.Second
|
||
|
cfg := wgtypes.Config{
|
||
|
ReplacePeers: false,
|
||
|
Peers: []wgtypes.PeerConfig{
|
||
|
{
|
||
|
PublicKey: key,
|
||
|
UpdateOnly: false,
|
||
|
Endpoint: endpoint,
|
||
|
AllowedIPs: []net.IPNet{*allowedIPs},
|
||
|
PersistentKeepaliveInterval: &keepAlive,
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
return prettyWgError(client.ConfigureDevice(netInterface, cfg))
|
||
|
}
|
||
|
|
||
|
// RemovePeer removes a peer from the wireguard interface.
|
||
|
func (w *Wireguard) RemovePeer(pubKey []byte) error {
|
||
|
client, err := wgctrl.New()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to open wgctrl: %w", err)
|
||
|
}
|
||
|
defer client.Close()
|
||
|
|
||
|
key, err := wgtypes.NewKey(pubKey)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
cfg := wgtypes.Config{Peers: []wgtypes.PeerConfig{{PublicKey: key, Remove: true}}}
|
||
|
|
||
|
return prettyWgError(client.ConfigureDevice(netInterface, cfg))
|
||
|
}
|
||
|
|
||
|
func prettyWgError(err error) error {
|
||
|
if errors.Is(err, os.ErrNotExist) {
|
||
|
return errors.New("interface not found or is not a WireGuard interface")
|
||
|
}
|
||
|
return err
|
||
|
}
|