mirror of https://github.com/slackhq/nebula.git
IPv6 support for outside (udp) (#369)
This commit is contained in:
parent
9e94442ce7
commit
7073d204a8
4
Makefile
4
Makefile
|
@ -113,8 +113,8 @@ bench-cpu-long:
|
|||
proto: nebula.pb.go cert/cert.pb.go
|
||||
|
||||
nebula.pb.go: nebula.proto .FORCE
|
||||
go build github.com/golang/protobuf/protoc-gen-go
|
||||
PATH="$(PWD):$(PATH)" protoc --go_out=. $<
|
||||
go build google.golang.org/protobuf/cmd/protoc-gen-go
|
||||
PATH="$(CURDIR):$(PATH)" protoc --go_out=. --go_opt=paths=source_relative $<
|
||||
rm protoc-gen-go
|
||||
|
||||
cert/cert.pb.go: cert/cert.proto .FORCE
|
||||
|
|
|
@ -2,12 +2,13 @@ package nebula
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type AllowList struct {
|
||||
// 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.
|
||||
nameRules []AllowListNameRule
|
||||
|
@ -18,7 +19,7 @@ type AllowListNameRule struct {
|
|||
Allow bool
|
||||
}
|
||||
|
||||
func (al *AllowList) Allow(ip uint32) bool {
|
||||
func (al *AllowList) Allow(ip net.IP) bool {
|
||||
if al == nil {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -9,17 +9,26 @@ import (
|
|||
)
|
||||
|
||||
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("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"), false)
|
||||
tree.AddCIDR(getCIDR("::1/128"), true)
|
||||
tree.AddCIDR(getCIDR("::2/128"), false)
|
||||
al := &AllowList{cidrTree: tree}
|
||||
|
||||
assert.Equal(t, true, al.Allow(ip2int(net.ParseIP("1.1.1.1"))))
|
||||
assert.Equal(t, false, al.Allow(ip2int(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("1.1.1.1")))
|
||||
assert.Equal(t, false, al.Allow(net.ParseIP("10.0.0.4")))
|
||||
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) {
|
||||
|
|
|
@ -2,8 +2,8 @@ GO111MODULE = on
|
|||
export GO111MODULE
|
||||
|
||||
cert.pb.go: cert.proto .FORCE
|
||||
go build github.com/golang/protobuf/protoc-gen-go
|
||||
PATH="$(PWD):$(PATH)" protoc --go_out=. $<
|
||||
go build google.golang.org/protobuf/cmd/protoc-gen-go
|
||||
PATH="$(CURDIR):$(PATH)" protoc --go_out=. --go_opt=paths=source_relative $<
|
||||
rm protoc-gen-go
|
||||
|
||||
.FORCE:
|
||||
|
|
358
cert/cert.pb.go
358
cert/cert.pb.go
|
@ -1,202 +1,298 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.14.0
|
||||
// source: cert.proto
|
||||
|
||||
package cert
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
math "math"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// 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
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type RawNebulaCertificate struct {
|
||||
Details *RawNebulaCertificateDetails `protobuf:"bytes,1,opt,name=Details,json=details,proto3" json:"Details,omitempty"`
|
||||
Signature []byte `protobuf:"bytes,2,opt,name=Signature,json=signature,proto3" json:"Signature,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
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 (m *RawNebulaCertificate) String() string { return proto.CompactTextString(m) }
|
||||
func (*RawNebulaCertificate) ProtoMessage() {}
|
||||
func (x *RawNebulaCertificate) Reset() {
|
||||
*x = RawNebulaCertificate{}
|
||||
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) {
|
||||
return fileDescriptor_a142e29cbef9b1cf, []int{0}
|
||||
return file_cert_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (m *RawNebulaCertificate) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_RawNebulaCertificate.Unmarshal(m, b)
|
||||
}
|
||||
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
|
||||
func (x *RawNebulaCertificate) GetDetails() *RawNebulaCertificateDetails {
|
||||
if x != nil {
|
||||
return x.Details
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *RawNebulaCertificate) GetSignature() []byte {
|
||||
if m != nil {
|
||||
return m.Signature
|
||||
func (x *RawNebulaCertificate) GetSignature() []byte {
|
||||
if x != nil {
|
||||
return x.Signature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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 []uint32 `protobuf:"varint,2,rep,packed,name=Ips,json=ips,proto3" json:"Ips,omitempty"`
|
||||
Subnets []uint32 `protobuf:"varint,3,rep,packed,name=Subnets,json=subnets,proto3" json:"Subnets,omitempty"`
|
||||
Groups []string `protobuf:"bytes,4,rep,name=Groups,json=groups,proto3" json:"Groups,omitempty"`
|
||||
NotBefore int64 `protobuf:"varint,5,opt,name=NotBefore,json=notBefore,proto3" json:"NotBefore,omitempty"`
|
||||
NotAfter int64 `protobuf:"varint,6,opt,name=NotAfter,json=notAfter,proto3" json:"NotAfter,omitempty"`
|
||||
PublicKey []byte `protobuf:"bytes,7,opt,name=PublicKey,json=publicKey,proto3" json:"PublicKey,omitempty"`
|
||||
IsCA bool `protobuf:"varint,8,opt,name=IsCA,json=isCA,proto3" json:"IsCA,omitempty"`
|
||||
Ips []uint32 `protobuf:"varint,2,rep,packed,name=Ips,proto3" json:"Ips,omitempty"`
|
||||
Subnets []uint32 `protobuf:"varint,3,rep,packed,name=Subnets,proto3" json:"Subnets,omitempty"`
|
||||
Groups []string `protobuf:"bytes,4,rep,name=Groups,proto3" json:"Groups,omitempty"`
|
||||
NotBefore int64 `protobuf:"varint,5,opt,name=NotBefore,proto3" json:"NotBefore,omitempty"`
|
||||
NotAfter int64 `protobuf:"varint,6,opt,name=NotAfter,proto3" json:"NotAfter,omitempty"`
|
||||
PublicKey []byte `protobuf:"bytes,7,opt,name=PublicKey,proto3" json:"PublicKey,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
|
||||
Issuer []byte `protobuf:"bytes,9,opt,name=Issuer,json=issuer,proto3" json:"Issuer,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Issuer []byte `protobuf:"bytes,9,opt,name=Issuer,proto3" json:"Issuer,omitempty"`
|
||||
}
|
||||
|
||||
func (m *RawNebulaCertificateDetails) Reset() { *m = RawNebulaCertificateDetails{} }
|
||||
func (m *RawNebulaCertificateDetails) String() string { return proto.CompactTextString(m) }
|
||||
func (*RawNebulaCertificateDetails) ProtoMessage() {}
|
||||
func (x *RawNebulaCertificateDetails) Reset() {
|
||||
*x = RawNebulaCertificateDetails{}
|
||||
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) {
|
||||
return fileDescriptor_a142e29cbef9b1cf, []int{1}
|
||||
return file_cert_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (m *RawNebulaCertificateDetails) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_RawNebulaCertificateDetails.Unmarshal(m, b)
|
||||
}
|
||||
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
|
||||
func (x *RawNebulaCertificateDetails) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *RawNebulaCertificateDetails) GetIps() []uint32 {
|
||||
if m != nil {
|
||||
return m.Ips
|
||||
func (x *RawNebulaCertificateDetails) GetIps() []uint32 {
|
||||
if x != nil {
|
||||
return x.Ips
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *RawNebulaCertificateDetails) GetSubnets() []uint32 {
|
||||
if m != nil {
|
||||
return m.Subnets
|
||||
func (x *RawNebulaCertificateDetails) GetSubnets() []uint32 {
|
||||
if x != nil {
|
||||
return x.Subnets
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *RawNebulaCertificateDetails) GetGroups() []string {
|
||||
if m != nil {
|
||||
return m.Groups
|
||||
func (x *RawNebulaCertificateDetails) GetGroups() []string {
|
||||
if x != nil {
|
||||
return x.Groups
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *RawNebulaCertificateDetails) GetNotBefore() int64 {
|
||||
if m != nil {
|
||||
return m.NotBefore
|
||||
func (x *RawNebulaCertificateDetails) GetNotBefore() int64 {
|
||||
if x != nil {
|
||||
return x.NotBefore
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *RawNebulaCertificateDetails) GetNotAfter() int64 {
|
||||
if m != nil {
|
||||
return m.NotAfter
|
||||
func (x *RawNebulaCertificateDetails) GetNotAfter() int64 {
|
||||
if x != nil {
|
||||
return x.NotAfter
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *RawNebulaCertificateDetails) GetPublicKey() []byte {
|
||||
if m != nil {
|
||||
return m.PublicKey
|
||||
func (x *RawNebulaCertificateDetails) GetPublicKey() []byte {
|
||||
if x != nil {
|
||||
return x.PublicKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *RawNebulaCertificateDetails) GetIsCA() bool {
|
||||
if m != nil {
|
||||
return m.IsCA
|
||||
func (x *RawNebulaCertificateDetails) GetIsCA() bool {
|
||||
if x != nil {
|
||||
return x.IsCA
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *RawNebulaCertificateDetails) GetIssuer() []byte {
|
||||
if m != nil {
|
||||
return m.Issuer
|
||||
func (x *RawNebulaCertificateDetails) GetIssuer() []byte {
|
||||
if x != nil {
|
||||
return x.Issuer
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*RawNebulaCertificate)(nil), "cert.RawNebulaCertificate")
|
||||
proto.RegisterType((*RawNebulaCertificateDetails)(nil), "cert.RawNebulaCertificateDetails")
|
||||
var File_cert_proto protoreflect.FileDescriptor
|
||||
|
||||
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{
|
||||
// 279 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0xcf, 0x4a, 0xf4, 0x30,
|
||||
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,
|
||||
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,
|
||||
0x78, 0x86, 0xa0, 0x4d, 0xef, 0x39, 0x12, 0x48, 0xfe, 0xbf, 0xbf, 0xdb, 0xa4, 0xec, 0x6f, 0xe6,
|
||||
0x93, 0x51, 0x15, 0xef, 0xf3, 0xc0, 0x6e, 0x29, 0xd9, 0x9b, 0xc3, 0xa0, 0x43, 0x74, 0xc0, 0x57,
|
||||
0x02, 0xc9, 0x33, 0x45, 0xfc, 0x02, 0xd6, 0xdf, 0x88, 0xde, 0xfc, 0x71, 0x0d, 0x63, 0x34, 0xab,
|
||||
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,
|
||||
0x7e, 0x96, 0xec, 0x8a, 0xe6, 0x2f, 0xce, 0xc6, 0xd1, 0xf3, 0x4c, 0x60, 0x49, 0x54, 0x7e, 0x48,
|
||||
0x6a, 0x6a, 0x55, 0xdb, 0xf0, 0x04, 0x9d, 0x75, 0xc0, 0xff, 0x09, 0x24, 0xb1, 0x22, 0xc3, 0x02,
|
||||
0xd8, 0x35, 0x2d, 0x6b, 0x1b, 0xb6, 0x5d, 0x00, 0xc7, 0xf3, 0x74, 0x58, 0x0e, 0x27, 0x3d, 0x25,
|
||||
0xdf, 0x62, 0xd3, 0x9b, 0xf6, 0x15, 0xbe, 0x78, 0x31, 0xff, 0x67, 0x5c, 0xc0, 0xd4, 0xb7, 0xf2,
|
||||
0xbb, 0x2d, 0x2f, 0x05, 0x92, 0xa5, 0xca, 0x8c, 0xdf, 0x6d, 0xa7, 0x0e, 0x95, 0xf7, 0x11, 0x1c,
|
||||
0x27, 0xc9, 0x9e, 0x9b, 0xa4, 0x9a, 0x3c, 0xed, 0xfe, 0xe1, 0x27, 0x00, 0x00, 0xff, 0xff, 0x2c,
|
||||
0xe3, 0x08, 0x37, 0x89, 0x01, 0x00, 0x00,
|
||||
func file_cert_proto_rawDescGZIP() []byte {
|
||||
file_cert_proto_rawDescOnce.Do(func() {
|
||||
file_cert_proto_rawDescData = protoimpl.X.CompressGZIP(file_cert_proto_rawDescData)
|
||||
})
|
||||
return file_cert_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_cert_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_cert_proto_goTypes = []interface{}{
|
||||
(*RawNebulaCertificate)(nil), // 0: cert.RawNebulaCertificate
|
||||
(*RawNebulaCertificateDetails)(nil), // 1: cert.RawNebulaCertificateDetails
|
||||
}
|
||||
var file_cert_proto_depIdxs = []int32{
|
||||
1, // 0: cert.RawNebulaCertificate.Details:type_name -> cert.RawNebulaCertificateDetails
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
syntax = "proto3";
|
||||
package cert;
|
||||
|
||||
option go_package = "github.com/slackhq/nebula/cert";
|
||||
|
||||
//import "google/protobuf/timestamp.proto";
|
||||
|
||||
message RawNebulaCertificate {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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")))
|
||||
}
|
|
@ -76,7 +76,7 @@ func (tree *CIDRTree) AddCIDR(cidr *net.IPNet, val interface{}) {
|
|||
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{}) {
|
||||
bit := startbit
|
||||
node := tree.root
|
||||
|
|
56
config.go
56
config.go
|
@ -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)
|
||||
}
|
||||
|
||||
tree := NewCIDRTree()
|
||||
tree := NewCIDR6Tree()
|
||||
var nameRules []AllowListNameRule
|
||||
|
||||
firstValue := true
|
||||
allValuesMatch := true
|
||||
defaultSet := false
|
||||
var allValues bool
|
||||
// Keep track of the rules we have added for both ipv4 and ipv6
|
||||
type allowListRules struct {
|
||||
firstValue 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 {
|
||||
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?
|
||||
tree.AddCIDR(cidr, value)
|
||||
|
||||
if firstValue {
|
||||
allValues = value
|
||||
firstValue = false
|
||||
maskBits, maskSize := cidr.Mask.Size()
|
||||
|
||||
var rules *allowListRules
|
||||
if maskSize == 32 {
|
||||
rules = &rules4
|
||||
} else {
|
||||
if value != allValues {
|
||||
allValuesMatch = false
|
||||
rules = &rules6
|
||||
}
|
||||
|
||||
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
|
||||
bits, size := cidr.Mask.Size()
|
||||
if bits == 0 && size == 32 {
|
||||
defaultSet = true
|
||||
// Check if this is 0.0.0.0/0 or ::/0
|
||||
if maskBits == 0 {
|
||||
rules.defaultSet = true
|
||||
}
|
||||
}
|
||||
|
||||
if !defaultSet {
|
||||
if allValuesMatch {
|
||||
if !rules4.defaultSet {
|
||||
if rules4.allValuesMatch {
|
||||
_, zeroCIDR, _ := net.ParseCIDR("0.0.0.0/0")
|
||||
tree.AddCIDR(zeroCIDR, !allValues)
|
||||
tree.AddCIDR(zeroCIDR, !rules4.allValues)
|
||||
} else {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,16 @@ func TestConfig_GetAllowList(t *testing.T) {
|
|||
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")
|
||||
|
||||
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{}{
|
||||
"0.0.0.0/0": true,
|
||||
"10.0.0.0/8": false,
|
||||
|
@ -119,6 +129,19 @@ func TestConfig_GetAllowList(t *testing.T) {
|
|||
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
|
||||
|
||||
c.Settings["allowlist"] = map[interface{}]interface{}{
|
||||
|
|
42
control.go
42
control.go
|
@ -23,11 +23,11 @@ type ControlHostInfo struct {
|
|||
VpnIP net.IP `json:"vpnIp"`
|
||||
LocalIndex uint32 `json:"localIndex"`
|
||||
RemoteIndex uint32 `json:"remoteIndex"`
|
||||
RemoteAddrs []udpAddr `json:"remoteAddrs"`
|
||||
RemoteAddrs []*udpAddr `json:"remoteAddrs"`
|
||||
CachedPackets int `json:"cachedPackets"`
|
||||
Cert *cert.NebulaCertificate `json:"cert"`
|
||||
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()
|
||||
|
@ -38,16 +38,7 @@ func (c *Control) Start() {
|
|||
// Stop signals nebula to shutdown, returns after the shutdown is complete
|
||||
func (c *Control) Stop() {
|
||||
//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.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.CloseAllTunnels(false)
|
||||
c.l.Info("Goodbye")
|
||||
}
|
||||
|
||||
|
@ -149,13 +140,36 @@ func (c *Control) CloseTunnel(vpnIP uint32, localOnly bool) bool {
|
|||
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 {
|
||||
addrs := h.RemoteUDPAddrs()
|
||||
chi := ControlHostInfo{
|
||||
VpnIP: int2ip(h.hostId),
|
||||
LocalIndex: h.localIndexId,
|
||||
RemoteIndex: h.remoteIndexId,
|
||||
RemoteAddrs: make([]udpAddr, len(addrs), len(addrs)),
|
||||
RemoteAddrs: make([]*udpAddr, len(addrs), len(addrs)),
|
||||
CachedPackets: len(h.packetStore),
|
||||
MessageCounter: atomic.LoadUint64(&h.ConnectionState.atomicMessageCounter),
|
||||
}
|
||||
|
@ -165,7 +179,7 @@ func copyHostInfo(h *HostInfo) ControlHostInfo {
|
|||
}
|
||||
|
||||
if h.remote != nil {
|
||||
chi.CurrentRemote = *h.remote
|
||||
chi.CurrentRemote = h.remote.Copy()
|
||||
}
|
||||
|
||||
for i, addr := range addrs {
|
||||
|
|
|
@ -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
|
||||
// To properly ensure we are not exposing core memory to the caller
|
||||
hm := NewHostMap("test", &net.IPNet{}, make([]*net.IPNet, 0))
|
||||
remote1 := NewUDPAddr(100, 4444)
|
||||
remote2 := NewUDPAddr(101, 4444)
|
||||
remote1 := NewUDPAddr(int2ip(100), 4444)
|
||||
remote2 := NewUDPAddr(net.ParseIP("1:2:3:4:5:6:7:8"), 4444)
|
||||
ipNet := net.IPNet{
|
||||
IP: net.IPv4(1, 2, 3, 4),
|
||||
Mask: net.IPMask{255, 255, 255, 0},
|
||||
}
|
||||
|
||||
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},
|
||||
}
|
||||
|
||||
|
@ -80,11 +80,11 @@ func TestControl_GetHostInfoByVpnIP(t *testing.T) {
|
|||
VpnIP: net.IPv4(1, 2, 3, 4).To4(),
|
||||
LocalIndex: 201,
|
||||
RemoteIndex: 200,
|
||||
RemoteAddrs: []udpAddr{*remote1, *remote2},
|
||||
RemoteAddrs: []*udpAddr{remote1, remote2},
|
||||
CachedPackets: 0,
|
||||
Cert: crt.Copy(),
|
||||
MessageCounter: 0,
|
||||
CurrentRemote: *NewUDPAddr(100, 4444),
|
||||
CurrentRemote: NewUDPAddr(int2ip(100), 4444),
|
||||
}
|
||||
|
||||
// Make sure we don't have any unexpected fields
|
||||
|
|
|
@ -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,
|
||||
# however using port 0 will dynamically assign a port and is recommended for roaming nodes.
|
||||
listen:
|
||||
# To listen on both any ipv4 and ipv6 use "[::]"
|
||||
host: 0.0.0.0
|
||||
port: 4242
|
||||
# Sets the max number of packets to pull from the kernel for each syscall (under systems that support recvmmsg)
|
||||
|
|
4
go.mod
4
go.mod
|
@ -9,7 +9,7 @@ require (
|
|||
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/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/kardianos/service v1.1.0
|
||||
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/net v0.0.0-20191209160850-c0dbc17a3553
|
||||
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/yaml.v2 v2.2.7
|
||||
)
|
||||
|
|
62
go.sum
62
go.sum
|
@ -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-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
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.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
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/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/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/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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
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/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
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-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/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/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.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
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/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
|
||||
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-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
|
||||
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-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-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-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/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-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/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/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-20181116152217-5ac8a444bdc5/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.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-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/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/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=
|
||||
|
@ -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.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
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=
|
||||
|
|
|
@ -6,7 +6,7 @@ const (
|
|||
)
|
||||
|
||||
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")
|
||||
return
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ func ixHandshakeStage1(f *Interface, addr *udpAddr, packet []byte, h *Header) {
|
|||
//l.Debugln("got symmetric pairs")
|
||||
|
||||
//hostinfo.ClearRemotes()
|
||||
hostinfo.AddRemote(*addr)
|
||||
hostinfo.AddRemote(addr)
|
||||
hostinfo.ForcePromoteBest(f.hostMap.preferredRanges)
|
||||
hostinfo.CreateRemoteCIDR(remoteCert)
|
||||
|
||||
|
@ -358,7 +358,7 @@ func ixHandshakeStage2(f *Interface, addr *udpAddr, hostinfo *HostInfo, packet [
|
|||
ci.eKey = NewNebulaCipherState(eKey)
|
||||
//l.Debugln("got symmetric pairs")
|
||||
|
||||
hostinfo.SetRemote(*addr)
|
||||
hostinfo.SetRemote(addr)
|
||||
hostinfo.CreateRemoteCIDR(remoteCert)
|
||||
|
||||
f.handshakeManager.Complete(hostinfo, f)
|
||||
|
|
|
@ -140,8 +140,8 @@ func Test_NewHandshakeManagerTrigger(t *testing.T) {
|
|||
hi := blah.pendingHostMap.Hosts[ip]
|
||||
assert.Nil(t, hi.remote)
|
||||
|
||||
lh.addrMap = map[uint32][]udpAddr{
|
||||
ip: {*NewUDPAddrFromString("10.1.1.1:4242")},
|
||||
lh.addrMap = map[uint32][]*udpAddr{
|
||||
ip: {NewUDPAddrFromString("10.1.1.1:4242")},
|
||||
}
|
||||
|
||||
// This should trigger the hostmap to populate the hostinfo
|
||||
|
|
29
hostmap.go
29
hostmap.go
|
@ -303,7 +303,7 @@ func (hm *HostMap) AddRemote(vpnIp uint32, remote *udpAddr) *HostInfo {
|
|||
hm.Lock()
|
||||
i, v := hm.Hosts[vpnIp]
|
||||
if v {
|
||||
i.AddRemote(*remote)
|
||||
i.AddRemote(remote)
|
||||
} else {
|
||||
i = &HostInfo{
|
||||
Remotes: []*HostInfoDest{NewHostInfoDest(remote)},
|
||||
|
@ -424,10 +424,11 @@ func (hm *HostMap) Punchy(conn *udpConn) {
|
|||
metricsTxPunchy = metrics.NilCounter{}
|
||||
}
|
||||
|
||||
b := []byte{1}
|
||||
for {
|
||||
for _, addr := range hm.PunchList() {
|
||||
metricsTxPunchy.Inc(1)
|
||||
conn.WriteTo([]byte{1}, addr)
|
||||
conn.WriteTo(b, addr)
|
||||
}
|
||||
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 {
|
||||
// return early if we are already on a preferred remote
|
||||
rIP := udp2ip(i.remote)
|
||||
rIP := i.remote.IP
|
||||
for _, l := range preferredRanges {
|
||||
if l.Contains(rIP) {
|
||||
return
|
||||
|
@ -506,7 +507,7 @@ func (i *HostInfo) ForcePromoteBest(preferredRanges []*net.IPNet) {
|
|||
func (i *HostInfo) getBestRemote(preferredRanges []*net.IPNet) (best *udpAddr, preferred bool) {
|
||||
if len(i.Remotes) > 0 {
|
||||
for _, r := range i.Remotes {
|
||||
rIP := udp2ip(r.addr)
|
||||
rIP := r.addr.IP
|
||||
|
||||
for _, l := range preferredRanges {
|
||||
if l.Contains(rIP) {
|
||||
|
@ -625,8 +626,7 @@ func (i *HostInfo) GetCert() *cert.NebulaCertificate {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (i *HostInfo) AddRemote(r udpAddr) *udpAddr {
|
||||
remote := &r
|
||||
func (i *HostInfo) AddRemote(remote *udpAddr) *udpAddr {
|
||||
//add := true
|
||||
for _, r := range i.Remotes {
|
||||
if r.addr.Equals(remote) {
|
||||
|
@ -638,12 +638,13 @@ func (i *HostInfo) AddRemote(r udpAddr) *udpAddr {
|
|||
if len(i.Remotes) > MaxRemotes {
|
||||
i.Remotes = i.Remotes[len(i.Remotes)-MaxRemotes:]
|
||||
}
|
||||
i.Remotes = append(i.Remotes, NewHostInfoDest(remote))
|
||||
return remote
|
||||
r := NewHostInfoDest(remote)
|
||||
i.Remotes = append(i.Remotes, r)
|
||||
return r.addr
|
||||
//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)
|
||||
}
|
||||
|
||||
|
@ -701,7 +702,7 @@ func (i *HostInfo) logger() *logrus.Entry {
|
|||
|
||||
func NewHostInfoDest(addr *udpAddr) *HostInfoDest {
|
||||
i := &HostInfoDest{
|
||||
addr: addr,
|
||||
addr: addr.Copy(),
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
@ -816,8 +817,11 @@ func localIps(allowList *AllowList) *[]net.IP {
|
|||
case *net.IPAddr:
|
||||
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")
|
||||
if !allow {
|
||||
continue
|
||||
|
@ -831,6 +835,7 @@ func localIps(allowList *AllowList) *[]net.IP {
|
|||
}
|
||||
|
||||
func PrivateIP(ip net.IP) bool {
|
||||
//TODO: Private for ipv6 or just let it ride?
|
||||
private := false
|
||||
_, private24BitBlock, _ := net.ParseCIDR("10.0.0.0/8")
|
||||
_, private20BitBlock, _ := net.ParseCIDR("172.16.0.0/12")
|
||||
|
|
|
@ -98,7 +98,7 @@ func TestHostmap(t *testing.T) {
|
|||
|
||||
// Promotion should ensure that the best remote is chosen (y)
|
||||
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)
|
||||
|
||||
// 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()
|
||||
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(ip2int(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, 2}, 0))
|
||||
h.AddRemote(NewUDPAddr(net.IP{1, 1, 1, 3}, 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
|
||||
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()
|
||||
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()
|
||||
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
|
||||
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) {
|
||||
|
|
181
lighthouse.go
181
lighthouse.go
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/rcrowley/go-metrics"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/slackhq/nebula/cert"
|
||||
)
|
||||
|
||||
|
@ -21,7 +22,7 @@ type LightHouse struct {
|
|||
punchConn *udpConn
|
||||
|
||||
// Local cache of answers from light houses
|
||||
addrMap map[uint32][]udpAddr
|
||||
addrMap map[uint32][]*udpAddr
|
||||
|
||||
// filters remote addresses allowed for each host
|
||||
// - When we are a lighthouse, this filters what addresses we store and
|
||||
|
@ -41,7 +42,7 @@ type LightHouse struct {
|
|||
staticList map[uint32]struct{}
|
||||
lighthouses map[uint32]struct{}
|
||||
interval int
|
||||
nebulaPort uint32
|
||||
nebulaPort uint32 // 32 bits because protobuf does not have a uint16
|
||||
punchBack bool
|
||||
punchDelay time.Duration
|
||||
|
||||
|
@ -58,7 +59,7 @@ func NewLightHouse(amLighthouse bool, myIp uint32, ips []uint32, interval int, n
|
|||
h := LightHouse{
|
||||
amLighthouse: amLighthouse,
|
||||
myIp: myIp,
|
||||
addrMap: make(map[uint32][]udpAddr),
|
||||
addrMap: make(map[uint32][]*udpAddr),
|
||||
nebulaPort: nebulaPort,
|
||||
lighthouses: make(map[uint32]struct{}),
|
||||
staticList: make(map[uint32]struct{}),
|
||||
|
@ -106,7 +107,7 @@ func (lh *LightHouse) ValidateLHStaticEntries() error {
|
|||
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) {
|
||||
lh.QueryServer(ip, f)
|
||||
}
|
||||
|
@ -139,7 +140,7 @@ func (lh *LightHouse) QueryServer(ip uint32, f EncWriter) {
|
|||
}
|
||||
|
||||
// Query our local lighthouse cached results
|
||||
func (lh *LightHouse) QueryCache(ip uint32) []udpAddr {
|
||||
func (lh *LightHouse) QueryCache(ip uint32) []*udpAddr {
|
||||
lh.RLock()
|
||||
if v, ok := lh.addrMap[ip]; ok {
|
||||
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")
|
||||
if !allow {
|
||||
return
|
||||
|
@ -189,7 +190,8 @@ func (lh *LightHouse) AddRemote(vpnIP uint32, toIp *udpAddr, static bool) {
|
|||
if static {
|
||||
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) {
|
||||
|
@ -216,12 +218,41 @@ func NewLhQueryByInt(VpnIp uint32) *NebulaMeta {
|
|||
}
|
||||
}
|
||||
|
||||
func NewIpAndPort(ip net.IP, port uint32) IpAndPort {
|
||||
return IpAndPort{Ip: ip2int(ip), Port: port}
|
||||
type ip4Or6 struct {
|
||||
v4 IpAndPort
|
||||
v6 Ip6AndPort
|
||||
}
|
||||
|
||||
func NewIpAndPortFromUDPAddr(addr udpAddr) IpAndPort {
|
||||
return IpAndPort{Ip: udp2ipInt(&addr), Port: uint32(addr.Port)}
|
||||
func NewIpAndPort(ip net.IP, port uint32) ip4Or6 {
|
||||
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) {
|
||||
|
@ -236,20 +267,27 @@ func (lh *LightHouse) LhUpdateWorker(f EncWriter) {
|
|||
}
|
||||
|
||||
func (lh *LightHouse) SendUpdate(f EncWriter) {
|
||||
var ipps []*IpAndPort
|
||||
var v4 []*IpAndPort
|
||||
var v6 []*Ip6AndPort
|
||||
|
||||
for _, e := range *localIps(lh.localAllowList) {
|
||||
// Only add IPs that aren't my VPN/tun IP
|
||||
if ip2int(e) != lh.myIp {
|
||||
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{
|
||||
Type: NebulaMeta_HostUpdateNotification,
|
||||
Details: &NebulaMetaDetails{
|
||||
VpnIp: lh.myIp,
|
||||
IpAndPorts: ipps,
|
||||
VpnIp: lh.myIp,
|
||||
IpAndPorts: v4,
|
||||
Ip6AndPorts: v6,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -272,8 +310,8 @@ type LightHouseHandler struct {
|
|||
nb []byte
|
||||
out []byte
|
||||
meta *NebulaMeta
|
||||
iap []IpAndPort
|
||||
iapp []*IpAndPort
|
||||
iap []ip4Or6
|
||||
iapp []*ip4Or6
|
||||
}
|
||||
|
||||
func (lh *LightHouse) NewRequestHandler() *LightHouseHandler {
|
||||
|
@ -306,8 +344,8 @@ func (lhh *LightHouseHandler) resetMeta() *NebulaMeta {
|
|||
|
||||
func (lhh *LightHouseHandler) resizeIpAndPorts(n int) {
|
||||
if cap(lhh.iap) < n {
|
||||
lhh.iap = make([]IpAndPort, n)
|
||||
lhh.iapp = make([]*IpAndPort, n)
|
||||
lhh.iap = make([]ip4Or6, n)
|
||||
lhh.iapp = make([]*ip4Or6, n)
|
||||
|
||||
for i := range lhh.iap {
|
||||
lhh.iapp[i] = &lhh.iap[i]
|
||||
|
@ -317,7 +355,7 @@ func (lhh *LightHouseHandler) resizeIpAndPorts(n int) {
|
|||
lhh.iapp = lhh.iapp[:n]
|
||||
}
|
||||
|
||||
func (lhh *LightHouseHandler) setIpAndPortsFromNetIps(ips []udpAddr) []*IpAndPort {
|
||||
func (lhh *LightHouseHandler) setIpAndPortsFromNetIps(ips []*udpAddr) []*ip4Or6 {
|
||||
lhh.resizeIpAndPorts(len(ips))
|
||||
for i, e := range ips {
|
||||
lhh.iap[i] = NewIpAndPortFromUDPAddr(e)
|
||||
|
@ -363,7 +401,25 @@ func (lhh *LightHouseHandler) HandleRequest(rAddr *udpAddr, vpnIp uint32, p []by
|
|||
n = lhh.resetMeta()
|
||||
n.Type = NebulaMeta_HostQueryReply
|
||||
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)
|
||||
if err != nil {
|
||||
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.Type = NebulaMeta_HostPunchNotification
|
||||
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)
|
||||
lh.metricTx(NebulaMeta_HostPunchNotification, 1)
|
||||
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) {
|
||||
return
|
||||
}
|
||||
|
||||
for _, a := range n.Details.IpAndPorts {
|
||||
//first := n.Details.IpAndPorts[0]
|
||||
ans := NewUDPAddr(a.Ip, uint16(a.Port))
|
||||
lh.AddRemote(n.Details.VpnIp, ans, false)
|
||||
ans := NewUDPAddrFromLH4(a)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// Non-blocking attempt to trigger, skip if it would block
|
||||
select {
|
||||
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")
|
||||
return
|
||||
}
|
||||
|
||||
for _, a := range n.Details.IpAndPorts {
|
||||
ans := NewUDPAddr(a.Ip, uint16(a.Port))
|
||||
lh.AddRemote(n.Details.VpnIp, ans, false)
|
||||
ans := NewUDPAddrFromLH4(a)
|
||||
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_HostPunchNotification:
|
||||
if !lh.IsLighthouseIP(vpnIp) {
|
||||
|
@ -423,15 +518,43 @@ func (lhh *LightHouseHandler) HandleRequest(rAddr *udpAddr, vpnIp uint32, p []by
|
|||
|
||||
empty := []byte{0}
|
||||
for _, a := range n.Details.IpAndPorts {
|
||||
vpnPeer := NewUDPAddr(a.Ip, uint16(a.Port))
|
||||
vpnPeer := NewUDPAddrFromLH4(a)
|
||||
if vpnPeer == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
go func() {
|
||||
time.Sleep(lh.punchDelay)
|
||||
lh.metricHolepunchTx.Inc(1)
|
||||
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
|
||||
// of a double nat or other difficult scenario, this may help establish
|
||||
// a tunnel.
|
||||
|
|
|
@ -8,6 +8,17 @@ import (
|
|||
"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) {
|
||||
myIp := net.ParseIP("192.1.1.1")
|
||||
myIpint := ip2int(myIp)
|
||||
|
@ -31,24 +42,24 @@ func TestNewLhQuery(t *testing.T) {
|
|||
|
||||
func TestNewipandportfromudpaddr(t *testing.T) {
|
||||
blah := NewUDPAddrFromString("1.2.2.3:12345")
|
||||
meh := NewIpAndPortFromUDPAddr(*blah)
|
||||
assert.Equal(t, uint32(16908803), meh.Ip)
|
||||
assert.Equal(t, uint32(12345), meh.Port)
|
||||
meh := NewIpAndPortFromUDPAddr(blah)
|
||||
assert.Equal(t, uint32(16908803), meh.v4.Ip)
|
||||
assert.Equal(t, uint32(12345), meh.v4.Port)
|
||||
}
|
||||
|
||||
func TestSetipandportsfromudpaddrs(t *testing.T) {
|
||||
blah := NewUDPAddrFromString("1.2.2.3:12345")
|
||||
blah2 := NewUDPAddrFromString("9.9.9.9:47828")
|
||||
group := []udpAddr{*blah, *blah2}
|
||||
group := []*udpAddr{blah, blah2}
|
||||
var lh *LightHouse
|
||||
lhh := lh.NewRequestHandler()
|
||||
result := lhh.setIpAndPortsFromNetIps(group)
|
||||
assert.IsType(t, []*IpAndPort{}, result)
|
||||
assert.IsType(t, []*ip4Or6{}, result)
|
||||
assert.Len(t, result, 2)
|
||||
assert.Equal(t, uint32(0x01020203), result[0].Ip)
|
||||
assert.Equal(t, uint32(12345), result[0].Port)
|
||||
assert.Equal(t, uint32(0x09090909), result[1].Ip)
|
||||
assert.Equal(t, uint32(47828), result[1].Port)
|
||||
assert.Equal(t, uint32(0x01020203), result[0].v4.Ip)
|
||||
assert.Equal(t, uint32(12345), result[0].v4.Port)
|
||||
assert.Equal(t, uint32(0x09090909), result[1].v4.Ip)
|
||||
assert.Equal(t, uint32(47828), result[1].v4.Port)
|
||||
//t.Error(reflect.TypeOf(hah))
|
||||
|
||||
}
|
||||
|
@ -60,7 +71,7 @@ func Test_lhStaticMapping(t *testing.T) {
|
|||
udpServer, _ := NewListener("0.0.0.0", 0, true)
|
||||
|
||||
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()
|
||||
assert.Nil(t, err)
|
||||
|
||||
|
@ -68,7 +79,7 @@ func Test_lhStaticMapping(t *testing.T) {
|
|||
lh2IP := net.ParseIP(lh2)
|
||||
|
||||
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()
|
||||
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")
|
||||
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")
|
||||
rAddr2 := NewUDPAddrFromString("1.2.2.3:12346")
|
||||
lh.addrMap[2] = []udpAddr{*rAddr, *rAddr2}
|
||||
lh.addrMap[2] = []*udpAddr{rAddr, rAddr2}
|
||||
|
||||
mw := &mockEncWriter{}
|
||||
|
||||
|
@ -142,15 +153,17 @@ func Test_lhRemoteAllowList(t *testing.T) {
|
|||
|
||||
remote1 := "10.20.0.3"
|
||||
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)])
|
||||
|
||||
remote2 := "10.128.0.3"
|
||||
remote2IP := net.ParseIP(remote2)
|
||||
remote2UDPAddr := NewUDPAddr(ip2int(remote2IP), uint16(4242))
|
||||
remote2UDPAddr := NewUDPAddr(remote2IP, uint16(4242))
|
||||
|
||||
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 {
|
||||
|
|
27
main.go
27
main.go
|
@ -4,8 +4,6 @@ import (
|
|||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -301,28 +299,19 @@ func Main(config *Config, configTest bool, buildVersion string, logger *logrus.L
|
|||
vals, ok := v.([]interface{})
|
||||
if ok {
|
||||
for _, v := range vals {
|
||||
parts := strings.Split(fmt.Sprintf("%v", v), ":")
|
||||
addr, err := net.ResolveIPAddr("ip", parts[0])
|
||||
ip, port, err := parseIPAndPort(fmt.Sprintf("%v", v))
|
||||
if err == nil {
|
||||
ip := addr.IP
|
||||
port, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return nil, NewContextualError("Static host address could not be parsed", m{"vpnIp": vpnIp}, err)
|
||||
}
|
||||
lightHouse.AddRemote(ip2int(vpnIp), NewUDPAddr(ip2int(ip), uint16(port)), true)
|
||||
lightHouse.AddRemote(ip2int(vpnIp), NewUDPAddr(ip, port), true)
|
||||
} else {
|
||||
return nil, NewContextualError("Static host address could not be parsed", m{"vpnIp": vpnIp}, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//TODO: make this all a helper
|
||||
parts := strings.Split(fmt.Sprintf("%v", v), ":")
|
||||
addr, err := net.ResolveIPAddr("ip", parts[0])
|
||||
ip, port, err := parseIPAndPort(fmt.Sprintf("%v", v))
|
||||
if err == nil {
|
||||
ip := addr.IP
|
||||
port, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return nil, NewContextualError("Static host address could not be parsed", m{"vpnIp": vpnIp}, err)
|
||||
}
|
||||
lightHouse.AddRemote(ip2int(vpnIp), NewUDPAddr(ip2int(ip), uint16(port)), true)
|
||||
lightHouse.AddRemote(ip2int(vpnIp), NewUDPAddr(ip, port), true)
|
||||
} else {
|
||||
return nil, NewContextualError("Static host address could not be parsed", m{"vpnIp": vpnIp}, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
936
nebula.pb.go
936
nebula.pb.go
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,8 @@
|
|||
syntax = "proto3";
|
||||
package nebula;
|
||||
|
||||
option go_package = "github.com/slackhq/nebula";
|
||||
|
||||
message NebulaMeta {
|
||||
enum MessageType {
|
||||
None = 0;
|
||||
|
@ -20,11 +22,10 @@ message NebulaMeta {
|
|||
NebulaMetaDetails Details = 2;
|
||||
}
|
||||
|
||||
|
||||
message NebulaMetaDetails {
|
||||
|
||||
uint32 VpnIp = 1;
|
||||
repeated IpAndPort IpAndPorts = 2;
|
||||
repeated Ip6AndPort Ip6AndPorts = 4;
|
||||
uint32 counter = 3;
|
||||
}
|
||||
|
||||
|
@ -33,6 +34,10 @@ message IpAndPort {
|
|||
uint32 Port = 2;
|
||||
}
|
||||
|
||||
message Ip6AndPort {
|
||||
bytes Ip = 1;
|
||||
uint32 Port = 2;
|
||||
}
|
||||
|
||||
message NebulaPing {
|
||||
enum MessageType {
|
||||
|
|
|
@ -142,7 +142,7 @@ func (f *Interface) closeTunnel(hostInfo *HostInfo) {
|
|||
|
||||
func (f *Interface) handleHostRoaming(hostinfo *HostInfo, addr *udpAddr) {
|
||||
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")
|
||||
return
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ func (f *Interface) handleHostRoaming(hostinfo *HostInfo, addr *udpAddr) {
|
|||
hostinfo.lastRoam = time.Now()
|
||||
remoteCopy := *hostinfo.remote
|
||||
hostinfo.lastRoamRemote = &remoteCopy
|
||||
hostinfo.SetRemote(*addr)
|
||||
hostinfo.SetRemote(addr)
|
||||
if f.lightHouse.amLighthouse {
|
||||
f.lightHouse.AddRemote(hostinfo.hostId, addr, false)
|
||||
}
|
||||
|
|
4
ssh.go
4
ssh.go
|
@ -562,7 +562,7 @@ func sshCreateTunnel(ifce *Interface, fs interface{}, a []string, w sshd.StringW
|
|||
|
||||
hostInfo = ifce.handshakeManager.AddVpnIP(vpnIp)
|
||||
if addr != nil {
|
||||
hostInfo.SetRemote(*addr)
|
||||
hostInfo.SetRemote(addr)
|
||||
}
|
||||
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]))
|
||||
}
|
||||
|
||||
hostInfo.SetRemote(*addr)
|
||||
hostInfo.SetRemote(addr)
|
||||
return w.WriteLine("Changed")
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -28,6 +28,7 @@ func NewListenConfig(multi bool) net.ListenConfig {
|
|||
return controlErr
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -39,5 +40,5 @@ func (u *udpConn) Rebind() error {
|
|||
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)
|
||||
}
|
||||
|
|
|
@ -7,48 +7,17 @@ package nebula
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type udpAddr struct {
|
||||
net.UDPAddr
|
||||
}
|
||||
|
||||
type udpConn struct {
|
||||
*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) {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
_, err := uc.UDPConn.WriteToUDP(b, &addr.UDPAddr)
|
||||
_, err := uc.UDPConn.WriteToUDP(b, &net.UDPAddr{IP: addr.IP, Port: int(addr.Port)})
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -86,7 +37,11 @@ func (uc *udpConn) LocalAddr() (*udpAddr, error) {
|
|||
|
||||
switch v := a.(type) {
|
||||
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:
|
||||
return nil, fmt.Errorf("LocalAddr returned: %#v", a)
|
||||
}
|
||||
|
@ -110,7 +65,7 @@ func (u *udpConn) ListenOut(f *Interface, q int) {
|
|||
buffer := make([]byte, mtu)
|
||||
header := &Header{}
|
||||
fwPacket := &FirewallPacket{}
|
||||
udpAddr := &udpAddr{}
|
||||
udpAddr := &udpAddr{IP: make([]byte, 16)}
|
||||
nb := make([]byte, 12, 12)
|
||||
|
||||
lhh := f.lightHouse.NewRequestHandler()
|
||||
|
@ -125,19 +80,12 @@ func (u *udpConn) ListenOut(f *Interface, q int) {
|
|||
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())
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
return !addr.Equals(newaddr)
|
||||
}
|
||||
|
|
105
udp_linux.go
105
udp_linux.go
|
@ -4,11 +4,8 @@ package nebula
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
|
@ -22,38 +19,6 @@ type udpConn struct {
|
|||
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
|
||||
|
||||
// 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) {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
var lip [4]byte
|
||||
copy(lip[:], net.ParseIP(ip).To4())
|
||||
var lip [16]byte
|
||||
copy(lip[:], net.ParseIP(ip))
|
||||
|
||||
if multi {
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -111,10 +77,6 @@ func (u *udpConn) Rebind() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (ua *udpAddr) Copy() udpAddr {
|
||||
return *ua
|
||||
}
|
||||
|
||||
func (u *udpConn) SetRecvBuffer(n int) error {
|
||||
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) {
|
||||
var rsa rawSockaddrAny
|
||||
var rsa unix.RawSockaddrAny
|
||||
var rLen = unix.SizeofSockaddrAny
|
||||
|
||||
_, _, err := unix.Syscall(
|
||||
|
@ -148,12 +110,24 @@ func (u *udpConn) LocalAddr() (*udpAddr, error) {
|
|||
|
||||
addr := &udpAddr{}
|
||||
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.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 {
|
||||
addr.Port = 0
|
||||
addr.IP = 0
|
||||
addr.IP = []byte{}
|
||||
}
|
||||
|
||||
//TODO: Just use this instead?
|
||||
//a, b := unix.Getsockname(u.sysFd)
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
|
@ -185,9 +159,8 @@ func (u *udpConn) ListenOut(f *Interface, q int) {
|
|||
|
||||
//metric.Update(int64(n))
|
||||
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])
|
||||
|
||||
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 {
|
||||
var rsa unix.RawSockaddrInet4
|
||||
|
||||
//TODO: sometimes addr is nil!
|
||||
rsa.Family = unix.AF_INET
|
||||
var rsa unix.RawSockaddrInet6
|
||||
rsa.Family = unix.AF_INET6
|
||||
p := (*[2]byte)(unsafe.Pointer(&rsa.Port))
|
||||
p[0] = byte(addr.Port >> 8)
|
||||
p[1] = byte(addr.Port)
|
||||
|
||||
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)
|
||||
copy(rsa.Addr[:], addr.IP)
|
||||
|
||||
for {
|
||||
_, _, err := unix.Syscall6(
|
||||
|
@ -256,7 +224,7 @@ func (u *udpConn) WriteTo(b []byte, addr *udpAddr) error {
|
|||
uintptr(len(b)),
|
||||
uintptr(0),
|
||||
uintptr(unsafe.Pointer(&rsa)),
|
||||
uintptr(unix.SizeofSockaddrInet4),
|
||||
uintptr(unix.SizeofSockaddrInet6),
|
||||
)
|
||||
|
||||
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 {
|
||||
return !addr.Equals(newaddr)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
package nebula
|
||||
|
||||
import "unsafe"
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type iovec struct {
|
||||
Base *byte
|
||||
|
@ -33,17 +35,17 @@ func (u *udpConn) PrepareRawMessages(n int) ([]rawMessage, [][]byte, [][]byte) {
|
|||
|
||||
for i := range msgs {
|
||||
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
|
||||
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.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]))
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
package nebula
|
||||
|
||||
import "unsafe"
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type iovec struct {
|
||||
Base *byte
|
||||
|
@ -36,17 +38,17 @@ func (u *udpConn) PrepareRawMessages(n int) ([]rawMessage, [][]byte, [][]byte) {
|
|||
|
||||
for i := range msgs {
|
||||
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
|
||||
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.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]))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue