From 480cbb45f5342a2ecd9195a968363cf8da993998 Mon Sep 17 00:00:00 2001 From: Jacob McSwain Date: Thu, 12 Nov 2020 14:03:31 -0600 Subject: [PATCH] Add keepalive to wesher (cherry picked from commit 982cac3b1a69d5759eaf477785301a564b551bc5) --- README.md | 1 + config.go | 31 ++++++++++++++++--------------- main.go | 8 +++++++- wg/wireguard.go | 34 +++++++++++++++++++--------------- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 5db484a..c6f1ed7 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,7 @@ All options can be passed either as command-line flags or environment variables: | `--interface DEV` | WESHER_INTERFACE | name of the wireguard interface to create and manage | `wgoverlay` | | `--no-etc-hosts` | WESHER_NO_ETC_HOSTS | whether to skip writing hosts entries for each node in mesh | `false` | | `--log-level LEVEL` | WESHER_LOG_LEVEL | set the verbosity (one of debug/info/warn/error) | `warn` | +| `--keepalive-interval INTERVAL` | WESHER_KEEPALIVE_INTERVAL | interval for which to send keepalive packets | `30s` | ## Running multiple clusters diff --git a/config.go b/config.go index f1bb86b..34528c3 100644 --- a/config.go +++ b/config.go @@ -11,21 +11,22 @@ import ( ) type config struct { - ClusterKey []byte `id:"cluster-key" desc:"shared key for cluster membership; must be 32 bytes base64 encoded; will be generated if not provided"` - Join []string `desc:"comma separated list of hostnames or IP addresses to existing cluster members; if not provided, will attempt resuming any known state or otherwise wait for further members."` - Rejoin int `desc:"interval at which join nodes are joined again if away, 0 disables rejoining altogether" default:"0"` - Init bool `desc:"whether to explicitly (re)initialize the cluster; any known state from previous runs will be forgotten"` - BindAddr string `id:"bind-addr" desc:"IP address to bind to for cluster membership traffic (cannot be used with --bind-iface)"` - BindIface string `id:"bind-iface" desc:"Interface to bind to for cluster membership traffic (cannot be used with --bind-addr)"` - ClusterPort int `id:"cluster-port" desc:"port used for membership gossip traffic (both TCP and UDP); must be the same across cluster" default:"7946"` - WireguardPort int `id:"wireguard-port" desc:"port used for wireguard traffic (UDP); must be the same across cluster" default:"51820"` - BaseMtu int `id:"mtu" desc:"MTU of the underlying network, taking intermediary hops into account" default:"1500"` - OverlayNet *network `id:"overlay-net" desc:"the network in which to allocate addresses for the overlay mesh network (CIDR format); smaller networks increase the chance of IP collision" default:"10.0.0.0/8"` - RoutedNet *network `id:"routed-net" desc:"network used to filter routes that nodes are allowed to announce (CIDR format)" default:"0.0.0.0/32"` - Interface string `desc:"name of the wireguard interface to create and manage" default:"wgoverlay"` - NoEtcHosts bool `id:"no-etc-hosts" desc:"disable writing of entries to /etc/hosts"` - LogLevel string `id:"log-level" desc:"set the verbosity (debug/info/warn/error)" default:"warn"` - Version bool `desc:"display current version and exit"` + ClusterKey []byte `id:"cluster-key" desc:"shared key for cluster membership; must be 32 bytes base64 encoded; will be generated if not provided"` + Join []string `desc:"comma separated list of hostnames or IP addresses to existing cluster members; if not provided, will attempt resuming any known state or otherwise wait for further members."` + Rejoin int `desc:"interval at which join nodes are joined again if away, 0 disables rejoining altogether" default:"0"` + Init bool `desc:"whether to explicitly (re)initialize the cluster; any known state from previous runs will be forgotten"` + BindAddr string `id:"bind-addr" desc:"IP address to bind to for cluster membership traffic (cannot be used with --bind-iface)"` + BindIface string `id:"bind-iface" desc:"Interface to bind to for cluster membership traffic (cannot be used with --bind-addr)"` + ClusterPort int `id:"cluster-port" desc:"port used for membership gossip traffic (both TCP and UDP); must be the same across cluster" default:"7946"` + WireguardPort int `id:"wireguard-port" desc:"port used for wireguard traffic (UDP); must be the same across cluster" default:"51820"` + BaseMtu int `id:"mtu" desc:"MTU of the underlying network, taking intermediary hops into account" default:"1500"` + OverlayNet *network `id:"overlay-net" desc:"the network in which to allocate addresses for the overlay mesh network (CIDR format); smaller networks increase the chance of IP collision" default:"10.0.0.0/8"` + RoutedNet *network `id:"routed-net" desc:"network used to filter routes that nodes are allowed to announce (CIDR format)" default:"0.0.0.0/32"` + Interface string `desc:"name of the wireguard interface to create and manage" default:"wgoverlay"` + NoEtcHosts bool `id:"no-etc-hosts" desc:"disable writing of entries to /etc/hosts"` + LogLevel string `id:"log-level" desc:"set the verbosity (debug/info/warn/error)" default:"warn"` + Version bool `desc:"display current version and exit"` + KeepaliveInterval string `id:"keepalive-interval" desc:"interval for which to send keepalive packets" default:"30s"` // for easier local testing; will break etchosts entry UseIPAsName bool `id:"ip-as-name" default:"false" opts:"hidden"` diff --git a/main.go b/main.go index 9908a78..28c8fd3 100644 --- a/main.go +++ b/main.go @@ -39,7 +39,13 @@ func main() { if err != nil { logrus.WithError(err).Fatal("could not create cluster") } - wgstate, localNode, err := wg.New(config.Interface, config.WireguardPort, config.BaseMtu, (*net.IPNet)(config.OverlayNet), cluster.LocalName) + + keepaliveDuration, err := time.ParseDuration(config.KeepaliveInterval) + if err != nil { + logrus.WithError(err).Fatal("could not parse time duration for keepalive") + } + + wgstate, localNode, err := wg.New(config.Interface, config.WireguardPort, config.BaseMtu, (*net.IPNet)(config.OverlayNet), cluster.LocalName, &keepaliveDuration) if err != nil { logrus.WithError(err).Fatal("could not instantiate wireguard controller") } diff --git a/wg/wireguard.go b/wg/wireguard.go index 569cf64..3b0d579 100644 --- a/wg/wireguard.go +++ b/wg/wireguard.go @@ -4,6 +4,7 @@ import ( "hash/fnv" "net" "os" + "time" "github.com/costela/wesher/common" "github.com/pkg/errors" @@ -14,19 +15,20 @@ import ( // State holds the configured state of a Wesher Wireguard interface type State struct { - iface string - client *wgctrl.Client - OverlayAddr net.IPNet - Port int - Mtu int - PrivKey wgtypes.Key - PubKey wgtypes.Key + iface string + client *wgctrl.Client + OverlayAddr net.IPNet + Port int + Mtu int + PrivKey wgtypes.Key + PubKey wgtypes.Key + KeepaliveInterval *time.Duration } // New creates a new Wesher Wireguard state // The Wireguard keys are generated for every new interface // The interface must later be setup using SetUpInterface -func New(iface string, port int, mtu int, ipnet *net.IPNet, name string) (*State, *common.Node, error) { +func New(iface string, port int, mtu int, ipnet *net.IPNet, name string, keepaliveInterval *time.Duration) (*State, *common.Node, error) { client, err := wgctrl.New() if err != nil { return nil, nil, errors.Wrap(err, "could not instantiate wireguard client") @@ -39,12 +41,13 @@ func New(iface string, port int, mtu int, ipnet *net.IPNet, name string) (*State pubKey := privKey.PublicKey() state := State{ - iface: iface, - client: client, - Port: port, - Mtu: mtu, - PrivKey: privKey, - PubKey: pubKey, + iface: iface, + client: client, + Port: port, + Mtu: mtu, + PrivKey: privKey, + PubKey: pubKey, + KeepaliveInterval: keepaliveInterval, } state.assignOverlayAddr(ipnet, name) @@ -192,7 +195,8 @@ func (s *State) nodesToPeerConfigs(nodes []common.Node) ([]wgtypes.PeerConfig, e IP: node.Addr, Port: s.Port, }, - AllowedIPs: append([]net.IPNet{node.OverlayAddr}, node.Routes...), + AllowedIPs: append([]net.IPNet{node.OverlayAddr}, node.Routes...), + PersistentKeepaliveInterval: s.KeepaliveInterval, } } return peerCfgs, nil