diff --git a/connection/connection.go b/connection/connection.go index 69ff2a58a12..d64131384a2 100644 --- a/connection/connection.go +++ b/connection/connection.go @@ -94,9 +94,9 @@ func (conn *Connection) Open(timeout time.Duration) error { // create an ice.Agent that will be responsible for negotiating and establishing actual peer-to-peer connection a, err := ice.NewAgent(&ice.AgentConfig{ - MulticastDNSMode: ice.MulticastDNSModeQueryAndGather, - NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4}, - Urls: conn.Config.StunTurnURLS, + // MulticastDNSMode: ice.MulticastDNSModeQueryAndGather, + NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4}, + Urls: conn.Config.StunTurnURLS, InterfaceFilter: func(s string) bool { if conn.Config.iFaceBlackList == nil { return true diff --git a/iface/iface.go b/iface/iface.go index 5909aaeaf23..d0d185f121f 100644 --- a/iface/iface.go +++ b/iface/iface.go @@ -1,15 +1,12 @@ +// +build !linux + package iface import ( - "net" - "time" - log "github.com/sirupsen/logrus" "golang.zx2c4.com/wireguard/conn" "golang.zx2c4.com/wireguard/device" "golang.zx2c4.com/wireguard/tun" - "golang.zx2c4.com/wireguard/wgctrl" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) const ( diff --git a/iface/iface_configuration.go b/iface/iface_configuration.go new file mode 100644 index 00000000000..8f56bd4ced4 --- /dev/null +++ b/iface/iface_configuration.go @@ -0,0 +1,207 @@ +package iface + +import ( + "net" + "time" + + log "github.com/sirupsen/logrus" + "golang.zx2c4.com/wireguard/wgctrl" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +const ( + defaultMTU = 1280 +) + +// ConfigureWithKeyGen Extends the functionality of Configure(iface string, privateKey string) by generating a new Wireguard private key +func ConfigureWithKeyGen(iface string) (*wgtypes.Key, error) { + key, err := wgtypes.GeneratePrivateKey() + if err != nil { + return nil, err + } + return &key, Configure(iface, key.String()) +} + +// Configure configures a Wireguard interface +// The interface must exist before calling this method (e.g. call interface.Create() before) +func Configure(iface string, privateKey string) error { + + log.Debugf("configuring Wireguard interface %s", iface) + wg, err := wgctrl.New() + if err != nil { + return err + } + defer wg.Close() + + log.Debugf("adding Wireguard private key") + key, err := wgtypes.ParseKey(privateKey) + if err != nil { + return err + } + fwmark := 0 + cfg := wgtypes.Config{ + PrivateKey: &key, + ReplacePeers: false, + FirewallMark: &fwmark, + } + err = wg.ConfigureDevice(iface, cfg) + if err != nil { + return err + } + + return nil +} + +// GetListenPort returns the listening port of the Wireguard endpoint +func GetListenPort(iface string) (*int, error) { + log.Debugf("getting Wireguard listen port of interface %s", iface) + + //discover Wireguard current configuration + wg, err := wgctrl.New() + if err != nil { + return nil, err + } + defer wg.Close() + + d, err := wg.Device(iface) + if err != nil { + return nil, err + } + log.Debugf("got Wireguard device listen port %s, %d", iface, &d.ListenPort) + + return &d.ListenPort, nil +} + +// UpdateListenPort updates a Wireguard interface listen port +func UpdateListenPort(iface string, newPort int) error { + log.Debugf("updating Wireguard listen port of interface %s, new port %d", iface, newPort) + + //discover Wireguard current configuration + wg, err := wgctrl.New() + if err != nil { + return err + } + defer wg.Close() + + _, err = wg.Device(iface) + if err != nil { + return err + } + log.Debugf("got Wireguard device %s", iface) + + config := wgtypes.Config{ + ListenPort: &newPort, + ReplacePeers: false, + } + err = wg.ConfigureDevice(iface, config) + if err != nil { + return err + } + + log.Debugf("updated Wireguard listen port of interface %s, new port %d", iface, newPort) + + return nil +} + +// UpdatePeer updates existing Wireguard Peer or creates a new one if doesn't exist +// Endpoint is optional +func UpdatePeer(iface string, peerKey string, allowedIps string, keepAlive time.Duration, endpoint string) error { + + log.Debugf("updating interface %s peer %s: endpoint %s ", iface, peerKey, endpoint) + + wg, err := wgctrl.New() + if err != nil { + return err + } + defer wg.Close() + + _, err = wg.Device(iface) + if err != nil { + return err + } + log.Debugf("got Wireguard device %s", iface) + + //parse allowed ips + _, ipNet, err := net.ParseCIDR(allowedIps) + if err != nil { + return err + } + + peerKeyParsed, err := wgtypes.ParseKey(peerKey) + if err != nil { + return err + } + peers := make([]wgtypes.PeerConfig, 0) + peer := wgtypes.PeerConfig{ + PublicKey: peerKeyParsed, + ReplaceAllowedIPs: true, + AllowedIPs: []net.IPNet{*ipNet}, + PersistentKeepaliveInterval: &keepAlive, + } + peers = append(peers, peer) + + config := wgtypes.Config{ + ReplacePeers: false, + Peers: peers, + } + err = wg.ConfigureDevice(iface, config) + if err != nil { + return err + } + + if endpoint != "" { + return UpdatePeerEndpoint(iface, peerKey, endpoint) + } + + return nil +} + +// UpdatePeerEndpoint updates a Wireguard interface Peer with the new endpoint +// Used when NAT hole punching was successful and an update of the remote peer endpoint is required +func UpdatePeerEndpoint(iface string, peerKey string, newEndpoint string) error { + + log.Debugf("updating peer %s endpoint %s ", peerKey, newEndpoint) + + wg, err := wgctrl.New() + if err != nil { + return err + } + defer wg.Close() + + _, err = wg.Device(iface) + if err != nil { + return err + } + log.Debugf("got Wireguard device %s", iface) + + peerAddr, err := net.ResolveUDPAddr("udp4", newEndpoint) + if err != nil { + return err + } + + log.Debugf("parsed peer endpoint [%s]", peerAddr.String()) + + peerKeyParsed, err := wgtypes.ParseKey(peerKey) + if err != nil { + return err + } + peers := make([]wgtypes.PeerConfig, 0) + peer := wgtypes.PeerConfig{ + PublicKey: peerKeyParsed, + ReplaceAllowedIPs: false, + UpdateOnly: true, + Endpoint: peerAddr, + } + peers = append(peers, peer) + + config := wgtypes.Config{ + ReplacePeers: false, + Peers: peers, + } + err = wg.ConfigureDevice(iface, config) + if err != nil { + return err + } + + return nil +} diff --git a/iface/iface_linux.go b/iface/iface_linux.go index 346ac5a0a39..120d67954ff 100644 --- a/iface/iface_linux.go +++ b/iface/iface_linux.go @@ -3,24 +3,64 @@ package iface import ( log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" - "golang.zx2c4.com/wireguard/tun" - "os" ) -//const ( -// interfacePrefix = "wg" -//) - -// assignAddr Adds IP address to the tunnel interface -func assignAddr(address string, tunDevice tun.Device) error { - var err error +// Create Creates a new Wireguard interface, sets a given IP and brings it up. +// Will reuse an existing one. +func Create(iface string, address string) error { attrs := netlink.NewLinkAttrs() - attrs.Name, err = tunDevice.Name() + attrs.Name = iface + + link := wgLink{ + attrs: &attrs, + } + + log.Debugf("adding device: %s", iface) + err := netlink.LinkAdd(&link) + if os.IsExist(err) { + log.Infof("interface %s already exists. Will reuse.", iface) + } else if err != nil { + return err + } + + log.Debugf("adding address %s to interface: %s", address, iface) + addr, _ := netlink.ParseAddr(address) + err = netlink.AddrAdd(&link, addr) + if os.IsExist(err) { + log.Infof("interface %s already has the address: %s", iface, address) + } else if err != nil { + return err + } + err = assignAddr(address, iface) if err != nil { return err } + // todo do a discovery + log.Debugf("setting MTU: %s", iface) + err = netlink.LinkSetMTU(&link, defaultMTU) + if err != nil { + log.Errorf("error setting MTU on interface: %s", iface) + return err + } + + log.Debugf("bringing up interface: %s", iface) + err = netlink.LinkSetUp(&link) + if err != nil { + log.Errorf("error bringing up interface: %s", iface) + return err + } + + return nil +} + +// assignAddr Adds IP address to the tunnel interface +func assignAddr(address, name string) error { + var err error + attrs := netlink.NewLinkAttrs() + attrs.Name = name + link := wgLink{ attrs: &attrs, }