mirror of
https://github.com/netbirdio/netbird.git
synced 2024-12-27 09:09:00 +01:00
1012172f04
Handle routes updates from management Manage routing firewall rules Manage peer RIB table Add get peer and get notification channel from the status recorder Update interface peers allowed IPs
259 lines
6.3 KiB
Go
259 lines
6.3 KiB
Go
package iface
|
|
|
|
import (
|
|
"fmt"
|
|
log "github.com/sirupsen/logrus"
|
|
"golang.zx2c4.com/wireguard/wgctrl"
|
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
// GetName returns the interface name
|
|
func (w *WGIface) GetName() string {
|
|
return w.Name
|
|
}
|
|
|
|
// GetAddress returns the interface address
|
|
func (w *WGIface) GetAddress() WGAddress {
|
|
return w.Address
|
|
}
|
|
|
|
// configureDevice configures the wireguard device
|
|
func (w *WGIface) configureDevice(config wgtypes.Config) error {
|
|
wg, err := wgctrl.New()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer wg.Close()
|
|
|
|
// validate if device with name exists
|
|
_, err = wg.Device(w.Name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Debugf("got Wireguard device %s", w.Name)
|
|
|
|
return wg.ConfigureDevice(w.Name, config)
|
|
}
|
|
|
|
// Configure configures a Wireguard interface
|
|
// The interface must exist before calling this method (e.g. call interface.Create() before)
|
|
func (w *WGIface) Configure(privateKey string, port int) error {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
|
|
log.Debugf("configuring Wireguard interface %s", w.Name)
|
|
|
|
log.Debugf("adding Wireguard private key")
|
|
key, err := wgtypes.ParseKey(privateKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fwmark := 0
|
|
config := wgtypes.Config{
|
|
PrivateKey: &key,
|
|
ReplacePeers: true,
|
|
FirewallMark: &fwmark,
|
|
ListenPort: &port,
|
|
}
|
|
|
|
err = w.configureDevice(config)
|
|
if err != nil {
|
|
return fmt.Errorf("received error \"%v\" while configuring interface %s with port %d", err, w.Name, port)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetListenPort returns the listening port of the Wireguard endpoint
|
|
func (w *WGIface) GetListenPort() (*int, error) {
|
|
log.Debugf("getting Wireguard listen port of interface %s", w.Name)
|
|
|
|
//discover Wireguard current configuration
|
|
wg, err := wgctrl.New()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer wg.Close()
|
|
|
|
d, err := wg.Device(w.Name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
log.Debugf("got Wireguard device listen port %s, %d", w.Name, d.ListenPort)
|
|
|
|
return &d.ListenPort, nil
|
|
}
|
|
|
|
// UpdatePeer updates existing Wireguard Peer or creates a new one if doesn't exist
|
|
// Endpoint is optional
|
|
func (w *WGIface) UpdatePeer(peerKey string, allowedIps string, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
|
|
log.Debugf("updating interface %s peer %s: endpoint %s ", w.Name, peerKey, endpoint)
|
|
|
|
//parse allowed ips
|
|
_, ipNet, err := net.ParseCIDR(allowedIps)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
peer := wgtypes.PeerConfig{
|
|
PublicKey: peerKeyParsed,
|
|
ReplaceAllowedIPs: true,
|
|
AllowedIPs: []net.IPNet{*ipNet},
|
|
PersistentKeepaliveInterval: &keepAlive,
|
|
PresharedKey: preSharedKey,
|
|
Endpoint: endpoint,
|
|
}
|
|
|
|
config := wgtypes.Config{
|
|
Peers: []wgtypes.PeerConfig{peer},
|
|
}
|
|
err = w.configureDevice(config)
|
|
if err != nil {
|
|
return fmt.Errorf("received error \"%v\" while updating peer on interface %s with settings: allowed ips %s, endpoint %s", err, w.Name, allowedIps, endpoint.String())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AddAllowedIP adds a prefix to the allowed IPs list of peer
|
|
func (w *WGIface) AddAllowedIP(peerKey string, allowedIP string) error {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
|
|
log.Debugf("adding allowed IP to interface %s and peer %s: allowed IP %s ", w.Name, peerKey, allowedIP)
|
|
|
|
_, ipNet, err := net.ParseCIDR(allowedIP)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
peer := wgtypes.PeerConfig{
|
|
PublicKey: peerKeyParsed,
|
|
UpdateOnly: true,
|
|
ReplaceAllowedIPs: false,
|
|
AllowedIPs: []net.IPNet{*ipNet},
|
|
}
|
|
|
|
config := wgtypes.Config{
|
|
Peers: []wgtypes.PeerConfig{peer},
|
|
}
|
|
err = w.configureDevice(config)
|
|
if err != nil {
|
|
return fmt.Errorf("received error \"%v\" while adding allowed Ip to peer on interface %s with settings: allowed ips %s", err, w.Name, allowedIP)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RemoveAllowedIP removes a prefix from the allowed IPs list of peer
|
|
func (w *WGIface) RemoveAllowedIP(peerKey string, allowedIP string) error {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
|
|
log.Debugf("removing allowed IP from interface %s and peer %s: allowed IP %s ", w.Name, peerKey, allowedIP)
|
|
|
|
_, ipNet, err := net.ParseCIDR(allowedIP)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
existingPeer, err := getPeer(w.Name, peerKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
newAllowedIPs := existingPeer.AllowedIPs
|
|
|
|
for i, existingAllowedIP := range existingPeer.AllowedIPs {
|
|
if existingAllowedIP.String() == ipNet.String() {
|
|
newAllowedIPs = append(existingPeer.AllowedIPs[:i], existingPeer.AllowedIPs[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
peer := wgtypes.PeerConfig{
|
|
PublicKey: peerKeyParsed,
|
|
UpdateOnly: true,
|
|
ReplaceAllowedIPs: true,
|
|
AllowedIPs: newAllowedIPs,
|
|
}
|
|
|
|
config := wgtypes.Config{
|
|
Peers: []wgtypes.PeerConfig{peer},
|
|
}
|
|
err = w.configureDevice(config)
|
|
if err != nil {
|
|
return fmt.Errorf("received error \"%v\" while removing allowed IP from peer on interface %s with settings: allowed ips %s", err, w.Name, allowedIP)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getPeer(ifaceName, peerPubKey string) (wgtypes.Peer, error) {
|
|
wg, err := wgctrl.New()
|
|
if err != nil {
|
|
return wgtypes.Peer{}, err
|
|
}
|
|
defer func() {
|
|
err = wg.Close()
|
|
if err != nil {
|
|
log.Errorf("got error while closing wgctl: %v", err)
|
|
}
|
|
}()
|
|
|
|
wgDevice, err := wg.Device(ifaceName)
|
|
if err != nil {
|
|
return wgtypes.Peer{}, err
|
|
}
|
|
for _, peer := range wgDevice.Peers {
|
|
if peer.PublicKey.String() == peerPubKey {
|
|
return peer, nil
|
|
}
|
|
}
|
|
return wgtypes.Peer{}, fmt.Errorf("peer not found")
|
|
}
|
|
|
|
// RemovePeer removes a Wireguard Peer from the interface iface
|
|
func (w *WGIface) RemovePeer(peerKey string) error {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
|
|
log.Debugf("Removing peer %s from interface %s ", peerKey, w.Name)
|
|
|
|
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
peer := wgtypes.PeerConfig{
|
|
PublicKey: peerKeyParsed,
|
|
Remove: true,
|
|
}
|
|
|
|
config := wgtypes.Config{
|
|
Peers: []wgtypes.PeerConfig{peer},
|
|
}
|
|
err = w.configureDevice(config)
|
|
if err != nil {
|
|
return fmt.Errorf("received error \"%v\" while removing peer %s from interface %s", err, peerKey, w.Name)
|
|
}
|
|
return nil
|
|
}
|