diff --git a/api/v1/heimdall.pb.go b/api/v1/heimdall.pb.go index b1c32a0..968201d 100644 --- a/api/v1/heimdall.pb.go +++ b/api/v1/heimdall.pb.go @@ -166,6 +166,9 @@ func (m *ConnectResponse) GetMaster() *Master { type Node struct { ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"` + PrivateKey string `protobuf:"bytes,3,opt,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"` + ListenPort uint64 `protobuf:"varint,4,opt,name=listen_port,json=listenPort,proto3" json:"listen_port,omitempty"` + GatewayAddress string `protobuf:"bytes,5,opt,name=gateway_address,json=gatewayAddress,proto3" json:"gateway_address,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -209,6 +212,27 @@ func (m *Node) GetAddr() string { return "" } +func (m *Node) GetPrivateKey() string { + if m != nil { + return m.PrivateKey + } + return "" +} + +func (m *Node) GetListenPort() uint64 { + if m != nil { + return m.ListenPort + } + return 0 +} + +func (m *Node) GetGatewayAddress() string { + if m != nil { + return m.GatewayAddress + } + return "" +} + type NodesRequest struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -277,6 +301,68 @@ func (m *NodesResponse) GetNodes() []*Node { return nil } +type Peer struct { + PrivateKey string `protobuf:"bytes,1,opt,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"` + PublicKey string `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + AllowedIPs []string `protobuf:"bytes,3,rep,name=allowed_ips,json=allowedIps,proto3" json:"allowed_ips,omitempty"` + Endpoint string `protobuf:"bytes,4,opt,name=endpoint,proto3" json:"endpoint,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Peer) Reset() { *m = Peer{} } +func (m *Peer) String() string { return proto.CompactTextString(m) } +func (*Peer) ProtoMessage() {} +func (*Peer) Descriptor() ([]byte, []int) { + return fileDescriptor_b6184fc395da86b1, []int{6} +} +func (m *Peer) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Peer.Unmarshal(m, b) +} +func (m *Peer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Peer.Marshal(b, m, deterministic) +} +func (m *Peer) XXX_Merge(src proto.Message) { + xxx_messageInfo_Peer.Merge(m, src) +} +func (m *Peer) XXX_Size() int { + return xxx_messageInfo_Peer.Size(m) +} +func (m *Peer) XXX_DiscardUnknown() { + xxx_messageInfo_Peer.DiscardUnknown(m) +} + +var xxx_messageInfo_Peer proto.InternalMessageInfo + +func (m *Peer) GetPrivateKey() string { + if m != nil { + return m.PrivateKey + } + return "" +} + +func (m *Peer) GetPublicKey() string { + if m != nil { + return m.PublicKey + } + return "" +} + +func (m *Peer) GetAllowedIPs() []string { + if m != nil { + return m.AllowedIPs + } + return nil +} + +func (m *Peer) GetEndpoint() string { + if m != nil { + return m.Endpoint + } + return "" +} + func init() { proto.RegisterType((*Master)(nil), "io.stellarproject.heimdall.api.v1.Master") proto.RegisterType((*ConnectRequest)(nil), "io.stellarproject.heimdall.api.v1.ConnectRequest") @@ -284,6 +370,7 @@ func init() { proto.RegisterType((*Node)(nil), "io.stellarproject.heimdall.api.v1.Node") proto.RegisterType((*NodesRequest)(nil), "io.stellarproject.heimdall.api.v1.NodesRequest") proto.RegisterType((*NodesResponse)(nil), "io.stellarproject.heimdall.api.v1.NodesResponse") + proto.RegisterType((*Peer)(nil), "io.stellarproject.heimdall.api.v1.Peer") } func init() { @@ -291,31 +378,39 @@ func init() { } var fileDescriptor_b6184fc395da86b1 = []byte{ - // 375 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xc1, 0xab, 0xda, 0x40, - 0x10, 0xc6, 0x31, 0xda, 0x54, 0x27, 0x56, 0x61, 0x29, 0x25, 0x78, 0x89, 0xcd, 0xa5, 0x0a, 0x65, - 0x43, 0xd2, 0x4b, 0xa1, 0xf4, 0xa0, 0x16, 0x5a, 0x69, 0x2b, 0x65, 0xa9, 0x97, 0x5e, 0x24, 0x26, - 0x4b, 0xdc, 0x36, 0x66, 0xd3, 0xdd, 0x44, 0x10, 0x0a, 0xfd, 0x4f, 0x3d, 0xf8, 0x97, 0x3c, 0x76, - 0xb3, 0x08, 0x1e, 0xe4, 0xf9, 0x6e, 0x3b, 0xb3, 0xf3, 0x7d, 0xfc, 0xe6, 0x63, 0xe0, 0x7d, 0xc6, - 0xaa, 0x5d, 0xbd, 0xc5, 0x09, 0xdf, 0x07, 0xb2, 0xa2, 0x79, 0x1e, 0x8b, 0x52, 0xf0, 0xdf, 0x34, - 0xa9, 0x82, 0x1d, 0x65, 0xfb, 0x34, 0xce, 0xf3, 0x20, 0x2e, 0x59, 0x70, 0x08, 0x2f, 0x35, 0x2e, - 0x05, 0xaf, 0x38, 0x7a, 0xcd, 0x38, 0xbe, 0x56, 0xe0, 0xcb, 0x44, 0x5c, 0x32, 0x7c, 0x08, 0x47, - 0x2f, 0x33, 0x9e, 0x71, 0x3d, 0x1d, 0xa8, 0x57, 0x23, 0xf4, 0xff, 0x83, 0xfd, 0x3d, 0x96, 0x15, - 0x15, 0xe8, 0x15, 0x58, 0x2c, 0x75, 0x5b, 0xe3, 0xd6, 0xa4, 0x37, 0xb7, 0xcf, 0x27, 0xcf, 0x5a, - 0x7e, 0x22, 0x16, 0x4b, 0x51, 0x04, 0xfd, 0x4c, 0x94, 0xc9, 0x26, 0x4e, 0x53, 0x41, 0xa5, 0x74, - 0x2d, 0x3d, 0x31, 0x3c, 0x9f, 0x3c, 0xe7, 0x33, 0xf9, 0xb1, 0x98, 0x35, 0x6d, 0xe2, 0xa8, 0x21, - 0x53, 0xa0, 0x29, 0xf4, 0x04, 0x4d, 0x99, 0xdc, 0xd4, 0x22, 0x77, 0xdb, 0x5a, 0xd0, 0x3f, 0x9f, - 0xbc, 0x2e, 0x51, 0xcd, 0x35, 0xf9, 0x46, 0xba, 0xfa, 0x7b, 0x2d, 0x72, 0x7f, 0x09, 0x83, 0x05, - 0x2f, 0x0a, 0x9a, 0x54, 0x84, 0xfe, 0xad, 0xa9, 0xac, 0x6e, 0x82, 0x78, 0xe0, 0x24, 0x79, 0xad, - 0x58, 0x37, 0x7f, 0xe8, 0xb1, 0xe1, 0x20, 0x60, 0x5a, 0x5f, 0xe9, 0xd1, 0xff, 0x09, 0xc3, 0x8b, - 0x95, 0x2c, 0x79, 0x21, 0x29, 0x9a, 0x81, 0xbd, 0xd7, 0xeb, 0x69, 0x3f, 0x27, 0x9a, 0xe2, 0x47, - 0x83, 0xc2, 0x4d, 0x1e, 0xc4, 0x08, 0xfd, 0x08, 0x3a, 0x2b, 0x9e, 0xd2, 0x9b, 0x58, 0x08, 0x3a, - 0x2a, 0x1a, 0xc3, 0xa3, 0xdf, 0xfe, 0x00, 0xfa, 0x4a, 0x23, 0xcd, 0x4a, 0xfe, 0x0a, 0x5e, 0x98, - 0xda, 0x70, 0x7d, 0x84, 0x67, 0x85, 0x6a, 0xb8, 0xad, 0x71, 0x7b, 0xe2, 0x44, 0x6f, 0xee, 0xc0, - 0x52, 0x06, 0xa4, 0x51, 0x45, 0xff, 0xa0, 0xfb, 0xc5, 0x7c, 0xa3, 0x12, 0x9e, 0x9b, 0xad, 0x51, - 0x78, 0x87, 0xcd, 0x75, 0xd8, 0xa3, 0xe8, 0x29, 0x92, 0x06, 0x7e, 0x8e, 0x7f, 0xbd, 0xbd, 0xfb, - 0x50, 0x3f, 0x1c, 0xc2, 0xad, 0xad, 0x4f, 0xed, 0xdd, 0x43, 0x00, 0x00, 0x00, 0xff, 0xff, 0x57, - 0x3c, 0x78, 0x51, 0xdf, 0x02, 0x00, 0x00, + // 504 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x51, 0x8b, 0x1a, 0x3d, + 0x14, 0x65, 0xd4, 0xf5, 0xd3, 0x3b, 0x7e, 0x0a, 0x43, 0x29, 0x83, 0x50, 0xb4, 0xf3, 0xb2, 0x2e, + 0x94, 0x19, 0xb4, 0x2f, 0x85, 0xd2, 0x07, 0xdd, 0x42, 0x2b, 0xdb, 0x2e, 0x12, 0xba, 0x2f, 0x7d, + 0x91, 0x71, 0xe6, 0xe2, 0xa6, 0x8d, 0x93, 0x34, 0x89, 0x2e, 0x42, 0xa1, 0x3f, 0xa2, 0xcf, 0xfd, + 0x6b, 0x3e, 0xf8, 0x4b, 0x4a, 0x26, 0x61, 0xe8, 0xb2, 0x2c, 0xb5, 0x6f, 0xb9, 0x27, 0xe7, 0x5c, + 0xce, 0x3d, 0xc9, 0x85, 0x57, 0x6b, 0xaa, 0x6f, 0xb7, 0xab, 0x38, 0xe3, 0x9b, 0x44, 0x69, 0x64, + 0x2c, 0x95, 0x42, 0xf2, 0x2f, 0x98, 0xe9, 0xe4, 0x16, 0xe9, 0x26, 0x4f, 0x19, 0x4b, 0x52, 0x41, + 0x93, 0xdd, 0xb8, 0xaa, 0x63, 0x21, 0xb9, 0xe6, 0xc1, 0x73, 0xca, 0xe3, 0xfb, 0x8a, 0xb8, 0x62, + 0xa4, 0x82, 0xc6, 0xbb, 0x71, 0xff, 0xc9, 0x9a, 0xaf, 0x79, 0xc9, 0x4e, 0xcc, 0xc9, 0x0a, 0xa3, + 0x1f, 0xd0, 0xfc, 0x98, 0x2a, 0x8d, 0x32, 0x78, 0x0a, 0x35, 0x9a, 0x87, 0xde, 0xd0, 0x1b, 0xb5, + 0x67, 0xcd, 0xe3, 0x61, 0x50, 0x9b, 0xbf, 0x25, 0x35, 0x9a, 0x07, 0x13, 0xe8, 0xac, 0xa5, 0xc8, + 0x96, 0x69, 0x9e, 0x4b, 0x54, 0x2a, 0xac, 0x95, 0x8c, 0xde, 0xf1, 0x30, 0xf0, 0xdf, 0x91, 0xc5, + 0xe5, 0xd4, 0xc2, 0xc4, 0x37, 0x24, 0x57, 0x04, 0x17, 0xd0, 0x96, 0x98, 0x53, 0xb5, 0xdc, 0x4a, + 0x16, 0xd6, 0x4b, 0x41, 0xe7, 0x78, 0x18, 0xb4, 0x88, 0x01, 0x6f, 0xc8, 0x07, 0xd2, 0x2a, 0xaf, + 0x6f, 0x24, 0x8b, 0xe6, 0xd0, 0xbd, 0xe4, 0x45, 0x81, 0x99, 0x26, 0xf8, 0x6d, 0x8b, 0x4a, 0x3f, + 0x6a, 0x64, 0x00, 0x7e, 0xc6, 0xb6, 0xc6, 0xeb, 0xf2, 0x2b, 0xee, 0xad, 0x0f, 0x02, 0x0e, 0xba, + 0xc2, 0x7d, 0xf4, 0x09, 0x7a, 0x55, 0x2b, 0x25, 0x78, 0xa1, 0x30, 0x98, 0x42, 0x73, 0x53, 0x8e, + 0x57, 0xf6, 0xf3, 0x27, 0x17, 0xf1, 0x5f, 0x83, 0x8a, 0x6d, 0x1e, 0xc4, 0x09, 0xa3, 0x5f, 0x1e, + 0x34, 0xae, 0x79, 0x8e, 0x8f, 0xfa, 0x0a, 0xa0, 0x61, 0xb2, 0x71, 0x86, 0xca, 0xb3, 0xf1, 0x2a, + 0x24, 0xdd, 0xa5, 0x1a, 0x4b, 0xaf, 0x75, 0xeb, 0xd5, 0x41, 0x57, 0xb8, 0x37, 0x04, 0x46, 0x95, + 0xc6, 0x62, 0x29, 0xb8, 0xd4, 0x61, 0x63, 0xe8, 0x8d, 0x1a, 0x04, 0x2c, 0xb4, 0xe0, 0x52, 0x07, + 0xe7, 0xd0, 0x5b, 0xa7, 0x1a, 0xef, 0xd2, 0x7d, 0x95, 0xfc, 0x59, 0xd9, 0xa5, 0xeb, 0x60, 0x97, + 0x75, 0xd4, 0x85, 0x8e, 0xb1, 0xa7, 0x5c, 0x7c, 0xd1, 0x35, 0xfc, 0xef, 0x6a, 0x97, 0xc1, 0x1b, + 0x38, 0x2b, 0x0c, 0x10, 0x7a, 0xc3, 0xfa, 0xc8, 0x9f, 0x9c, 0x9f, 0x10, 0x81, 0x69, 0x40, 0xac, + 0x2a, 0xfa, 0xe9, 0x41, 0x63, 0x81, 0xf8, 0x60, 0x26, 0xef, 0xc1, 0x4c, 0xcf, 0x00, 0xc4, 0x76, + 0xc5, 0x68, 0xf6, 0xc7, 0xfb, 0xb4, 0x2d, 0x62, 0xae, 0x13, 0xf0, 0x53, 0xc6, 0xf8, 0x1d, 0xe6, + 0x4b, 0x2a, 0x54, 0x58, 0x1f, 0xd6, 0x47, 0xed, 0x59, 0xf7, 0x78, 0x18, 0xc0, 0xd4, 0xc2, 0xf3, + 0x85, 0x22, 0xe0, 0x28, 0x73, 0xa1, 0x82, 0x3e, 0xb4, 0xb0, 0xc8, 0x05, 0xa7, 0x85, 0x0d, 0xa8, + 0x4d, 0xaa, 0x7a, 0xf2, 0x1d, 0x5a, 0xef, 0x9d, 0xe9, 0x40, 0xc0, 0x7f, 0xee, 0xdd, 0x83, 0xf1, + 0x09, 0xc3, 0xdd, 0xff, 0x6e, 0xfd, 0xc9, 0xbf, 0x48, 0x6c, 0xa4, 0xb3, 0xf8, 0xf3, 0x8b, 0x93, + 0x57, 0xf5, 0xf5, 0x6e, 0xbc, 0x6a, 0x96, 0xcb, 0xf6, 0xf2, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x41, 0x0d, 0xf8, 0xa1, 0xe1, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/api/v1/heimdall.proto b/api/v1/heimdall.proto index d2be522..038b3d5 100644 --- a/api/v1/heimdall.proto +++ b/api/v1/heimdall.proto @@ -32,6 +32,9 @@ message ConnectResponse { message Node { string id = 1 [(gogoproto.customname) = "ID"]; string addr = 2; + string private_key = 3; + uint64 listen_port = 4; + string gateway_address = 5; } message NodesRequest {} @@ -39,3 +42,10 @@ message NodesRequest {} message NodesResponse { repeated Node nodes = 1; } + +message Peer { + string private_key = 1; + string public_key = 2; + repeated string allowed_ips = 3 [(gogoproto.customname) = "AllowedIPs"]; + string endpoint = 4; +} diff --git a/cmd/heimdall/main.go b/cmd/heimdall/main.go index 8355f31..cc8c88e 100644 --- a/cmd/heimdall/main.go +++ b/cmd/heimdall/main.go @@ -83,6 +83,18 @@ func main() { Value: generateKey(), EnvVar: "HEIMDALL_CLUSTER_KEY", }, + cli.StringFlag{ + Name: "peer-network", + Usage: "subnet to be used for peers", + Value: "10.254.0.0/16", + EnvVar: "HEIMDALL_PEER_NETWORK", + }, + cli.IntFlag{ + Name: "wireguard-port", + Usage: "wireguard port for peers", + Value: 10100, + EnvVar: "HEIMDALL_WIREGUARD_PORT", + }, } app.Before = func(c *cli.Context) error { if c.Bool("debug") { diff --git a/cmd/heimdall/run.go b/cmd/heimdall/run.go index a491a1f..f751704 100644 --- a/cmd/heimdall/run.go +++ b/cmd/heimdall/run.go @@ -45,6 +45,8 @@ func runServer(cx *cli.Context) error { GRPCAddress: cx.String("addr"), GRPCPeerAddress: cx.String("peer"), ClusterKey: cx.String("cluster-key"), + PeerNetwork: cx.String("peer-network"), + WireguardPort: cx.Int("wireguard-port"), RedisURL: cx.String("redis-url"), AdvertiseRedisURL: cx.String("advertise-redis-url"), } diff --git a/config.go b/config.go index cfe2a06..04f97a7 100644 --- a/config.go +++ b/config.go @@ -31,6 +31,10 @@ type Config struct { GRPCPeerAddress string // ClusterKey is a preshared key for cluster peers ClusterKey string + // PeerNetwork is the subnet that will be used for cluster peers + PeerNetwork string + // WireguardPort is the peer port used for Wireguard + WireguardPort int // RedisURL is the uri to the redis backend RedisURL string // AdvertiseRedisURL is the uri to the public redis backend diff --git a/go.mod b/go.mod index 7e70619..fb485c9 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,20 @@ module github.com/stellarproject/heimdall go 1.12 require ( + github.com/certifi/gocertifi v0.0.0-20190905060710-a5e0173ced67 // indirect + github.com/crosbymichael/guard v0.0.0-20190716141324-5c2daadf8067 // indirect + github.com/getsentry/raven-go v0.2.0 // indirect github.com/gogo/googleapis v1.3.0 github.com/gogo/protobuf v1.3.0 github.com/gomodule/redigo v2.0.0+incompatible github.com/google/uuid v1.1.1 + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect github.com/pkg/errors v0.8.1 + github.com/prometheus/client_golang v1.1.0 // indirect github.com/sirupsen/logrus v1.4.2 + github.com/stellarproject/guard v0.0.0-20190716141324-5c2daadf8067 github.com/urfave/cli v1.22.1 google.golang.org/grpc v1.24.0 ) diff --git a/go.sum b/go.sum index 705a42f..6f00238 100644 --- a/go.sum +++ b/go.sum @@ -1,48 +1,113 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/certifi/gocertifi v0.0.0-20190905060710-a5e0173ced67 h1:8k9FLYBLKT+9v2HQJ/a95ZemmTx+/ltJcAiRhVushG8= +github.com/certifi/gocertifi v0.0.0-20190905060710-a5e0173ced67/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/crosbymichael/guard v0.0.0-20190716141324-5c2daadf8067 h1:jlV8Svz9lOwvxWBt2RN3uA1JUZ8AFj46boym2+Fx488= +github.com/crosbymichael/guard v0.0.0-20190716141324-5c2daadf8067/go.mod h1:+l2fIHwwiNb/sUw9RcsUH6wXnO07793PC4XjDWCuiHs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/googleapis v1.3.0 h1:M695OaDJ5ipWvDPcoAg/YL9c3uORAegkEfBqTQF/fTQ= github.com/gogo/googleapis v1.3.0/go.mod h1:d+q1s/xVJxZGKWwC/6UfPIF33J+G1Tq4GYv9Y+Tg/EU= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stellarproject/guard v0.0.0-20190716141324-5c2daadf8067 h1:rXVdzLEX//pCEeoLSu5p61PktACUZY1pFXQ9dCsnMA4= +github.com/stellarproject/guard v0.0.0-20190716141324-5c2daadf8067/go.mod h1:pJTo5Hd/Kb63HIoU6r3wfqWA7AMQWstyu7qvlOq+mqM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -53,6 +118,8 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/server/node.go b/server/node.go index 2e82ba9..1d9bd99 100644 --- a/server/node.go +++ b/server/node.go @@ -23,6 +23,7 @@ package server import ( "context" + "crypto/sha256" "fmt" "net/url" "strings" @@ -32,12 +33,13 @@ import ( "github.com/gomodule/redigo/redis" "github.com/pkg/errors" "github.com/sirupsen/logrus" + "github.com/stellarproject/heimdall" v1 "github.com/stellarproject/heimdall/api/v1" ) func (s *Server) configureNode() error { ctx := context.Background() - nodes, err := redis.Strings(s.local(ctx, "KEYS", fmt.Sprintf("%s:*", nodesKey))) + nodes, err := redis.Strings(s.local(ctx, "KEYS", s.getNodeKey("*"))) if err != nil { return err } @@ -222,11 +224,75 @@ func (s *Server) updateMasterInfo(ctx context.Context) error { return nil } +func (s *Server) updatePeerInfo(ctx context.Context) error { + // check for existing key + endpoint := fmt.Sprintf("%s:%d", heimdall.GetIP(), s.cfg.WireguardPort) + + peer, err := s.getPeerInfo(ctx) + if err != nil { + return err + } + + // TODO: build allowedIPs from routes and peer network + allowedIPs := []string{s.cfg.PeerNetwork} + ipHash := hashIPs(allowedIPs) + + // check cached info and validate + if peer != nil { + peerIPHash := hashIPs(peer.AllowedIPs) + // if endpoint is the same assume unchanged + if peer.Endpoint == endpoint && peerIPHash == ipHash { + logrus.Debugf("peer info: public=%s endpoint=%s", peer.PublicKey, peer.Endpoint) + return nil + } + } + + privateKey, publicKey, err := generateWireguardKeys(ctx) + if err != nil { + return err + } + // TODO: allowed IPs + n := &v1.Peer{ + PrivateKey: privateKey, + PublicKey: publicKey, + AllowedIPs: allowedIPs, + Endpoint: endpoint, + } + + logrus.Debugf("peer info: public=%s endpoint=%s", n.PublicKey, n.Endpoint) + data, err := proto.Marshal(n) + if err != nil { + return err + } + key := s.getPeerKey(s.cfg.ID) + if _, err := s.master(ctx, "SET", key, data); err != nil { + return err + } + return nil +} + +func (s *Server) getPeerInfo(ctx context.Context) (*v1.Peer, error) { + key := s.getPeerKey(s.cfg.ID) + data, err := redis.Bytes(s.local(ctx, "GET", key)) + if err != nil { + if err == redis.ErrNil { + return nil, nil + } + return nil, err + } + var peer v1.Peer + if err := proto.Unmarshal(data, &peer); err != nil { + return nil, err + } + + return &peer, nil +} + func (s *Server) nodeHeartbeat() { logrus.Debugf("starting node heartbeat: ttl=%s", nodeHeartbeatInterval) ctx := context.Background() t := time.NewTicker(nodeHeartbeatInterval) - key := fmt.Sprintf("%s:%s", nodesKey, s.cfg.ID) + key := s.getNodeKey(s.cfg.ID) for range t.C { if _, err := s.master(ctx, "SET", key, s.cfg.GRPCAddress); err != nil { logrus.Error(err) @@ -239,3 +305,11 @@ func (s *Server) nodeHeartbeat() { } } } + +func hashIPs(ips []string) string { + h := sha256.New() + for _, ip := range ips { + h.Write([]byte(ip)) + } + return fmt.Sprintf("%x", h.Sum(nil)) +} diff --git a/server/server.go b/server/server.go index 4af4023..9ffb4d7 100644 --- a/server/server.go +++ b/server/server.go @@ -23,6 +23,7 @@ package server import ( "context" + "fmt" "io/ioutil" "runtime" "runtime/pprof" @@ -43,6 +44,9 @@ const ( clusterKey = "heimdall:key" nodesKey = "heimdall:nodes" nodeJoinKey = "heimdall:join" + peersKey = "heimdall:peers" + + wireguardConfigPath = "/etc/wireguard/darknet.conf" ) var ( @@ -90,6 +94,7 @@ func (s *Server) GenerateProfile() (string, error) { } func (s *Server) Run() error { + ctx := context.Background() // check peer address and make a grpc request for master info if present if s.cfg.GRPCPeerAddress != "" { logrus.Debugf("joining %s", s.cfg.GRPCPeerAddress) @@ -117,6 +122,10 @@ func (s *Server) Run() error { } } + if err := s.updatePeerInfo(ctx); err != nil { + return err + } + go s.nodeHeartbeat() // start listener for pub/sub @@ -161,6 +170,14 @@ func getPool(u string) *redis.Pool { return pool } +func (s *Server) getNodeKey(id string) string { + return fmt.Sprintf("%s:%s", nodesKey, id) +} + +func (s *Server) getPeerKey(id string) string { + return fmt.Sprintf("%s:%s", peersKey, id) +} + func (s *Server) getClient(addr string) (*client.Client, error) { return client.NewClient(s.cfg.ID, addr) } diff --git a/server/wireguard.go b/server/wireguard.go new file mode 100644 index 0000000..fbff411 --- /dev/null +++ b/server/wireguard.go @@ -0,0 +1,114 @@ +/* + 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" + + v1 "github.com/stellarproject/heimdall/api/v1" +) + +const ( + defaultInterface = "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 = {{ .PublicKey }} +AllowedIPs = {{ allowedIPs .AllowedIPs }} +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) (*os.File, error) { + f, err := ioutil.TempFile("", "heimdall-wireguard-") + if err != nil { + return nil, err + } + t, err := template.New("wireguard").Funcs(template.FuncMap{ + "allowedIPs": allowedIPs, + }).Parse(wireguardTemplate) + if err != nil { + return nil, err + } + + if err := os.MkdirAll(filepath.Dir(wireguardConfigPath), 0755); err != nil { + return nil, err + } + + if err := t.Execute(f, cfg); err != nil { + return nil, err + } + f.Close() + + return f, 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 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() +} diff --git a/server/wireguard_test.go b/server/wireguard_test.go new file mode 100644 index 0000000..bbae951 --- /dev/null +++ b/server/wireguard_test.go @@ -0,0 +1,74 @@ +/* + 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 ( + "io/ioutil" + "os" + "testing" + + v1 "github.com/stellarproject/heimdall/api/v1" +) + +func TestWireguardTemplate(t *testing.T) { + expectedConf := `# managed by heimdall +[Interface] +PrivateKey = SERVER-PRIVATE-KEY +ListenPort = 10000 +Address = 1.2.3.4:10000 +PostUp = iptables -A FORWARD -i darknet -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i darknet -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE +PostDown = iptables -D FORWARD -i darknet -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i darknet -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE + +[Peer] +PublicKey = PEER-PUBLIC-KEY +AllowedIPs = 10.100.0.0/24, 10.254.0.0/16 +Endpoint = 100.100.100.100:10000 + +` + cfg := &wireguardConfig{ + Iface: "darknet", + PrivateKey: "SERVER-PRIVATE-KEY", + ListenPort: 10000, + Address: "1.2.3.4:10000", + Peers: []*v1.Peer{ + { + PrivateKey: "PEER-PRIVATE-KEY", + PublicKey: "PEER-PUBLIC-KEY", + AllowedIPs: []string{"10.100.0.0/24", "10.254.0.0/16"}, + Endpoint: "100.100.100.100:10000", + }, + }, + } + f, err := generateWireguardConfig(cfg) + if err != nil { + t.Fatal(err) + } + defer os.Remove(f.Name()) + data, err := ioutil.ReadFile(f.Name()) + if err != nil { + t.Fatal(err) + } + + if string(data) != expectedConf { + t.Fatalf("config does not match; expected \n %q \n received \n %q", expectedConf, string(data)) + } +}