add hpeer for non-node peers
Signed-off-by: Evan Hazlett <ejhazlett@gmail.com>
This commit is contained in:
parent
9b07492180
commit
332378e3ff
20 changed files with 1348 additions and 195 deletions
|
@ -25,42 +25,86 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ptypes "github.com/gogo/protobuf/types"
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"github.com/sirupsen/logrus"
|
||||
v1 "github.com/stellarproject/heimdall/api/v1"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidAuth is returned when an invalid cluster key is specified upon connect
|
||||
ErrInvalidAuth = errors.New("invalid cluster key specified")
|
||||
// ErrNoMaster is returned if there is no configured master yet
|
||||
ErrNoMaster = errors.New("no configured master")
|
||||
// ErrAccessDenied is returned when an unauthorized non-node peer attempts to join
|
||||
ErrAccessDenied = errors.New("access denied")
|
||||
)
|
||||
|
||||
// Connect is called when a peer wants to connect to the node
|
||||
func (s *Server) Connect(ctx context.Context, req *v1.ConnectRequest) (*v1.ConnectResponse, error) {
|
||||
logrus.Debugf("connect request from %s", req.ID)
|
||||
key, err := s.getClusterKey(ctx)
|
||||
func (s *Server) AuthorizedPeers(ctx context.Context, req *v1.AuthorizedPeersRequest) (*v1.AuthorizedPeersResponse, error) {
|
||||
authorized, err := redis.Strings(s.local(ctx, "SMEMBERS", authorizedPeersKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.ClusterKey != key {
|
||||
return nil, ErrInvalidAuth
|
||||
}
|
||||
data, err := redis.Bytes(s.local(ctx, "GET", masterKey))
|
||||
if err != nil {
|
||||
if err == redis.ErrNil {
|
||||
return nil, ErrNoMaster
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var master v1.Master
|
||||
if err := proto.Unmarshal(data, &master); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.ConnectResponse{
|
||||
Master: &master,
|
||||
return &v1.AuthorizedPeersResponse{
|
||||
IDs: authorized,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AuthorizePeer authorizes a peer to the cluster
|
||||
func (s *Server) AuthorizePeer(ctx context.Context, req *v1.AuthorizePeerRequest) (*ptypes.Empty, error) {
|
||||
logrus.Debugf("authorizing peer %s", req.ID)
|
||||
if _, err := s.master(ctx, "SADD", authorizedPeersKey, req.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logrus.Infof("authorized peer %s", req.ID)
|
||||
return empty, nil
|
||||
}
|
||||
|
||||
// DeauthorizePeer deauthorizes a peer from the cluster
|
||||
func (s *Server) DeauthorizePeer(ctx context.Context, req *v1.DeauthorizePeerRequest) (*ptypes.Empty, error) {
|
||||
logrus.Debugf("deauthorizing peer %s", req.ID)
|
||||
if _, err := s.master(ctx, "SREM", authorizedPeersKey, req.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logrus.Infof("deauthorized peer %s", req.ID)
|
||||
return empty, nil
|
||||
}
|
||||
|
||||
// Connect is called when a non-node peer wants to connect to the cluster
|
||||
func (s *Server) Connect(ctx context.Context, req *v1.ConnectRequest) (*v1.ConnectResponse, error) {
|
||||
authorized, err := redis.Bool(s.local(ctx, "SISMEMBER", authorizedPeersKey, req.ID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !authorized {
|
||||
logrus.Warnf("unauthorized request attempt from %s", req.ID)
|
||||
return nil, ErrAccessDenied
|
||||
}
|
||||
keyPair, err := s.getOrCreateKeyPair(ctx, req.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodes, err := s.getNodes(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dnsAddrs := []string{}
|
||||
for _, n := range nodes {
|
||||
dnsAddrs = append(dnsAddrs, n.GatewayIP)
|
||||
}
|
||||
|
||||
peers, err := s.getPeers(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ip, _, err := s.getOrAllocatePeerIP(ctx, req.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.updatePeerInfo(ctx, req.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// save peer
|
||||
return &v1.ConnectResponse{
|
||||
KeyPair: keyPair,
|
||||
Address: ip.String() + "/32",
|
||||
Peers: peers,
|
||||
DNS: dnsAddrs,
|
||||
}, nil
|
||||
}
|
||||
|
|
66
server/join.go
Normal file
66
server/join.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
Copyright 2019 Stellar Project
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies
|
||||
or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"github.com/sirupsen/logrus"
|
||||
v1 "github.com/stellarproject/heimdall/api/v1"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidAuth is returned when an invalid cluster key is specified upon connect
|
||||
ErrInvalidAuth = errors.New("invalid cluster key specified")
|
||||
// ErrNoMaster is returned if there is no configured master yet
|
||||
ErrNoMaster = errors.New("no configured master")
|
||||
)
|
||||
|
||||
// Join is called when a peer wants to join the cluster
|
||||
func (s *Server) Join(ctx context.Context, req *v1.JoinRequest) (*v1.JoinResponse, error) {
|
||||
logrus.Debugf("join request from %s", req.ID)
|
||||
key, err := s.getClusterKey(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.ClusterKey != key {
|
||||
return nil, ErrInvalidAuth
|
||||
}
|
||||
data, err := redis.Bytes(s.local(ctx, "GET", masterKey))
|
||||
if err != nil {
|
||||
if err == redis.ErrNil {
|
||||
return nil, ErrNoMaster
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var master v1.Master
|
||||
if err := proto.Unmarshal(data, &master); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.JoinResponse{
|
||||
Master: &master,
|
||||
}, nil
|
||||
}
|
|
@ -109,7 +109,7 @@ func (s *Server) configureNode() error {
|
|||
logrus.Warn(err)
|
||||
continue
|
||||
}
|
||||
m, err := c.Connect(s.cfg.ClusterKey)
|
||||
m, err := c.Join(s.cfg.ClusterKey)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
logrus.Warn(err)
|
||||
|
|
|
@ -23,16 +23,16 @@ package server
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stellarproject/heimdall"
|
||||
v1 "github.com/stellarproject/heimdall/api/v1"
|
||||
"github.com/stellarproject/heimdall/wg"
|
||||
)
|
||||
|
||||
// Peers returns a list of known peers
|
||||
|
@ -74,8 +74,8 @@ func (s *Server) peerUpdater(ctx context.Context) {
|
|||
|
||||
for range t.C {
|
||||
uctx, cancel := context.WithTimeout(ctx, peerConfigUpdateInterval)
|
||||
if err := s.updatePeerInfo(uctx); err != nil {
|
||||
logrus.Errorf("updatePeerInfo: %s", err)
|
||||
if err := s.updatePeerInfo(uctx, s.cfg.ID); err != nil {
|
||||
logrus.Errorf("updateLocalPeerInfo: %s", err)
|
||||
cancel()
|
||||
continue
|
||||
}
|
||||
|
@ -89,16 +89,24 @@ func (s *Server) peerUpdater(ctx context.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Server) updatePeerInfo(ctx context.Context) error {
|
||||
keypair, err := s.getOrCreateKeyPair(ctx, s.cfg.ID)
|
||||
func (s *Server) updatePeerInfo(ctx context.Context, id string) error {
|
||||
keypair, err := s.getOrCreateKeyPair(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoint := fmt.Sprintf("%s:%d", s.cfg.EndpointIP, s.cfg.EndpointPort)
|
||||
endpoint, err := s.getPeerEndpoint(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// build allowedIPs from routes and peer network
|
||||
allowedIPs := []string{}
|
||||
|
||||
// add peer net
|
||||
if endpoint == "" {
|
||||
allowedIPs = append(allowedIPs, s.cfg.PeerNetwork)
|
||||
}
|
||||
nodes, err := s.getNodes(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -106,7 +114,7 @@ func (s *Server) updatePeerInfo(ctx context.Context) error {
|
|||
|
||||
for _, node := range nodes {
|
||||
// only add the route if a peer to prevent route duplicate
|
||||
if node.ID != s.cfg.ID {
|
||||
if node.ID != id {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -124,17 +132,16 @@ func (s *Server) updatePeerInfo(ctx context.Context) error {
|
|||
}
|
||||
|
||||
for _, route := range routes {
|
||||
// only add the route if a peer to prevent route duplicate
|
||||
if route.NodeID != s.cfg.ID {
|
||||
// only add the route if a peer to prevent route blackhole
|
||||
if route.NodeID != id {
|
||||
continue
|
||||
}
|
||||
|
||||
logrus.Debugf("adding route to allowed IPs: %s", route.Network)
|
||||
allowedIPs = append(allowedIPs, route.Network)
|
||||
}
|
||||
|
||||
n := &v1.Peer{
|
||||
ID: s.cfg.ID,
|
||||
ID: id,
|
||||
KeyPair: keypair,
|
||||
AllowedIPs: allowedIPs,
|
||||
Endpoint: endpoint,
|
||||
|
@ -144,9 +151,9 @@ func (s *Server) updatePeerInfo(ctx context.Context) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pHash := hashData(data)
|
||||
pHash := heimdall.HashData(data)
|
||||
|
||||
key := s.getPeerKey(s.cfg.ID)
|
||||
key := s.getPeerKey(id)
|
||||
peerData, err := redis.Bytes(s.local(ctx, "GET", key))
|
||||
if err != nil {
|
||||
if err != redis.ErrNil {
|
||||
|
@ -154,7 +161,7 @@ func (s *Server) updatePeerInfo(ctx context.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
eHash := hashData(peerData)
|
||||
eHash := heimdall.HashData(peerData)
|
||||
|
||||
// skip update if same
|
||||
if pHash == eHash {
|
||||
|
@ -165,11 +172,25 @@ func (s *Server) updatePeerInfo(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
logrus.Debugf("peer info: endpoint=%s allowedips=%+v", n.Endpoint, n.Endpoint)
|
||||
logrus.Debugf("peer info updated: id=%s", id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) getPeerEndpoint(ctx context.Context, id string) (string, error) {
|
||||
node, err := s.getNode(ctx, id)
|
||||
if err != nil {
|
||||
if err == redis.ErrNil {
|
||||
return "", nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
if node == nil {
|
||||
return "", nil
|
||||
}
|
||||
return fmt.Sprintf("%s:%d", node.EndpointIP, node.EndpointPort), nil
|
||||
}
|
||||
|
||||
func (s *Server) getPeerInfo(ctx context.Context, id string) (*v1.Peer, error) {
|
||||
key := s.getPeerKey(id)
|
||||
data, err := redis.Bytes(s.local(ctx, "GET", key))
|
||||
|
@ -222,25 +243,26 @@ func (s *Server) updatePeerConfig(ctx context.Context) error {
|
|||
}
|
||||
|
||||
size, _ := gatewayNet.Mask.Size()
|
||||
wireguardCfg := &wireguardConfig{
|
||||
Iface: defaultWireguardInterface,
|
||||
wireguardCfg := &wg.Config{
|
||||
Iface: s.cfg.InterfaceName,
|
||||
PrivateKey: keyPair.PrivateKey,
|
||||
ListenPort: s.cfg.EndpointPort,
|
||||
Address: fmt.Sprintf("%s/%d", gatewayIP.To4().String(), size),
|
||||
Peers: peers,
|
||||
}
|
||||
|
||||
tmpCfg, err := generateNodeWireguardConfig(wireguardCfg)
|
||||
wireguardConfigPath := s.getWireguardConfigPath()
|
||||
tmpCfg, err := wg.GenerateNodeConfig(wireguardCfg, wireguardConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h, err := hashConfig(tmpCfg)
|
||||
h, err := heimdall.HashConfig(tmpCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e, err := hashConfig(wireguardConfigPath)
|
||||
e, err := heimdall.HashConfig(wireguardConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -257,30 +279,9 @@ func (s *Server) updatePeerConfig(ctx context.Context) error {
|
|||
}
|
||||
|
||||
// reload wireguard
|
||||
if err := restartWireguardTunnel(ctx); err != nil {
|
||||
if err := wg.RestartTunnel(ctx, s.getTunnelName()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func hashData(data []byte) string {
|
||||
h := sha256.New()
|
||||
h.Write(data)
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
func hashConfig(cfgPath string) (string, error) {
|
||||
if _, err := os.Stat(cfgPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return "", nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
peerData, err := ioutil.ReadFile(cfgPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return hashData(peerData), nil
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"time"
|
||||
|
@ -37,22 +38,24 @@ import (
|
|||
"github.com/stellarproject/heimdall"
|
||||
v1 "github.com/stellarproject/heimdall/api/v1"
|
||||
"github.com/stellarproject/heimdall/client"
|
||||
"github.com/stellarproject/heimdall/wg"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const (
|
||||
masterKey = "heimdall:master"
|
||||
clusterKey = "heimdall:key"
|
||||
keypairsKey = "heimdall:keypairs"
|
||||
nodesKey = "heimdall:nodes"
|
||||
nodeJoinKey = "heimdall:join"
|
||||
peersKey = "heimdall:peers"
|
||||
routesKey = "heimdall:routes"
|
||||
peerIPsKey = "heimdall:peerips"
|
||||
nodeIPsKey = "heimdall:nodeips"
|
||||
nodeNetworksKey = "heimdall:nodenetworks"
|
||||
masterKey = "heimdall:master"
|
||||
clusterKey = "heimdall:key"
|
||||
keypairsKey = "heimdall:keypairs"
|
||||
nodesKey = "heimdall:nodes"
|
||||
nodeJoinKey = "heimdall:join"
|
||||
peersKey = "heimdall:peers"
|
||||
routesKey = "heimdall:routes"
|
||||
peerIPsKey = "heimdall:peerips"
|
||||
nodeIPsKey = "heimdall:nodeips"
|
||||
nodeNetworksKey = "heimdall:nodenetworks"
|
||||
authorizedPeersKey = "heimdall:authorized"
|
||||
|
||||
wireguardConfigPath = "/etc/wireguard/darknet.conf"
|
||||
wireguardConfigDir = "/etc/wireguard"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -118,7 +121,7 @@ func (s *Server) Run() error {
|
|||
}
|
||||
defer c.Close()
|
||||
|
||||
master, err := c.Connect(s.cfg.ClusterKey)
|
||||
master, err := c.Join(s.cfg.ClusterKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -149,7 +152,7 @@ func (s *Server) Run() error {
|
|||
go s.nodeHeartbeat(ctx)
|
||||
|
||||
// initial peer info update
|
||||
if err := s.updatePeerInfo(ctx); err != nil {
|
||||
if err := s.updatePeerInfo(ctx, s.cfg.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -262,7 +265,7 @@ func (s *Server) getOrCreateKeyPair(ctx context.Context, id string) (*v1.KeyPair
|
|||
return nil, err
|
||||
}
|
||||
logrus.Debugf("generating new keypair for %s", s.cfg.ID)
|
||||
privateKey, publicKey, err := generateWireguardKeys(ctx)
|
||||
privateKey, publicKey, err := wg.GenerateWireguardKeys(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -315,6 +318,14 @@ func (s *Server) getClusterKey(ctx context.Context) (string, error) {
|
|||
return redis.String(s.local(ctx, "GET", clusterKey))
|
||||
}
|
||||
|
||||
func (s *Server) getWireguardConfigPath() string {
|
||||
return filepath.Join(wireguardConfigDir, s.cfg.InterfaceName+".conf")
|
||||
}
|
||||
|
||||
func (s *Server) getTunnelName() string {
|
||||
return s.cfg.InterfaceName
|
||||
}
|
||||
|
||||
func (s *Server) local(ctx context.Context, cmd string, args ...interface{}) (interface{}, error) {
|
||||
return s.do(ctx, s.rpool, cmd, args...)
|
||||
}
|
||||
|
|
|
@ -1,146 +0,0 @@
|
|||
/*
|
||||
Copyright 2019 Stellar Project
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies
|
||||
or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
v1 "github.com/stellarproject/heimdall/api/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultWireguardInterface = "darknet"
|
||||
wireguardTemplate = `# managed by heimdall
|
||||
[Interface]
|
||||
PrivateKey = {{ .PrivateKey }}
|
||||
ListenPort = {{ .ListenPort }}
|
||||
Address = {{ .Address }}
|
||||
PostUp = iptables -A FORWARD -i {{ .Iface }} -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i {{ .Iface }} -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
|
||||
PostDown = iptables -D FORWARD -i {{ .Iface }} -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i {{ .Iface }} -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
|
||||
{{ range .Peers }}
|
||||
[Peer]
|
||||
PublicKey = {{ .KeyPair.PublicKey }}
|
||||
{{ if .AllowedIPs }}AllowedIPs = {{ allowedIPs .AllowedIPs }}{{ end }}
|
||||
Endpoint = {{ .Endpoint }}
|
||||
{{ end }}
|
||||
`
|
||||
)
|
||||
|
||||
func allowedIPs(s []string) string {
|
||||
return strings.Join(s, ", ")
|
||||
}
|
||||
|
||||
type wireguardConfig struct {
|
||||
Iface string
|
||||
PrivateKey string
|
||||
ListenPort int
|
||||
Address string
|
||||
Peers []*v1.Peer
|
||||
}
|
||||
|
||||
func generateNodeWireguardConfig(cfg *wireguardConfig) (string, error) {
|
||||
f, err := ioutil.TempFile("", "heimdall-wireguard-")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
t, err := template.New("wireguard").Funcs(template.FuncMap{
|
||||
"allowedIPs": allowedIPs,
|
||||
}).Parse(wireguardTemplate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(wireguardConfigPath), 0755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := t.Execute(f, cfg); err != nil {
|
||||
return "", err
|
||||
}
|
||||
f.Close()
|
||||
|
||||
return f.Name(), nil
|
||||
}
|
||||
|
||||
func generateWireguardKeys(ctx context.Context) (string, string, error) {
|
||||
kData, err := wg(ctx, nil, "genkey")
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
privateKey := strings.TrimSpace(string(kData))
|
||||
buf := bytes.NewBufferString(privateKey)
|
||||
pubData, err := wg(ctx, buf, "pubkey")
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
publicKey := strings.TrimSpace(string(pubData))
|
||||
|
||||
return privateKey, publicKey, nil
|
||||
}
|
||||
|
||||
func getTunnelName() string {
|
||||
return strings.Replace(filepath.Base(wireguardConfigPath), filepath.Ext(filepath.Base(wireguardConfigPath)), "", 1)
|
||||
}
|
||||
|
||||
func restartWireguardTunnel(ctx context.Context) error {
|
||||
tunnelName := getTunnelName()
|
||||
logrus.Infof("restarting tunnel %s", tunnelName)
|
||||
d, err := wg(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// only stop if running
|
||||
if string(d) != "" {
|
||||
d, err := wgquick(ctx, "down", tunnelName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, string(d))
|
||||
}
|
||||
}
|
||||
u, err := wgquick(ctx, "up", tunnelName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, string(u))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func wg(ctx context.Context, in io.Reader, args ...string) ([]byte, error) {
|
||||
cmd := exec.CommandContext(ctx, "wg", args...)
|
||||
if in != nil {
|
||||
cmd.Stdin = in
|
||||
}
|
||||
return cmd.CombinedOutput()
|
||||
}
|
||||
|
||||
func wgquick(ctx context.Context, args ...string) ([]byte, error) {
|
||||
cmd := exec.CommandContext(ctx, "wg-quick", args...)
|
||||
return cmd.CombinedOutput()
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue