IPv6 support for outside (udp) (#369)

This commit is contained in:
Nathan Brown 2021-03-18 20:37:24 -05:00 committed by GitHub
parent 9e94442ce7
commit 7073d204a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1726 additions and 732 deletions

View File

@ -113,8 +113,8 @@ bench-cpu-long:
proto: nebula.pb.go cert/cert.pb.go proto: nebula.pb.go cert/cert.pb.go
nebula.pb.go: nebula.proto .FORCE nebula.pb.go: nebula.proto .FORCE
go build github.com/golang/protobuf/protoc-gen-go go build google.golang.org/protobuf/cmd/protoc-gen-go
PATH="$(PWD):$(PATH)" protoc --go_out=. $< PATH="$(CURDIR):$(PATH)" protoc --go_out=. --go_opt=paths=source_relative $<
rm protoc-gen-go rm protoc-gen-go
cert/cert.pb.go: cert/cert.proto .FORCE cert/cert.pb.go: cert/cert.proto .FORCE

View File

@ -2,12 +2,13 @@ package nebula
import ( import (
"fmt" "fmt"
"net"
"regexp" "regexp"
) )
type AllowList struct { type AllowList struct {
// The values of this cidrTree are `bool`, signifying allow/deny // The values of this cidrTree are `bool`, signifying allow/deny
cidrTree *CIDRTree cidrTree *CIDR6Tree
// To avoid ambiguity, all rules must be true, or all rules must be false. // To avoid ambiguity, all rules must be true, or all rules must be false.
nameRules []AllowListNameRule nameRules []AllowListNameRule
@ -18,7 +19,7 @@ type AllowListNameRule struct {
Allow bool Allow bool
} }
func (al *AllowList) Allow(ip uint32) bool { func (al *AllowList) Allow(ip net.IP) bool {
if al == nil { if al == nil {
return true return true
} }

View File

@ -9,17 +9,26 @@ import (
) )
func TestAllowList_Allow(t *testing.T) { func TestAllowList_Allow(t *testing.T) {
assert.Equal(t, true, ((*AllowList)(nil)).Allow(ip2int(net.ParseIP("1.1.1.1")))) assert.Equal(t, true, ((*AllowList)(nil)).Allow(net.ParseIP("1.1.1.1")))
tree := NewCIDRTree() tree := NewCIDR6Tree()
tree.AddCIDR(getCIDR("0.0.0.0/0"), true) tree.AddCIDR(getCIDR("0.0.0.0/0"), true)
tree.AddCIDR(getCIDR("10.0.0.0/8"), false) tree.AddCIDR(getCIDR("10.0.0.0/8"), false)
tree.AddCIDR(getCIDR("10.42.42.42/32"), true)
tree.AddCIDR(getCIDR("10.42.0.0/16"), true)
tree.AddCIDR(getCIDR("10.42.42.0/24"), true) tree.AddCIDR(getCIDR("10.42.42.0/24"), true)
tree.AddCIDR(getCIDR("10.42.42.0/24"), false)
tree.AddCIDR(getCIDR("::1/128"), true)
tree.AddCIDR(getCIDR("::2/128"), false)
al := &AllowList{cidrTree: tree} al := &AllowList{cidrTree: tree}
assert.Equal(t, true, al.Allow(ip2int(net.ParseIP("1.1.1.1")))) assert.Equal(t, true, al.Allow(net.ParseIP("1.1.1.1")))
assert.Equal(t, false, al.Allow(ip2int(net.ParseIP("10.0.0.4")))) assert.Equal(t, false, al.Allow(net.ParseIP("10.0.0.4")))
assert.Equal(t, true, al.Allow(ip2int(net.ParseIP("10.42.42.42")))) assert.Equal(t, true, al.Allow(net.ParseIP("10.42.42.42")))
assert.Equal(t, false, al.Allow(net.ParseIP("10.42.42.41")))
assert.Equal(t, true, al.Allow(net.ParseIP("10.42.0.1")))
assert.Equal(t, true, al.Allow(net.ParseIP("::1")))
assert.Equal(t, false, al.Allow(net.ParseIP("::2")))
} }
func TestAllowList_AllowName(t *testing.T) { func TestAllowList_AllowName(t *testing.T) {

View File

@ -2,8 +2,8 @@ GO111MODULE = on
export GO111MODULE export GO111MODULE
cert.pb.go: cert.proto .FORCE cert.pb.go: cert.proto .FORCE
go build github.com/golang/protobuf/protoc-gen-go go build google.golang.org/protobuf/cmd/protoc-gen-go
PATH="$(PWD):$(PATH)" protoc --go_out=. $< PATH="$(CURDIR):$(PATH)" protoc --go_out=. --go_opt=paths=source_relative $<
rm protoc-gen-go rm protoc-gen-go
.FORCE: .FORCE:

View File

@ -1,202 +1,298 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.14.0
// source: cert.proto // source: cert.proto
package cert package cert
import ( import (
fmt "fmt" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
proto "github.com/golang/protobuf/proto" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
math "math" reflect "reflect"
sync "sync"
) )
// Reference imports to suppress errors if they are not otherwise used. const (
var _ = proto.Marshal // Verify that this generated code is sufficiently up-to-date.
var _ = fmt.Errorf _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
var _ = math.Inf // Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
// This is a compile-time assertion to ensure that this generated file )
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type RawNebulaCertificate struct { type RawNebulaCertificate struct {
Details *RawNebulaCertificateDetails `protobuf:"bytes,1,opt,name=Details,json=details,proto3" json:"Details,omitempty"` state protoimpl.MessageState
Signature []byte `protobuf:"bytes,2,opt,name=Signature,json=signature,proto3" json:"Signature,omitempty"` sizeCache protoimpl.SizeCache
XXX_NoUnkeyedLiteral struct{} `json:"-"` unknownFields protoimpl.UnknownFields
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` Details *RawNebulaCertificateDetails `protobuf:"bytes,1,opt,name=Details,proto3" json:"Details,omitempty"`
Signature []byte `protobuf:"bytes,2,opt,name=Signature,proto3" json:"Signature,omitempty"`
} }
func (m *RawNebulaCertificate) Reset() { *m = RawNebulaCertificate{} } func (x *RawNebulaCertificate) Reset() {
func (m *RawNebulaCertificate) String() string { return proto.CompactTextString(m) } *x = RawNebulaCertificate{}
func (*RawNebulaCertificate) ProtoMessage() {} if protoimpl.UnsafeEnabled {
mi := &file_cert_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RawNebulaCertificate) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RawNebulaCertificate) ProtoMessage() {}
func (x *RawNebulaCertificate) ProtoReflect() protoreflect.Message {
mi := &file_cert_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RawNebulaCertificate.ProtoReflect.Descriptor instead.
func (*RawNebulaCertificate) Descriptor() ([]byte, []int) { func (*RawNebulaCertificate) Descriptor() ([]byte, []int) {
return fileDescriptor_a142e29cbef9b1cf, []int{0} return file_cert_proto_rawDescGZIP(), []int{0}
} }
func (m *RawNebulaCertificate) XXX_Unmarshal(b []byte) error { func (x *RawNebulaCertificate) GetDetails() *RawNebulaCertificateDetails {
return xxx_messageInfo_RawNebulaCertificate.Unmarshal(m, b) if x != nil {
} return x.Details
func (m *RawNebulaCertificate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RawNebulaCertificate.Marshal(b, m, deterministic)
}
func (m *RawNebulaCertificate) XXX_Merge(src proto.Message) {
xxx_messageInfo_RawNebulaCertificate.Merge(m, src)
}
func (m *RawNebulaCertificate) XXX_Size() int {
return xxx_messageInfo_RawNebulaCertificate.Size(m)
}
func (m *RawNebulaCertificate) XXX_DiscardUnknown() {
xxx_messageInfo_RawNebulaCertificate.DiscardUnknown(m)
}
var xxx_messageInfo_RawNebulaCertificate proto.InternalMessageInfo
func (m *RawNebulaCertificate) GetDetails() *RawNebulaCertificateDetails {
if m != nil {
return m.Details
} }
return nil return nil
} }
func (m *RawNebulaCertificate) GetSignature() []byte { func (x *RawNebulaCertificate) GetSignature() []byte {
if m != nil { if x != nil {
return m.Signature return x.Signature
} }
return nil return nil
} }
type RawNebulaCertificateDetails struct { type RawNebulaCertificateDetails struct {
Name string `protobuf:"bytes,1,opt,name=Name,json=name,proto3" json:"Name,omitempty"` state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
// Ips and Subnets are in big endian 32 bit pairs, 1st the ip, 2nd the mask // Ips and Subnets are in big endian 32 bit pairs, 1st the ip, 2nd the mask
Ips []uint32 `protobuf:"varint,2,rep,packed,name=Ips,json=ips,proto3" json:"Ips,omitempty"` Ips []uint32 `protobuf:"varint,2,rep,packed,name=Ips,proto3" json:"Ips,omitempty"`
Subnets []uint32 `protobuf:"varint,3,rep,packed,name=Subnets,json=subnets,proto3" json:"Subnets,omitempty"` Subnets []uint32 `protobuf:"varint,3,rep,packed,name=Subnets,proto3" json:"Subnets,omitempty"`
Groups []string `protobuf:"bytes,4,rep,name=Groups,json=groups,proto3" json:"Groups,omitempty"` Groups []string `protobuf:"bytes,4,rep,name=Groups,proto3" json:"Groups,omitempty"`
NotBefore int64 `protobuf:"varint,5,opt,name=NotBefore,json=notBefore,proto3" json:"NotBefore,omitempty"` NotBefore int64 `protobuf:"varint,5,opt,name=NotBefore,proto3" json:"NotBefore,omitempty"`
NotAfter int64 `protobuf:"varint,6,opt,name=NotAfter,json=notAfter,proto3" json:"NotAfter,omitempty"` NotAfter int64 `protobuf:"varint,6,opt,name=NotAfter,proto3" json:"NotAfter,omitempty"`
PublicKey []byte `protobuf:"bytes,7,opt,name=PublicKey,json=publicKey,proto3" json:"PublicKey,omitempty"` PublicKey []byte `protobuf:"bytes,7,opt,name=PublicKey,proto3" json:"PublicKey,omitempty"`
IsCA bool `protobuf:"varint,8,opt,name=IsCA,json=isCA,proto3" json:"IsCA,omitempty"` IsCA bool `protobuf:"varint,8,opt,name=IsCA,proto3" json:"IsCA,omitempty"`
// sha-256 of the issuer certificate, if this field is blank the cert is self-signed // sha-256 of the issuer certificate, if this field is blank the cert is self-signed
Issuer []byte `protobuf:"bytes,9,opt,name=Issuer,json=issuer,proto3" json:"Issuer,omitempty"` Issuer []byte `protobuf:"bytes,9,opt,name=Issuer,proto3" json:"Issuer,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *RawNebulaCertificateDetails) Reset() { *m = RawNebulaCertificateDetails{} } func (x *RawNebulaCertificateDetails) Reset() {
func (m *RawNebulaCertificateDetails) String() string { return proto.CompactTextString(m) } *x = RawNebulaCertificateDetails{}
func (*RawNebulaCertificateDetails) ProtoMessage() {} if protoimpl.UnsafeEnabled {
mi := &file_cert_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RawNebulaCertificateDetails) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RawNebulaCertificateDetails) ProtoMessage() {}
func (x *RawNebulaCertificateDetails) ProtoReflect() protoreflect.Message {
mi := &file_cert_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RawNebulaCertificateDetails.ProtoReflect.Descriptor instead.
func (*RawNebulaCertificateDetails) Descriptor() ([]byte, []int) { func (*RawNebulaCertificateDetails) Descriptor() ([]byte, []int) {
return fileDescriptor_a142e29cbef9b1cf, []int{1} return file_cert_proto_rawDescGZIP(), []int{1}
} }
func (m *RawNebulaCertificateDetails) XXX_Unmarshal(b []byte) error { func (x *RawNebulaCertificateDetails) GetName() string {
return xxx_messageInfo_RawNebulaCertificateDetails.Unmarshal(m, b) if x != nil {
} return x.Name
func (m *RawNebulaCertificateDetails) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RawNebulaCertificateDetails.Marshal(b, m, deterministic)
}
func (m *RawNebulaCertificateDetails) XXX_Merge(src proto.Message) {
xxx_messageInfo_RawNebulaCertificateDetails.Merge(m, src)
}
func (m *RawNebulaCertificateDetails) XXX_Size() int {
return xxx_messageInfo_RawNebulaCertificateDetails.Size(m)
}
func (m *RawNebulaCertificateDetails) XXX_DiscardUnknown() {
xxx_messageInfo_RawNebulaCertificateDetails.DiscardUnknown(m)
}
var xxx_messageInfo_RawNebulaCertificateDetails proto.InternalMessageInfo
func (m *RawNebulaCertificateDetails) GetName() string {
if m != nil {
return m.Name
} }
return "" return ""
} }
func (m *RawNebulaCertificateDetails) GetIps() []uint32 { func (x *RawNebulaCertificateDetails) GetIps() []uint32 {
if m != nil { if x != nil {
return m.Ips return x.Ips
} }
return nil return nil
} }
func (m *RawNebulaCertificateDetails) GetSubnets() []uint32 { func (x *RawNebulaCertificateDetails) GetSubnets() []uint32 {
if m != nil { if x != nil {
return m.Subnets return x.Subnets
} }
return nil return nil
} }
func (m *RawNebulaCertificateDetails) GetGroups() []string { func (x *RawNebulaCertificateDetails) GetGroups() []string {
if m != nil { if x != nil {
return m.Groups return x.Groups
} }
return nil return nil
} }
func (m *RawNebulaCertificateDetails) GetNotBefore() int64 { func (x *RawNebulaCertificateDetails) GetNotBefore() int64 {
if m != nil { if x != nil {
return m.NotBefore return x.NotBefore
} }
return 0 return 0
} }
func (m *RawNebulaCertificateDetails) GetNotAfter() int64 { func (x *RawNebulaCertificateDetails) GetNotAfter() int64 {
if m != nil { if x != nil {
return m.NotAfter return x.NotAfter
} }
return 0 return 0
} }
func (m *RawNebulaCertificateDetails) GetPublicKey() []byte { func (x *RawNebulaCertificateDetails) GetPublicKey() []byte {
if m != nil { if x != nil {
return m.PublicKey return x.PublicKey
} }
return nil return nil
} }
func (m *RawNebulaCertificateDetails) GetIsCA() bool { func (x *RawNebulaCertificateDetails) GetIsCA() bool {
if m != nil { if x != nil {
return m.IsCA return x.IsCA
} }
return false return false
} }
func (m *RawNebulaCertificateDetails) GetIssuer() []byte { func (x *RawNebulaCertificateDetails) GetIssuer() []byte {
if m != nil { if x != nil {
return m.Issuer return x.Issuer
} }
return nil return nil
} }
func init() { var File_cert_proto protoreflect.FileDescriptor
proto.RegisterType((*RawNebulaCertificate)(nil), "cert.RawNebulaCertificate")
proto.RegisterType((*RawNebulaCertificateDetails)(nil), "cert.RawNebulaCertificateDetails") var file_cert_proto_rawDesc = []byte{
0x0a, 0x0a, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x63, 0x65,
0x72, 0x74, 0x22, 0x71, 0x0a, 0x14, 0x52, 0x61, 0x77, 0x4e, 0x65, 0x62, 0x75, 0x6c, 0x61, 0x43,
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x07, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x65,
0x72, 0x74, 0x2e, 0x52, 0x61, 0x77, 0x4e, 0x65, 0x62, 0x75, 0x6c, 0x61, 0x43, 0x65, 0x72, 0x74,
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x07,
0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61,
0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x53, 0x69, 0x67, 0x6e,
0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xf9, 0x01, 0x0a, 0x1b, 0x52, 0x61, 0x77, 0x4e, 0x65, 0x62,
0x75, 0x6c, 0x61, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x49, 0x70, 0x73,
0x18, 0x02, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x03, 0x49, 0x70, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x53,
0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x07, 0x53, 0x75,
0x62, 0x6e, 0x65, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18,
0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x1c, 0x0a,
0x09, 0x4e, 0x6f, 0x74, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03,
0x52, 0x09, 0x4e, 0x6f, 0x74, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x4e,
0x6f, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x4e,
0x6f, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x4b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x50, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x49, 0x73, 0x43, 0x41, 0x18, 0x08, 0x20,
0x01, 0x28, 0x08, 0x52, 0x04, 0x49, 0x73, 0x43, 0x41, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x73, 0x73,
0x75, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x49, 0x73, 0x73, 0x75, 0x65,
0x72, 0x42, 0x20, 0x5a, 0x1e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x73, 0x6c, 0x61, 0x63, 0x6b, 0x68, 0x71, 0x2f, 0x6e, 0x65, 0x62, 0x75, 0x6c, 0x61, 0x2f, 0x63,
0x65, 0x72, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
func init() { proto.RegisterFile("cert.proto", fileDescriptor_a142e29cbef9b1cf) } var (
file_cert_proto_rawDescOnce sync.Once
file_cert_proto_rawDescData = file_cert_proto_rawDesc
)
var fileDescriptor_a142e29cbef9b1cf = []byte{ func file_cert_proto_rawDescGZIP() []byte {
// 279 bytes of a gzipped FileDescriptorProto file_cert_proto_rawDescOnce.Do(func() {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0xcf, 0x4a, 0xf4, 0x30, file_cert_proto_rawDescData = protoimpl.X.CompressGZIP(file_cert_proto_rawDescData)
0x14, 0xc5, 0xc9, 0xa4, 0x5f, 0xdb, 0xe4, 0x53, 0x90, 0x20, 0x12, 0xd4, 0x45, 0x9c, 0x55, 0x56, })
0xb3, 0xd0, 0xa5, 0xab, 0x71, 0x04, 0x29, 0x42, 0x91, 0xcc, 0x13, 0xa4, 0xf5, 0x76, 0x08, 0x74, return file_cert_proto_rawDescData
0x9a, 0x9a, 0x3f, 0x88, 0x8f, 0xee, 0x4e, 0x9a, 0x4e, 0x77, 0xe2, 0xee, 0x9e, 0x5f, 0xce, 0x49, }
0x4e, 0x2e, 0xa5, 0x2d, 0xb8, 0xb0, 0x19, 0x9d, 0x0d, 0x96, 0x65, 0xd3, 0xbc, 0xfe, 0xa0, 0x97,
0x4a, 0x7f, 0xd6, 0xd0, 0xc4, 0x5e, 0xef, 0xc0, 0x05, 0xd3, 0x99, 0x56, 0x07, 0x60, 0x8f, 0xb4, var file_cert_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
0x78, 0x86, 0xa0, 0x4d, 0xef, 0x39, 0x12, 0x48, 0xfe, 0xbf, 0xbf, 0xdb, 0xa4, 0xec, 0x6f, 0xe6, var file_cert_proto_goTypes = []interface{}{
0x93, 0x51, 0x15, 0xef, 0xf3, 0xc0, 0x6e, 0x29, 0xd9, 0x9b, 0xc3, 0xa0, 0x43, 0x74, 0xc0, 0x57, (*RawNebulaCertificate)(nil), // 0: cert.RawNebulaCertificate
0x02, 0xc9, 0x33, 0x45, 0xfc, 0x02, 0xd6, 0xdf, 0x88, 0xde, 0xfc, 0x71, 0x0d, 0x63, 0x34, 0xab, (*RawNebulaCertificateDetails)(nil), // 1: cert.RawNebulaCertificateDetails
0xf5, 0x11, 0xd2, 0xbb, 0x44, 0x65, 0x83, 0x3e, 0x02, 0xbb, 0xa0, 0xb8, 0x1a, 0x3d, 0x5f, 0x09, }
0x2c, 0xcf, 0x15, 0x36, 0xa3, 0x67, 0x9c, 0x16, 0xfb, 0xd8, 0x0c, 0x10, 0x3c, 0xc7, 0x89, 0x16, var file_cert_proto_depIdxs = []int32{
0x7e, 0x96, 0xec, 0x8a, 0xe6, 0x2f, 0xce, 0xc6, 0xd1, 0xf3, 0x4c, 0x60, 0x49, 0x54, 0x7e, 0x48, 1, // 0: cert.RawNebulaCertificate.Details:type_name -> cert.RawNebulaCertificateDetails
0x6a, 0x6a, 0x55, 0xdb, 0xf0, 0x04, 0x9d, 0x75, 0xc0, 0xff, 0x09, 0x24, 0xb1, 0x22, 0xc3, 0x02, 1, // [1:1] is the sub-list for method output_type
0xd8, 0x35, 0x2d, 0x6b, 0x1b, 0xb6, 0x5d, 0x00, 0xc7, 0xf3, 0x74, 0x58, 0x0e, 0x27, 0x3d, 0x25, 1, // [1:1] is the sub-list for method input_type
0xdf, 0x62, 0xd3, 0x9b, 0xf6, 0x15, 0xbe, 0x78, 0x31, 0xff, 0x67, 0x5c, 0xc0, 0xd4, 0xb7, 0xf2, 1, // [1:1] is the sub-list for extension type_name
0xbb, 0x2d, 0x2f, 0x05, 0x92, 0xa5, 0xca, 0x8c, 0xdf, 0x6d, 0xa7, 0x0e, 0x95, 0xf7, 0x11, 0x1c, 1, // [1:1] is the sub-list for extension extendee
0x27, 0xc9, 0x9e, 0x9b, 0xa4, 0x9a, 0x3c, 0xed, 0xfe, 0xe1, 0x27, 0x00, 0x00, 0xff, 0xff, 0x2c, 0, // [0:1] is the sub-list for field type_name
0xe3, 0x08, 0x37, 0x89, 0x01, 0x00, 0x00, }
func init() { file_cert_proto_init() }
func file_cert_proto_init() {
if File_cert_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_cert_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RawNebulaCertificate); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_cert_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RawNebulaCertificateDetails); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_cert_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_cert_proto_goTypes,
DependencyIndexes: file_cert_proto_depIdxs,
MessageInfos: file_cert_proto_msgTypes,
}.Build()
File_cert_proto = out.File
file_cert_proto_rawDesc = nil
file_cert_proto_goTypes = nil
file_cert_proto_depIdxs = nil
} }

View File

@ -1,6 +1,8 @@
syntax = "proto3"; syntax = "proto3";
package cert; package cert;
option go_package = "github.com/slackhq/nebula/cert";
//import "google/protobuf/timestamp.proto"; //import "google/protobuf/timestamp.proto";
message RawNebulaCertificate { message RawNebulaCertificate {

203
cidr6_radix.go Normal file
View File

@ -0,0 +1,203 @@
package nebula
import (
"encoding/binary"
"net"
)
type CIDR6Tree struct {
root4 *CIDRNode
root6 *CIDRNode
}
func NewCIDR6Tree() *CIDR6Tree {
tree := new(CIDR6Tree)
tree.root4 = &CIDRNode{}
tree.root6 = &CIDRNode{}
return tree
}
func (tree *CIDR6Tree) AddCIDR(cidr *net.IPNet, val interface{}) {
var node, next *CIDRNode
cidrIP, ipv4 := isIPV4(cidr.IP)
if ipv4 {
node = tree.root4
next = tree.root4
} else {
node = tree.root6
next = tree.root6
}
for i := 0; i < len(cidrIP); i += 4 {
ip := binary.BigEndian.Uint32(cidrIP[i : i+4])
mask := binary.BigEndian.Uint32(cidr.Mask[i : i+4])
bit := startbit
// Find our last ancestor in the tree
for bit&mask != 0 {
if ip&bit != 0 {
next = node.right
} else {
next = node.left
}
if next == nil {
break
}
bit = bit >> 1
node = next
}
// Build up the rest of the tree we don't already have
for bit&mask != 0 {
next = &CIDRNode{}
next.parent = node
if ip&bit != 0 {
node.right = next
} else {
node.left = next
}
bit >>= 1
node = next
}
}
// Final node marks our cidr, set the value
node.value = val
}
// Finds the first match, which may be the least specific
func (tree *CIDR6Tree) Contains(ip net.IP) (value interface{}) {
var node *CIDRNode
wholeIP, ipv4 := isIPV4(ip)
if ipv4 {
node = tree.root4
} else {
node = tree.root6
}
for i := 0; i < len(wholeIP); i += 4 {
ip := ip2int(wholeIP[i : i+4])
bit := startbit
for node != nil {
if node.value != nil {
return node.value
}
// Check if we have reached the end and the above return did not trigger, move to the next uint32 if available
if bit == 0 {
break
}
if ip&bit != 0 {
node = node.right
} else {
node = node.left
}
bit >>= 1
}
}
// Nothing found
return
}
// Finds the most specific match
func (tree *CIDR6Tree) MostSpecificContains(ip net.IP) (value interface{}) {
var node *CIDRNode
wholeIP, ipv4 := isIPV4(ip)
if ipv4 {
node = tree.root4
} else {
node = tree.root6
}
for i := 0; i < len(wholeIP); i += 4 {
ip := ip2int(wholeIP[i : i+4])
bit := startbit
for node != nil {
if node.value != nil {
value = node.value
}
if bit == 0 {
break
}
if ip&bit != 0 {
node = node.right
} else {
node = node.left
}
bit >>= 1
}
}
return value
}
// Finds the most specific match
func (tree *CIDR6Tree) Match(ip net.IP) (value interface{}) {
var node *CIDRNode
var bit uint32
wholeIP, ipv4 := isIPV4(ip)
if ipv4 {
node = tree.root4
} else {
node = tree.root6
}
for i := 0; i < len(wholeIP); i += 4 {
ip := ip2int(wholeIP[i : i+4])
bit = startbit
for node != nil && bit > 0 {
if ip&bit != 0 {
node = node.right
} else {
node = node.left
}
bit >>= 1
}
}
if bit == 0 && node != nil {
value = node.value
}
return value
}
func isIPV4(ip net.IP) (net.IP, bool) {
if len(ip) == net.IPv4len {
return ip, true
}
if len(ip) == net.IPv6len && isZeros(ip[0:10]) && ip[10] == 0xff && ip[11] == 0xff {
return ip[12:16], true
}
return ip, false
}
func isZeros(p net.IP) bool {
for i := 0; i < len(p); i++ {
if p[i] != 0 {
return false
}
}
return true
}

134
cidr6_radix_test.go Normal file
View File

@ -0,0 +1,134 @@
package nebula
import (
"net"
"testing"
"github.com/stretchr/testify/assert"
)
func TestCIDR6Tree_Contains(t *testing.T) {
tree := NewCIDR6Tree()
tree.AddCIDR(getCIDR("1.0.0.0/8"), "1")
tree.AddCIDR(getCIDR("2.1.0.0/16"), "2")
tree.AddCIDR(getCIDR("3.1.1.0/24"), "3")
tree.AddCIDR(getCIDR("4.1.1.0/24"), "4a")
tree.AddCIDR(getCIDR("4.1.1.1/32"), "4b")
tree.AddCIDR(getCIDR("4.1.2.1/32"), "4c")
tree.AddCIDR(getCIDR("254.0.0.0/4"), "5")
tree.AddCIDR(getCIDR("2800::FFFF:1/128"), "a")
tree.AddCIDR(getCIDR("2800:1:2:3::0/64"), "b")
tests := []struct {
Result interface{}
IP string
}{
{"1", "1.0.0.0"},
{"1", "1.255.255.255"},
{"2", "2.1.0.0"},
{"2", "2.1.255.255"},
{"3", "3.1.1.0"},
{"3", "3.1.1.255"},
{"4a", "4.1.1.255"},
{"4a", "4.1.1.1"},
{"5", "240.0.0.0"},
{"5", "255.255.255.255"},
{nil, "239.0.0.0"},
{nil, "4.1.2.2"},
{"a", "2800::FFFF:1"},
{"b", "2800:1:2:3::1"},
{"b", "2800:1:2:3::6"},
}
for _, tt := range tests {
assert.Equal(t, tt.Result, tree.Contains(net.ParseIP(tt.IP)))
}
tree = NewCIDR6Tree()
tree.AddCIDR(getCIDR("1.1.1.1/0"), "cool")
tree.AddCIDR(getCIDR("::/0"), "cool6")
assert.Equal(t, "cool", tree.Contains(net.ParseIP("0.0.0.0")))
assert.Equal(t, "cool", tree.Contains(net.ParseIP("255.255.255.255")))
assert.Equal(t, "cool6", tree.Contains(net.ParseIP("::")))
assert.Equal(t, "cool6", tree.Contains(net.ParseIP("1:2:3:4:5:6:7:8")))
}
func TestCIDR6Tree_MostSpecificContains(t *testing.T) {
tree := NewCIDR6Tree()
tree.AddCIDR(getCIDR("1.0.0.0/8"), "1")
tree.AddCIDR(getCIDR("2.1.0.0/16"), "2")
tree.AddCIDR(getCIDR("3.1.1.0/24"), "3")
tree.AddCIDR(getCIDR("4.1.1.1/24"), "4a")
tree.AddCIDR(getCIDR("4.1.1.1/30"), "4b")
tree.AddCIDR(getCIDR("4.1.1.1/32"), "4c")
tree.AddCIDR(getCIDR("254.0.0.0/4"), "5")
tree.AddCIDR(getCIDR("1:2:0:4:5:0:0:0/64"), "6a")
tree.AddCIDR(getCIDR("1:2:0:4:5:0:0:0/80"), "6b")
tree.AddCIDR(getCIDR("1:2:0:4:5:0:0:0/96"), "6c")
tests := []struct {
Result interface{}
IP string
}{
{"1", "1.0.0.0"},
{"1", "1.255.255.255"},
{"2", "2.1.0.0"},
{"2", "2.1.255.255"},
{"3", "3.1.1.0"},
{"3", "3.1.1.255"},
{"4a", "4.1.1.255"},
{"4b", "4.1.1.2"},
{"4c", "4.1.1.1"},
{"5", "240.0.0.0"},
{"5", "255.255.255.255"},
{"6a", "1:2:0:4:1:1:1:1"},
{"6b", "1:2:0:4:5:1:1:1"},
{"6c", "1:2:0:4:5:0:0:0"},
{nil, "239.0.0.0"},
{nil, "4.1.2.2"},
}
for _, tt := range tests {
assert.Equal(t, tt.Result, tree.MostSpecificContains(net.ParseIP(tt.IP)))
}
tree = NewCIDR6Tree()
tree.AddCIDR(getCIDR("1.1.1.1/0"), "cool")
tree.AddCIDR(getCIDR("::/0"), "cool6")
assert.Equal(t, "cool", tree.MostSpecificContains(net.ParseIP("0.0.0.0")))
assert.Equal(t, "cool", tree.MostSpecificContains(net.ParseIP("255.255.255.255")))
assert.Equal(t, "cool6", tree.Contains(net.ParseIP("::")))
assert.Equal(t, "cool6", tree.Contains(net.ParseIP("1:2:3:4:5:6:7:8")))
}
func TestCIDR6Tree_Match(t *testing.T) {
tree := NewCIDR6Tree()
tree.AddCIDR(getCIDR("4.1.1.0/32"), "1a")
tree.AddCIDR(getCIDR("4.1.1.1/32"), "1b")
tree.AddCIDR(getCIDR("1:2:3:4:5:6:7:8/128"), "2a")
tree.AddCIDR(getCIDR("1:2:3:4:5:6:7:0/128"), "2b")
tests := []struct {
Result interface{}
IP string
}{
{"1a", "4.1.1.0"},
{"1b", "4.1.1.1"},
{nil, "4.1.1.2"},
{"2a", "1:2:3:4:5:6:7:8"},
{"2b", "1:2:3:4:5:6:7:0"},
{nil, "1:2:3:4:5:6:7:9"},
}
for _, tt := range tests {
assert.Equal(t, tt.Result, tree.Match(net.ParseIP(tt.IP)))
}
tree = NewCIDR6Tree()
tree.AddCIDR(getCIDR("1.1.1.1/0"), "cool")
tree.AddCIDR(getCIDR("1:2:3:4:5:6:7:8/0"), "cool6")
assert.Equal(t, "cool", tree.Contains(net.ParseIP("0.0.0.0")))
assert.Equal(t, "cool", tree.Contains(net.ParseIP("255.255.255.255")))
assert.Equal(t, "cool6", tree.Contains(net.ParseIP("::")))
assert.Equal(t, "cool6", tree.Contains(net.ParseIP("1:2:3:4:5:6:7:8")))
}

View File

@ -76,7 +76,7 @@ func (tree *CIDRTree) AddCIDR(cidr *net.IPNet, val interface{}) {
node.value = val node.value = val
} }
// Finds the first match, which way be the least specific // Finds the first match, which may be the least specific
func (tree *CIDRTree) Contains(ip uint32) (value interface{}) { func (tree *CIDRTree) Contains(ip uint32) (value interface{}) {
bit := startbit bit := startbit
node := tree.root node := tree.root

View File

@ -235,13 +235,18 @@ func (c *Config) GetAllowList(k string, allowInterfaces bool) (*AllowList, error
return nil, fmt.Errorf("config `%s` has invalid type: %T", k, r) return nil, fmt.Errorf("config `%s` has invalid type: %T", k, r)
} }
tree := NewCIDRTree() tree := NewCIDR6Tree()
var nameRules []AllowListNameRule var nameRules []AllowListNameRule
firstValue := true // Keep track of the rules we have added for both ipv4 and ipv6
allValuesMatch := true type allowListRules struct {
defaultSet := false firstValue bool
var allValues bool allValuesMatch bool
defaultSet bool
allValues bool
}
rules4 := allowListRules{firstValue: true, allValuesMatch: true, defaultSet: false}
rules6 := allowListRules{firstValue: true, allValuesMatch: true, defaultSet: false}
for rawKey, rawValue := range rawMap { for rawKey, rawValue := range rawMap {
rawCIDR, ok := rawKey.(string) rawCIDR, ok := rawKey.(string)
@ -276,31 +281,48 @@ func (c *Config) GetAllowList(k string, allowInterfaces bool) (*AllowList, error
// TODO: should we error on duplicate CIDRs in the config? // TODO: should we error on duplicate CIDRs in the config?
tree.AddCIDR(cidr, value) tree.AddCIDR(cidr, value)
if firstValue { maskBits, maskSize := cidr.Mask.Size()
allValues = value
firstValue = false var rules *allowListRules
if maskSize == 32 {
rules = &rules4
} else { } else {
if value != allValues { rules = &rules6
allValuesMatch = false }
if rules.firstValue {
rules.allValues = value
rules.firstValue = false
} else {
if value != rules.allValues {
rules.allValuesMatch = false
} }
} }
// Check if this is 0.0.0.0/0 // Check if this is 0.0.0.0/0 or ::/0
bits, size := cidr.Mask.Size() if maskBits == 0 {
if bits == 0 && size == 32 { rules.defaultSet = true
defaultSet = true
} }
} }
if !defaultSet { if !rules4.defaultSet {
if allValuesMatch { if rules4.allValuesMatch {
_, zeroCIDR, _ := net.ParseCIDR("0.0.0.0/0") _, zeroCIDR, _ := net.ParseCIDR("0.0.0.0/0")
tree.AddCIDR(zeroCIDR, !allValues) tree.AddCIDR(zeroCIDR, !rules4.allValues)
} else { } else {
return nil, fmt.Errorf("config `%s` contains both true and false rules, but no default set for 0.0.0.0/0", k) return nil, fmt.Errorf("config `%s` contains both true and false rules, but no default set for 0.0.0.0/0", k)
} }
} }
if !rules6.defaultSet {
if rules6.allValuesMatch {
_, zeroCIDR, _ := net.ParseCIDR("::/0")
tree.AddCIDR(zeroCIDR, !rules6.allValues)
} else {
return nil, fmt.Errorf("config `%s` contains both true and false rules, but no default set for ::/0", k)
}
}
return &AllowList{cidrTree: tree, nameRules: nameRules}, nil return &AllowList{cidrTree: tree, nameRules: nameRules}, nil
} }

View File

@ -109,6 +109,16 @@ func TestConfig_GetAllowList(t *testing.T) {
r, err = c.GetAllowList("allowlist", false) r, err = c.GetAllowList("allowlist", false)
assert.EqualError(t, err, "config `allowlist` contains both true and false rules, but no default set for 0.0.0.0/0") assert.EqualError(t, err, "config `allowlist` contains both true and false rules, but no default set for 0.0.0.0/0")
c.Settings["allowlist"] = map[interface{}]interface{}{
"0.0.0.0/0": true,
"10.0.0.0/8": false,
"10.42.42.0/24": true,
"fd00::/8": true,
"fd00:fd00::/16": false,
}
r, err = c.GetAllowList("allowlist", false)
assert.EqualError(t, err, "config `allowlist` contains both true and false rules, but no default set for ::/0")
c.Settings["allowlist"] = map[interface{}]interface{}{ c.Settings["allowlist"] = map[interface{}]interface{}{
"0.0.0.0/0": true, "0.0.0.0/0": true,
"10.0.0.0/8": false, "10.0.0.0/8": false,
@ -119,6 +129,19 @@ func TestConfig_GetAllowList(t *testing.T) {
assert.NotNil(t, r) assert.NotNil(t, r)
} }
c.Settings["allowlist"] = map[interface{}]interface{}{
"0.0.0.0/0": true,
"10.0.0.0/8": false,
"10.42.42.0/24": true,
"::/0": false,
"fd00::/8": true,
"fd00:fd00::/16": false,
}
r, err = c.GetAllowList("allowlist", false)
if assert.NoError(t, err) {
assert.NotNil(t, r)
}
// Test interface names // Test interface names
c.Settings["allowlist"] = map[interface{}]interface{}{ c.Settings["allowlist"] = map[interface{}]interface{}{

View File

@ -23,11 +23,11 @@ type ControlHostInfo struct {
VpnIP net.IP `json:"vpnIp"` VpnIP net.IP `json:"vpnIp"`
LocalIndex uint32 `json:"localIndex"` LocalIndex uint32 `json:"localIndex"`
RemoteIndex uint32 `json:"remoteIndex"` RemoteIndex uint32 `json:"remoteIndex"`
RemoteAddrs []udpAddr `json:"remoteAddrs"` RemoteAddrs []*udpAddr `json:"remoteAddrs"`
CachedPackets int `json:"cachedPackets"` CachedPackets int `json:"cachedPackets"`
Cert *cert.NebulaCertificate `json:"cert"` Cert *cert.NebulaCertificate `json:"cert"`
MessageCounter uint64 `json:"messageCounter"` MessageCounter uint64 `json:"messageCounter"`
CurrentRemote udpAddr `json:"currentRemote"` CurrentRemote *udpAddr `json:"currentRemote"`
} }
// Start actually runs nebula, this is a nonblocking call. To block use Control.ShutdownBlock() // Start actually runs nebula, this is a nonblocking call. To block use Control.ShutdownBlock()
@ -38,16 +38,7 @@ func (c *Control) Start() {
// Stop signals nebula to shutdown, returns after the shutdown is complete // Stop signals nebula to shutdown, returns after the shutdown is complete
func (c *Control) Stop() { func (c *Control) Stop() {
//TODO: stop tun and udp routines, the lock on hostMap effectively does that though //TODO: stop tun and udp routines, the lock on hostMap effectively does that though
//TODO: this is probably better as a function in ConnectionManager or HostMap directly c.CloseAllTunnels(false)
c.f.hostMap.Lock()
for _, h := range c.f.hostMap.Hosts {
if h.ConnectionState.ready {
c.f.send(closeTunnel, 0, h.ConnectionState, h, h.remote, []byte{}, make([]byte, 12, 12), make([]byte, mtu))
c.l.WithField("vpnIp", IntIp(h.hostId)).WithField("udpAddr", h.remote).
Debug("Sending close tunnel message")
}
}
c.f.hostMap.Unlock()
c.l.Info("Goodbye") c.l.Info("Goodbye")
} }
@ -149,13 +140,36 @@ func (c *Control) CloseTunnel(vpnIP uint32, localOnly bool) bool {
return true return true
} }
// CloseAllTunnels is just like CloseTunnel except it goes through and shuts them all down, optionally you can avoid shutting down lighthouse tunnels
// the int returned is a count of tunnels closed
func (c *Control) CloseAllTunnels(excludeLighthouses bool) (closed int) {
//TODO: this is probably better as a function in ConnectionManager or HostMap directly
c.f.hostMap.Lock()
for _, h := range c.f.hostMap.Hosts {
if excludeLighthouses {
if _, ok := c.f.lightHouse.lighthouses[h.hostId]; ok {
continue
}
}
if h.ConnectionState.ready {
c.f.send(closeTunnel, 0, h.ConnectionState, h, h.remote, []byte{}, make([]byte, 12, 12), make([]byte, mtu))
c.l.WithField("vpnIp", IntIp(h.hostId)).WithField("udpAddr", h.remote).
Debug("Sending close tunnel message")
closed++
}
}
c.f.hostMap.Unlock()
return
}
func copyHostInfo(h *HostInfo) ControlHostInfo { func copyHostInfo(h *HostInfo) ControlHostInfo {
addrs := h.RemoteUDPAddrs() addrs := h.RemoteUDPAddrs()
chi := ControlHostInfo{ chi := ControlHostInfo{
VpnIP: int2ip(h.hostId), VpnIP: int2ip(h.hostId),
LocalIndex: h.localIndexId, LocalIndex: h.localIndexId,
RemoteIndex: h.remoteIndexId, RemoteIndex: h.remoteIndexId,
RemoteAddrs: make([]udpAddr, len(addrs), len(addrs)), RemoteAddrs: make([]*udpAddr, len(addrs), len(addrs)),
CachedPackets: len(h.packetStore), CachedPackets: len(h.packetStore),
MessageCounter: atomic.LoadUint64(&h.ConnectionState.atomicMessageCounter), MessageCounter: atomic.LoadUint64(&h.ConnectionState.atomicMessageCounter),
} }
@ -165,7 +179,7 @@ func copyHostInfo(h *HostInfo) ControlHostInfo {
} }
if h.remote != nil { if h.remote != nil {
chi.CurrentRemote = *h.remote chi.CurrentRemote = h.remote.Copy()
} }
for i, addr := range addrs { for i, addr := range addrs {

View File

@ -16,15 +16,15 @@ func TestControl_GetHostInfoByVpnIP(t *testing.T) {
// Special care must be taken to re-use all objects provided to the hostmap and certificate in the expectedInfo object // Special care must be taken to re-use all objects provided to the hostmap and certificate in the expectedInfo object
// To properly ensure we are not exposing core memory to the caller // To properly ensure we are not exposing core memory to the caller
hm := NewHostMap("test", &net.IPNet{}, make([]*net.IPNet, 0)) hm := NewHostMap("test", &net.IPNet{}, make([]*net.IPNet, 0))
remote1 := NewUDPAddr(100, 4444) remote1 := NewUDPAddr(int2ip(100), 4444)
remote2 := NewUDPAddr(101, 4444) remote2 := NewUDPAddr(net.ParseIP("1:2:3:4:5:6:7:8"), 4444)
ipNet := net.IPNet{ ipNet := net.IPNet{
IP: net.IPv4(1, 2, 3, 4), IP: net.IPv4(1, 2, 3, 4),
Mask: net.IPMask{255, 255, 255, 0}, Mask: net.IPMask{255, 255, 255, 0},
} }
ipNet2 := net.IPNet{ ipNet2 := net.IPNet{
IP: net.IPv4(1, 2, 3, 5), IP: net.ParseIP("1:2:3:4:5:6:7:8"),
Mask: net.IPMask{255, 255, 255, 0}, Mask: net.IPMask{255, 255, 255, 0},
} }
@ -80,11 +80,11 @@ func TestControl_GetHostInfoByVpnIP(t *testing.T) {
VpnIP: net.IPv4(1, 2, 3, 4).To4(), VpnIP: net.IPv4(1, 2, 3, 4).To4(),
LocalIndex: 201, LocalIndex: 201,
RemoteIndex: 200, RemoteIndex: 200,
RemoteAddrs: []udpAddr{*remote1, *remote2}, RemoteAddrs: []*udpAddr{remote1, remote2},
CachedPackets: 0, CachedPackets: 0,
Cert: crt.Copy(), Cert: crt.Copy(),
MessageCounter: 0, MessageCounter: 0,
CurrentRemote: *NewUDPAddr(100, 4444), CurrentRemote: NewUDPAddr(int2ip(100), 4444),
} }
// Make sure we don't have any unexpected fields // Make sure we don't have any unexpected fields

View File

@ -74,6 +74,7 @@ lighthouse:
# Port Nebula will be listening on. The default here is 4242. For a lighthouse node, the port should be defined, # Port Nebula will be listening on. The default here is 4242. For a lighthouse node, the port should be defined,
# however using port 0 will dynamically assign a port and is recommended for roaming nodes. # however using port 0 will dynamically assign a port and is recommended for roaming nodes.
listen: listen:
# To listen on both any ipv4 and ipv6 use "[::]"
host: 0.0.0.0 host: 0.0.0.0
port: 4242 port: 4242
# Sets the max number of packets to pull from the kernel for each syscall (under systems that support recvmmsg) # Sets the max number of packets to pull from the kernel for each syscall (under systems that support recvmmsg)

4
go.mod
View File

@ -9,7 +9,7 @@ require (
github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432 github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6
github.com/golang/protobuf v1.3.2 github.com/golang/protobuf v1.5.0
github.com/imdario/mergo v0.3.8 github.com/imdario/mergo v0.3.8
github.com/kardianos/service v1.1.0 github.com/kardianos/service v1.1.0
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
@ -29,6 +29,8 @@ require (
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 golang.org/x/sys v0.0.0-20191210023423-ac6580df4449
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/protobuf v1.26.0
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/yaml.v2 v2.2.7 gopkg.in/yaml.v2 v2.2.7
) )

62
go.sum
View File

@ -1,3 +1,5 @@
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/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@ -11,15 +13,19 @@ github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA= github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432 h1:M5QgkYacWj0Xs8MhpIK/5uwU02icXpEoSo9sM2aRCps= github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432 h1:M5QgkYacWj0Xs8MhpIK/5uwU02icXpEoSo9sM2aRCps=
github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432/go.mod h1:xwIwAxMvYnVrGJPe2FKx5prTrnAjGOD8zvDOnxnrrkM= github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432/go.mod h1:xwIwAxMvYnVrGJPe2FKx5prTrnAjGOD8zvDOnxnrrkM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as=
@ -30,14 +36,31 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 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/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
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.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/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 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
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/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
@ -118,19 +141,30 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/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-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -145,8 +179,34 @@ golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
@ -158,3 +218,5 @@ gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -6,7 +6,7 @@ const (
) )
func HandleIncomingHandshake(f *Interface, addr *udpAddr, packet []byte, h *Header, hostinfo *HostInfo) { func HandleIncomingHandshake(f *Interface, addr *udpAddr, packet []byte, h *Header, hostinfo *HostInfo) {
if !f.lightHouse.remoteAllowList.Allow(udp2ipInt(addr)) { if !f.lightHouse.remoteAllowList.Allow(addr.IP) {
l.WithField("udpAddr", addr).Debug("lighthouse.remote_allow_list denied incoming handshake") l.WithField("udpAddr", addr).Debug("lighthouse.remote_allow_list denied incoming handshake")
return return
} }

View File

@ -186,7 +186,7 @@ func ixHandshakeStage1(f *Interface, addr *udpAddr, packet []byte, h *Header) {
//l.Debugln("got symmetric pairs") //l.Debugln("got symmetric pairs")
//hostinfo.ClearRemotes() //hostinfo.ClearRemotes()
hostinfo.AddRemote(*addr) hostinfo.AddRemote(addr)
hostinfo.ForcePromoteBest(f.hostMap.preferredRanges) hostinfo.ForcePromoteBest(f.hostMap.preferredRanges)
hostinfo.CreateRemoteCIDR(remoteCert) hostinfo.CreateRemoteCIDR(remoteCert)
@ -358,7 +358,7 @@ func ixHandshakeStage2(f *Interface, addr *udpAddr, hostinfo *HostInfo, packet [
ci.eKey = NewNebulaCipherState(eKey) ci.eKey = NewNebulaCipherState(eKey)
//l.Debugln("got symmetric pairs") //l.Debugln("got symmetric pairs")
hostinfo.SetRemote(*addr) hostinfo.SetRemote(addr)
hostinfo.CreateRemoteCIDR(remoteCert) hostinfo.CreateRemoteCIDR(remoteCert)
f.handshakeManager.Complete(hostinfo, f) f.handshakeManager.Complete(hostinfo, f)

View File

@ -140,8 +140,8 @@ func Test_NewHandshakeManagerTrigger(t *testing.T) {
hi := blah.pendingHostMap.Hosts[ip] hi := blah.pendingHostMap.Hosts[ip]
assert.Nil(t, hi.remote) assert.Nil(t, hi.remote)
lh.addrMap = map[uint32][]udpAddr{ lh.addrMap = map[uint32][]*udpAddr{
ip: {*NewUDPAddrFromString("10.1.1.1:4242")}, ip: {NewUDPAddrFromString("10.1.1.1:4242")},
} }
// This should trigger the hostmap to populate the hostinfo // This should trigger the hostmap to populate the hostinfo

View File

@ -303,7 +303,7 @@ func (hm *HostMap) AddRemote(vpnIp uint32, remote *udpAddr) *HostInfo {
hm.Lock() hm.Lock()
i, v := hm.Hosts[vpnIp] i, v := hm.Hosts[vpnIp]
if v { if v {
i.AddRemote(*remote) i.AddRemote(remote)
} else { } else {
i = &HostInfo{ i = &HostInfo{
Remotes: []*HostInfoDest{NewHostInfoDest(remote)}, Remotes: []*HostInfoDest{NewHostInfoDest(remote)},
@ -424,10 +424,11 @@ func (hm *HostMap) Punchy(conn *udpConn) {
metricsTxPunchy = metrics.NilCounter{} metricsTxPunchy = metrics.NilCounter{}
} }
b := []byte{1}
for { for {
for _, addr := range hm.PunchList() { for _, addr := range hm.PunchList() {
metricsTxPunchy.Inc(1) metricsTxPunchy.Inc(1)
conn.WriteTo([]byte{1}, addr) conn.WriteTo(b, addr)
} }
time.Sleep(time.Second * 30) time.Sleep(time.Second * 30)
} }
@ -473,7 +474,7 @@ func (i *HostInfo) TryPromoteBest(preferredRanges []*net.IPNet, ifce *Interface)
if atomic.AddUint32(&i.promoteCounter, 1)&PromoteEvery == 0 { if atomic.AddUint32(&i.promoteCounter, 1)&PromoteEvery == 0 {
// return early if we are already on a preferred remote // return early if we are already on a preferred remote
rIP := udp2ip(i.remote) rIP := i.remote.IP
for _, l := range preferredRanges { for _, l := range preferredRanges {
if l.Contains(rIP) { if l.Contains(rIP) {
return return
@ -506,7 +507,7 @@ func (i *HostInfo) ForcePromoteBest(preferredRanges []*net.IPNet) {
func (i *HostInfo) getBestRemote(preferredRanges []*net.IPNet) (best *udpAddr, preferred bool) { func (i *HostInfo) getBestRemote(preferredRanges []*net.IPNet) (best *udpAddr, preferred bool) {
if len(i.Remotes) > 0 { if len(i.Remotes) > 0 {
for _, r := range i.Remotes { for _, r := range i.Remotes {
rIP := udp2ip(r.addr) rIP := r.addr.IP
for _, l := range preferredRanges { for _, l := range preferredRanges {
if l.Contains(rIP) { if l.Contains(rIP) {
@ -625,8 +626,7 @@ func (i *HostInfo) GetCert() *cert.NebulaCertificate {
return nil return nil
} }
func (i *HostInfo) AddRemote(r udpAddr) *udpAddr { func (i *HostInfo) AddRemote(remote *udpAddr) *udpAddr {
remote := &r
//add := true //add := true
for _, r := range i.Remotes { for _, r := range i.Remotes {
if r.addr.Equals(remote) { if r.addr.Equals(remote) {
@ -638,12 +638,13 @@ func (i *HostInfo) AddRemote(r udpAddr) *udpAddr {
if len(i.Remotes) > MaxRemotes { if len(i.Remotes) > MaxRemotes {
i.Remotes = i.Remotes[len(i.Remotes)-MaxRemotes:] i.Remotes = i.Remotes[len(i.Remotes)-MaxRemotes:]
} }
i.Remotes = append(i.Remotes, NewHostInfoDest(remote)) r := NewHostInfoDest(remote)
return remote i.Remotes = append(i.Remotes, r)
return r.addr
//l.Debugf("Added remote %s for vpn ip", remote) //l.Debugf("Added remote %s for vpn ip", remote)
} }
func (i *HostInfo) SetRemote(remote udpAddr) { func (i *HostInfo) SetRemote(remote *udpAddr) {
i.remote = i.AddRemote(remote) i.remote = i.AddRemote(remote)
} }
@ -701,7 +702,7 @@ func (i *HostInfo) logger() *logrus.Entry {
func NewHostInfoDest(addr *udpAddr) *HostInfoDest { func NewHostInfoDest(addr *udpAddr) *HostInfoDest {
i := &HostInfoDest{ i := &HostInfoDest{
addr: addr, addr: addr.Copy(),
} }
return i return i
} }
@ -816,8 +817,11 @@ func localIps(allowList *AllowList) *[]net.IP {
case *net.IPAddr: case *net.IPAddr:
ip = v.IP ip = v.IP
} }
if ip.To4() != nil && ip.IsLoopback() == false {
allow := allowList.Allow(ip2int(ip)) //TODO: Filtering out link local for now, this is probably the most correct thing
//TODO: Would be nice to filter out SLAAC MAC based ips as well
if ip.IsLoopback() == false && !ip.IsLinkLocalUnicast() {
allow := allowList.Allow(ip)
l.WithField("localIp", ip).WithField("allow", allow).Debug("localAllowList.Allow") l.WithField("localIp", ip).WithField("allow", allow).Debug("localAllowList.Allow")
if !allow { if !allow {
continue continue
@ -831,6 +835,7 @@ func localIps(allowList *AllowList) *[]net.IP {
} }
func PrivateIP(ip net.IP) bool { func PrivateIP(ip net.IP) bool {
//TODO: Private for ipv6 or just let it ride?
private := false private := false
_, private24BitBlock, _ := net.ParseCIDR("10.0.0.0/8") _, private24BitBlock, _ := net.ParseCIDR("10.0.0.0/8")
_, private20BitBlock, _ := net.ParseCIDR("172.16.0.0/12") _, private20BitBlock, _ := net.ParseCIDR("172.16.0.0/12")

View File

@ -98,7 +98,7 @@ func TestHostmap(t *testing.T) {
// Promotion should ensure that the best remote is chosen (y) // Promotion should ensure that the best remote is chosen (y)
info.ForcePromoteBest(myNets) info.ForcePromoteBest(myNets)
assert.True(t, myNet.Contains(udp2ip(info.remote))) assert.True(t, myNet.Contains(info.remote.IP))
} }
@ -125,27 +125,29 @@ func TestHostMap_rotateRemote(t *testing.T) {
assert.Nil(t, h.remote) assert.Nil(t, h.remote)
// 1 remote, no panic // 1 remote, no panic
h.AddRemote(*NewUDPAddr(ip2int(net.IP{1, 1, 1, 1}), 0)) h.AddRemote(NewUDPAddr(net.IP{1, 1, 1, 1}, 0))
h.rotateRemote() h.rotateRemote()
assert.Equal(t, udp2ipInt(h.remote), ip2int(net.IP{1, 1, 1, 1})) assert.Equal(t, h.remote.IP, net.IP{1, 1, 1, 1})
h.AddRemote(*NewUDPAddr(ip2int(net.IP{1, 1, 1, 2}), 0)) h.AddRemote(NewUDPAddr(net.IP{1, 1, 1, 2}, 0))
h.AddRemote(*NewUDPAddr(ip2int(net.IP{1, 1, 1, 3}), 0)) h.AddRemote(NewUDPAddr(net.IP{1, 1, 1, 3}, 0))
h.AddRemote(*NewUDPAddr(ip2int(net.IP{1, 1, 1, 4}), 0)) h.AddRemote(NewUDPAddr(net.IP{1, 1, 1, 4}, 0))
//TODO: ensure we are copying and not storing the slice!
// Rotate through those 3 // Rotate through those 3
h.rotateRemote() h.rotateRemote()
assert.Equal(t, udp2ipInt(h.remote), ip2int(net.IP{1, 1, 1, 2})) assert.Equal(t, h.remote.IP, net.IP{1, 1, 1, 2})
h.rotateRemote() h.rotateRemote()
assert.Equal(t, udp2ipInt(h.remote), ip2int(net.IP{1, 1, 1, 3})) assert.Equal(t, h.remote.IP, net.IP{1, 1, 1, 3})
h.rotateRemote() h.rotateRemote()
assert.Equal(t, udp2ipInt(h.remote), ip2int(net.IP{1, 1, 1, 4})) assert.Equal(t, h.remote, &udpAddr{IP: net.IP{1, 1, 1, 4}, Port: 0})
// Finally, we should start over // Finally, we should start over
h.rotateRemote() h.rotateRemote()
assert.Equal(t, udp2ipInt(h.remote), ip2int(net.IP{1, 1, 1, 1})) assert.Equal(t, h.remote, &udpAddr{IP: net.IP{1, 1, 1, 1}, Port: 0})
} }
func BenchmarkHostmappromote2(b *testing.B) { func BenchmarkHostmappromote2(b *testing.B) {

View File

@ -9,6 +9,7 @@ import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/rcrowley/go-metrics" "github.com/rcrowley/go-metrics"
"github.com/sirupsen/logrus"
"github.com/slackhq/nebula/cert" "github.com/slackhq/nebula/cert"
) )
@ -21,7 +22,7 @@ type LightHouse struct {
punchConn *udpConn punchConn *udpConn
// Local cache of answers from light houses // Local cache of answers from light houses
addrMap map[uint32][]udpAddr addrMap map[uint32][]*udpAddr
// filters remote addresses allowed for each host // filters remote addresses allowed for each host
// - When we are a lighthouse, this filters what addresses we store and // - When we are a lighthouse, this filters what addresses we store and
@ -41,7 +42,7 @@ type LightHouse struct {
staticList map[uint32]struct{} staticList map[uint32]struct{}
lighthouses map[uint32]struct{} lighthouses map[uint32]struct{}
interval int interval int
nebulaPort uint32 nebulaPort uint32 // 32 bits because protobuf does not have a uint16
punchBack bool punchBack bool
punchDelay time.Duration punchDelay time.Duration
@ -58,7 +59,7 @@ func NewLightHouse(amLighthouse bool, myIp uint32, ips []uint32, interval int, n
h := LightHouse{ h := LightHouse{
amLighthouse: amLighthouse, amLighthouse: amLighthouse,
myIp: myIp, myIp: myIp,
addrMap: make(map[uint32][]udpAddr), addrMap: make(map[uint32][]*udpAddr),
nebulaPort: nebulaPort, nebulaPort: nebulaPort,
lighthouses: make(map[uint32]struct{}), lighthouses: make(map[uint32]struct{}),
staticList: make(map[uint32]struct{}), staticList: make(map[uint32]struct{}),
@ -106,7 +107,7 @@ func (lh *LightHouse) ValidateLHStaticEntries() error {
return nil return nil
} }
func (lh *LightHouse) Query(ip uint32, f EncWriter) ([]udpAddr, error) { func (lh *LightHouse) Query(ip uint32, f EncWriter) ([]*udpAddr, error) {
if !lh.IsLighthouseIP(ip) { if !lh.IsLighthouseIP(ip) {
lh.QueryServer(ip, f) lh.QueryServer(ip, f)
} }
@ -139,7 +140,7 @@ func (lh *LightHouse) QueryServer(ip uint32, f EncWriter) {
} }
// Query our local lighthouse cached results // Query our local lighthouse cached results
func (lh *LightHouse) QueryCache(ip uint32) []udpAddr { func (lh *LightHouse) QueryCache(ip uint32) []*udpAddr {
lh.RLock() lh.RLock()
if v, ok := lh.addrMap[ip]; ok { if v, ok := lh.addrMap[ip]; ok {
lh.RUnlock() lh.RUnlock()
@ -179,7 +180,7 @@ func (lh *LightHouse) AddRemote(vpnIP uint32, toIp *udpAddr, static bool) {
} }
} }
allow := lh.remoteAllowList.Allow(udp2ipInt(toIp)) allow := lh.remoteAllowList.Allow(toIp.IP)
l.WithField("remoteIp", toIp).WithField("allow", allow).Debug("remoteAllowList.Allow") l.WithField("remoteIp", toIp).WithField("allow", allow).Debug("remoteAllowList.Allow")
if !allow { if !allow {
return return
@ -189,7 +190,8 @@ func (lh *LightHouse) AddRemote(vpnIP uint32, toIp *udpAddr, static bool) {
if static { if static {
lh.staticList[vpnIP] = struct{}{} lh.staticList[vpnIP] = struct{}{}
} }
lh.addrMap[vpnIP] = append(lh.addrMap[vpnIP], *toIp)
lh.addrMap[vpnIP] = append(lh.addrMap[vpnIP], toIp.Copy())
} }
func (lh *LightHouse) AddRemoteAndReset(vpnIP uint32, toIp *udpAddr) { func (lh *LightHouse) AddRemoteAndReset(vpnIP uint32, toIp *udpAddr) {
@ -216,12 +218,41 @@ func NewLhQueryByInt(VpnIp uint32) *NebulaMeta {
} }
} }
func NewIpAndPort(ip net.IP, port uint32) IpAndPort { type ip4Or6 struct {
return IpAndPort{Ip: ip2int(ip), Port: port} v4 IpAndPort
v6 Ip6AndPort
} }
func NewIpAndPortFromUDPAddr(addr udpAddr) IpAndPort { func NewIpAndPort(ip net.IP, port uint32) ip4Or6 {
return IpAndPort{Ip: udp2ipInt(&addr), Port: uint32(addr.Port)} ipp := ip4Or6{}
if ipv4 := ip.To4(); ipv4 != nil {
ipp.v4 = IpAndPort{Port: port}
ipp.v4.Ip = ip2int(ip)
} else {
ipp.v6 = Ip6AndPort{Port: port}
ipp.v6.Ip = make([]byte, len(ip))
copy(ipp.v6.Ip, ip)
}
return ipp
}
func NewIpAndPortFromUDPAddr(addr *udpAddr) ip4Or6 {
return NewIpAndPort(addr.IP, uint32(addr.Port))
}
func NewUDPAddrFromLH4(ipp *IpAndPort) *udpAddr {
ip := ipp.Ip
return NewUDPAddr(
net.IPv4(byte(ip&0xff000000>>24), byte(ip&0x00ff0000>>16), byte(ip&0x0000ff00>>8), byte(ip&0x000000ff)),
uint16(ipp.Port),
)
}
func NewUDPAddrFromLH6(ipp *Ip6AndPort) *udpAddr {
return NewUDPAddr(ipp.Ip, uint16(ipp.Port))
} }
func (lh *LightHouse) LhUpdateWorker(f EncWriter) { func (lh *LightHouse) LhUpdateWorker(f EncWriter) {
@ -236,20 +267,27 @@ func (lh *LightHouse) LhUpdateWorker(f EncWriter) {
} }
func (lh *LightHouse) SendUpdate(f EncWriter) { func (lh *LightHouse) SendUpdate(f EncWriter) {
var ipps []*IpAndPort var v4 []*IpAndPort
var v6 []*Ip6AndPort
for _, e := range *localIps(lh.localAllowList) { for _, e := range *localIps(lh.localAllowList) {
// Only add IPs that aren't my VPN/tun IP // Only add IPs that aren't my VPN/tun IP
if ip2int(e) != lh.myIp { if ip2int(e) != lh.myIp {
ipp := NewIpAndPort(e, lh.nebulaPort) ipp := NewIpAndPort(e, lh.nebulaPort)
ipps = append(ipps, &ipp) if len(ipp.v6.Ip) > 0 {
v6 = append(v6, &ipp.v6)
} else {
v4 = append(v4, &ipp.v4)
}
} }
} }
m := &NebulaMeta{ m := &NebulaMeta{
Type: NebulaMeta_HostUpdateNotification, Type: NebulaMeta_HostUpdateNotification,
Details: &NebulaMetaDetails{ Details: &NebulaMetaDetails{
VpnIp: lh.myIp, VpnIp: lh.myIp,
IpAndPorts: ipps, IpAndPorts: v4,
Ip6AndPorts: v6,
}, },
} }
@ -272,8 +310,8 @@ type LightHouseHandler struct {
nb []byte nb []byte
out []byte out []byte
meta *NebulaMeta meta *NebulaMeta
iap []IpAndPort iap []ip4Or6
iapp []*IpAndPort iapp []*ip4Or6
} }
func (lh *LightHouse) NewRequestHandler() *LightHouseHandler { func (lh *LightHouse) NewRequestHandler() *LightHouseHandler {
@ -306,8 +344,8 @@ func (lhh *LightHouseHandler) resetMeta() *NebulaMeta {
func (lhh *LightHouseHandler) resizeIpAndPorts(n int) { func (lhh *LightHouseHandler) resizeIpAndPorts(n int) {
if cap(lhh.iap) < n { if cap(lhh.iap) < n {
lhh.iap = make([]IpAndPort, n) lhh.iap = make([]ip4Or6, n)
lhh.iapp = make([]*IpAndPort, n) lhh.iapp = make([]*ip4Or6, n)
for i := range lhh.iap { for i := range lhh.iap {
lhh.iapp[i] = &lhh.iap[i] lhh.iapp[i] = &lhh.iap[i]
@ -317,7 +355,7 @@ func (lhh *LightHouseHandler) resizeIpAndPorts(n int) {
lhh.iapp = lhh.iapp[:n] lhh.iapp = lhh.iapp[:n]
} }
func (lhh *LightHouseHandler) setIpAndPortsFromNetIps(ips []udpAddr) []*IpAndPort { func (lhh *LightHouseHandler) setIpAndPortsFromNetIps(ips []*udpAddr) []*ip4Or6 {
lhh.resizeIpAndPorts(len(ips)) lhh.resizeIpAndPorts(len(ips))
for i, e := range ips { for i, e := range ips {
lhh.iap[i] = NewIpAndPortFromUDPAddr(e) lhh.iap[i] = NewIpAndPortFromUDPAddr(e)
@ -363,7 +401,25 @@ func (lhh *LightHouseHandler) HandleRequest(rAddr *udpAddr, vpnIp uint32, p []by
n = lhh.resetMeta() n = lhh.resetMeta()
n.Type = NebulaMeta_HostQueryReply n.Type = NebulaMeta_HostQueryReply
n.Details.VpnIp = reqVpnIP n.Details.VpnIp = reqVpnIP
n.Details.IpAndPorts = lhh.setIpAndPortsFromNetIps(ips)
v4s := make([]*IpAndPort, 0)
v6s := make([]*Ip6AndPort, 0)
for _, v := range lhh.setIpAndPortsFromNetIps(ips) {
if len(v.v6.Ip) > 0 {
v6s = append(v6s, &v.v6)
} else {
v4s = append(v4s, &v.v4)
}
}
if len(v4s) > 0 {
n.Details.IpAndPorts = v4s
}
if len(v6s) > 0 {
n.Details.Ip6AndPorts = v6s
}
reply, err := proto.Marshal(n) reply, err := proto.Marshal(n)
if err != nil { if err != nil {
l.WithError(err).WithField("vpnIp", IntIp(vpnIp)).Error("Failed to marshal lighthouse host query reply") l.WithError(err).WithField("vpnIp", IntIp(vpnIp)).Error("Failed to marshal lighthouse host query reply")
@ -382,7 +438,25 @@ func (lhh *LightHouseHandler) HandleRequest(rAddr *udpAddr, vpnIp uint32, p []by
n = lhh.resetMeta() n = lhh.resetMeta()
n.Type = NebulaMeta_HostPunchNotification n.Type = NebulaMeta_HostPunchNotification
n.Details.VpnIp = vpnIp n.Details.VpnIp = vpnIp
n.Details.IpAndPorts = lhh.setIpAndPortsFromNetIps(ips)
v4s := make([]*IpAndPort, 0)
v6s := make([]*Ip6AndPort, 0)
for _, v := range lhh.setIpAndPortsFromNetIps(ips) {
if len(v.v6.Ip) > 0 {
v6s = append(v6s, &v.v6)
} else {
v4s = append(v4s, &v.v4)
}
}
if len(v4s) > 0 {
n.Details.IpAndPorts = v4s
}
if len(v6s) > 0 {
n.Details.Ip6AndPorts = v6s
}
reply, _ := proto.Marshal(n) reply, _ := proto.Marshal(n)
lh.metricTx(NebulaMeta_HostPunchNotification, 1) lh.metricTx(NebulaMeta_HostPunchNotification, 1)
f.SendMessageToVpnIp(lightHouse, 0, reqVpnIP, reply, lhh.nb, lhh.out[:0]) f.SendMessageToVpnIp(lightHouse, 0, reqVpnIP, reply, lhh.nb, lhh.out[:0])
@ -394,11 +468,21 @@ func (lhh *LightHouseHandler) HandleRequest(rAddr *udpAddr, vpnIp uint32, p []by
if !lh.IsLighthouseIP(vpnIp) { if !lh.IsLighthouseIP(vpnIp) {
return return
} }
for _, a := range n.Details.IpAndPorts { for _, a := range n.Details.IpAndPorts {
//first := n.Details.IpAndPorts[0] ans := NewUDPAddrFromLH4(a)
ans := NewUDPAddr(a.Ip, uint16(a.Port)) if ans != nil {
lh.AddRemote(n.Details.VpnIp, ans, false) lh.AddRemote(n.Details.VpnIp, ans, false)
}
} }
for _, a := range n.Details.Ip6AndPorts {
ans := NewUDPAddrFromLH6(a)
if ans != nil {
lh.AddRemote(n.Details.VpnIp, ans, false)
}
}
// Non-blocking attempt to trigger, skip if it would block // Non-blocking attempt to trigger, skip if it would block
select { select {
case lh.handshakeTrigger <- n.Details.VpnIp: case lh.handshakeTrigger <- n.Details.VpnIp:
@ -411,10 +495,21 @@ func (lhh *LightHouseHandler) HandleRequest(rAddr *udpAddr, vpnIp uint32, p []by
l.WithField("vpnIp", IntIp(vpnIp)).WithField("answer", IntIp(n.Details.VpnIp)).Debugln("Host sent invalid update") l.WithField("vpnIp", IntIp(vpnIp)).WithField("answer", IntIp(n.Details.VpnIp)).Debugln("Host sent invalid update")
return return
} }
for _, a := range n.Details.IpAndPorts { for _, a := range n.Details.IpAndPorts {
ans := NewUDPAddr(a.Ip, uint16(a.Port)) ans := NewUDPAddrFromLH4(a)
lh.AddRemote(n.Details.VpnIp, ans, false) if ans != nil {
lh.AddRemote(n.Details.VpnIp, ans, false)
}
} }
for _, a := range n.Details.Ip6AndPorts {
ans := NewUDPAddrFromLH6(a)
if ans != nil {
lh.AddRemote(n.Details.VpnIp, ans, false)
}
}
case NebulaMeta_HostMovedNotification: case NebulaMeta_HostMovedNotification:
case NebulaMeta_HostPunchNotification: case NebulaMeta_HostPunchNotification:
if !lh.IsLighthouseIP(vpnIp) { if !lh.IsLighthouseIP(vpnIp) {
@ -423,15 +518,43 @@ func (lhh *LightHouseHandler) HandleRequest(rAddr *udpAddr, vpnIp uint32, p []by
empty := []byte{0} empty := []byte{0}
for _, a := range n.Details.IpAndPorts { for _, a := range n.Details.IpAndPorts {
vpnPeer := NewUDPAddr(a.Ip, uint16(a.Port)) vpnPeer := NewUDPAddrFromLH4(a)
if vpnPeer == nil {
continue
}
go func() { go func() {
time.Sleep(lh.punchDelay) time.Sleep(lh.punchDelay)
lh.metricHolepunchTx.Inc(1) lh.metricHolepunchTx.Inc(1)
lh.punchConn.WriteTo(empty, vpnPeer) lh.punchConn.WriteTo(empty, vpnPeer)
}() }()
l.Debugf("Punching %s on %d for %s", IntIp(a.Ip), a.Port, IntIp(n.Details.VpnIp))
if l.Level >= logrus.DebugLevel {
//TODO: lacking the ip we are actually punching on, old: l.Debugf("Punching %s on %d for %s", IntIp(a.Ip), a.Port, IntIp(n.Details.VpnIp))
l.Debugf("Punching on %d for %s", a.Port, IntIp(n.Details.VpnIp))
}
} }
for _, a := range n.Details.Ip6AndPorts {
vpnPeer := NewUDPAddrFromLH6(a)
if vpnPeer == nil {
continue
}
go func() {
time.Sleep(lh.punchDelay)
lh.metricHolepunchTx.Inc(1)
lh.punchConn.WriteTo(empty, vpnPeer)
}()
if l.Level >= logrus.DebugLevel {
//TODO: lacking the ip we are actually punching on, old: l.Debugf("Punching %s on %d for %s", IntIp(a.Ip), a.Port, IntIp(n.Details.VpnIp))
l.Debugf("Punching on %d for %s", a.Port, IntIp(n.Details.VpnIp))
}
}
// This sends a nebula test packet to the host trying to contact us. In the case // This sends a nebula test packet to the host trying to contact us. In the case
// of a double nat or other difficult scenario, this may help establish // of a double nat or other difficult scenario, this may help establish
// a tunnel. // a tunnel.

View File

@ -8,6 +8,17 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
//TODO: Add a test to ensure udpAddr is copied and not reused
func TestOldIPv4Only(t *testing.T) {
// This test ensures our new ipv6 enabled LH protobuf IpAndPorts works with the old style to enable backwards compatibility
b := []byte{8, 129, 130, 132, 80, 16, 10}
var m IpAndPort
err := proto.Unmarshal(b, &m)
assert.NoError(t, err)
assert.Equal(t, "10.1.1.1", int2ip(m.GetIp()).String())
}
func TestNewLhQuery(t *testing.T) { func TestNewLhQuery(t *testing.T) {
myIp := net.ParseIP("192.1.1.1") myIp := net.ParseIP("192.1.1.1")
myIpint := ip2int(myIp) myIpint := ip2int(myIp)
@ -31,24 +42,24 @@ func TestNewLhQuery(t *testing.T) {
func TestNewipandportfromudpaddr(t *testing.T) { func TestNewipandportfromudpaddr(t *testing.T) {
blah := NewUDPAddrFromString("1.2.2.3:12345") blah := NewUDPAddrFromString("1.2.2.3:12345")
meh := NewIpAndPortFromUDPAddr(*blah) meh := NewIpAndPortFromUDPAddr(blah)
assert.Equal(t, uint32(16908803), meh.Ip) assert.Equal(t, uint32(16908803), meh.v4.Ip)
assert.Equal(t, uint32(12345), meh.Port) assert.Equal(t, uint32(12345), meh.v4.Port)
} }
func TestSetipandportsfromudpaddrs(t *testing.T) { func TestSetipandportsfromudpaddrs(t *testing.T) {
blah := NewUDPAddrFromString("1.2.2.3:12345") blah := NewUDPAddrFromString("1.2.2.3:12345")
blah2 := NewUDPAddrFromString("9.9.9.9:47828") blah2 := NewUDPAddrFromString("9.9.9.9:47828")
group := []udpAddr{*blah, *blah2} group := []*udpAddr{blah, blah2}
var lh *LightHouse var lh *LightHouse
lhh := lh.NewRequestHandler() lhh := lh.NewRequestHandler()
result := lhh.setIpAndPortsFromNetIps(group) result := lhh.setIpAndPortsFromNetIps(group)
assert.IsType(t, []*IpAndPort{}, result) assert.IsType(t, []*ip4Or6{}, result)
assert.Len(t, result, 2) assert.Len(t, result, 2)
assert.Equal(t, uint32(0x01020203), result[0].Ip) assert.Equal(t, uint32(0x01020203), result[0].v4.Ip)
assert.Equal(t, uint32(12345), result[0].Port) assert.Equal(t, uint32(12345), result[0].v4.Port)
assert.Equal(t, uint32(0x09090909), result[1].Ip) assert.Equal(t, uint32(0x09090909), result[1].v4.Ip)
assert.Equal(t, uint32(47828), result[1].Port) assert.Equal(t, uint32(47828), result[1].v4.Port)
//t.Error(reflect.TypeOf(hah)) //t.Error(reflect.TypeOf(hah))
} }
@ -60,7 +71,7 @@ func Test_lhStaticMapping(t *testing.T) {
udpServer, _ := NewListener("0.0.0.0", 0, true) udpServer, _ := NewListener("0.0.0.0", 0, true)
meh := NewLightHouse(true, 1, []uint32{ip2int(lh1IP)}, 10, 10003, udpServer, false, 1, false) meh := NewLightHouse(true, 1, []uint32{ip2int(lh1IP)}, 10, 10003, udpServer, false, 1, false)
meh.AddRemote(ip2int(lh1IP), NewUDPAddr(ip2int(lh1IP), uint16(4242)), true) meh.AddRemote(ip2int(lh1IP), NewUDPAddr(lh1IP, uint16(4242)), true)
err := meh.ValidateLHStaticEntries() err := meh.ValidateLHStaticEntries()
assert.Nil(t, err) assert.Nil(t, err)
@ -68,7 +79,7 @@ func Test_lhStaticMapping(t *testing.T) {
lh2IP := net.ParseIP(lh2) lh2IP := net.ParseIP(lh2)
meh = NewLightHouse(true, 1, []uint32{ip2int(lh1IP), ip2int(lh2IP)}, 10, 10003, udpServer, false, 1, false) meh = NewLightHouse(true, 1, []uint32{ip2int(lh1IP), ip2int(lh2IP)}, 10, 10003, udpServer, false, 1, false)
meh.AddRemote(ip2int(lh1IP), NewUDPAddr(ip2int(lh1IP), uint16(4242)), true) meh.AddRemote(ip2int(lh1IP), NewUDPAddr(lh1IP, uint16(4242)), true)
err = meh.ValidateLHStaticEntries() err = meh.ValidateLHStaticEntries()
assert.EqualError(t, err, "Lighthouse 10.128.0.3 does not have a static_host_map entry") assert.EqualError(t, err, "Lighthouse 10.128.0.3 does not have a static_host_map entry")
} }
@ -83,11 +94,11 @@ func BenchmarkLighthouseHandleRequest(b *testing.B) {
hAddr := NewUDPAddrFromString("4.5.6.7:12345") hAddr := NewUDPAddrFromString("4.5.6.7:12345")
hAddr2 := NewUDPAddrFromString("4.5.6.7:12346") hAddr2 := NewUDPAddrFromString("4.5.6.7:12346")
lh.addrMap[3] = []udpAddr{*hAddr, *hAddr2} lh.addrMap[3] = []*udpAddr{hAddr, hAddr2}
rAddr := NewUDPAddrFromString("1.2.2.3:12345") rAddr := NewUDPAddrFromString("1.2.2.3:12345")
rAddr2 := NewUDPAddrFromString("1.2.2.3:12346") rAddr2 := NewUDPAddrFromString("1.2.2.3:12346")
lh.addrMap[2] = []udpAddr{*rAddr, *rAddr2} lh.addrMap[2] = []*udpAddr{rAddr, rAddr2}
mw := &mockEncWriter{} mw := &mockEncWriter{}
@ -142,15 +153,17 @@ func Test_lhRemoteAllowList(t *testing.T) {
remote1 := "10.20.0.3" remote1 := "10.20.0.3"
remote1IP := net.ParseIP(remote1) remote1IP := net.ParseIP(remote1)
lh.AddRemote(ip2int(remote1IP), NewUDPAddr(ip2int(remote1IP), uint16(4242)), true) lh.AddRemote(ip2int(remote1IP), NewUDPAddr(remote1IP, uint16(4242)), true)
assert.Nil(t, lh.addrMap[ip2int(remote1IP)]) assert.Nil(t, lh.addrMap[ip2int(remote1IP)])
remote2 := "10.128.0.3" remote2 := "10.128.0.3"
remote2IP := net.ParseIP(remote2) remote2IP := net.ParseIP(remote2)
remote2UDPAddr := NewUDPAddr(ip2int(remote2IP), uint16(4242)) remote2UDPAddr := NewUDPAddr(remote2IP, uint16(4242))
lh.AddRemote(ip2int(remote2IP), remote2UDPAddr, true) lh.AddRemote(ip2int(remote2IP), remote2UDPAddr, true)
assert.Equal(t, remote2UDPAddr, &lh.addrMap[ip2int(remote2IP)][0]) // Make sure the pointers are different but the contents are equal since we are using slices
assert.False(t, remote2UDPAddr == lh.addrMap[ip2int(remote2IP)][0])
assert.Equal(t, remote2UDPAddr, lh.addrMap[ip2int(remote2IP)][0])
} }
//func NewLightHouse(amLighthouse bool, myIp uint32, ips []string, interval int, nebulaPort int, pc *udpConn, punchBack bool) *LightHouse { //func NewLightHouse(amLighthouse bool, myIp uint32, ips []string, interval int, nebulaPort int, pc *udpConn, punchBack bool) *LightHouse {

27
main.go
View File

@ -4,8 +4,6 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"net" "net"
"strconv"
"strings"
"time" "time"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -301,28 +299,19 @@ func Main(config *Config, configTest bool, buildVersion string, logger *logrus.L
vals, ok := v.([]interface{}) vals, ok := v.([]interface{})
if ok { if ok {
for _, v := range vals { for _, v := range vals {
parts := strings.Split(fmt.Sprintf("%v", v), ":") ip, port, err := parseIPAndPort(fmt.Sprintf("%v", v))
addr, err := net.ResolveIPAddr("ip", parts[0])
if err == nil { if err == nil {
ip := addr.IP lightHouse.AddRemote(ip2int(vpnIp), NewUDPAddr(ip, port), true)
port, err := strconv.Atoi(parts[1]) } else {
if err != nil { return nil, NewContextualError("Static host address could not be parsed", m{"vpnIp": vpnIp}, err)
return nil, NewContextualError("Static host address could not be parsed", m{"vpnIp": vpnIp}, err)
}
lightHouse.AddRemote(ip2int(vpnIp), NewUDPAddr(ip2int(ip), uint16(port)), true)
} }
} }
} else { } else {
//TODO: make this all a helper ip, port, err := parseIPAndPort(fmt.Sprintf("%v", v))
parts := strings.Split(fmt.Sprintf("%v", v), ":")
addr, err := net.ResolveIPAddr("ip", parts[0])
if err == nil { if err == nil {
ip := addr.IP lightHouse.AddRemote(ip2int(vpnIp), NewUDPAddr(ip, port), true)
port, err := strconv.Atoi(parts[1]) } else {
if err != nil { return nil, NewContextualError("Static host address could not be parsed", m{"vpnIp": vpnIp}, err)
return nil, NewContextualError("Static host address could not be parsed", m{"vpnIp": vpnIp}, err)
}
lightHouse.AddRemote(ip2int(vpnIp), NewUDPAddr(ip2int(ip), uint16(port)), true)
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,8 @@
syntax = "proto3"; syntax = "proto3";
package nebula; package nebula;
option go_package = "github.com/slackhq/nebula";
message NebulaMeta { message NebulaMeta {
enum MessageType { enum MessageType {
None = 0; None = 0;
@ -20,11 +22,10 @@ message NebulaMeta {
NebulaMetaDetails Details = 2; NebulaMetaDetails Details = 2;
} }
message NebulaMetaDetails { message NebulaMetaDetails {
uint32 VpnIp = 1; uint32 VpnIp = 1;
repeated IpAndPort IpAndPorts = 2; repeated IpAndPort IpAndPorts = 2;
repeated Ip6AndPort Ip6AndPorts = 4;
uint32 counter = 3; uint32 counter = 3;
} }
@ -33,6 +34,10 @@ message IpAndPort {
uint32 Port = 2; uint32 Port = 2;
} }
message Ip6AndPort {
bytes Ip = 1;
uint32 Port = 2;
}
message NebulaPing { message NebulaPing {
enum MessageType { enum MessageType {

View File

@ -142,7 +142,7 @@ func (f *Interface) closeTunnel(hostInfo *HostInfo) {
func (f *Interface) handleHostRoaming(hostinfo *HostInfo, addr *udpAddr) { func (f *Interface) handleHostRoaming(hostinfo *HostInfo, addr *udpAddr) {
if hostDidRoam(hostinfo.remote, addr) { if hostDidRoam(hostinfo.remote, addr) {
if !f.lightHouse.remoteAllowList.Allow(udp2ipInt(addr)) { if !f.lightHouse.remoteAllowList.Allow(addr.IP) {
hostinfo.logger().WithField("newAddr", addr).Debug("lighthouse.remote_allow_list denied roaming") hostinfo.logger().WithField("newAddr", addr).Debug("lighthouse.remote_allow_list denied roaming")
return return
} }
@ -159,7 +159,7 @@ func (f *Interface) handleHostRoaming(hostinfo *HostInfo, addr *udpAddr) {
hostinfo.lastRoam = time.Now() hostinfo.lastRoam = time.Now()
remoteCopy := *hostinfo.remote remoteCopy := *hostinfo.remote
hostinfo.lastRoamRemote = &remoteCopy hostinfo.lastRoamRemote = &remoteCopy
hostinfo.SetRemote(*addr) hostinfo.SetRemote(addr)
if f.lightHouse.amLighthouse { if f.lightHouse.amLighthouse {
f.lightHouse.AddRemote(hostinfo.hostId, addr, false) f.lightHouse.AddRemote(hostinfo.hostId, addr, false)
} }

4
ssh.go
View File

@ -562,7 +562,7 @@ func sshCreateTunnel(ifce *Interface, fs interface{}, a []string, w sshd.StringW
hostInfo = ifce.handshakeManager.AddVpnIP(vpnIp) hostInfo = ifce.handshakeManager.AddVpnIP(vpnIp)
if addr != nil { if addr != nil {
hostInfo.SetRemote(*addr) hostInfo.SetRemote(addr)
} }
ifce.getOrHandshake(vpnIp) ifce.getOrHandshake(vpnIp)
@ -604,7 +604,7 @@ func sshChangeRemote(ifce *Interface, fs interface{}, a []string, w sshd.StringW
return w.WriteLine(fmt.Sprintf("Could not find tunnel for vpn ip: %v", a[0])) return w.WriteLine(fmt.Sprintf("Could not find tunnel for vpn ip: %v", a[0]))
} }
hostInfo.SetRemote(*addr) hostInfo.SetRemote(addr)
return w.WriteLine("Changed") return w.WriteLine("Changed")
} }

62
udp_all.go Normal file
View File

@ -0,0 +1,62 @@
package nebula
import (
"encoding/json"
"fmt"
"net"
"strconv"
)
type udpAddr struct {
IP net.IP
Port uint16
}
func NewUDPAddr(ip net.IP, port uint16) *udpAddr {
addr := udpAddr{IP: make([]byte, len(ip)), Port: port}
copy(addr.IP, ip)
return &addr
}
func NewUDPAddrFromString(s string) *udpAddr {
ip, port, err := parseIPAndPort(s)
//TODO: handle err
_ = err
return &udpAddr{IP: ip, Port: port}
}
func (ua *udpAddr) Equals(t *udpAddr) bool {
if t == nil || ua == nil {
return t == nil && ua == nil
}
return ua.IP.Equal(t.IP) && ua.Port == t.Port
}
func (ua *udpAddr) String() string {
return net.JoinHostPort(ua.IP.String(), fmt.Sprintf("%v", ua.Port))
}
func (ua *udpAddr) MarshalJSON() ([]byte, error) {
return json.Marshal(m{"ip": ua.IP, "port": ua.Port})
}
func (ua *udpAddr) Copy() *udpAddr {
nu := udpAddr{
Port: ua.Port,
IP: make(net.IP, len(ua.IP)),
}
copy(nu.IP, ua.IP)
return &nu
}
func parseIPAndPort(s string) (net.IP, uint16, error) {
rIp, sPort, err := net.SplitHostPort(s)
if err != nil {
return nil, 0, err
}
iPort, err := strconv.Atoi(sPort)
ip := net.ParseIP(rIp)
return ip, uint16(iPort), nil
}

View File

@ -28,6 +28,7 @@ func NewListenConfig(multi bool) net.ListenConfig {
return controlErr return controlErr
} }
} }
return nil return nil
}, },
} }
@ -39,5 +40,5 @@ func (u *udpConn) Rebind() error {
return err return err
} }
return syscall.SetsockoptInt(int(file.Fd()), unix.IPPROTO_IP, unix.IP_BOUND_IF, 0) return syscall.SetsockoptInt(int(file.Fd()), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, 0)
} }

View File

@ -7,48 +7,17 @@ package nebula
import ( import (
"context" "context"
"encoding/binary"
"fmt" "fmt"
"net" "net"
"strconv"
"strings"
) )
type udpAddr struct {
net.UDPAddr
}
type udpConn struct { type udpConn struct {
*net.UDPConn *net.UDPConn
} }
func NewUDPAddr(ip uint32, port uint16) *udpAddr {
return &udpAddr{
UDPAddr: net.UDPAddr{
IP: int2ip(ip),
Port: int(port),
},
}
}
func NewUDPAddrFromString(s string) *udpAddr {
p := strings.Split(s, ":")
if len(p) < 2 {
return nil
}
port, _ := strconv.Atoi(p[1])
return &udpAddr{
UDPAddr: net.UDPAddr{
IP: net.ParseIP(p[0]),
Port: port,
},
}
}
func NewListener(ip string, port int, multi bool) (*udpConn, error) { func NewListener(ip string, port int, multi bool) (*udpConn, error) {
lc := NewListenConfig(multi) lc := NewListenConfig(multi)
pc, err := lc.ListenPacket(context.TODO(), "udp4", fmt.Sprintf("%s:%d", ip, port)) pc, err := lc.ListenPacket(context.TODO(), "udp", fmt.Sprintf("%s:%d", ip, port))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -58,26 +27,8 @@ func NewListener(ip string, port int, multi bool) (*udpConn, error) {
return nil, fmt.Errorf("Unexpected PacketConn: %T %#v", pc, pc) return nil, fmt.Errorf("Unexpected PacketConn: %T %#v", pc, pc)
} }
func (ua *udpAddr) Equals(t *udpAddr) bool {
if t == nil || ua == nil {
return t == nil && ua == nil
}
return ua.IP.Equal(t.IP) && ua.Port == t.Port
}
func (ua *udpAddr) Copy() udpAddr {
nu := udpAddr{net.UDPAddr{
Port: ua.Port,
Zone: ua.Zone,
IP: make(net.IP, len(ua.IP)),
}}
copy(nu.IP, ua.IP)
return nu
}
func (uc *udpConn) WriteTo(b []byte, addr *udpAddr) error { func (uc *udpConn) WriteTo(b []byte, addr *udpAddr) error {
_, err := uc.UDPConn.WriteToUDP(b, &addr.UDPAddr) _, err := uc.UDPConn.WriteToUDP(b, &net.UDPAddr{IP: addr.IP, Port: int(addr.Port)})
return err return err
} }
@ -86,7 +37,11 @@ func (uc *udpConn) LocalAddr() (*udpAddr, error) {
switch v := a.(type) { switch v := a.(type) {
case *net.UDPAddr: case *net.UDPAddr:
return &udpAddr{UDPAddr: *v}, nil addr := &udpAddr{IP: make([]byte, len(v.IP))}
copy(addr.IP, v.IP)
addr.Port = uint16(v.Port)
return addr, nil
default: default:
return nil, fmt.Errorf("LocalAddr returned: %#v", a) return nil, fmt.Errorf("LocalAddr returned: %#v", a)
} }
@ -110,7 +65,7 @@ func (u *udpConn) ListenOut(f *Interface, q int) {
buffer := make([]byte, mtu) buffer := make([]byte, mtu)
header := &Header{} header := &Header{}
fwPacket := &FirewallPacket{} fwPacket := &FirewallPacket{}
udpAddr := &udpAddr{} udpAddr := &udpAddr{IP: make([]byte, 16)}
nb := make([]byte, 12, 12) nb := make([]byte, 12, 12)
lhh := f.lightHouse.NewRequestHandler() lhh := f.lightHouse.NewRequestHandler()
@ -125,19 +80,12 @@ func (u *udpConn) ListenOut(f *Interface, q int) {
continue continue
} }
udpAddr.UDPAddr = *rua udpAddr.IP = rua.IP
udpAddr.Port = uint16(rua.Port)
f.readOutsidePackets(udpAddr, plaintext[:0], buffer[:n], header, fwPacket, lhh, nb, q, conntrackCache.Get()) f.readOutsidePackets(udpAddr, plaintext[:0], buffer[:n], header, fwPacket, lhh, nb, q, conntrackCache.Get())
} }
} }
func udp2ip(addr *udpAddr) net.IP {
return addr.IP
}
func udp2ipInt(addr *udpAddr) uint32 {
return binary.BigEndian.Uint32(addr.IP.To4())
}
func hostDidRoam(addr *udpAddr, newaddr *udpAddr) bool { func hostDidRoam(addr *udpAddr, newaddr *udpAddr) bool {
return !addr.Equals(newaddr) return !addr.Equals(newaddr)
} }

View File

@ -4,11 +4,8 @@ package nebula
import ( import (
"encoding/binary" "encoding/binary"
"encoding/json"
"fmt" "fmt"
"net" "net"
"strconv"
"strings"
"syscall" "syscall"
"unsafe" "unsafe"
@ -22,38 +19,6 @@ type udpConn struct {
sysFd int sysFd int
} }
type udpAddr struct {
IP uint32
Port uint16
}
func NewUDPAddr(ip uint32, port uint16) *udpAddr {
return &udpAddr{IP: ip, Port: port}
}
func NewUDPAddrFromString(s string) *udpAddr {
p := strings.Split(s, ":")
if len(p) < 2 {
return nil
}
port, _ := strconv.Atoi(p[1])
return &udpAddr{
IP: ip2int(net.ParseIP(p[0])),
Port: uint16(port),
}
}
type rawSockaddr struct {
Family uint16
Data [14]uint8
}
type rawSockaddrAny struct {
Addr rawSockaddr
Pad [96]int8
}
var x int var x int
// From linux/sock_diag.h // From linux/sock_diag.h
@ -75,7 +40,7 @@ type _SK_MEMINFO [_SK_MEMINFO_VARS]uint32
func NewListener(ip string, port int, multi bool) (*udpConn, error) { func NewListener(ip string, port int, multi bool) (*udpConn, error) {
syscall.ForkLock.RLock() syscall.ForkLock.RLock()
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_UDP) fd, err := unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, unix.IPPROTO_UDP)
if err == nil { if err == nil {
unix.CloseOnExec(fd) unix.CloseOnExec(fd)
} }
@ -86,8 +51,8 @@ func NewListener(ip string, port int, multi bool) (*udpConn, error) {
return nil, fmt.Errorf("unable to open socket: %s", err) return nil, fmt.Errorf("unable to open socket: %s", err)
} }
var lip [4]byte var lip [16]byte
copy(lip[:], net.ParseIP(ip).To4()) copy(lip[:], net.ParseIP(ip))
if multi { if multi {
if err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil { if err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
@ -95,7 +60,8 @@ func NewListener(ip string, port int, multi bool) (*udpConn, error) {
} }
} }
if err = unix.Bind(fd, &unix.SockaddrInet4{Addr: lip, Port: port}); err != nil { //TODO: support multiple listening IPs (for limiting ipv6)
if err = unix.Bind(fd, &unix.SockaddrInet6{Addr: lip, Port: port}); err != nil {
return nil, fmt.Errorf("unable to bind to socket: %s", err) return nil, fmt.Errorf("unable to bind to socket: %s", err)
} }
@ -111,10 +77,6 @@ func (u *udpConn) Rebind() error {
return nil return nil
} }
func (ua *udpAddr) Copy() udpAddr {
return *ua
}
func (u *udpConn) SetRecvBuffer(n int) error { func (u *udpConn) SetRecvBuffer(n int) error {
return unix.SetsockoptInt(u.sysFd, unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, n) return unix.SetsockoptInt(u.sysFd, unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, n)
} }
@ -132,7 +94,7 @@ func (u *udpConn) GetSendBuffer() (int, error) {
} }
func (u *udpConn) LocalAddr() (*udpAddr, error) { func (u *udpConn) LocalAddr() (*udpAddr, error) {
var rsa rawSockaddrAny var rsa unix.RawSockaddrAny
var rLen = unix.SizeofSockaddrAny var rLen = unix.SizeofSockaddrAny
_, _, err := unix.Syscall( _, _, err := unix.Syscall(
@ -148,12 +110,24 @@ func (u *udpConn) LocalAddr() (*udpAddr, error) {
addr := &udpAddr{} addr := &udpAddr{}
if rsa.Addr.Family == unix.AF_INET { if rsa.Addr.Family == unix.AF_INET {
pp := (*unix.RawSockaddrInet4)(unsafe.Pointer(&rsa))
addr.Port = uint16(rsa.Addr.Data[0])<<8 + uint16(rsa.Addr.Data[1]) addr.Port = uint16(rsa.Addr.Data[0])<<8 + uint16(rsa.Addr.Data[1])
addr.IP = uint32(rsa.Addr.Data[2])<<24 + uint32(rsa.Addr.Data[3])<<16 + uint32(rsa.Addr.Data[4])<<8 + uint32(rsa.Addr.Data[5]) copy(addr.IP, pp.Addr[:])
} else if rsa.Addr.Family == unix.AF_INET6 {
//TODO: this cast sucks and we can do better
pp := (*unix.RawSockaddrInet6)(unsafe.Pointer(&rsa))
addr.Port = uint16(rsa.Addr.Data[0])<<8 + uint16(rsa.Addr.Data[1])
copy(addr.IP, pp.Addr[:])
} else { } else {
addr.Port = 0 addr.Port = 0
addr.IP = 0 addr.IP = []byte{}
} }
//TODO: Just use this instead?
//a, b := unix.Getsockname(u.sysFd)
return addr, nil return addr, nil
} }
@ -185,9 +159,8 @@ func (u *udpConn) ListenOut(f *Interface, q int) {
//metric.Update(int64(n)) //metric.Update(int64(n))
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
udpAddr.IP = binary.BigEndian.Uint32(names[i][4:8]) udpAddr.IP = names[i][8:24]
udpAddr.Port = binary.BigEndian.Uint16(names[i][2:4]) udpAddr.Port = binary.BigEndian.Uint16(names[i][2:4])
f.readOutsidePackets(udpAddr, plaintext[:0], buffers[i][:msgs[i].Len], header, fwPacket, lhh, nb, q, conntrackCache.Get()) f.readOutsidePackets(udpAddr, plaintext[:0], buffers[i][:msgs[i].Len], header, fwPacket, lhh, nb, q, conntrackCache.Get())
} }
} }
@ -235,18 +208,13 @@ func (u *udpConn) ReadMulti(msgs []rawMessage) (int, error) {
} }
func (u *udpConn) WriteTo(b []byte, addr *udpAddr) error { func (u *udpConn) WriteTo(b []byte, addr *udpAddr) error {
var rsa unix.RawSockaddrInet4
//TODO: sometimes addr is nil! var rsa unix.RawSockaddrInet6
rsa.Family = unix.AF_INET rsa.Family = unix.AF_INET6
p := (*[2]byte)(unsafe.Pointer(&rsa.Port)) p := (*[2]byte)(unsafe.Pointer(&rsa.Port))
p[0] = byte(addr.Port >> 8) p[0] = byte(addr.Port >> 8)
p[1] = byte(addr.Port) p[1] = byte(addr.Port)
copy(rsa.Addr[:], addr.IP)
rsa.Addr[0] = byte(addr.IP & 0xff000000 >> 24)
rsa.Addr[1] = byte(addr.IP & 0x00ff0000 >> 16)
rsa.Addr[2] = byte(addr.IP & 0x0000ff00 >> 8)
rsa.Addr[3] = byte(addr.IP & 0x000000ff)
for { for {
_, _, err := unix.Syscall6( _, _, err := unix.Syscall6(
@ -256,7 +224,7 @@ func (u *udpConn) WriteTo(b []byte, addr *udpAddr) error {
uintptr(len(b)), uintptr(len(b)),
uintptr(0), uintptr(0),
uintptr(unsafe.Pointer(&rsa)), uintptr(unsafe.Pointer(&rsa)),
uintptr(unix.SizeofSockaddrInet4), uintptr(unix.SizeofSockaddrInet6),
) )
if err != 0 { if err != 0 {
@ -342,29 +310,6 @@ func NewUDPStatsEmitter(udpConns []*udpConn) func() {
} }
} }
func (ua *udpAddr) Equals(t *udpAddr) bool {
if t == nil || ua == nil {
return t == nil && ua == nil
}
return ua.IP == t.IP && ua.Port == t.Port
}
func (ua *udpAddr) String() string {
return fmt.Sprintf("%s:%v", int2ip(ua.IP), ua.Port)
}
func (ua *udpAddr) MarshalJSON() ([]byte, error) {
return json.Marshal(m{"ip": int2ip(ua.IP), "port": ua.Port})
}
func udp2ip(addr *udpAddr) net.IP {
return int2ip(addr.IP)
}
func udp2ipInt(addr *udpAddr) uint32 {
return addr.IP
}
func hostDidRoam(addr *udpAddr, newaddr *udpAddr) bool { func hostDidRoam(addr *udpAddr, newaddr *udpAddr) bool {
return !addr.Equals(newaddr) return !addr.Equals(newaddr)
} }

View File

@ -4,7 +4,9 @@
package nebula package nebula
import "unsafe" import (
"golang.org/x/sys/unix"
)
type iovec struct { type iovec struct {
Base *byte Base *byte
@ -33,17 +35,17 @@ func (u *udpConn) PrepareRawMessages(n int) ([]rawMessage, [][]byte, [][]byte) {
for i := range msgs { for i := range msgs {
buffers[i] = make([]byte, mtu) buffers[i] = make([]byte, mtu)
names[i] = make([]byte, 0x1c) //TODO = sizeofSockaddrInet6 names[i] = make([]byte, unix.SizeofSockaddrInet6)
//TODO: this is still silly, no need for an array //TODO: this is still silly, no need for an array
vs := []iovec{ vs := []iovec{
{Base: (*byte)(unsafe.Pointer(&buffers[i][0])), Len: uint32(len(buffers[i]))}, {Base: &buffers[i][0], Len: uint32(len(buffers[i]))},
} }
msgs[i].Hdr.Iov = &vs[0] msgs[i].Hdr.Iov = &vs[0]
msgs[i].Hdr.Iovlen = uint32(len(vs)) msgs[i].Hdr.Iovlen = uint32(len(vs))
msgs[i].Hdr.Name = (*byte)(unsafe.Pointer(&names[i][0])) msgs[i].Hdr.Name = &names[i][0]
msgs[i].Hdr.Namelen = uint32(len(names[i])) msgs[i].Hdr.Namelen = uint32(len(names[i]))
} }

View File

@ -4,7 +4,9 @@
package nebula package nebula
import "unsafe" import (
"golang.org/x/sys/unix"
)
type iovec struct { type iovec struct {
Base *byte Base *byte
@ -36,17 +38,17 @@ func (u *udpConn) PrepareRawMessages(n int) ([]rawMessage, [][]byte, [][]byte) {
for i := range msgs { for i := range msgs {
buffers[i] = make([]byte, mtu) buffers[i] = make([]byte, mtu)
names[i] = make([]byte, 0x1c) //TODO = sizeofSockaddrInet6 names[i] = make([]byte, unix.SizeofSockaddrInet6)
//TODO: this is still silly, no need for an array //TODO: this is still silly, no need for an array
vs := []iovec{ vs := []iovec{
{Base: (*byte)(unsafe.Pointer(&buffers[i][0])), Len: uint64(len(buffers[i]))}, {Base: &buffers[i][0], Len: uint64(len(buffers[i]))},
} }
msgs[i].Hdr.Iov = &vs[0] msgs[i].Hdr.Iov = &vs[0]
msgs[i].Hdr.Iovlen = uint64(len(vs)) msgs[i].Hdr.Iovlen = uint64(len(vs))
msgs[i].Hdr.Name = (*byte)(unsafe.Pointer(&names[i][0])) msgs[i].Hdr.Name = &names[i][0]
msgs[i].Hdr.Namelen = uint32(len(names[i])) msgs[i].Hdr.Namelen = uint32(len(names[i]))
} }