add wireguard connectivity between nodes

Signed-off-by: Evan Hazlett <ejhazlett@gmail.com>
This commit is contained in:
Evan Hazlett 2019-10-04 09:46:03 -04:00
parent 2e34c8746e
commit c0515d4802
No known key found for this signature in database
GPG key ID: A519480096146526
11 changed files with 640 additions and 180 deletions

View file

@ -163,12 +163,58 @@ func (m *ConnectResponse) GetMaster() *Master {
return nil return nil
} }
type KeyPair 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"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *KeyPair) Reset() { *m = KeyPair{} }
func (m *KeyPair) String() string { return proto.CompactTextString(m) }
func (*KeyPair) ProtoMessage() {}
func (*KeyPair) Descriptor() ([]byte, []int) {
return fileDescriptor_b6184fc395da86b1, []int{3}
}
func (m *KeyPair) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_KeyPair.Unmarshal(m, b)
}
func (m *KeyPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_KeyPair.Marshal(b, m, deterministic)
}
func (m *KeyPair) XXX_Merge(src proto.Message) {
xxx_messageInfo_KeyPair.Merge(m, src)
}
func (m *KeyPair) XXX_Size() int {
return xxx_messageInfo_KeyPair.Size(m)
}
func (m *KeyPair) XXX_DiscardUnknown() {
xxx_messageInfo_KeyPair.DiscardUnknown(m)
}
var xxx_messageInfo_KeyPair proto.InternalMessageInfo
func (m *KeyPair) GetPrivateKey() string {
if m != nil {
return m.PrivateKey
}
return ""
}
func (m *KeyPair) GetPublicKey() string {
if m != nil {
return m.PublicKey
}
return ""
}
type Node struct { type Node struct {
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,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"` KeyPair *KeyPair `protobuf:"bytes,3,opt,name=keypair,proto3" json:"keypair,omitempty"`
ListenPort uint64 `protobuf:"varint,4,opt,name=listen_port,json=listenPort,proto3" json:"listen_port,omitempty"` GatewayIP string `protobuf:"bytes,4,opt,name=gateway_ip,json=gatewayIp,proto3" json:"gateway_ip,omitempty"`
GatewayAddress string `protobuf:"bytes,5,opt,name=gateway_address,json=gatewayAddress,proto3" json:"gateway_address,omitempty"` GatewayPort uint64 `protobuf:"varint,5,opt,name=gateway_port,json=gatewayPort,proto3" json:"gateway_port,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -178,7 +224,7 @@ func (m *Node) Reset() { *m = Node{} }
func (m *Node) String() string { return proto.CompactTextString(m) } func (m *Node) String() string { return proto.CompactTextString(m) }
func (*Node) ProtoMessage() {} func (*Node) ProtoMessage() {}
func (*Node) Descriptor() ([]byte, []int) { func (*Node) Descriptor() ([]byte, []int) {
return fileDescriptor_b6184fc395da86b1, []int{3} return fileDescriptor_b6184fc395da86b1, []int{4}
} }
func (m *Node) XXX_Unmarshal(b []byte) error { func (m *Node) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Node.Unmarshal(m, b) return xxx_messageInfo_Node.Unmarshal(m, b)
@ -212,27 +258,27 @@ func (m *Node) GetAddr() string {
return "" return ""
} }
func (m *Node) GetPrivateKey() string { func (m *Node) GetKeyPair() *KeyPair {
if m != nil { if m != nil {
return m.PrivateKey return m.KeyPair
}
return nil
}
func (m *Node) GetGatewayIP() string {
if m != nil {
return m.GatewayIP
} }
return "" return ""
} }
func (m *Node) GetListenPort() uint64 { func (m *Node) GetGatewayPort() uint64 {
if m != nil { if m != nil {
return m.ListenPort return m.GatewayPort
} }
return 0 return 0
} }
func (m *Node) GetGatewayAddress() string {
if m != nil {
return m.GatewayAddress
}
return ""
}
type NodesRequest struct { type NodesRequest struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
@ -243,7 +289,7 @@ func (m *NodesRequest) Reset() { *m = NodesRequest{} }
func (m *NodesRequest) String() string { return proto.CompactTextString(m) } func (m *NodesRequest) String() string { return proto.CompactTextString(m) }
func (*NodesRequest) ProtoMessage() {} func (*NodesRequest) ProtoMessage() {}
func (*NodesRequest) Descriptor() ([]byte, []int) { func (*NodesRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_b6184fc395da86b1, []int{4} return fileDescriptor_b6184fc395da86b1, []int{5}
} }
func (m *NodesRequest) XXX_Unmarshal(b []byte) error { func (m *NodesRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_NodesRequest.Unmarshal(m, b) return xxx_messageInfo_NodesRequest.Unmarshal(m, b)
@ -274,7 +320,7 @@ func (m *NodesResponse) Reset() { *m = NodesResponse{} }
func (m *NodesResponse) String() string { return proto.CompactTextString(m) } func (m *NodesResponse) String() string { return proto.CompactTextString(m) }
func (*NodesResponse) ProtoMessage() {} func (*NodesResponse) ProtoMessage() {}
func (*NodesResponse) Descriptor() ([]byte, []int) { func (*NodesResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_b6184fc395da86b1, []int{5} return fileDescriptor_b6184fc395da86b1, []int{6}
} }
func (m *NodesResponse) XXX_Unmarshal(b []byte) error { func (m *NodesResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_NodesResponse.Unmarshal(m, b) return xxx_messageInfo_NodesResponse.Unmarshal(m, b)
@ -302,8 +348,8 @@ func (m *NodesResponse) GetNodes() []*Node {
} }
type Peer struct { type Peer struct {
PrivateKey string `protobuf:"bytes,1,opt,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"` ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
PublicKey string `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` KeyPair *KeyPair `protobuf:"bytes,2,opt,name=keypair,proto3" json:"keypair,omitempty"`
AllowedIPs []string `protobuf:"bytes,3,rep,name=allowed_ips,json=allowedIps,proto3" json:"allowed_ips,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"` Endpoint string `protobuf:"bytes,4,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
@ -315,7 +361,7 @@ func (m *Peer) Reset() { *m = Peer{} }
func (m *Peer) String() string { return proto.CompactTextString(m) } func (m *Peer) String() string { return proto.CompactTextString(m) }
func (*Peer) ProtoMessage() {} func (*Peer) ProtoMessage() {}
func (*Peer) Descriptor() ([]byte, []int) { func (*Peer) Descriptor() ([]byte, []int) {
return fileDescriptor_b6184fc395da86b1, []int{6} return fileDescriptor_b6184fc395da86b1, []int{7}
} }
func (m *Peer) XXX_Unmarshal(b []byte) error { func (m *Peer) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Peer.Unmarshal(m, b) return xxx_messageInfo_Peer.Unmarshal(m, b)
@ -335,18 +381,18 @@ func (m *Peer) XXX_DiscardUnknown() {
var xxx_messageInfo_Peer proto.InternalMessageInfo var xxx_messageInfo_Peer proto.InternalMessageInfo
func (m *Peer) GetPrivateKey() string { func (m *Peer) GetID() string {
if m != nil { if m != nil {
return m.PrivateKey return m.ID
} }
return "" return ""
} }
func (m *Peer) GetPublicKey() string { func (m *Peer) GetKeyPair() *KeyPair {
if m != nil { if m != nil {
return m.PublicKey return m.KeyPair
} }
return "" return nil
} }
func (m *Peer) GetAllowedIPs() []string { func (m *Peer) GetAllowedIPs() []string {
@ -367,6 +413,7 @@ func init() {
proto.RegisterType((*Master)(nil), "io.stellarproject.heimdall.api.v1.Master") proto.RegisterType((*Master)(nil), "io.stellarproject.heimdall.api.v1.Master")
proto.RegisterType((*ConnectRequest)(nil), "io.stellarproject.heimdall.api.v1.ConnectRequest") proto.RegisterType((*ConnectRequest)(nil), "io.stellarproject.heimdall.api.v1.ConnectRequest")
proto.RegisterType((*ConnectResponse)(nil), "io.stellarproject.heimdall.api.v1.ConnectResponse") proto.RegisterType((*ConnectResponse)(nil), "io.stellarproject.heimdall.api.v1.ConnectResponse")
proto.RegisterType((*KeyPair)(nil), "io.stellarproject.heimdall.api.v1.KeyPair")
proto.RegisterType((*Node)(nil), "io.stellarproject.heimdall.api.v1.Node") proto.RegisterType((*Node)(nil), "io.stellarproject.heimdall.api.v1.Node")
proto.RegisterType((*NodesRequest)(nil), "io.stellarproject.heimdall.api.v1.NodesRequest") proto.RegisterType((*NodesRequest)(nil), "io.stellarproject.heimdall.api.v1.NodesRequest")
proto.RegisterType((*NodesResponse)(nil), "io.stellarproject.heimdall.api.v1.NodesResponse") proto.RegisterType((*NodesResponse)(nil), "io.stellarproject.heimdall.api.v1.NodesResponse")
@ -378,39 +425,42 @@ func init() {
} }
var fileDescriptor_b6184fc395da86b1 = []byte{ var fileDescriptor_b6184fc395da86b1 = []byte{
// 504 bytes of a gzipped FileDescriptorProto // 552 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x51, 0x8b, 0x1a, 0x3d, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcd, 0x6a, 0xdb, 0x4c,
0x14, 0x65, 0xd4, 0xf5, 0xd3, 0x3b, 0x7e, 0x0a, 0x43, 0x29, 0x83, 0x50, 0xb4, 0xf3, 0xb2, 0x2e, 0x14, 0x45, 0xb6, 0xe3, 0xd8, 0x57, 0x4e, 0x02, 0xc3, 0xc7, 0x87, 0x08, 0x14, 0x39, 0xda, 0xd4,
0x94, 0x19, 0xb4, 0x2f, 0x85, 0xd2, 0x07, 0xdd, 0x42, 0x2b, 0xdb, 0x2e, 0x12, 0xba, 0x2f, 0x7d, 0x29, 0x41, 0xc2, 0xea, 0xa6, 0x50, 0xba, 0x88, 0x53, 0x48, 0x45, 0xda, 0xa0, 0x0e, 0xcd, 0xa6,
0x91, 0x71, 0xe6, 0xe2, 0xa6, 0x8d, 0x93, 0x34, 0x89, 0x2e, 0x42, 0xa1, 0x3f, 0xa2, 0xcf, 0xfd, 0x1b, 0x33, 0x91, 0x06, 0x67, 0x1a, 0x45, 0x33, 0x9d, 0x19, 0x3b, 0x08, 0x0a, 0x7d, 0xb3, 0x3e,
0x6b, 0x3e, 0xf8, 0x4b, 0x4a, 0x26, 0x61, 0xe8, 0xb2, 0x2c, 0xb5, 0x6f, 0xb9, 0x27, 0xe7, 0x5c, 0x46, 0x97, 0x5a, 0xe8, 0x49, 0x8a, 0xa4, 0xb1, 0x49, 0x16, 0x69, 0x5d, 0xe8, 0x6e, 0xee, 0xd1,
0xce, 0x3d, 0xc9, 0x85, 0x57, 0x6b, 0xaa, 0x6f, 0xb7, 0xab, 0x38, 0xe3, 0x9b, 0x44, 0x69, 0x64, 0x39, 0x57, 0xe7, 0x9e, 0xf9, 0x81, 0x57, 0x0b, 0xa6, 0x6f, 0x96, 0xd7, 0x7e, 0xc2, 0xef, 0x02,
0x2c, 0x95, 0x42, 0xf2, 0x2f, 0x98, 0xe9, 0xe4, 0x16, 0xe9, 0x26, 0x4f, 0x19, 0x4b, 0x52, 0x41, 0xa5, 0x69, 0x96, 0x11, 0x29, 0x24, 0xff, 0x42, 0x13, 0x1d, 0xdc, 0x50, 0x76, 0x97, 0x92, 0x2c,
0x93, 0xdd, 0xb8, 0xaa, 0x63, 0x21, 0xb9, 0xe6, 0xc1, 0x73, 0xca, 0xe3, 0xfb, 0x8a, 0xb8, 0x62, 0x0b, 0x88, 0x60, 0xc1, 0x6a, 0xba, 0xa9, 0x7d, 0x21, 0xb9, 0xe6, 0xe8, 0x88, 0x71, 0xff, 0xb1,
0xa4, 0x82, 0xc6, 0xbb, 0x71, 0xff, 0xc9, 0x9a, 0xaf, 0x79, 0xc9, 0x4e, 0xcc, 0xc9, 0x0a, 0xa3, 0xc2, 0xdf, 0x30, 0x88, 0x60, 0xfe, 0x6a, 0x7a, 0xf8, 0xdf, 0x82, 0x2f, 0x78, 0xc3, 0x0e, 0xea,
0x1f, 0xd0, 0xfc, 0x98, 0x2a, 0x8d, 0x32, 0x78, 0x0a, 0x35, 0x9a, 0x87, 0xde, 0xd0, 0x1b, 0xb5, 0x55, 0x2b, 0xf4, 0xbe, 0x43, 0xff, 0x03, 0x51, 0x9a, 0x4a, 0xf4, 0x3f, 0x74, 0x58, 0xea, 0x58,
0x67, 0xcd, 0xe3, 0x61, 0x50, 0x9b, 0xbf, 0x25, 0x35, 0x9a, 0x07, 0x13, 0xe8, 0xac, 0xa5, 0xc8, 0x63, 0x6b, 0x32, 0x9c, 0xf5, 0xab, 0xd2, 0xed, 0x44, 0x6f, 0x71, 0x87, 0xa5, 0x28, 0x84, 0xd1,
0x96, 0x69, 0x9e, 0x4b, 0x54, 0x2a, 0xac, 0x95, 0x8c, 0xde, 0xf1, 0x30, 0xf0, 0xdf, 0x91, 0xc5, 0x42, 0x8a, 0x64, 0x4e, 0xd2, 0x54, 0x52, 0xa5, 0x9c, 0x4e, 0xc3, 0x38, 0xa8, 0x4a, 0xd7, 0x3e,
0xe5, 0xd4, 0xc2, 0xc4, 0x37, 0x24, 0x57, 0x04, 0x17, 0xd0, 0x96, 0x98, 0x53, 0xb5, 0xdc, 0x4a, 0xc7, 0xf1, 0xd9, 0x69, 0x0b, 0x63, 0xbb, 0x26, 0x99, 0x02, 0x1d, 0xc3, 0x50, 0xd2, 0x94, 0xa9,
0x16, 0xd6, 0x4b, 0x41, 0xe7, 0x78, 0x18, 0xb4, 0x88, 0x01, 0x6f, 0xc8, 0x07, 0xd2, 0x2a, 0xaf, 0xf9, 0x52, 0x66, 0x4e, 0xb7, 0x11, 0x8c, 0xaa, 0xd2, 0x1d, 0xe0, 0x1a, 0xbc, 0xc2, 0xef, 0xf1,
0x6f, 0x24, 0x8b, 0xe6, 0xd0, 0xbd, 0xe4, 0x45, 0x81, 0x99, 0x26, 0xf8, 0x6d, 0x8b, 0x4a, 0x3f, 0xa0, 0xf9, 0x7c, 0x25, 0x33, 0x2f, 0x82, 0xfd, 0x33, 0x9e, 0xe7, 0x34, 0xd1, 0x98, 0x7e, 0x5d,
0x6a, 0x64, 0x00, 0x7e, 0xc6, 0xb6, 0xc6, 0xeb, 0xf2, 0x2b, 0xee, 0xad, 0x0f, 0x02, 0x0e, 0xba, 0x52, 0xa5, 0x9f, 0x34, 0xe2, 0x82, 0x9d, 0x64, 0xcb, 0xda, 0xeb, 0xfc, 0x96, 0x16, 0xad, 0x0f,
0xc2, 0x7d, 0xf4, 0x09, 0x7a, 0x55, 0x2b, 0x25, 0x78, 0xa1, 0x30, 0x98, 0x42, 0x73, 0x53, 0x8e, 0x0c, 0x06, 0xba, 0xa0, 0x85, 0xf7, 0x09, 0x0e, 0x36, 0xad, 0x94, 0xe0, 0xb9, 0xa2, 0xe8, 0x14,
0x57, 0xf6, 0xf3, 0x27, 0x17, 0xf1, 0x5f, 0x83, 0x8a, 0x6d, 0x1e, 0xc4, 0x09, 0xa3, 0x5f, 0x1e, 0xfa, 0x77, 0xcd, 0x78, 0x4d, 0x3f, 0x3b, 0x3c, 0xf6, 0xff, 0x18, 0x94, 0xdf, 0xe6, 0x81, 0x8d,
0x34, 0xae, 0x79, 0x8e, 0x8f, 0xfa, 0x0a, 0xa0, 0x61, 0xb2, 0x71, 0x86, 0xca, 0xb3, 0xf1, 0x2a, 0xd0, 0x8b, 0x60, 0xf7, 0x82, 0x16, 0x31, 0x61, 0xb2, 0x76, 0x20, 0x24, 0x5b, 0x11, 0x4d, 0x1b,
0x24, 0xdd, 0xa5, 0x1a, 0x4b, 0xaf, 0x75, 0xeb, 0xd5, 0x41, 0x57, 0xb8, 0x37, 0x04, 0x46, 0x95, 0x07, 0x56, 0xeb, 0xc0, 0x40, 0x17, 0xb4, 0x40, 0xcf, 0x00, 0xc4, 0xf2, 0x3a, 0x63, 0xc9, 0x03,
0xc6, 0x62, 0x29, 0xb8, 0xd4, 0x61, 0x63, 0xe8, 0x8d, 0x1a, 0x04, 0x2c, 0xb4, 0xe0, 0x52, 0x07, 0x87, 0xc3, 0x16, 0xa9, 0x0d, 0xfe, 0xb4, 0xa0, 0x77, 0xc9, 0x53, 0xfa, 0xe4, 0x88, 0x08, 0x7a,
0xe7, 0xd0, 0x5b, 0xa7, 0x1a, 0xef, 0xd2, 0x7d, 0x95, 0xfc, 0x59, 0xd9, 0xa5, 0xeb, 0x60, 0x97, 0x75, 0xcc, 0x46, 0xd9, 0xac, 0xd1, 0x47, 0xd8, 0xbd, 0xa5, 0x85, 0x20, 0x4c, 0x36, 0x49, 0xda,
0x75, 0xd4, 0x85, 0x8e, 0xb1, 0xa7, 0x5c, 0x7c, 0xd1, 0x35, 0xfc, 0xef, 0x6a, 0x97, 0xc1, 0x1b, 0xe1, 0x8b, 0x2d, 0x66, 0x30, 0x8e, 0x67, 0x76, 0x55, 0xba, 0x6b, 0xfb, 0x78, 0xdd, 0x07, 0x9d,
0x38, 0x2b, 0x0c, 0x10, 0x7a, 0xc3, 0xfa, 0xc8, 0x9f, 0x9c, 0x9f, 0x10, 0x81, 0x69, 0x40, 0xac, 0x00, 0x2c, 0x88, 0xa6, 0xf7, 0xa4, 0x98, 0x33, 0xe1, 0xf4, 0x1a, 0x1b, 0x7b, 0x55, 0xe9, 0x0e,
0x2a, 0xfa, 0xe9, 0x41, 0x63, 0x81, 0xf8, 0x60, 0x26, 0xef, 0xc1, 0x4c, 0xcf, 0x00, 0xc4, 0x76, 0xcf, 0x5b, 0x34, 0x8a, 0xf1, 0xd0, 0x10, 0x22, 0x81, 0x8e, 0x60, 0xb4, 0x66, 0x0b, 0x2e, 0xb5,
0xc5, 0x68, 0xf6, 0xc7, 0xfb, 0xb4, 0x2d, 0x62, 0xae, 0x13, 0xf0, 0x53, 0xc6, 0xf8, 0x1d, 0xe6, 0xb3, 0x33, 0xb6, 0x26, 0x3d, 0x6c, 0x1b, 0x2c, 0xe6, 0x52, 0x7b, 0xfb, 0x30, 0xaa, 0xe7, 0x52,
0x4b, 0x2a, 0x54, 0x58, 0x1f, 0xd6, 0x47, 0xed, 0x59, 0xf7, 0x78, 0x18, 0xc0, 0xd4, 0xc2, 0xf3, 0x66, 0x0b, 0xbd, 0x4b, 0xd8, 0x33, 0xb5, 0xd9, 0x87, 0x37, 0xb0, 0x93, 0xd7, 0x80, 0x63, 0x8d,
0x85, 0x22, 0xe0, 0x28, 0x73, 0xa1, 0x82, 0x3e, 0xb4, 0xb0, 0xc8, 0x05, 0xa7, 0x85, 0x0d, 0xa8, 0xbb, 0x13, 0x3b, 0x7c, 0xbe, 0xc5, 0x08, 0x75, 0x03, 0xdc, 0xaa, 0xbc, 0x1f, 0x16, 0xf4, 0x62,
0x4d, 0xaa, 0x7a, 0xf2, 0x1d, 0x5a, 0xef, 0x9d, 0xe9, 0x40, 0xc0, 0x7f, 0xee, 0xdd, 0x83, 0xf1, 0xfa, 0x9b, 0x43, 0xfa, 0x20, 0xa4, 0xce, 0x3f, 0x0a, 0x29, 0x00, 0x9b, 0x64, 0x19, 0xbf, 0xa7,
0x09, 0xc3, 0xdd, 0xff, 0x6e, 0xfd, 0xc9, 0xbf, 0x48, 0x6c, 0xa4, 0xb3, 0xf8, 0xf3, 0x8b, 0x93, 0xe9, 0x9c, 0x09, 0xe5, 0x74, 0xc7, 0xdd, 0xc9, 0x70, 0xb6, 0x5f, 0x95, 0x2e, 0x9c, 0xb6, 0x70,
0x57, 0xf5, 0xf5, 0x6e, 0xbc, 0x6a, 0x96, 0xcb, 0xf6, 0xf2, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x14, 0x2b, 0x0c, 0x86, 0x12, 0x09, 0x85, 0x0e, 0x61, 0x40, 0xf3, 0x54, 0x70, 0x96, 0xeb, 0x36,
0x41, 0x0d, 0xf8, 0xa1, 0xe1, 0x03, 0x00, 0x00, 0x53, 0xbc, 0xa9, 0xc3, 0x6f, 0x30, 0x78, 0x67, 0xfe, 0x8e, 0x04, 0xec, 0x9a, 0x63, 0x8a, 0xa6,
0x5b, 0xb8, 0x7c, 0x7c, 0x3b, 0x0e, 0xc3, 0xbf, 0x91, 0xb4, 0xe9, 0xcf, 0xfc, 0xcf, 0x27, 0x5b,
0xbf, 0x2c, 0xaf, 0x57, 0xd3, 0xeb, 0x7e, 0xf3, 0x36, 0xbc, 0xfc, 0x15, 0x00, 0x00, 0xff, 0xff,
0x5f, 0xf4, 0xa8, 0x6a, 0x90, 0x04, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.

View file

@ -29,12 +29,17 @@ message ConnectResponse {
Master master = 1; Master master = 1;
} }
message KeyPair {
string private_key = 1;
string public_key = 2;
}
message Node { message Node {
string id = 1 [(gogoproto.customname) = "ID"]; string id = 1 [(gogoproto.customname) = "ID"];
string addr = 2; string addr = 2;
string private_key = 3; KeyPair keypair = 3 [(gogoproto.customname) = "KeyPair"];
uint64 listen_port = 4; string gateway_ip = 4 [(gogoproto.customname) = "GatewayIP"];
string gateway_address = 5; uint64 gateway_port = 5;
} }
message NodesRequest {} message NodesRequest {}
@ -44,8 +49,8 @@ message NodesResponse {
} }
message Peer { message Peer {
string private_key = 1; string id = 1 [(gogoproto.customname) = "ID"];
string public_key = 2; KeyPair keypair = 2 [(gogoproto.customname) = "KeyPair"];
repeated string allowed_ips = 3 [(gogoproto.customname) = "AllowedIPs"]; repeated string allowed_ips = 3 [(gogoproto.customname) = "AllowedIPs"];
string endpoint = 4; string endpoint = 4;
} }

View file

@ -89,11 +89,17 @@ func main() {
Value: "10.254.0.0/16", Value: "10.254.0.0/16",
EnvVar: "HEIMDALL_PEER_NETWORK", EnvVar: "HEIMDALL_PEER_NETWORK",
}, },
cli.StringFlag{
Name: "gateway-ip",
Usage: "IP used for peer communication",
Value: heimdall.GetIP(),
EnvVar: "HEIMDALL_GATEWAY_IP",
},
cli.IntFlag{ cli.IntFlag{
Name: "wireguard-port", Name: "gateway-port",
Usage: "wireguard port for peers", Usage: "port for peer communication",
Value: 10100, Value: 10100,
EnvVar: "HEIMDALL_WIREGUARD_PORT", EnvVar: "HEIMDALL_GATEWAY_PORT",
}, },
} }
app.Before = func(c *cli.Context) error { app.Before = func(c *cli.Context) error {

View file

@ -46,7 +46,8 @@ func runServer(cx *cli.Context) error {
GRPCPeerAddress: cx.String("peer"), GRPCPeerAddress: cx.String("peer"),
ClusterKey: cx.String("cluster-key"), ClusterKey: cx.String("cluster-key"),
PeerNetwork: cx.String("peer-network"), PeerNetwork: cx.String("peer-network"),
WireguardPort: cx.Int("wireguard-port"), GatewayIP: cx.String("gateway-ip"),
GatewayPort: cx.Int("gateway-port"),
RedisURL: cx.String("redis-url"), RedisURL: cx.String("redis-url"),
AdvertiseRedisURL: cx.String("advertise-redis-url"), AdvertiseRedisURL: cx.String("advertise-redis-url"),
} }

View file

@ -33,8 +33,10 @@ type Config struct {
ClusterKey string ClusterKey string
// PeerNetwork is the subnet that will be used for cluster peers // PeerNetwork is the subnet that will be used for cluster peers
PeerNetwork string PeerNetwork string
// WireguardPort is the peer port used for Wireguard // GatewayIP is the IP used for peer communication
WireguardPort int GatewayIP string
// GatewayPort is the port used for peer communication
GatewayPort int
// RedisURL is the uri to the redis backend // RedisURL is the uri to the redis backend
RedisURL string RedisURL string
// AdvertiseRedisURL is the uri to the public redis backend // AdvertiseRedisURL is the uri to the public redis backend

187
server/net.go Normal file
View file

@ -0,0 +1,187 @@
/*
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"
"fmt"
"net"
"strings"
"github.com/gomodule/redigo/redis"
)
type subnetRange struct {
Start net.IP
End net.IP
Subnet *net.IPNet
}
func (s *Server) getIPs(ctx context.Context) (map[string]net.IP, error) {
values, err := redis.StringMap(s.local(ctx, "HGETALL", ipsKey))
if err != nil {
return nil, err
}
ips := make(map[string]net.IP, len(values))
for id, val := range values {
ip := net.ParseIP(string(val))
ips[id] = ip
}
return ips, nil
}
func (s *Server) getIP(ctx context.Context, id string) (net.IP, error) {
allIPs, err := s.getIPs(ctx)
if err != nil {
return nil, err
}
if ip, exists := allIPs[id]; exists {
return ip, nil
}
return nil, nil
}
func (s *Server) getOrAllocateIP(ctx context.Context, id string) (net.IP, *net.IPNet, error) {
r, err := s.parseSubnetRange(s.cfg.PeerNetwork)
if err != nil {
return nil, nil, err
}
ip, err := s.getIP(ctx, id)
if err != nil {
return nil, nil, err
}
if ip != nil {
return ip, r.Subnet, nil
}
ip, err = s.allocateIP(ctx, id, r)
if err != nil {
return nil, nil, err
}
return ip, r.Subnet, nil
}
func (s *Server) allocateIP(ctx context.Context, id string, r *subnetRange) (net.IP, error) {
reservedIPs, err := s.getIPs(ctx)
if err != nil {
return nil, err
}
if ip, exists := reservedIPs[id]; exists {
return ip, nil
}
lookup := map[string]string{}
for id, ip := range reservedIPs {
lookup[ip.String()] = id
}
for ip := r.Start; !ip.Equal(r.End); s.nextIP(ip) {
// filter out network, gateway and broadcast
if !s.validIP(ip) {
continue
}
if _, exists := lookup[ip.String()]; exists {
// ip already reserved
continue
}
// save
if _, err := s.master(ctx, "HSET", ipsKey, id, ip.String()); err != nil {
return nil, err
}
return ip, nil
}
return nil, fmt.Errorf("no available IPs")
}
func (s *Server) releaseIP(ctx context.Context, id string) error {
ip, err := s.getIP(ctx, id)
if err != nil {
return err
}
if ip != nil {
if _, err := s.master(ctx, "HDEL", ipsKey, id); err != nil {
return err
}
}
return nil
}
func (s *Server) nextIP(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}
func (s *Server) validIP(ip net.IP) bool {
v := ip[len(ip)-1]
switch v {
case 0, 1, 255:
return false
}
return true
}
// parseSubnetRange parses the subnet range
// format can either be a subnet like 10.0.0.0/8 or range like 10.0.0.100-10.0.0.200/24
func (s *Server) parseSubnetRange(subnet string) (*subnetRange, error) {
parts := strings.Split(subnet, "-")
if len(parts) == 1 {
ip, sub, err := net.ParseCIDR(parts[0])
if err != nil {
return nil, err
}
end := make(net.IP, len(ip))
copy(end, ip)
end[len(end)-1] = 254
return &subnetRange{
Start: ip,
End: end,
Subnet: sub,
}, nil
}
if len(parts) > 2 || !strings.Contains(subnet, "/") {
return nil, fmt.Errorf("invalid range specified; expect format 10.0.0.100-10.0.0.200/24")
}
start := net.ParseIP(parts[0])
end, sub, err := net.ParseCIDR(parts[1])
if err != nil {
return nil, err
}
return &subnetRange{
Start: start,
End: end,
Subnet: sub,
}, nil
}

View file

@ -23,8 +23,6 @@ package server
import ( import (
"context" "context"
"crypto/sha256"
"fmt"
"net/url" "net/url"
"strings" "strings"
"time" "time"
@ -33,31 +31,34 @@ import (
"github.com/gomodule/redigo/redis" "github.com/gomodule/redigo/redis"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/stellarproject/heimdall"
v1 "github.com/stellarproject/heimdall/api/v1" v1 "github.com/stellarproject/heimdall/api/v1"
) )
func (s *Server) configureNode() error { func (s *Server) configureNode() error {
ctx := context.Background() ctx := context.Background()
nodes, err := redis.Strings(s.local(ctx, "KEYS", s.getNodeKey("*"))) nodeKeys, err := redis.Strings(s.local(ctx, "KEYS", s.getNodeKey("*")))
if err != nil { if err != nil {
return err return err
} }
// attempt to connect to existing // attempt to connect to existing
if len(nodes) > 0 { if len(nodeKeys) > 0 {
for _, node := range nodes { for _, nodeKey := range nodeKeys {
addr, err := redis.String(s.local(ctx, "GET", node)) nodeData, err := redis.Bytes(s.local(ctx, "GET", nodeKey))
if err != nil { if err != nil {
logrus.Warn(err) logrus.Warn(err)
continue continue
} }
var node v1.Node
if err := proto.Unmarshal(nodeData, &node); err != nil {
return err
}
// ignore self // ignore self
if addr == s.cfg.GRPCAddress { if node.Addr == s.cfg.GRPCAddress {
continue continue
} }
logrus.Infof("attempting to join existing node %s", addr) logrus.Infof("attempting to join existing node %s", node.Addr)
c, err := s.getClient(addr) c, err := s.getClient(node.Addr)
if err != nil { if err != nil {
logrus.Warn(err) logrus.Warn(err)
continue continue
@ -125,9 +126,9 @@ func (s *Server) disableReplica() {
} }
func (s *Server) replicaMonitor() { func (s *Server) replicaMonitor() {
logrus.Debugf("starting replica monitor: ttl=%s", heartbeatInterval) logrus.Debugf("starting replica monitor: ttl=%s", masterHeartbeatInterval)
s.replicaCh = make(chan struct{}, 1) s.replicaCh = make(chan struct{}, 1)
t := time.NewTicker(heartbeatInterval) t := time.NewTicker(masterHeartbeatInterval)
go func() { go func() {
for range t.C { for range t.C {
if _, err := redis.Bytes(s.local(context.Background(), "GET", masterKey)); err != nil { if _, err := redis.Bytes(s.local(context.Background(), "GET", masterKey)); err != nil {
@ -149,9 +150,9 @@ func (s *Server) replicaMonitor() {
} }
func (s *Server) masterHeartbeat() { func (s *Server) masterHeartbeat() {
logrus.Debugf("starting master heartbeat: ttl=%s", heartbeatInterval) logrus.Debugf("starting master heartbeat: ttl=%s", masterHeartbeatInterval)
// initial update // initial update
ctx, cancel := context.WithTimeout(context.Background(), heartbeatInterval) ctx, cancel := context.WithTimeout(context.Background(), masterHeartbeatInterval)
defer cancel() defer cancel()
logrus.Infof("cluster master key=%s", s.cfg.ClusterKey) logrus.Infof("cluster master key=%s", s.cfg.ClusterKey)
@ -159,7 +160,7 @@ func (s *Server) masterHeartbeat() {
logrus.Error(err) logrus.Error(err)
} }
t := time.NewTicker(heartbeatInterval) t := time.NewTicker(masterHeartbeatInterval)
for range t.C { for range t.C {
if err := s.updateMasterInfo(ctx); err != nil { if err := s.updateMasterInfo(ctx); err != nil {
logrus.Error(err) logrus.Error(err)
@ -218,83 +219,37 @@ func (s *Server) updateMasterInfo(ctx context.Context) error {
return errors.Wrap(err, "error setting master info") return errors.Wrap(err, "error setting master info")
} }
if _, err := s.master(ctx, "EXPIRE", masterKey, int(heartbeatInterval.Seconds())); err != nil { if _, err := s.master(ctx, "EXPIRE", masterKey, int(masterHeartbeatInterval.Seconds())); err != nil {
return errors.Wrap(err, "error setting expire for master info") return errors.Wrap(err, "error setting expire for master info")
} }
return nil return nil
} }
func (s *Server) updatePeerInfo(ctx context.Context) error { func (s *Server) nodeHeartbeat(ctx context.Context) {
// 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) logrus.Debugf("starting node heartbeat: ttl=%s", nodeHeartbeatInterval)
ctx := context.Background()
t := time.NewTicker(nodeHeartbeatInterval) t := time.NewTicker(nodeHeartbeatInterval)
key := s.getNodeKey(s.cfg.ID) key := s.getNodeKey(s.cfg.ID)
for range t.C { for range t.C {
if _, err := s.master(ctx, "SET", key, s.cfg.GRPCAddress); err != nil { keyPair, err := s.getOrCreateKeyPair(ctx, s.cfg.ID)
if err != nil {
logrus.Error(err)
continue
}
node := &v1.Node{
ID: s.cfg.ID,
Addr: s.cfg.GRPCAddress,
KeyPair: keyPair,
GatewayIP: s.cfg.GatewayIP,
GatewayPort: uint64(s.cfg.GatewayPort),
}
data, err := proto.Marshal(node)
if err != nil {
logrus.Error(err)
continue
}
if _, err := s.master(ctx, "SET", key, data); err != nil {
logrus.Error(err) logrus.Error(err)
continue continue
} }
@ -305,11 +260,3 @@ 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))
}

190
server/peer.go Normal file
View file

@ -0,0 +1,190 @@
/*
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"
"crypto/sha256"
"fmt"
"io/ioutil"
"os"
"time"
"github.com/gogo/protobuf/proto"
"github.com/gomodule/redigo/redis"
"github.com/sirupsen/logrus"
v1 "github.com/stellarproject/heimdall/api/v1"
)
func (s *Server) updatePeerInfo(ctx context.Context) error {
keypair, err := s.getOrCreateKeyPair(ctx, s.cfg.ID)
if err != nil {
return err
}
endpoint := fmt.Sprintf("%s:%d", s.cfg.GatewayIP, s.cfg.GatewayPort)
// TODO: build allowedIPs from routes and peer network
allowedIPs := []string{s.cfg.PeerNetwork}
n := &v1.Peer{
ID: s.cfg.ID,
KeyPair: keypair,
AllowedIPs: allowedIPs,
Endpoint: 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
}
logrus.Debugf("peer info: endpoint=%s allowedips=%+v", n.Endpoint, n.Endpoint)
return 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))
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) updatePeerConfig(ctx context.Context) {
logrus.Debugf("starting peer config updater: ttl=%s", peerConfigUpdateInterval)
t := time.NewTicker(peerConfigUpdateInterval)
configHash := ""
for range t.C {
uctx, cancel := context.WithTimeout(ctx, peerConfigUpdateInterval)
peerKeys, err := redis.Strings(s.local(uctx, "KEYS", s.getPeerKey("*")))
if err != nil {
logrus.Error(err)
cancel()
continue
}
var peers []*v1.Peer
for _, peerKey := range peerKeys {
peerData, err := redis.Bytes(s.local(uctx, "GET", peerKey))
if err != nil {
logrus.Error(err)
cancel()
continue
}
var p v1.Peer
if err := proto.Unmarshal(peerData, &p); err != nil {
logrus.Error(err)
cancel()
continue
}
// do not add self as a peer
if p.ID == s.cfg.ID {
continue
}
peers = append(peers, &p)
}
keyPair, err := s.getOrCreateKeyPair(ctx, s.cfg.ID)
if err != nil {
logrus.Error(err)
cancel()
continue
}
gatewayIP, _, err := s.getOrAllocateIP(ctx, s.cfg.ID)
if err != nil {
logrus.Error(err)
cancel()
continue
}
wireguardCfg := &wireguardConfig{
Iface: defaultWireguardInterface,
PrivateKey: keyPair.PrivateKey,
ListenPort: s.cfg.GatewayPort,
Address: gatewayIP.String() + "/32",
Peers: peers,
}
tmpCfg, err := generateNodeWireguardConfig(wireguardCfg)
if err != nil {
logrus.Error(err)
cancel()
continue
}
h, err := hashConfig(tmpCfg)
if err != nil {
logrus.Error(err)
cancel()
continue
}
// if config has not change skip update
if h == configHash {
continue
}
logrus.Debugf("updating peer config to version %s", h)
// update wireguard config
if err := os.Rename(tmpCfg, wireguardConfigPath); err != nil {
logrus.Error(err)
cancel()
continue
}
// reload wireguard
if err := restartWireguardTunnel(ctx); err != nil {
logrus.Error(err)
cancel()
continue
}
configHash = h
}
}
func hashConfig(cfgPath string) (string, error) {
peerData, err := ioutil.ReadFile(cfgPath)
if err != nil {
return "", err
}
h := sha256.New()
h.Write(peerData)
return fmt.Sprintf("%x", h.Sum(nil)), nil
}

View file

@ -29,6 +29,7 @@ import (
"runtime/pprof" "runtime/pprof"
"time" "time"
"github.com/gogo/protobuf/proto"
ptypes "github.com/gogo/protobuf/types" ptypes "github.com/gogo/protobuf/types"
"github.com/gomodule/redigo/redis" "github.com/gomodule/redigo/redis"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -42,18 +43,21 @@ import (
const ( const (
masterKey = "heimdall:master" masterKey = "heimdall:master"
clusterKey = "heimdall:key" clusterKey = "heimdall:key"
keypairsKey = "heimdall:keypairs"
nodesKey = "heimdall:nodes" nodesKey = "heimdall:nodes"
nodeJoinKey = "heimdall:join" nodeJoinKey = "heimdall:join"
peersKey = "heimdall:peers" peersKey = "heimdall:peers"
ipsKey = "heimdall:ips"
wireguardConfigPath = "/etc/wireguard/darknet.conf" wireguardConfigPath = "/etc/wireguard/darknet.conf"
) )
var ( var (
empty = &ptypes.Empty{} empty = &ptypes.Empty{}
heartbeatInterval = time.Second * 5 masterHeartbeatInterval = time.Second * 5
nodeHeartbeatInterval = time.Second * 60 nodeHeartbeatInterval = time.Second * 60
nodeHeartbeatExpiry = 86400 nodeHeartbeatExpiry = 86400
peerConfigUpdateInterval = time.Second * 10
) )
type Server struct { type Server struct {
@ -122,11 +126,19 @@ func (s *Server) Run() error {
} }
} }
if _, err := s.getOrCreateKeyPair(ctx, s.cfg.ID); err != nil {
return err
}
if err := s.updatePeerInfo(ctx); err != nil { if err := s.updatePeerInfo(ctx); err != nil {
return err return err
} }
go s.nodeHeartbeat() // start node heartbeat to update in redis
go s.nodeHeartbeat(ctx)
// start peer config updater to configure wireguard as peers join
go s.updatePeerConfig(ctx)
// start listener for pub/sub // start listener for pub/sub
errCh := make(chan error, 1) errCh := make(chan error, 1)
@ -170,6 +182,39 @@ func getPool(u string) *redis.Pool {
return pool return pool
} }
func (s *Server) getOrCreateKeyPair(ctx context.Context, id string) (*v1.KeyPair, error) {
key := s.getKeyPairKey(id)
keyData, err := redis.Bytes(s.master(ctx, "GET", key))
if err != nil {
if err != redis.ErrNil {
return nil, err
}
logrus.Debugf("generating new keypair for %s", s.cfg.ID)
privateKey, publicKey, err := generateWireguardKeys(ctx)
if err != nil {
return nil, err
}
keyPair := &v1.KeyPair{
PrivateKey: privateKey,
PublicKey: publicKey,
}
data, err := proto.Marshal(keyPair)
if err != nil {
return nil, err
}
if _, err := s.master(ctx, "SET", key, data); err != nil {
return nil, err
}
return keyPair, nil
}
var keyPair v1.KeyPair
if err := proto.Unmarshal(keyData, &keyPair); err != nil {
return nil, err
}
return &keyPair, nil
}
func (s *Server) getNodeKey(id string) string { func (s *Server) getNodeKey(id string) string {
return fmt.Sprintf("%s:%s", nodesKey, id) return fmt.Sprintf("%s:%s", nodesKey, id)
} }
@ -178,6 +223,10 @@ func (s *Server) getPeerKey(id string) string {
return fmt.Sprintf("%s:%s", peersKey, id) return fmt.Sprintf("%s:%s", peersKey, id)
} }
func (s *Server) getKeyPairKey(id string) string {
return fmt.Sprintf("%s:%s", keypairsKey, id)
}
func (s *Server) getClient(addr string) (*client.Client, error) { func (s *Server) getClient(addr string) (*client.Client, error) {
return client.NewClient(s.cfg.ID, addr) return client.NewClient(s.cfg.ID, addr)
} }

View file

@ -32,12 +32,14 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
v1 "github.com/stellarproject/heimdall/api/v1" v1 "github.com/stellarproject/heimdall/api/v1"
) )
const ( const (
defaultInterface = "darknet" defaultWireguardInterface = "darknet"
wireguardTemplate = `# managed by heimdall wireguardTemplate = `# managed by heimdall
[Interface] [Interface]
PrivateKey = {{ .PrivateKey }} PrivateKey = {{ .PrivateKey }}
ListenPort = {{ .ListenPort }} ListenPort = {{ .ListenPort }}
@ -46,7 +48,7 @@ PostUp = iptables -A FORWARD -i {{ .Iface }} -j ACCEPT; iptables -t nat -A POSTR
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 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 }} {{ range .Peers }}
[Peer] [Peer]
PublicKey = {{ .PublicKey }} PublicKey = {{ .KeyPair.PublicKey }}
AllowedIPs = {{ allowedIPs .AllowedIPs }} AllowedIPs = {{ allowedIPs .AllowedIPs }}
Endpoint = {{ .Endpoint }} Endpoint = {{ .Endpoint }}
{{ end }} {{ end }}
@ -65,28 +67,28 @@ type wireguardConfig struct {
Peers []*v1.Peer Peers []*v1.Peer
} }
func generateNodeWireguardConfig(cfg *wireguardConfig) (*os.File, error) { func generateNodeWireguardConfig(cfg *wireguardConfig) (string, error) {
f, err := ioutil.TempFile("", "heimdall-wireguard-") f, err := ioutil.TempFile("", "heimdall-wireguard-")
if err != nil { if err != nil {
return nil, err return "", err
} }
t, err := template.New("wireguard").Funcs(template.FuncMap{ t, err := template.New("wireguard").Funcs(template.FuncMap{
"allowedIPs": allowedIPs, "allowedIPs": allowedIPs,
}).Parse(wireguardTemplate) }).Parse(wireguardTemplate)
if err != nil { if err != nil {
return nil, err return "", err
} }
if err := os.MkdirAll(filepath.Dir(wireguardConfigPath), 0755); err != nil { if err := os.MkdirAll(filepath.Dir(wireguardConfigPath), 0755); err != nil {
return nil, err return "", err
} }
if err := t.Execute(f, cfg); err != nil { if err := t.Execute(f, cfg); err != nil {
return nil, err return "", err
} }
f.Close() f.Close()
return f, nil return f.Name(), nil
} }
func generateWireguardKeys(ctx context.Context) (string, string, error) { func generateWireguardKeys(ctx context.Context) (string, string, error) {
@ -105,6 +107,20 @@ func generateWireguardKeys(ctx context.Context) (string, string, error) {
return privateKey, publicKey, nil return privateKey, publicKey, nil
} }
func restartWireguardTunnel(ctx context.Context) error {
tunnelName := strings.Replace(filepath.Base(wireguardConfigPath), filepath.Ext(filepath.Base(wireguardConfigPath)), "", 1)
logrus.Infof("restarting tunnel %s", tunnelName)
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) { func wg(ctx context.Context, in io.Reader, args ...string) ([]byte, error) {
cmd := exec.CommandContext(ctx, "wg", args...) cmd := exec.CommandContext(ctx, "wg", args...)
if in != nil { if in != nil {
@ -112,3 +128,8 @@ func wg(ctx context.Context, in io.Reader, args ...string) ([]byte, error) {
} }
return cmd.CombinedOutput() return cmd.CombinedOutput()
} }
func wgquick(ctx context.Context, args ...string) ([]byte, error) {
cmd := exec.CommandContext(ctx, "wg-quick", args...)
return cmd.CombinedOutput()
}

View file

@ -45,25 +45,27 @@ Endpoint = 100.100.100.100:10000
` `
cfg := &wireguardConfig{ cfg := &wireguardConfig{
Iface: "darknet", Iface: defaultWireguardInterface,
PrivateKey: "SERVER-PRIVATE-KEY", PrivateKey: "SERVER-PRIVATE-KEY",
ListenPort: 10000, ListenPort: 10000,
Address: "1.2.3.4:10000", Address: "1.2.3.4:10000",
Peers: []*v1.Peer{ Peers: []*v1.Peer{
{ {
PrivateKey: "PEER-PRIVATE-KEY", KeyPair: &v1.KeyPair{
PublicKey: "PEER-PUBLIC-KEY", PrivateKey: "PEER-PRIVATE-KEY",
PublicKey: "PEER-PUBLIC-KEY",
},
AllowedIPs: []string{"10.100.0.0/24", "10.254.0.0/16"}, AllowedIPs: []string{"10.100.0.0/24", "10.254.0.0/16"},
Endpoint: "100.100.100.100:10000", Endpoint: "100.100.100.100:10000",
}, },
}, },
} }
f, err := generateWireguardConfig(cfg) configPath, err := generateNodeWireguardConfig(cfg)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.Remove(f.Name()) defer os.Remove(configPath)
data, err := ioutil.ReadFile(f.Name()) data, err := ioutil.ReadFile(configPath)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }