mirror of
https://github.com/slackhq/nebula.git
synced 2025-11-22 00:15:37 +01:00
Compare commits
8 Commits
multiport
...
update-lh-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9642afa149 | ||
|
|
65cc253c19 | ||
|
|
73cfa7b5b1 | ||
|
|
768325c9b4 | ||
|
|
932e329164 | ||
|
|
4bea299265 | ||
|
|
5cff83b282 | ||
|
|
7da79685ff |
8
.github/workflows/smoke.yml
vendored
8
.github/workflows/smoke.yml
vendored
@@ -52,12 +52,4 @@ jobs:
|
||||
working-directory: ./.github/workflows/smoke
|
||||
run: NAME="smoke-p256" ./smoke.sh
|
||||
|
||||
- name: setup docker image for multiport
|
||||
working-directory: ./.github/workflows/smoke
|
||||
run: NAME="smoke-multiport" MULTIPORT_TX=true MULTIPORT_RX=true MULTIPORT_HANDSHAKE=true ./build.sh
|
||||
|
||||
- name: run smoke
|
||||
working-directory: ./.github/workflows/smoke
|
||||
run: NAME="smoke-multiport" ./smoke.sh
|
||||
|
||||
timeout-minutes: 10
|
||||
|
||||
4
.github/workflows/smoke/genconfig.sh
vendored
4
.github/workflows/smoke/genconfig.sh
vendored
@@ -48,10 +48,6 @@ listen:
|
||||
|
||||
tun:
|
||||
dev: ${TUN_DEV:-tun0}
|
||||
multiport:
|
||||
tx_enabled: ${MULTIPORT_TX:-false}
|
||||
rx_enabled: ${MULTIPORT_RX:-false}
|
||||
tx_handshake: ${MULTIPORT_HANDSHAKE:-false}
|
||||
|
||||
firewall:
|
||||
inbound_action: reject
|
||||
|
||||
4
Makefile
4
Makefile
@@ -227,10 +227,6 @@ smoke-relay-docker: bin-docker
|
||||
cd .github/workflows/smoke/ && ./build-relay.sh
|
||||
cd .github/workflows/smoke/ && ./smoke-relay.sh
|
||||
|
||||
smoke-multiport-docker: bin-docker
|
||||
cd .github/workflows/smoke/ && NAME="smoke-multiport" MULTIPORT_TX=true MULTIPORT_RX=true MULTIPORT_HANDSHAKE=true ./build.sh
|
||||
cd .github/workflows/smoke/ && NAME="smoke-multiport" ./smoke.sh
|
||||
|
||||
smoke-docker-race: BUILD_ARGS = -race
|
||||
smoke-docker-race: CGO_ENABLED = 1
|
||||
smoke-docker-race: smoke-docker
|
||||
|
||||
@@ -84,16 +84,11 @@ func NewCalculatedRemotesFromConfig(c *config.C, k string) (*bart.Table[[]*calcu
|
||||
|
||||
calculatedRemotes := new(bart.Table[[]*calculatedRemote])
|
||||
|
||||
rawMap, ok := value.(map[any]any)
|
||||
rawMap, ok := value.(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("config `%s` has invalid type: %T", k, value)
|
||||
}
|
||||
for rawKey, rawValue := range rawMap {
|
||||
rawCIDR, ok := rawKey.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("config `%s` has invalid key (type %T): %v", k, rawKey, rawKey)
|
||||
}
|
||||
|
||||
for rawCIDR, rawValue := range rawMap {
|
||||
cidr, err := netip.ParsePrefix(rawCIDR)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("config `%s` has invalid CIDR: %s", k, rawCIDR)
|
||||
@@ -129,7 +124,7 @@ func newCalculatedRemotesListFromConfig(cidr netip.Prefix, raw any) ([]*calculat
|
||||
}
|
||||
|
||||
func newCalculatedRemotesEntryFromConfig(cidr netip.Prefix, raw any) (*calculatedRemote, error) {
|
||||
rawMap, ok := raw.(map[any]any)
|
||||
rawMap, ok := raw.(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid type: %T", raw)
|
||||
}
|
||||
|
||||
@@ -135,8 +135,7 @@ func Recombine(v Version, rawCertBytes, publicKey []byte, curve Curve) (Certific
|
||||
case Version2:
|
||||
c, err = unmarshalCertificateV2(rawCertBytes, publicKey, curve)
|
||||
default:
|
||||
//TODO: CERT-V2 make a static var
|
||||
return nil, fmt.Errorf("unknown certificate version %d", v)
|
||||
return nil, ErrUnknownVersion
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -20,6 +20,7 @@ var (
|
||||
ErrPublicPrivateKeyMismatch = errors.New("public key and private key are not a pair")
|
||||
ErrPrivateKeyEncrypted = errors.New("private key must be decrypted")
|
||||
ErrCaNotFound = errors.New("could not find ca for the certificate")
|
||||
ErrUnknownVersion = errors.New("certificate version unrecognized")
|
||||
|
||||
ErrInvalidPEMBlock = errors.New("input did not contain a valid PEM encoded block")
|
||||
ErrInvalidPEMCertificateBanner = errors.New("bytes did not contain a proper certificate banner")
|
||||
|
||||
@@ -356,7 +356,7 @@ func (cm *connectionManager) makeTrafficDecision(localIndex uint32, now time.Tim
|
||||
decision = tryRehandshake
|
||||
|
||||
} else {
|
||||
if cm.shouldSwapPrimary(hostinfo, primary) {
|
||||
if cm.shouldSwapPrimary(hostinfo) {
|
||||
decision = swapPrimary
|
||||
} else {
|
||||
// migrate the relays to the primary, if in use.
|
||||
@@ -447,7 +447,7 @@ func (cm *connectionManager) isInactive(hostinfo *HostInfo, now time.Time) (time
|
||||
return inactiveDuration, true
|
||||
}
|
||||
|
||||
func (cm *connectionManager) shouldSwapPrimary(current, primary *HostInfo) bool {
|
||||
func (cm *connectionManager) shouldSwapPrimary(current *HostInfo) bool {
|
||||
// The primary tunnel is the most recent handshake to complete locally and should work entirely fine.
|
||||
// If we are here then we have multiple tunnels for a host pair and neither side believes the same tunnel is primary.
|
||||
// Let's sort this out.
|
||||
|
||||
@@ -280,47 +280,6 @@ tun:
|
||||
# SO_RCVBUFFORCE is used to avoid having to raise the system wide max
|
||||
#use_system_route_table_buffer_size: 0
|
||||
|
||||
# EXPERIMENTAL: This option may change or disappear in the future.
|
||||
# Multiport spreads outgoing UDP packets across multiple UDP send ports,
|
||||
# which allows nebula to work around any issues on the underlay network.
|
||||
# Some example issues this could work around:
|
||||
# - UDP rate limits on a per flow basis.
|
||||
# - Partial underlay network failure in which some flows work and some don't
|
||||
# Agreement is done during the handshake to decide if multiport mode will
|
||||
# be used for a given tunnel (one side must have tx_enabled set, the other
|
||||
# side must have rx_enabled set)
|
||||
#
|
||||
# NOTE: you cannot use multiport on a host if you are relying on UDP hole
|
||||
# punching to get through a NAT or firewall.
|
||||
#
|
||||
# NOTE: Linux only (uses raw sockets to send). Also currently only works
|
||||
# with IPv4 underlay network remotes.
|
||||
#
|
||||
# The default values are listed below:
|
||||
#multiport:
|
||||
# This host support sending via multiple UDP ports.
|
||||
#tx_enabled: false
|
||||
#
|
||||
# This host supports receiving packets sent from multiple UDP ports.
|
||||
#rx_enabled: false
|
||||
#
|
||||
# How many UDP ports to use when sending. The lowest source port will be
|
||||
# listen.port and go up to (but not including) listen.port + tx_ports.
|
||||
#tx_ports: 100
|
||||
#
|
||||
# NOTE: All of your hosts must be running a version of Nebula that supports
|
||||
# multiport if you want to enable this feature. Older versions of Nebula
|
||||
# will be confused by these multiport handshakes.
|
||||
#
|
||||
# If handshakes are not getting a response, attempt to transmit handshakes
|
||||
# using random UDP source ports (to get around partial underlay network
|
||||
# failures).
|
||||
#tx_handshake: false
|
||||
#
|
||||
# How many unresponded handshakes we should send before we attempt to
|
||||
# send multiport handshakes.
|
||||
#tx_handshake_delay: 2
|
||||
|
||||
# Configure logging level
|
||||
logging:
|
||||
# panic, fatal, error, warning, info, or debug. Default is info and is reloadable.
|
||||
|
||||
@@ -3,7 +3,6 @@ package firewall
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
mathrand "math/rand"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
@@ -61,30 +60,3 @@ func (fp Packet) MarshalJSON() ([]byte, error) {
|
||||
"Fragment": fp.Fragment,
|
||||
})
|
||||
}
|
||||
|
||||
// UDPSendPort calculates the UDP port to send from when using multiport mode.
|
||||
// The result will be from [0, numBuckets)
|
||||
func (fp Packet) UDPSendPort(numBuckets int) uint16 {
|
||||
if numBuckets <= 1 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// If there is no port (like an ICMP packet), pick a random UDP send port
|
||||
if fp.LocalPort == 0 {
|
||||
return uint16(mathrand.Intn(numBuckets))
|
||||
}
|
||||
|
||||
// A decent enough 32bit hash function
|
||||
// Prospecting for Hash Functions
|
||||
// - https://nullprogram.com/blog/2018/07/31/
|
||||
// - https://github.com/skeeto/hash-prospector
|
||||
// [16 21f0aaad 15 d35a2d97 15] = 0.10760229515479501
|
||||
x := (uint32(fp.LocalPort) << 16) | uint32(fp.RemotePort)
|
||||
x ^= x >> 16
|
||||
x *= 0x21f0aaad
|
||||
x ^= x >> 15
|
||||
x *= 0xd35a2d97
|
||||
x ^= x >> 15
|
||||
|
||||
return uint16(x) % uint16(numBuckets)
|
||||
}
|
||||
|
||||
197
firewall_test.go
197
firewall_test.go
@@ -68,6 +68,9 @@ func TestFirewall_AddRule(t *testing.T) {
|
||||
ti, err := netip.ParsePrefix("1.2.3.4/32")
|
||||
require.NoError(t, err)
|
||||
|
||||
ti6, err := netip.ParsePrefix("fd12::34/128")
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, fw.AddRule(true, firewall.ProtoTCP, 1, 1, []string{}, "", netip.Prefix{}, netip.Prefix{}, "", ""))
|
||||
// An empty rule is any
|
||||
assert.True(t, fw.InRules.TCP[1].Any.Any.Any)
|
||||
@@ -92,12 +95,24 @@ func TestFirewall_AddRule(t *testing.T) {
|
||||
_, ok := fw.OutRules.AnyProto[1].Any.CIDR.Get(ti)
|
||||
assert.True(t, ok)
|
||||
|
||||
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, c)
|
||||
require.NoError(t, fw.AddRule(false, firewall.ProtoAny, 1, 1, []string{}, "", ti6, netip.Prefix{}, "", ""))
|
||||
assert.Nil(t, fw.OutRules.AnyProto[1].Any.Any)
|
||||
_, ok = fw.OutRules.AnyProto[1].Any.CIDR.Get(ti6)
|
||||
assert.True(t, ok)
|
||||
|
||||
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, c)
|
||||
require.NoError(t, fw.AddRule(false, firewall.ProtoAny, 1, 1, []string{}, "", netip.Prefix{}, ti, "", ""))
|
||||
assert.NotNil(t, fw.OutRules.AnyProto[1].Any.Any)
|
||||
_, ok = fw.OutRules.AnyProto[1].Any.Any.LocalCIDR.Get(ti)
|
||||
assert.True(t, ok)
|
||||
|
||||
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, c)
|
||||
require.NoError(t, fw.AddRule(false, firewall.ProtoAny, 1, 1, []string{}, "", netip.Prefix{}, ti6, "", ""))
|
||||
assert.NotNil(t, fw.OutRules.AnyProto[1].Any.Any)
|
||||
_, ok = fw.OutRules.AnyProto[1].Any.Any.LocalCIDR.Get(ti6)
|
||||
assert.True(t, ok)
|
||||
|
||||
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, c)
|
||||
require.NoError(t, fw.AddRule(true, firewall.ProtoUDP, 1, 1, []string{"g1"}, "", netip.Prefix{}, netip.Prefix{}, "ca-name", ""))
|
||||
assert.Contains(t, fw.InRules.UDP[1].CANames, "ca-name")
|
||||
@@ -117,6 +132,13 @@ func TestFirewall_AddRule(t *testing.T) {
|
||||
require.NoError(t, fw.AddRule(false, firewall.ProtoAny, 0, 0, []string{}, "", anyIp, netip.Prefix{}, "", ""))
|
||||
assert.True(t, fw.OutRules.AnyProto[0].Any.Any.Any)
|
||||
|
||||
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, c)
|
||||
anyIp6, err := netip.ParsePrefix("::/0")
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, fw.AddRule(false, firewall.ProtoAny, 0, 0, []string{}, "", anyIp6, netip.Prefix{}, "", ""))
|
||||
assert.True(t, fw.OutRules.AnyProto[0].Any.Any.Any)
|
||||
|
||||
// Test error conditions
|
||||
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, c)
|
||||
require.Error(t, fw.AddRule(true, math.MaxUint8, 0, 0, []string{}, "", netip.Prefix{}, netip.Prefix{}, "", ""))
|
||||
@@ -199,6 +221,82 @@ func TestFirewall_Drop(t *testing.T) {
|
||||
require.NoError(t, fw.Drop(p, true, &h, cp, nil))
|
||||
}
|
||||
|
||||
func TestFirewall_DropV6(t *testing.T) {
|
||||
l := test.NewLogger()
|
||||
ob := &bytes.Buffer{}
|
||||
l.SetOutput(ob)
|
||||
|
||||
p := firewall.Packet{
|
||||
LocalAddr: netip.MustParseAddr("fd12::34"),
|
||||
RemoteAddr: netip.MustParseAddr("fd12::34"),
|
||||
LocalPort: 10,
|
||||
RemotePort: 90,
|
||||
Protocol: firewall.ProtoUDP,
|
||||
Fragment: false,
|
||||
}
|
||||
|
||||
c := dummyCert{
|
||||
name: "host1",
|
||||
networks: []netip.Prefix{netip.MustParsePrefix("fd12::34/120")},
|
||||
groups: []string{"default-group"},
|
||||
issuer: "signer-shasum",
|
||||
}
|
||||
h := HostInfo{
|
||||
ConnectionState: &ConnectionState{
|
||||
peerCert: &cert.CachedCertificate{
|
||||
Certificate: &c,
|
||||
InvertedGroups: map[string]struct{}{"default-group": {}},
|
||||
},
|
||||
},
|
||||
vpnAddrs: []netip.Addr{netip.MustParseAddr("fd12::34")},
|
||||
}
|
||||
h.buildNetworks(c.networks, c.unsafeNetworks)
|
||||
|
||||
fw := NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
||||
require.NoError(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"any"}, "", netip.Prefix{}, netip.Prefix{}, "", ""))
|
||||
cp := cert.NewCAPool()
|
||||
|
||||
// Drop outbound
|
||||
assert.Equal(t, ErrNoMatchingRule, fw.Drop(p, false, &h, cp, nil))
|
||||
// Allow inbound
|
||||
resetConntrack(fw)
|
||||
require.NoError(t, fw.Drop(p, true, &h, cp, nil))
|
||||
// Allow outbound because conntrack
|
||||
require.NoError(t, fw.Drop(p, false, &h, cp, nil))
|
||||
|
||||
// test remote mismatch
|
||||
oldRemote := p.RemoteAddr
|
||||
p.RemoteAddr = netip.MustParseAddr("fd12::56")
|
||||
assert.Equal(t, fw.Drop(p, false, &h, cp, nil), ErrInvalidRemoteIP)
|
||||
p.RemoteAddr = oldRemote
|
||||
|
||||
// ensure signer doesn't get in the way of group checks
|
||||
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
||||
require.NoError(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"nope"}, "", netip.Prefix{}, netip.Prefix{}, "", "signer-shasum"))
|
||||
require.NoError(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"default-group"}, "", netip.Prefix{}, netip.Prefix{}, "", "signer-shasum-bad"))
|
||||
assert.Equal(t, fw.Drop(p, true, &h, cp, nil), ErrNoMatchingRule)
|
||||
|
||||
// test caSha doesn't drop on match
|
||||
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
||||
require.NoError(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"nope"}, "", netip.Prefix{}, netip.Prefix{}, "", "signer-shasum-bad"))
|
||||
require.NoError(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"default-group"}, "", netip.Prefix{}, netip.Prefix{}, "", "signer-shasum"))
|
||||
require.NoError(t, fw.Drop(p, true, &h, cp, nil))
|
||||
|
||||
// ensure ca name doesn't get in the way of group checks
|
||||
cp.CAs["signer-shasum"] = &cert.CachedCertificate{Certificate: &dummyCert{name: "ca-good"}}
|
||||
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
||||
require.NoError(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"nope"}, "", netip.Prefix{}, netip.Prefix{}, "ca-good", ""))
|
||||
require.NoError(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"default-group"}, "", netip.Prefix{}, netip.Prefix{}, "ca-good-bad", ""))
|
||||
assert.Equal(t, fw.Drop(p, true, &h, cp, nil), ErrNoMatchingRule)
|
||||
|
||||
// test caName doesn't drop on match
|
||||
cp.CAs["signer-shasum"] = &cert.CachedCertificate{Certificate: &dummyCert{name: "ca-good"}}
|
||||
fw = NewFirewall(l, time.Second, time.Minute, time.Hour, &c)
|
||||
require.NoError(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"nope"}, "", netip.Prefix{}, netip.Prefix{}, "ca-good-bad", ""))
|
||||
require.NoError(t, fw.AddRule(true, firewall.ProtoAny, 0, 0, []string{"default-group"}, "", netip.Prefix{}, netip.Prefix{}, "ca-good", ""))
|
||||
require.NoError(t, fw.Drop(p, true, &h, cp, nil))
|
||||
}
|
||||
|
||||
func BenchmarkFirewallTable_match(b *testing.B) {
|
||||
f := &Firewall{}
|
||||
ft := FirewallTable{
|
||||
@@ -208,6 +306,10 @@ func BenchmarkFirewallTable_match(b *testing.B) {
|
||||
pfix := netip.MustParsePrefix("172.1.1.1/32")
|
||||
_ = ft.TCP.addRule(f, 10, 10, []string{"good-group"}, "good-host", pfix, netip.Prefix{}, "", "")
|
||||
_ = ft.TCP.addRule(f, 100, 100, []string{"good-group"}, "good-host", netip.Prefix{}, pfix, "", "")
|
||||
|
||||
pfix6 := netip.MustParsePrefix("fd11::11/128")
|
||||
_ = ft.TCP.addRule(f, 10, 10, []string{"good-group"}, "good-host", pfix6, netip.Prefix{}, "", "")
|
||||
_ = ft.TCP.addRule(f, 100, 100, []string{"good-group"}, "good-host", netip.Prefix{}, pfix6, "", "")
|
||||
cp := cert.NewCAPool()
|
||||
|
||||
b.Run("fail on proto", func(b *testing.B) {
|
||||
@@ -239,6 +341,15 @@ func BenchmarkFirewallTable_match(b *testing.B) {
|
||||
assert.False(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 100, LocalAddr: ip.Addr()}, true, c, cp))
|
||||
}
|
||||
})
|
||||
b.Run("pass proto, port, fail on local CIDRv6", func(b *testing.B) {
|
||||
c := &cert.CachedCertificate{
|
||||
Certificate: &dummyCert{},
|
||||
}
|
||||
ip := netip.MustParsePrefix("fd99::99/128")
|
||||
for n := 0; n < b.N; n++ {
|
||||
assert.False(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 100, LocalAddr: ip.Addr()}, true, c, cp))
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("pass proto, port, any local CIDR, fail all group, name, and cidr", func(b *testing.B) {
|
||||
c := &cert.CachedCertificate{
|
||||
@@ -252,6 +363,18 @@ func BenchmarkFirewallTable_match(b *testing.B) {
|
||||
assert.False(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 10}, true, c, cp))
|
||||
}
|
||||
})
|
||||
b.Run("pass proto, port, any local CIDRv6, fail all group, name, and cidr", func(b *testing.B) {
|
||||
c := &cert.CachedCertificate{
|
||||
Certificate: &dummyCert{
|
||||
name: "nope",
|
||||
networks: []netip.Prefix{netip.MustParsePrefix("fd99::99/128")},
|
||||
},
|
||||
InvertedGroups: map[string]struct{}{"nope": {}},
|
||||
}
|
||||
for n := 0; n < b.N; n++ {
|
||||
assert.False(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 10}, true, c, cp))
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("pass proto, port, specific local CIDR, fail all group, name, and cidr", func(b *testing.B) {
|
||||
c := &cert.CachedCertificate{
|
||||
@@ -265,6 +388,18 @@ func BenchmarkFirewallTable_match(b *testing.B) {
|
||||
assert.False(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 100, LocalAddr: pfix.Addr()}, true, c, cp))
|
||||
}
|
||||
})
|
||||
b.Run("pass proto, port, specific local CIDRv6, fail all group, name, and cidr", func(b *testing.B) {
|
||||
c := &cert.CachedCertificate{
|
||||
Certificate: &dummyCert{
|
||||
name: "nope",
|
||||
networks: []netip.Prefix{netip.MustParsePrefix("fd99:99/128")},
|
||||
},
|
||||
InvertedGroups: map[string]struct{}{"nope": {}},
|
||||
}
|
||||
for n := 0; n < b.N; n++ {
|
||||
assert.False(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 100, LocalAddr: pfix6.Addr()}, true, c, cp))
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("pass on group on any local cidr", func(b *testing.B) {
|
||||
c := &cert.CachedCertificate{
|
||||
@@ -289,6 +424,17 @@ func BenchmarkFirewallTable_match(b *testing.B) {
|
||||
assert.True(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 100, LocalAddr: pfix.Addr()}, true, c, cp))
|
||||
}
|
||||
})
|
||||
b.Run("pass on group on specific local cidr6", func(b *testing.B) {
|
||||
c := &cert.CachedCertificate{
|
||||
Certificate: &dummyCert{
|
||||
name: "nope",
|
||||
},
|
||||
InvertedGroups: map[string]struct{}{"good-group": {}},
|
||||
}
|
||||
for n := 0; n < b.N; n++ {
|
||||
assert.True(b, ft.match(firewall.Packet{Protocol: firewall.ProtoTCP, LocalPort: 100, LocalAddr: pfix6.Addr()}, true, c, cp))
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("pass on name", func(b *testing.B) {
|
||||
c := &cert.CachedCertificate{
|
||||
@@ -447,6 +593,42 @@ func TestFirewall_Drop3(t *testing.T) {
|
||||
require.NoError(t, fw.Drop(p, true, &h1, cp, nil))
|
||||
}
|
||||
|
||||
func TestFirewall_Drop3V6(t *testing.T) {
|
||||
l := test.NewLogger()
|
||||
ob := &bytes.Buffer{}
|
||||
l.SetOutput(ob)
|
||||
|
||||
p := firewall.Packet{
|
||||
LocalAddr: netip.MustParseAddr("fd12::34"),
|
||||
RemoteAddr: netip.MustParseAddr("fd12::34"),
|
||||
LocalPort: 1,
|
||||
RemotePort: 1,
|
||||
Protocol: firewall.ProtoUDP,
|
||||
Fragment: false,
|
||||
}
|
||||
|
||||
network := netip.MustParsePrefix("fd12::34/120")
|
||||
c := cert.CachedCertificate{
|
||||
Certificate: &dummyCert{
|
||||
name: "host-owner",
|
||||
networks: []netip.Prefix{network},
|
||||
},
|
||||
}
|
||||
h := HostInfo{
|
||||
ConnectionState: &ConnectionState{
|
||||
peerCert: &c,
|
||||
},
|
||||
vpnAddrs: []netip.Addr{network.Addr()},
|
||||
}
|
||||
h.buildNetworks(c.Certificate.Networks(), c.Certificate.UnsafeNetworks())
|
||||
|
||||
// Test a remote address match
|
||||
fw := NewFirewall(l, time.Second, time.Minute, time.Hour, c.Certificate)
|
||||
cp := cert.NewCAPool()
|
||||
require.NoError(t, fw.AddRule(true, firewall.ProtoAny, 1, 1, []string{}, "", netip.MustParsePrefix("fd12::34/120"), netip.Prefix{}, "", ""))
|
||||
require.NoError(t, fw.Drop(p, true, &h, cp, nil))
|
||||
}
|
||||
|
||||
func TestFirewall_DropConntrackReload(t *testing.T) {
|
||||
l := test.NewLogger()
|
||||
ob := &bytes.Buffer{}
|
||||
@@ -727,6 +909,21 @@ func TestAddFirewallRulesFromConfig(t *testing.T) {
|
||||
require.NoError(t, AddFirewallRulesFromConfig(l, true, conf, mf))
|
||||
assert.Equal(t, addRuleCall{incoming: true, proto: firewall.ProtoAny, startPort: 1, endPort: 1, groups: nil, ip: netip.Prefix{}, localIp: cidr}, mf.lastCall)
|
||||
|
||||
// Test adding rule with cidr ipv6
|
||||
cidr6 := netip.MustParsePrefix("fd00::/8")
|
||||
conf = config.NewC(l)
|
||||
mf = &mockFirewall{}
|
||||
conf.Settings["firewall"] = map[string]any{"inbound": []any{map[string]any{"port": "1", "proto": "any", "cidr": cidr6.String()}}}
|
||||
require.NoError(t, AddFirewallRulesFromConfig(l, true, conf, mf))
|
||||
assert.Equal(t, addRuleCall{incoming: true, proto: firewall.ProtoAny, startPort: 1, endPort: 1, groups: nil, ip: cidr6, localIp: netip.Prefix{}}, mf.lastCall)
|
||||
|
||||
// Test adding rule with local_cidr ipv6
|
||||
conf = config.NewC(l)
|
||||
mf = &mockFirewall{}
|
||||
conf.Settings["firewall"] = map[string]any{"inbound": []any{map[string]any{"port": "1", "proto": "any", "local_cidr": cidr6.String()}}}
|
||||
require.NoError(t, AddFirewallRulesFromConfig(l, true, conf, mf))
|
||||
assert.Equal(t, addRuleCall{incoming: true, proto: firewall.ProtoAny, startPort: 1, endPort: 1, groups: nil, ip: netip.Prefix{}, localIp: cidr6}, mf.lastCall)
|
||||
|
||||
// Test adding rule with ca_sha
|
||||
conf = config.NewC(l)
|
||||
mf = &mockFirewall{}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/slackhq/nebula/cert"
|
||||
"github.com/slackhq/nebula/header"
|
||||
"github.com/slackhq/nebula/udp"
|
||||
)
|
||||
|
||||
// NOISE IX Handshakes
|
||||
@@ -70,15 +69,6 @@ func ixHandshakeStage0(f *Interface, hh *HandshakeHostInfo) bool {
|
||||
},
|
||||
}
|
||||
|
||||
if f.multiPort.Tx || f.multiPort.Rx {
|
||||
hs.Details.InitiatorMultiPort = &MultiPortDetails{
|
||||
RxSupported: f.multiPort.Rx,
|
||||
TxSupported: f.multiPort.Tx,
|
||||
BasePort: uint32(f.multiPort.TxBasePort),
|
||||
TotalPorts: uint32(f.multiPort.TxPorts),
|
||||
}
|
||||
}
|
||||
|
||||
hsBytes, err := hs.Marshal()
|
||||
if err != nil {
|
||||
f.l.WithError(err).WithField("vpnAddrs", hh.hostinfo.vpnAddrs).
|
||||
@@ -251,26 +241,6 @@ func ixHandshakeStage1(f *Interface, addr netip.AddrPort, via *ViaSender, packet
|
||||
return
|
||||
}
|
||||
|
||||
var multiportTx, multiportRx bool
|
||||
if f.multiPort.Rx || f.multiPort.Tx {
|
||||
if hs.Details.InitiatorMultiPort != nil {
|
||||
multiportTx = hs.Details.InitiatorMultiPort.RxSupported && f.multiPort.Tx
|
||||
multiportRx = hs.Details.InitiatorMultiPort.TxSupported && f.multiPort.Rx
|
||||
}
|
||||
|
||||
hs.Details.ResponderMultiPort = &MultiPortDetails{
|
||||
TxSupported: f.multiPort.Tx,
|
||||
RxSupported: f.multiPort.Rx,
|
||||
BasePort: uint32(f.multiPort.TxBasePort),
|
||||
TotalPorts: uint32(f.multiPort.TxPorts),
|
||||
}
|
||||
}
|
||||
if hs.Details.InitiatorMultiPort != nil && hs.Details.InitiatorMultiPort.BasePort != uint32(addr.Port()) {
|
||||
// The other side sent us a handshake from a different port, make sure
|
||||
// we send responses back to the BasePort
|
||||
addr = netip.AddrPortFrom(addr.Addr(), uint16(hs.Details.InitiatorMultiPort.BasePort))
|
||||
}
|
||||
|
||||
hostinfo := &HostInfo{
|
||||
ConnectionState: ci,
|
||||
localIndexId: myIndex,
|
||||
@@ -278,8 +248,6 @@ func ixHandshakeStage1(f *Interface, addr netip.AddrPort, via *ViaSender, packet
|
||||
vpnAddrs: vpnAddrs,
|
||||
HandshakePacket: make(map[uint8][]byte, 0),
|
||||
lastHandshakeTime: hs.Details.Time,
|
||||
multiportTx: multiportTx,
|
||||
multiportRx: multiportRx,
|
||||
relayState: RelayState{
|
||||
relays: nil,
|
||||
relayForByAddr: map[netip.Addr]*Relay{},
|
||||
@@ -294,7 +262,6 @@ func ixHandshakeStage1(f *Interface, addr netip.AddrPort, via *ViaSender, packet
|
||||
WithField("issuer", issuer).
|
||||
WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
|
||||
WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
|
||||
WithField("multiportTx", multiportTx).WithField("multiportRx", multiportRx).
|
||||
Info("Handshake message received")
|
||||
|
||||
hs.Details.ResponderIndex = myIndex
|
||||
@@ -371,10 +338,6 @@ func ixHandshakeStage1(f *Interface, addr netip.AddrPort, via *ViaSender, packet
|
||||
if err != nil {
|
||||
switch err {
|
||||
case ErrAlreadySeen:
|
||||
if hostinfo.multiportRx {
|
||||
// The other host is sending to us with multiport, so only grab the IP
|
||||
addr = netip.AddrPortFrom(addr.Addr(), hostinfo.remote.Port())
|
||||
}
|
||||
// Update remote if preferred
|
||||
if existing.SetRemoteIfPreferred(f.hostMap, addr) {
|
||||
// Send a test packet to ensure the other side has also switched to
|
||||
@@ -385,14 +348,7 @@ func ixHandshakeStage1(f *Interface, addr netip.AddrPort, via *ViaSender, packet
|
||||
msg = existing.HandshakePacket[2]
|
||||
f.messageMetrics.Tx(header.Handshake, header.MessageSubType(msg[1]), 1)
|
||||
if addr.IsValid() {
|
||||
if multiportTx {
|
||||
// TODO remove alloc here
|
||||
raw := make([]byte, len(msg)+udp.RawOverhead)
|
||||
copy(raw[udp.RawOverhead:], msg)
|
||||
err = f.udpRaw.WriteTo(raw, udp.RandomSendPort.UDPSendPort(f.multiPort.TxPorts), addr)
|
||||
} else {
|
||||
err = f.outside.WriteTo(msg, addr)
|
||||
}
|
||||
err := f.outside.WriteTo(msg, addr)
|
||||
if err != nil {
|
||||
f.l.WithField("vpnAddrs", existing.vpnAddrs).WithField("udpAddr", addr).
|
||||
WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("cached", true).
|
||||
@@ -461,14 +417,7 @@ func ixHandshakeStage1(f *Interface, addr netip.AddrPort, via *ViaSender, packet
|
||||
// Do the send
|
||||
f.messageMetrics.Tx(header.Handshake, header.MessageSubType(msg[1]), 1)
|
||||
if addr.IsValid() {
|
||||
if multiportTx {
|
||||
// TODO remove alloc here
|
||||
raw := make([]byte, len(msg)+udp.RawOverhead)
|
||||
copy(raw[udp.RawOverhead:], msg)
|
||||
err = f.udpRaw.WriteTo(raw, udp.RandomSendPort.UDPSendPort(f.multiPort.TxPorts), addr)
|
||||
} else {
|
||||
err = f.outside.WriteTo(msg, addr)
|
||||
}
|
||||
err = f.outside.WriteTo(msg, addr)
|
||||
if err != nil {
|
||||
f.l.WithField("vpnAddrs", vpnAddrs).WithField("udpAddr", addr).
|
||||
WithField("certName", certName).
|
||||
@@ -564,20 +513,6 @@ func ixHandshakeStage2(f *Interface, addr netip.AddrPort, via *ViaSender, hh *Ha
|
||||
return true
|
||||
}
|
||||
|
||||
if (f.multiPort.Tx || f.multiPort.Rx) && hs.Details.ResponderMultiPort != nil {
|
||||
hostinfo.multiportTx = hs.Details.ResponderMultiPort.RxSupported && f.multiPort.Tx
|
||||
hostinfo.multiportRx = hs.Details.ResponderMultiPort.TxSupported && f.multiPort.Rx
|
||||
}
|
||||
|
||||
if hs.Details.ResponderMultiPort != nil && hs.Details.ResponderMultiPort.BasePort != uint32(addr.Port()) {
|
||||
// The other side sent us a handshake from a different port, make sure
|
||||
// we send responses back to the BasePort
|
||||
addr = netip.AddrPortFrom(
|
||||
addr.Addr(),
|
||||
uint16(hs.Details.ResponderMultiPort.BasePort),
|
||||
)
|
||||
}
|
||||
|
||||
rc, err := cert.Recombine(cert.Version(hs.Details.CertVersion), hs.Details.Cert, ci.H.PeerStatic(), ci.Curve())
|
||||
if err != nil {
|
||||
f.l.WithError(err).WithField("udpAddr", addr).
|
||||
@@ -709,7 +644,6 @@ func ixHandshakeStage2(f *Interface, addr netip.AddrPort, via *ViaSender, hh *Ha
|
||||
WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).
|
||||
WithField("durationNs", duration).
|
||||
WithField("sentCachedPackets", len(hh.packetStore)).
|
||||
WithField("multiportTx", hostinfo.multiportTx).WithField("multiportRx", hostinfo.multiportRx).
|
||||
Info("Handshake message received")
|
||||
|
||||
// Build up the radix for the firewall if we have subnets in the cert
|
||||
|
||||
@@ -61,9 +61,6 @@ type HandshakeManager struct {
|
||||
f *Interface
|
||||
l *logrus.Logger
|
||||
|
||||
multiPort MultiPortConfig
|
||||
udpRaw *udp.RawConn
|
||||
|
||||
// can be used to trigger outbound handshake for the given vpnIp
|
||||
trigger chan netip.Addr
|
||||
}
|
||||
@@ -239,7 +236,6 @@ func (hm *HandshakeManager) handleOutbound(vpnIp netip.Addr, lighthouseTriggered
|
||||
|
||||
// Send the handshake to all known ips, stage 2 takes care of assigning the hostinfo.remote based on the first to reply
|
||||
var sentTo []netip.AddrPort
|
||||
var sentMultiport bool
|
||||
hostinfo.remotes.ForEach(hm.mainHostMap.GetPreferredRanges(), func(addr netip.AddrPort, _ bool) {
|
||||
hm.messageMetrics.Tx(header.Handshake, header.MessageSubType(hostinfo.HandshakePacket[0][1]), 1)
|
||||
err := hm.outside.WriteTo(hostinfo.HandshakePacket[0], addr)
|
||||
@@ -252,27 +248,6 @@ func (hm *HandshakeManager) handleOutbound(vpnIp netip.Addr, lighthouseTriggered
|
||||
} else {
|
||||
sentTo = append(sentTo, addr)
|
||||
}
|
||||
|
||||
// Attempt a multiport handshake if we are past the TxHandshakeDelay attempts
|
||||
if hm.multiPort.TxHandshake && hm.udpRaw != nil && hh.counter >= hm.multiPort.TxHandshakeDelay {
|
||||
sentMultiport = true
|
||||
// We need to re-allocate with 8 bytes at the start of SOCK_RAW
|
||||
raw := hostinfo.HandshakePacket[0x80]
|
||||
if raw == nil {
|
||||
raw = make([]byte, len(hostinfo.HandshakePacket[0])+udp.RawOverhead)
|
||||
copy(raw[udp.RawOverhead:], hostinfo.HandshakePacket[0])
|
||||
hostinfo.HandshakePacket[0x80] = raw
|
||||
}
|
||||
|
||||
hm.messageMetrics.Tx(header.Handshake, header.MessageSubType(hostinfo.HandshakePacket[0][1]), 1)
|
||||
err = hm.udpRaw.WriteTo(raw, udp.RandomSendPort.UDPSendPort(hm.multiPort.TxPorts), addr)
|
||||
if err != nil {
|
||||
hostinfo.logger(hm.l).WithField("udpAddr", addr).
|
||||
WithField("initiatorIndex", hostinfo.localIndexId).
|
||||
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
|
||||
WithError(err).Error("Failed to send handshake message")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Don't be too noisy or confusing if we fail to send a handshake - if we don't get through we'll eventually log a timeout,
|
||||
@@ -281,7 +256,6 @@ func (hm *HandshakeManager) handleOutbound(vpnIp netip.Addr, lighthouseTriggered
|
||||
hostinfo.logger(hm.l).WithField("udpAddrs", sentTo).
|
||||
WithField("initiatorIndex", hostinfo.localIndexId).
|
||||
WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
|
||||
WithField("multiportHandshake", sentMultiport).
|
||||
Info("Handshake message sent")
|
||||
} else if hm.l.Level >= logrus.DebugLevel {
|
||||
hostinfo.logger(hm.l).WithField("udpAddrs", sentTo).
|
||||
|
||||
18
hostmap.go
18
hostmap.go
@@ -17,12 +17,10 @@ import (
|
||||
"github.com/slackhq/nebula/header"
|
||||
)
|
||||
|
||||
// const ProbeLen = 100
|
||||
const defaultPromoteEvery = 1000 // Count of packets sent before we try moving a tunnel to a preferred underlay ip address
|
||||
const defaultReQueryEvery = 5000 // Count of packets sent before re-querying a hostinfo to the lighthouse
|
||||
const defaultReQueryWait = time.Minute // Minimum amount of seconds to wait before re-querying a hostinfo the lighthouse. Evaluated every ReQueryEvery
|
||||
const MaxRemotes = 10
|
||||
const maxRecvError = 4
|
||||
|
||||
// MaxHostInfosPerVpnIp is the max number of hostinfos we will track for a given vpn ip
|
||||
// 5 allows for an initial handshake and each host pair re-handshaking twice
|
||||
@@ -225,19 +223,12 @@ type HostInfo struct {
|
||||
// vpnAddrs is a list of vpn addresses assigned to this host that are within our own vpn networks
|
||||
// The host may have other vpn addresses that are outside our
|
||||
// vpn networks but were removed because they are not usable
|
||||
vpnAddrs []netip.Addr
|
||||
recvError atomic.Uint32
|
||||
vpnAddrs []netip.Addr
|
||||
|
||||
// networks are both all vpn and unsafe networks assigned to this host
|
||||
networks *bart.Lite
|
||||
relayState RelayState
|
||||
|
||||
// If true, we should send to this remote using multiport
|
||||
multiportTx bool
|
||||
|
||||
// If true, we will receive from this remote using multiport
|
||||
multiportRx bool
|
||||
|
||||
// HandshakePacket records the packets used to create this hostinfo
|
||||
// We need these to avoid replayed handshake packets creating new hostinfos which causes churn
|
||||
HandshakePacket map[uint8][]byte
|
||||
@@ -739,13 +730,6 @@ func (i *HostInfo) SetRemoteIfPreferred(hm *HostMap, newRemote netip.AddrPort) b
|
||||
return false
|
||||
}
|
||||
|
||||
func (i *HostInfo) RecvErrorExceeded() bool {
|
||||
if i.recvError.Add(1) >= maxRecvError {
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (i *HostInfo) buildNetworks(networks, unsafeNetworks []netip.Prefix) {
|
||||
if len(networks) == 1 && len(unsafeNetworks) == 0 {
|
||||
// Simple case, no CIDRTree needed
|
||||
|
||||
46
inside.go
46
inside.go
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/slackhq/nebula/iputil"
|
||||
"github.com/slackhq/nebula/noiseutil"
|
||||
"github.com/slackhq/nebula/routing"
|
||||
"github.com/slackhq/nebula/udp"
|
||||
)
|
||||
|
||||
func (f *Interface) consumeInsidePacket(packet []byte, fwPacket *firewall.Packet, nb, out []byte, q int, localCache firewall.ConntrackCache) {
|
||||
@@ -69,7 +68,7 @@ func (f *Interface) consumeInsidePacket(packet []byte, fwPacket *firewall.Packet
|
||||
|
||||
dropReason := f.firewall.Drop(*fwPacket, false, hostinfo, f.pki.GetCAPool(), localCache)
|
||||
if dropReason == nil {
|
||||
f.sendNoMetrics(header.Message, 0, hostinfo.ConnectionState, hostinfo, netip.AddrPort{}, packet, nb, out, q, fwPacket)
|
||||
f.sendNoMetrics(header.Message, 0, hostinfo.ConnectionState, hostinfo, netip.AddrPort{}, packet, nb, out, q)
|
||||
|
||||
} else {
|
||||
f.rejectInside(packet, out, q)
|
||||
@@ -118,7 +117,7 @@ func (f *Interface) rejectOutside(packet []byte, ci *ConnectionState, hostinfo *
|
||||
return
|
||||
}
|
||||
|
||||
f.sendNoMetrics(header.Message, 0, ci, hostinfo, netip.AddrPort{}, out, nb, packet, q, nil)
|
||||
f.sendNoMetrics(header.Message, 0, ci, hostinfo, netip.AddrPort{}, out, nb, packet, q)
|
||||
}
|
||||
|
||||
// Handshake will attempt to initiate a tunnel with the provided vpn address if it is within our vpn networks. This is a no-op if the tunnel is already established or being established
|
||||
@@ -229,7 +228,7 @@ func (f *Interface) sendMessageNow(t header.MessageType, st header.MessageSubTyp
|
||||
return
|
||||
}
|
||||
|
||||
f.sendNoMetrics(header.Message, st, hostinfo.ConnectionState, hostinfo, netip.AddrPort{}, p, nb, out, 0, nil)
|
||||
f.sendNoMetrics(header.Message, st, hostinfo.ConnectionState, hostinfo, netip.AddrPort{}, p, nb, out, 0)
|
||||
}
|
||||
|
||||
// SendMessageToVpnAddr handles real addr:port lookup and sends to the current best known address for vpnAddr
|
||||
@@ -259,12 +258,12 @@ func (f *Interface) SendMessageToHostInfo(t header.MessageType, st header.Messag
|
||||
|
||||
func (f *Interface) send(t header.MessageType, st header.MessageSubType, ci *ConnectionState, hostinfo *HostInfo, p, nb, out []byte) {
|
||||
f.messageMetrics.Tx(t, st, 1)
|
||||
f.sendNoMetrics(t, st, ci, hostinfo, netip.AddrPort{}, p, nb, out, 0, nil)
|
||||
f.sendNoMetrics(t, st, ci, hostinfo, netip.AddrPort{}, p, nb, out, 0)
|
||||
}
|
||||
|
||||
func (f *Interface) sendTo(t header.MessageType, st header.MessageSubType, ci *ConnectionState, hostinfo *HostInfo, remote netip.AddrPort, p, nb, out []byte) {
|
||||
f.messageMetrics.Tx(t, st, 1)
|
||||
f.sendNoMetrics(t, st, ci, hostinfo, remote, p, nb, out, 0, nil)
|
||||
f.sendNoMetrics(t, st, ci, hostinfo, remote, p, nb, out, 0)
|
||||
}
|
||||
|
||||
// SendVia sends a payload through a Relay tunnel. No authentication or encryption is done
|
||||
@@ -332,27 +331,10 @@ func (f *Interface) SendVia(via *HostInfo,
|
||||
f.connectionManager.RelayUsed(relay.LocalIndex)
|
||||
}
|
||||
|
||||
func (f *Interface) sendNoMetrics(t header.MessageType, st header.MessageSubType, ci *ConnectionState, hostinfo *HostInfo, remote netip.AddrPort, p, nb, out []byte, q int, udpPortGetter udp.SendPortGetter) {
|
||||
func (f *Interface) sendNoMetrics(t header.MessageType, st header.MessageSubType, ci *ConnectionState, hostinfo *HostInfo, remote netip.AddrPort, p, nb, out []byte, q int) {
|
||||
if ci.eKey == nil {
|
||||
return
|
||||
}
|
||||
|
||||
multiport := f.multiPort.Tx && hostinfo.multiportTx
|
||||
rawOut := out
|
||||
if multiport {
|
||||
if len(out) < udp.RawOverhead {
|
||||
// NOTE: This is because some spots in the code send us `out[:0]`, so
|
||||
// we need to expand the slice back out to get our 8 bytes back.
|
||||
out = out[:udp.RawOverhead]
|
||||
}
|
||||
// Preserve bytes needed for the raw socket
|
||||
out = out[udp.RawOverhead:]
|
||||
|
||||
if udpPortGetter == nil {
|
||||
udpPortGetter = udp.RandomSendPort
|
||||
}
|
||||
}
|
||||
|
||||
useRelay := !remote.IsValid() && !hostinfo.remote.IsValid()
|
||||
fullOut := out
|
||||
|
||||
@@ -402,25 +384,13 @@ func (f *Interface) sendNoMetrics(t header.MessageType, st header.MessageSubType
|
||||
}
|
||||
|
||||
if remote.IsValid() {
|
||||
if multiport {
|
||||
rawOut = rawOut[:len(out)+udp.RawOverhead]
|
||||
port := udpPortGetter.UDPSendPort(f.multiPort.TxPorts)
|
||||
err = f.udpRaw.WriteTo(rawOut, port, remote)
|
||||
} else {
|
||||
err = f.writers[q].WriteTo(out, remote)
|
||||
}
|
||||
err = f.writers[q].WriteTo(out, remote)
|
||||
if err != nil {
|
||||
hostinfo.logger(f.l).WithError(err).
|
||||
WithField("udpAddr", remote).Error("Failed to write outgoing packet")
|
||||
}
|
||||
} else if hostinfo.remote.IsValid() {
|
||||
if multiport {
|
||||
rawOut = rawOut[:len(out)+udp.RawOverhead]
|
||||
port := udpPortGetter.UDPSendPort(f.multiPort.TxPorts)
|
||||
err = f.udpRaw.WriteTo(rawOut, port, hostinfo.remote)
|
||||
} else {
|
||||
err = f.writers[q].WriteTo(out, hostinfo.remote)
|
||||
}
|
||||
err = f.writers[q].WriteTo(out, hostinfo.remote)
|
||||
if err != nil {
|
||||
hostinfo.logger(f.l).WithError(err).
|
||||
WithField("udpAddr", remote).Error("Failed to write outgoing packet")
|
||||
|
||||
23
interface.go
23
interface.go
@@ -87,9 +87,6 @@ type Interface struct {
|
||||
|
||||
writers []udp.Conn
|
||||
readers []io.ReadWriteCloser
|
||||
udpRaw *udp.RawConn
|
||||
|
||||
multiPort MultiPortConfig
|
||||
|
||||
metricHandshakes metrics.Histogram
|
||||
messageMetrics *MessageMetrics
|
||||
@@ -98,15 +95,6 @@ type Interface struct {
|
||||
l *logrus.Logger
|
||||
}
|
||||
|
||||
type MultiPortConfig struct {
|
||||
Tx bool
|
||||
Rx bool
|
||||
TxBasePort uint16
|
||||
TxPorts int
|
||||
TxHandshake bool
|
||||
TxHandshakeDelay int64
|
||||
}
|
||||
|
||||
type EncWriter interface {
|
||||
SendVia(via *HostInfo,
|
||||
relay *Relay,
|
||||
@@ -236,8 +224,6 @@ func (f *Interface) activate() {
|
||||
|
||||
metrics.GetOrRegisterGauge("routines", nil).Update(int64(f.routines))
|
||||
|
||||
metrics.GetOrRegisterGauge("multiport.tx_ports", nil).Update(int64(f.multiPort.TxPorts))
|
||||
|
||||
// Prepare n tun queues
|
||||
var reader io.ReadWriteCloser = f.inside
|
||||
for i := 0; i < f.routines; i++ {
|
||||
@@ -426,8 +412,6 @@ func (f *Interface) emitStats(ctx context.Context, i time.Duration) {
|
||||
|
||||
udpStats := udp.NewUDPStatsEmitter(f.writers)
|
||||
|
||||
var rawStats func()
|
||||
|
||||
certExpirationGauge := metrics.GetOrRegisterGauge("certificate.ttl_seconds", nil)
|
||||
certInitiatingVersion := metrics.GetOrRegisterGauge("certificate.initiating_version", nil)
|
||||
certMaxVersion := metrics.GetOrRegisterGauge("certificate.max_version", nil)
|
||||
@@ -446,13 +430,6 @@ func (f *Interface) emitStats(ctx context.Context, i time.Duration) {
|
||||
certExpirationGauge.Update(int64(defaultCrt.NotAfter().Sub(time.Now()) / time.Second))
|
||||
certInitiatingVersion.Update(int64(defaultCrt.Version()))
|
||||
|
||||
if f.udpRaw != nil {
|
||||
if rawStats == nil {
|
||||
rawStats = udp.NewRawStatsEmitter(f.udpRaw)
|
||||
}
|
||||
rawStats()
|
||||
}
|
||||
|
||||
// Report the max certificate version we are capable of using
|
||||
if certState.v2Cert != nil {
|
||||
certMaxVersion.Update(int64(certState.v2Cert.Version()))
|
||||
|
||||
211
lighthouse.go
211
lighthouse.go
@@ -21,9 +21,11 @@ import (
|
||||
"github.com/slackhq/nebula/header"
|
||||
"github.com/slackhq/nebula/udp"
|
||||
"github.com/slackhq/nebula/util"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
var ErrHostNotKnown = errors.New("host not known")
|
||||
var ErrBadDetailsVpnAddr = errors.New("invalid packet, malformed detailsVpnAddr")
|
||||
|
||||
type LightHouse struct {
|
||||
//TODO: We need a timer wheel to kick out vpnAddrs that haven't reported in a long time
|
||||
@@ -228,7 +230,7 @@ func (lh *LightHouse) reload(c *config.C, initial bool) error {
|
||||
lh.updateCancel()
|
||||
}
|
||||
|
||||
lh.StartUpdateWorker()
|
||||
lh.StartUpdateWorkerNetlink()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,11 +521,15 @@ func (lh *LightHouse) queryAndPrepMessage(vpnAddr netip.Addr, f func(*cache) (in
|
||||
}
|
||||
|
||||
func (lh *LightHouse) DeleteVpnAddrs(allVpnAddrs []netip.Addr) {
|
||||
// First we check the static mapping
|
||||
// and do nothing if it is there
|
||||
if _, ok := lh.GetStaticHostList()[allVpnAddrs[0]]; ok {
|
||||
return
|
||||
// First we check the static host map. If any of the VpnAddrs to be deleted are present, do nothing.
|
||||
staticList := lh.GetStaticHostList()
|
||||
for _, addr := range allVpnAddrs {
|
||||
if _, ok := staticList[addr]; ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// None of the VpnAddrs were present. Now we can do the deletes.
|
||||
lh.Lock()
|
||||
rm, ok := lh.addrMap[allVpnAddrs[0]]
|
||||
if ok {
|
||||
@@ -627,16 +633,24 @@ func (lh *LightHouse) addCalculatedRemotes(vpnAddr netip.Addr) bool {
|
||||
return len(calculatedV4) > 0 || len(calculatedV6) > 0
|
||||
}
|
||||
|
||||
// unlockedGetRemoteList
|
||||
// assumes you have the lh lock
|
||||
// unlockedGetRemoteList assumes you have the lh lock
|
||||
func (lh *LightHouse) unlockedGetRemoteList(allAddrs []netip.Addr) *RemoteList {
|
||||
am, ok := lh.addrMap[allAddrs[0]]
|
||||
if !ok {
|
||||
am = NewRemoteList(allAddrs, func(a netip.Addr) bool { return lh.shouldAdd(allAddrs[0], a) })
|
||||
for _, addr := range allAddrs {
|
||||
lh.addrMap[addr] = am
|
||||
// before we go and make a new remotelist, we need to make sure we don't have one for any of this set of vpnaddrs yet
|
||||
for i, addr := range allAddrs {
|
||||
am, ok := lh.addrMap[addr]
|
||||
if ok {
|
||||
if i != 0 {
|
||||
lh.addrMap[allAddrs[0]] = am
|
||||
}
|
||||
return am
|
||||
}
|
||||
}
|
||||
|
||||
//TODO lighthouse.remote_allow_ranges is almost certainly broken in a multiple-address-per-cert scenario
|
||||
am := NewRemoteList(allAddrs, func(a netip.Addr) bool { return lh.shouldAdd(allAddrs[0], a) })
|
||||
for _, addr := range allAddrs {
|
||||
lh.addrMap[addr] = am
|
||||
}
|
||||
return am
|
||||
}
|
||||
|
||||
@@ -698,14 +712,10 @@ func (lh *LightHouse) unlockedShouldAddV6(vpnAddr netip.Addr, to *V6AddrPort) bo
|
||||
}
|
||||
|
||||
func (lh *LightHouse) IsLighthouseAddr(vpnAddr netip.Addr) bool {
|
||||
if _, ok := lh.GetLighthouses()[vpnAddr]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
_, ok := lh.GetLighthouses()[vpnAddr]
|
||||
return ok
|
||||
}
|
||||
|
||||
// TODO: CERT-V2 IsLighthouseAddr should be sufficient, we just need to update the vpnAddrs for lighthouses after a handshake
|
||||
// so that we know all the lighthouse vpnAddrs, not just the ones we were configured to talk to initially
|
||||
func (lh *LightHouse) IsAnyLighthouseAddr(vpnAddr []netip.Addr) bool {
|
||||
l := lh.GetLighthouses()
|
||||
for _, a := range vpnAddr {
|
||||
@@ -836,10 +846,65 @@ func (lh *LightHouse) StartUpdateWorker() {
|
||||
}()
|
||||
}
|
||||
|
||||
func (lh *LightHouse) StartUpdateWorkerNetlink() {
|
||||
if lh.amLighthouse {
|
||||
return
|
||||
}
|
||||
|
||||
addrChan := make(chan netlink.AddrUpdate)
|
||||
doneChan := make(chan struct{})
|
||||
|
||||
err := netlink.AddrSubscribe(addrChan, doneChan)
|
||||
if err != nil {
|
||||
lh.l.WithError(err).Error("Failed to subscribe to address updates")
|
||||
return
|
||||
}
|
||||
|
||||
updateCtx, cancel := context.WithCancel(lh.ctx)
|
||||
lh.updateCancel = cancel
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
x := struct{}{}
|
||||
doneChan <- x
|
||||
}()
|
||||
|
||||
lh.SendUpdate()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-updateCtx.Done():
|
||||
return
|
||||
case a := <-addrChan:
|
||||
addr, ok := netip.AddrFromSlice(a.LinkAddress.IP)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
ones, _ := a.LinkAddress.Mask.Size()
|
||||
pfx := netip.PrefixFrom(addr, ones)
|
||||
lh.l.WithFields(logrus.Fields{
|
||||
"LinkAddress": pfx,
|
||||
"LinkIndex": a.LinkIndex,
|
||||
"Flags": a.Flags,
|
||||
"Scope": a.Scope,
|
||||
"NewAddr": a.NewAddr,
|
||||
"ValidLft": a.ValidLft,
|
||||
"PreferedLft": a.PreferedLft,
|
||||
}).Warn("Received address update")
|
||||
|
||||
shouldSend := a.PreferedLft != 0 //example criteria
|
||||
if shouldSend {
|
||||
lh.SendUpdate()
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (lh *LightHouse) SendUpdate() {
|
||||
var v4 []*V4AddrPort
|
||||
var v6 []*V6AddrPort
|
||||
|
||||
lh.l.Warn("sending lh update!")
|
||||
for _, e := range lh.GetAdvertiseAddrs() {
|
||||
if e.Addr().Is4() {
|
||||
v4 = append(v4, netAddrToProtoV4AddrPort(e.Addr(), e.Port()))
|
||||
@@ -1048,17 +1113,8 @@ func (lhh *LightHouseHandler) handleHostQuery(n *NebulaMeta, fromVpnAddrs []neti
|
||||
return
|
||||
}
|
||||
|
||||
useVersion := cert.Version1
|
||||
var queryVpnAddr netip.Addr
|
||||
if n.Details.OldVpnAddr != 0 {
|
||||
b := [4]byte{}
|
||||
binary.BigEndian.PutUint32(b[:], n.Details.OldVpnAddr)
|
||||
queryVpnAddr = netip.AddrFrom4(b)
|
||||
useVersion = 1
|
||||
} else if n.Details.VpnAddr != nil {
|
||||
queryVpnAddr = protoAddrToNetAddr(n.Details.VpnAddr)
|
||||
useVersion = 2
|
||||
} else {
|
||||
queryVpnAddr, useVersion, err := n.Details.GetVpnAddrAndVersion()
|
||||
if err != nil {
|
||||
if lhh.l.Level >= logrus.DebugLevel {
|
||||
lhh.l.WithField("from", fromVpnAddrs).WithField("details", n.Details).Debugln("Dropping malformed HostQuery")
|
||||
}
|
||||
@@ -1116,8 +1172,9 @@ func (lhh *LightHouseHandler) sendHostPunchNotification(n *NebulaMeta, fromVpnAd
|
||||
if ok {
|
||||
whereToPunch = newDest
|
||||
} else {
|
||||
//TODO: CERT-V2 this means the destination will have no addresses in common with the punch-ee
|
||||
//choosing to do nothing for now, but maybe we return an error?
|
||||
if lhh.l.Level >= logrus.DebugLevel {
|
||||
lhh.l.WithField("to", crt.Networks()).Debugln("unable to punch to host, no addresses in common")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1176,19 +1233,17 @@ func (lhh *LightHouseHandler) coalesceAnswers(v cert.Version, c *cache, n *Nebul
|
||||
if !r.Is4() {
|
||||
continue
|
||||
}
|
||||
|
||||
b = r.As4()
|
||||
n.Details.OldRelayVpnAddrs = append(n.Details.OldRelayVpnAddrs, binary.BigEndian.Uint32(b[:]))
|
||||
}
|
||||
|
||||
} else if v == cert.Version2 {
|
||||
for _, r := range c.relay.relay {
|
||||
n.Details.RelayVpnAddrs = append(n.Details.RelayVpnAddrs, netAddrToProtoAddr(r))
|
||||
}
|
||||
|
||||
} else {
|
||||
//TODO: CERT-V2 don't panic
|
||||
panic("unsupported version")
|
||||
if lhh.l.Level >= logrus.DebugLevel {
|
||||
lhh.l.WithField("version", v).Debug("unsupported protocol version")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1198,18 +1253,16 @@ func (lhh *LightHouseHandler) handleHostQueryReply(n *NebulaMeta, fromVpnAddrs [
|
||||
return
|
||||
}
|
||||
|
||||
lhh.lh.Lock()
|
||||
|
||||
var certVpnAddr netip.Addr
|
||||
if n.Details.OldVpnAddr != 0 {
|
||||
b := [4]byte{}
|
||||
binary.BigEndian.PutUint32(b[:], n.Details.OldVpnAddr)
|
||||
certVpnAddr = netip.AddrFrom4(b)
|
||||
} else if n.Details.VpnAddr != nil {
|
||||
certVpnAddr = protoAddrToNetAddr(n.Details.VpnAddr)
|
||||
certVpnAddr, _, err := n.Details.GetVpnAddrAndVersion()
|
||||
if err != nil {
|
||||
if lhh.l.Level >= logrus.DebugLevel {
|
||||
lhh.l.WithError(err).WithField("vpnAddrs", fromVpnAddrs).Error("dropping malformed HostQueryReply")
|
||||
}
|
||||
return
|
||||
}
|
||||
relays := n.Details.GetRelays()
|
||||
|
||||
lhh.lh.Lock()
|
||||
am := lhh.lh.unlockedGetRemoteList([]netip.Addr{certVpnAddr})
|
||||
am.Lock()
|
||||
lhh.lh.Unlock()
|
||||
@@ -1234,24 +1287,13 @@ func (lhh *LightHouseHandler) handleHostUpdateNotification(n *NebulaMeta, fromVp
|
||||
return
|
||||
}
|
||||
|
||||
var detailsVpnAddr netip.Addr
|
||||
useVersion := cert.Version1
|
||||
if n.Details.OldVpnAddr != 0 {
|
||||
b := [4]byte{}
|
||||
binary.BigEndian.PutUint32(b[:], n.Details.OldVpnAddr)
|
||||
detailsVpnAddr = netip.AddrFrom4(b)
|
||||
useVersion = cert.Version1
|
||||
} else if n.Details.VpnAddr != nil {
|
||||
detailsVpnAddr = protoAddrToNetAddr(n.Details.VpnAddr)
|
||||
useVersion = cert.Version2
|
||||
} else {
|
||||
detailsVpnAddr, useVersion, err := n.Details.GetVpnAddrAndVersion()
|
||||
if err != nil {
|
||||
if lhh.l.Level >= logrus.DebugLevel {
|
||||
lhh.l.WithField("details", n.Details).Debugf("dropping invalid HostUpdateNotification")
|
||||
lhh.l.WithField("details", n.Details).WithError(err).Debugln("dropping invalid HostUpdateNotification")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//TODO: CERT-V2 hosts with only v2 certs cannot provide their ipv6 addr when contacting the lighthouse via v4?
|
||||
//TODO: CERT-V2 why do we care about the vpnAddr in the packet? We know where it came from, right?
|
||||
//Simple check that the host sent this not someone else
|
||||
if !slices.Contains(fromVpnAddrs, detailsVpnAddr) {
|
||||
@@ -1308,8 +1350,16 @@ func (lhh *LightHouseHandler) handleHostPunchNotification(n *NebulaMeta, fromVpn
|
||||
return
|
||||
}
|
||||
|
||||
detailsVpnAddr, _, err := n.Details.GetVpnAddrAndVersion()
|
||||
if err != nil {
|
||||
if lhh.l.Level >= logrus.DebugLevel {
|
||||
lhh.l.WithField("details", n.Details).WithError(err).Debugln("dropping invalid HostPunchNotification")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
empty := []byte{0}
|
||||
punch := func(vpnPeer netip.AddrPort) {
|
||||
punch := func(vpnPeer netip.AddrPort, logVpnAddr netip.Addr) {
|
||||
if !vpnPeer.IsValid() {
|
||||
return
|
||||
}
|
||||
@@ -1321,48 +1371,31 @@ func (lhh *LightHouseHandler) handleHostPunchNotification(n *NebulaMeta, fromVpn
|
||||
}()
|
||||
|
||||
if lhh.l.Level >= logrus.DebugLevel {
|
||||
var logVpnAddr netip.Addr
|
||||
if n.Details.OldVpnAddr != 0 {
|
||||
b := [4]byte{}
|
||||
binary.BigEndian.PutUint32(b[:], n.Details.OldVpnAddr)
|
||||
logVpnAddr = netip.AddrFrom4(b)
|
||||
} else if n.Details.VpnAddr != nil {
|
||||
logVpnAddr = protoAddrToNetAddr(n.Details.VpnAddr)
|
||||
}
|
||||
lhh.l.Debugf("Punching on %v for %v", vpnPeer, logVpnAddr)
|
||||
}
|
||||
}
|
||||
|
||||
for _, a := range n.Details.V4AddrPorts {
|
||||
punch(protoV4AddrPortToNetAddrPort(a))
|
||||
punch(protoV4AddrPortToNetAddrPort(a), detailsVpnAddr)
|
||||
}
|
||||
|
||||
for _, a := range n.Details.V6AddrPorts {
|
||||
punch(protoV6AddrPortToNetAddrPort(a))
|
||||
punch(protoV6AddrPortToNetAddrPort(a), detailsVpnAddr)
|
||||
}
|
||||
|
||||
// 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.
|
||||
if lhh.lh.punchy.GetRespond() {
|
||||
var queryVpnAddr netip.Addr
|
||||
if n.Details.OldVpnAddr != 0 {
|
||||
b := [4]byte{}
|
||||
binary.BigEndian.PutUint32(b[:], n.Details.OldVpnAddr)
|
||||
queryVpnAddr = netip.AddrFrom4(b)
|
||||
} else if n.Details.VpnAddr != nil {
|
||||
queryVpnAddr = protoAddrToNetAddr(n.Details.VpnAddr)
|
||||
}
|
||||
|
||||
go func() {
|
||||
time.Sleep(lhh.lh.punchy.GetRespondDelay())
|
||||
if lhh.l.Level >= logrus.DebugLevel {
|
||||
lhh.l.Debugf("Sending a nebula test packet to vpn addr %s", queryVpnAddr)
|
||||
lhh.l.Debugf("Sending a nebula test packet to vpn addr %s", detailsVpnAddr)
|
||||
}
|
||||
//NOTE: we have to allocate a new output buffer here since we are spawning a new goroutine
|
||||
// for each punchBack packet. We should move this into a timerwheel or a single goroutine
|
||||
// managed by a channel.
|
||||
w.SendMessageToVpnAddr(header.Test, header.TestRequest, queryVpnAddr, []byte(""), make([]byte, 12, 12), make([]byte, mtu))
|
||||
w.SendMessageToVpnAddr(header.Test, header.TestRequest, detailsVpnAddr, []byte(""), make([]byte, 12, 12), make([]byte, mtu))
|
||||
}()
|
||||
}
|
||||
}
|
||||
@@ -1441,3 +1474,17 @@ func findNetworkUnion(prefixes []netip.Prefix, addrs []netip.Addr) (netip.Addr,
|
||||
}
|
||||
return netip.Addr{}, false
|
||||
}
|
||||
|
||||
func (d *NebulaMetaDetails) GetVpnAddrAndVersion() (netip.Addr, cert.Version, error) {
|
||||
if d.OldVpnAddr != 0 {
|
||||
b := [4]byte{}
|
||||
binary.BigEndian.PutUint32(b[:], d.OldVpnAddr)
|
||||
detailsVpnAddr := netip.AddrFrom4(b)
|
||||
return detailsVpnAddr, cert.Version1, nil
|
||||
} else if d.VpnAddr != nil {
|
||||
detailsVpnAddr := protoAddrToNetAddr(d.VpnAddr)
|
||||
return detailsVpnAddr, cert.Version2, nil
|
||||
} else {
|
||||
return netip.Addr{}, cert.Version1, ErrBadDetailsVpnAddr
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,3 +493,123 @@ func Test_findNetworkUnion(t *testing.T) {
|
||||
out, ok = findNetworkUnion([]netip.Prefix{fc00}, []netip.Addr{a1, afe81})
|
||||
assert.False(t, ok)
|
||||
}
|
||||
|
||||
func TestLighthouse_Dont_Delete_Static_Hosts(t *testing.T) {
|
||||
l := test.NewLogger()
|
||||
|
||||
myUdpAddr2 := netip.MustParseAddrPort("1.2.3.4:4242")
|
||||
|
||||
testSameHostNotStatic := netip.MustParseAddr("10.128.0.41")
|
||||
testStaticHost := netip.MustParseAddr("10.128.0.42")
|
||||
//myVpnIp := netip.MustParseAddr("10.128.0.2")
|
||||
|
||||
c := config.NewC(l)
|
||||
lh1 := "10.128.0.2"
|
||||
c.Settings["lighthouse"] = map[string]any{
|
||||
"hosts": []any{lh1},
|
||||
"interval": "1s",
|
||||
}
|
||||
|
||||
c.Settings["listen"] = map[string]any{"port": 4242}
|
||||
c.Settings["static_host_map"] = map[string]any{
|
||||
lh1: []any{"1.1.1.1:4242"},
|
||||
"10.128.0.42": []any{"1.2.3.4:4242"},
|
||||
}
|
||||
|
||||
myVpnNet := netip.MustParsePrefix("10.128.0.1/24")
|
||||
nt := new(bart.Lite)
|
||||
nt.Insert(myVpnNet)
|
||||
cs := &CertState{
|
||||
myVpnNetworks: []netip.Prefix{myVpnNet},
|
||||
myVpnNetworksTable: nt,
|
||||
}
|
||||
lh, err := NewLightHouseFromConfig(context.Background(), l, c, cs, nil, nil)
|
||||
require.NoError(t, err)
|
||||
lh.ifce = &mockEncWriter{}
|
||||
|
||||
//test that we actually have the static entry:
|
||||
out := lh.Query(testStaticHost)
|
||||
assert.NotNil(t, out)
|
||||
assert.Equal(t, out.vpnAddrs[0], testStaticHost)
|
||||
out.Rebuild([]netip.Prefix{}) //why tho
|
||||
assert.Equal(t, out.addrs[0], myUdpAddr2)
|
||||
|
||||
//bolt on a lower numbered primary IP
|
||||
am := lh.unlockedGetRemoteList([]netip.Addr{testStaticHost})
|
||||
am.vpnAddrs = []netip.Addr{testSameHostNotStatic, testStaticHost}
|
||||
lh.addrMap[testSameHostNotStatic] = am
|
||||
out.Rebuild([]netip.Prefix{}) //???
|
||||
|
||||
//test that we actually have the static entry:
|
||||
out = lh.Query(testStaticHost)
|
||||
assert.NotNil(t, out)
|
||||
assert.Equal(t, out.vpnAddrs[0], testSameHostNotStatic)
|
||||
assert.Equal(t, out.vpnAddrs[1], testStaticHost)
|
||||
assert.Equal(t, out.addrs[0], myUdpAddr2)
|
||||
|
||||
//test that we actually have the static entry for BOTH:
|
||||
out2 := lh.Query(testSameHostNotStatic)
|
||||
assert.Same(t, out2, out)
|
||||
|
||||
//now do the delete
|
||||
lh.DeleteVpnAddrs([]netip.Addr{testSameHostNotStatic, testStaticHost})
|
||||
//verify
|
||||
out = lh.Query(testSameHostNotStatic)
|
||||
assert.NotNil(t, out)
|
||||
if out == nil {
|
||||
t.Fatal("expected non-nil query for the static host")
|
||||
}
|
||||
assert.Equal(t, out.vpnAddrs[0], testSameHostNotStatic)
|
||||
assert.Equal(t, out.vpnAddrs[1], testStaticHost)
|
||||
assert.Equal(t, out.addrs[0], myUdpAddr2)
|
||||
}
|
||||
|
||||
func TestLighthouse_DeletesWork(t *testing.T) {
|
||||
l := test.NewLogger()
|
||||
|
||||
myUdpAddr2 := netip.MustParseAddrPort("1.2.3.4:4242")
|
||||
testHost := netip.MustParseAddr("10.128.0.42")
|
||||
|
||||
c := config.NewC(l)
|
||||
lh1 := "10.128.0.2"
|
||||
c.Settings["lighthouse"] = map[string]any{
|
||||
"hosts": []any{lh1},
|
||||
"interval": "1s",
|
||||
}
|
||||
|
||||
c.Settings["listen"] = map[string]any{"port": 4242}
|
||||
c.Settings["static_host_map"] = map[string]any{
|
||||
lh1: []any{"1.1.1.1:4242"},
|
||||
}
|
||||
|
||||
myVpnNet := netip.MustParsePrefix("10.128.0.1/24")
|
||||
nt := new(bart.Lite)
|
||||
nt.Insert(myVpnNet)
|
||||
cs := &CertState{
|
||||
myVpnNetworks: []netip.Prefix{myVpnNet},
|
||||
myVpnNetworksTable: nt,
|
||||
}
|
||||
lh, err := NewLightHouseFromConfig(context.Background(), l, c, cs, nil, nil)
|
||||
require.NoError(t, err)
|
||||
lh.ifce = &mockEncWriter{}
|
||||
|
||||
//insert the host
|
||||
am := lh.unlockedGetRemoteList([]netip.Addr{testHost})
|
||||
am.vpnAddrs = []netip.Addr{testHost}
|
||||
am.addrs = []netip.AddrPort{myUdpAddr2}
|
||||
lh.addrMap[testHost] = am
|
||||
am.Rebuild([]netip.Prefix{}) //???
|
||||
|
||||
//test that we actually have the entry:
|
||||
out := lh.Query(testHost)
|
||||
assert.NotNil(t, out)
|
||||
assert.Equal(t, out.vpnAddrs[0], testHost)
|
||||
out.Rebuild([]netip.Prefix{}) //why tho
|
||||
assert.Equal(t, out.addrs[0], myUdpAddr2)
|
||||
|
||||
//now do the delete
|
||||
lh.DeleteVpnAddrs([]netip.Addr{testHost})
|
||||
//verify
|
||||
out = lh.Query(testHost)
|
||||
assert.Nil(t, out)
|
||||
}
|
||||
|
||||
35
main.go
35
main.go
@@ -255,39 +255,6 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg
|
||||
ifce.writers = udpConns
|
||||
lightHouse.ifce = ifce
|
||||
|
||||
loadMultiPortConfig := func(c *config.C) {
|
||||
ifce.multiPort.Rx = c.GetBool("tun.multiport.rx_enabled", false)
|
||||
|
||||
tx := c.GetBool("tun.multiport.tx_enabled", false)
|
||||
|
||||
if tx && ifce.udpRaw == nil {
|
||||
ifce.udpRaw, err = udp.NewRawConn(l, c.GetString("listen.host", "0.0.0.0"), port, uint16(port))
|
||||
if err != nil {
|
||||
l.WithError(err).Error("Failed to get raw socket for tun.multiport.tx_enabled")
|
||||
ifce.udpRaw = nil
|
||||
tx = false
|
||||
}
|
||||
}
|
||||
|
||||
if tx {
|
||||
ifce.multiPort.TxBasePort = uint16(port)
|
||||
ifce.multiPort.TxPorts = c.GetInt("tun.multiport.tx_ports", 100)
|
||||
ifce.multiPort.TxHandshake = c.GetBool("tun.multiport.tx_handshake", false)
|
||||
ifce.multiPort.TxHandshakeDelay = int64(c.GetInt("tun.multiport.tx_handshake_delay", 2))
|
||||
ifce.udpRaw.ReloadConfig(c)
|
||||
}
|
||||
ifce.multiPort.Tx = tx
|
||||
|
||||
// TODO: if we upstream this, make this cleaner
|
||||
handshakeManager.udpRaw = ifce.udpRaw
|
||||
handshakeManager.multiPort = ifce.multiPort
|
||||
|
||||
l.WithField("multiPort", ifce.multiPort).Info("Multiport configured")
|
||||
}
|
||||
|
||||
loadMultiPortConfig(c)
|
||||
c.RegisterReloadCallback(loadMultiPortConfig)
|
||||
|
||||
ifce.RegisterConfigChangeCallbacks(c)
|
||||
ifce.reloadDisconnectInvalid(c)
|
||||
ifce.reloadSendRecvError(c)
|
||||
@@ -324,7 +291,7 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg
|
||||
sshStart,
|
||||
statsStart,
|
||||
dnsStart,
|
||||
lightHouse.StartUpdateWorker,
|
||||
lightHouse.StartUpdateWorkerNetlink,
|
||||
connManager.Start,
|
||||
}, nil
|
||||
}
|
||||
|
||||
515
nebula.pb.go
515
nebula.pb.go
@@ -124,7 +124,7 @@ func (x NebulaControl_MessageType) String() string {
|
||||
}
|
||||
|
||||
func (NebulaControl_MessageType) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2d65afa7693df5ef, []int{9, 0}
|
||||
return fileDescriptor_2d65afa7693df5ef, []int{8, 0}
|
||||
}
|
||||
|
||||
type NebulaMeta struct {
|
||||
@@ -541,90 +541,20 @@ func (m *NebulaHandshake) GetHmac() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
type MultiPortDetails struct {
|
||||
RxSupported bool `protobuf:"varint,1,opt,name=RxSupported,proto3" json:"RxSupported,omitempty"`
|
||||
TxSupported bool `protobuf:"varint,2,opt,name=TxSupported,proto3" json:"TxSupported,omitempty"`
|
||||
BasePort uint32 `protobuf:"varint,3,opt,name=BasePort,proto3" json:"BasePort,omitempty"`
|
||||
TotalPorts uint32 `protobuf:"varint,4,opt,name=TotalPorts,proto3" json:"TotalPorts,omitempty"`
|
||||
}
|
||||
|
||||
func (m *MultiPortDetails) Reset() { *m = MultiPortDetails{} }
|
||||
func (m *MultiPortDetails) String() string { return proto.CompactTextString(m) }
|
||||
func (*MultiPortDetails) ProtoMessage() {}
|
||||
func (*MultiPortDetails) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2d65afa7693df5ef, []int{7}
|
||||
}
|
||||
func (m *MultiPortDetails) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *MultiPortDetails) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_MultiPortDetails.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *MultiPortDetails) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_MultiPortDetails.Merge(m, src)
|
||||
}
|
||||
func (m *MultiPortDetails) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *MultiPortDetails) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_MultiPortDetails.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_MultiPortDetails proto.InternalMessageInfo
|
||||
|
||||
func (m *MultiPortDetails) GetRxSupported() bool {
|
||||
if m != nil {
|
||||
return m.RxSupported
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *MultiPortDetails) GetTxSupported() bool {
|
||||
if m != nil {
|
||||
return m.TxSupported
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *MultiPortDetails) GetBasePort() uint32 {
|
||||
if m != nil {
|
||||
return m.BasePort
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *MultiPortDetails) GetTotalPorts() uint32 {
|
||||
if m != nil {
|
||||
return m.TotalPorts
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type NebulaHandshakeDetails struct {
|
||||
Cert []byte `protobuf:"bytes,1,opt,name=Cert,proto3" json:"Cert,omitempty"`
|
||||
InitiatorIndex uint32 `protobuf:"varint,2,opt,name=InitiatorIndex,proto3" json:"InitiatorIndex,omitempty"`
|
||||
ResponderIndex uint32 `protobuf:"varint,3,opt,name=ResponderIndex,proto3" json:"ResponderIndex,omitempty"`
|
||||
Cookie uint64 `protobuf:"varint,4,opt,name=Cookie,proto3" json:"Cookie,omitempty"`
|
||||
Time uint64 `protobuf:"varint,5,opt,name=Time,proto3" json:"Time,omitempty"`
|
||||
CertVersion uint32 `protobuf:"varint,8,opt,name=CertVersion,proto3" json:"CertVersion,omitempty"`
|
||||
InitiatorMultiPort *MultiPortDetails `protobuf:"bytes,6,opt,name=InitiatorMultiPort,proto3" json:"InitiatorMultiPort,omitempty"`
|
||||
ResponderMultiPort *MultiPortDetails `protobuf:"bytes,7,opt,name=ResponderMultiPort,proto3" json:"ResponderMultiPort,omitempty"`
|
||||
Cert []byte `protobuf:"bytes,1,opt,name=Cert,proto3" json:"Cert,omitempty"`
|
||||
InitiatorIndex uint32 `protobuf:"varint,2,opt,name=InitiatorIndex,proto3" json:"InitiatorIndex,omitempty"`
|
||||
ResponderIndex uint32 `protobuf:"varint,3,opt,name=ResponderIndex,proto3" json:"ResponderIndex,omitempty"`
|
||||
Cookie uint64 `protobuf:"varint,4,opt,name=Cookie,proto3" json:"Cookie,omitempty"`
|
||||
Time uint64 `protobuf:"varint,5,opt,name=Time,proto3" json:"Time,omitempty"`
|
||||
CertVersion uint32 `protobuf:"varint,8,opt,name=CertVersion,proto3" json:"CertVersion,omitempty"`
|
||||
}
|
||||
|
||||
func (m *NebulaHandshakeDetails) Reset() { *m = NebulaHandshakeDetails{} }
|
||||
func (m *NebulaHandshakeDetails) String() string { return proto.CompactTextString(m) }
|
||||
func (*NebulaHandshakeDetails) ProtoMessage() {}
|
||||
func (*NebulaHandshakeDetails) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2d65afa7693df5ef, []int{8}
|
||||
return fileDescriptor_2d65afa7693df5ef, []int{7}
|
||||
}
|
||||
func (m *NebulaHandshakeDetails) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -695,20 +625,6 @@ func (m *NebulaHandshakeDetails) GetCertVersion() uint32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *NebulaHandshakeDetails) GetInitiatorMultiPort() *MultiPortDetails {
|
||||
if m != nil {
|
||||
return m.InitiatorMultiPort
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *NebulaHandshakeDetails) GetResponderMultiPort() *MultiPortDetails {
|
||||
if m != nil {
|
||||
return m.ResponderMultiPort
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NebulaControl struct {
|
||||
Type NebulaControl_MessageType `protobuf:"varint,1,opt,name=Type,proto3,enum=nebula.NebulaControl_MessageType" json:"Type,omitempty"`
|
||||
InitiatorRelayIndex uint32 `protobuf:"varint,2,opt,name=InitiatorRelayIndex,proto3" json:"InitiatorRelayIndex,omitempty"`
|
||||
@@ -723,7 +639,7 @@ func (m *NebulaControl) Reset() { *m = NebulaControl{} }
|
||||
func (m *NebulaControl) String() string { return proto.CompactTextString(m) }
|
||||
func (*NebulaControl) ProtoMessage() {}
|
||||
func (*NebulaControl) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2d65afa7693df5ef, []int{9}
|
||||
return fileDescriptor_2d65afa7693df5ef, []int{8}
|
||||
}
|
||||
func (m *NebulaControl) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -814,7 +730,6 @@ func init() {
|
||||
proto.RegisterType((*V6AddrPort)(nil), "nebula.V6AddrPort")
|
||||
proto.RegisterType((*NebulaPing)(nil), "nebula.NebulaPing")
|
||||
proto.RegisterType((*NebulaHandshake)(nil), "nebula.NebulaHandshake")
|
||||
proto.RegisterType((*MultiPortDetails)(nil), "nebula.MultiPortDetails")
|
||||
proto.RegisterType((*NebulaHandshakeDetails)(nil), "nebula.NebulaHandshakeDetails")
|
||||
proto.RegisterType((*NebulaControl)(nil), "nebula.NebulaControl")
|
||||
}
|
||||
@@ -822,61 +737,57 @@ func init() {
|
||||
func init() { proto.RegisterFile("nebula.proto", fileDescriptor_2d65afa7693df5ef) }
|
||||
|
||||
var fileDescriptor_2d65afa7693df5ef = []byte{
|
||||
// 864 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x56, 0x4f, 0x6f, 0xe3, 0x44,
|
||||
0x14, 0x8f, 0x1d, 0xe7, 0x4f, 0x5f, 0x9a, 0xac, 0x79, 0x15, 0x25, 0x5d, 0x89, 0x28, 0xf8, 0x50,
|
||||
0xad, 0x38, 0x64, 0x51, 0x5b, 0x56, 0x1c, 0xd9, 0x06, 0xa1, 0xac, 0xb4, 0xed, 0x96, 0x21, 0x14,
|
||||
0x89, 0x0b, 0x9a, 0xc6, 0x43, 0x63, 0xc5, 0xf1, 0x78, 0xed, 0x31, 0x6a, 0xbe, 0x05, 0xe2, 0xb3,
|
||||
0xf0, 0x21, 0xe0, 0xb6, 0x47, 0x4e, 0x08, 0xb5, 0x47, 0x8e, 0x7c, 0x01, 0x34, 0xe3, 0x7f, 0xe3,
|
||||
0xc4, 0x6c, 0x6f, 0xf3, 0xde, 0xef, 0xf7, 0x7b, 0xfe, 0xcd, 0x9b, 0x79, 0x93, 0xc0, 0x7e, 0xc0,
|
||||
0x6e, 0x12, 0x9f, 0x4e, 0xc2, 0x88, 0x0b, 0x8e, 0xed, 0x34, 0x72, 0xfe, 0x31, 0x01, 0x2e, 0xd5,
|
||||
0xf2, 0x82, 0x09, 0x8a, 0x27, 0x60, 0xcd, 0x37, 0x21, 0x1b, 0x1a, 0x63, 0xe3, 0xd9, 0xe0, 0x64,
|
||||
0x34, 0xc9, 0x34, 0x25, 0x63, 0x72, 0xc1, 0xe2, 0x98, 0xde, 0x32, 0xc9, 0x22, 0x8a, 0x8b, 0xa7,
|
||||
0xd0, 0xf9, 0x8a, 0x09, 0xea, 0xf9, 0xf1, 0xd0, 0x1c, 0x1b, 0xcf, 0x7a, 0x27, 0x47, 0xbb, 0xb2,
|
||||
0x8c, 0x40, 0x72, 0xa6, 0xf3, 0xaf, 0x01, 0x3d, 0xad, 0x14, 0x76, 0xc1, 0xba, 0xe4, 0x01, 0xb3,
|
||||
0x1b, 0xd8, 0x87, 0xbd, 0x19, 0x8f, 0xc5, 0x37, 0x09, 0x8b, 0x36, 0xb6, 0x81, 0x08, 0x83, 0x22,
|
||||
0x24, 0x2c, 0xf4, 0x37, 0xb6, 0x89, 0x4f, 0xe1, 0x50, 0xe6, 0xbe, 0x0b, 0x5d, 0x2a, 0xd8, 0x25,
|
||||
0x17, 0xde, 0x4f, 0xde, 0x82, 0x0a, 0x8f, 0x07, 0x76, 0x13, 0x8f, 0xe0, 0x43, 0x89, 0x5d, 0xf0,
|
||||
0x9f, 0x99, 0x5b, 0x81, 0xac, 0x1c, 0xba, 0x4a, 0x82, 0xc5, 0xb2, 0x02, 0xb5, 0x70, 0x00, 0x20,
|
||||
0xa1, 0xef, 0x97, 0x9c, 0xae, 0x3d, 0xbb, 0x8d, 0x07, 0xf0, 0xa4, 0x8c, 0xd3, 0xcf, 0x76, 0xa4,
|
||||
0xb3, 0x2b, 0x2a, 0x96, 0xd3, 0x25, 0x5b, 0xac, 0xec, 0xae, 0x74, 0x56, 0x84, 0x29, 0x65, 0x0f,
|
||||
0x3f, 0x86, 0xa3, 0x7a, 0x67, 0x2f, 0x17, 0x2b, 0x1b, 0x9c, 0x3f, 0x4c, 0xf8, 0x60, 0xa7, 0x29,
|
||||
0xe8, 0x00, 0xbc, 0xf1, 0xdd, 0xeb, 0x30, 0x78, 0xe9, 0xba, 0x91, 0x6a, 0x7d, 0xff, 0xdc, 0x1c,
|
||||
0x1a, 0x44, 0xcb, 0xe2, 0x31, 0x74, 0x72, 0x42, 0x5b, 0x35, 0x79, 0x3f, 0x6f, 0xb2, 0xcc, 0x91,
|
||||
0x1c, 0xc4, 0x09, 0xd8, 0x6f, 0x7c, 0x97, 0x30, 0x9f, 0x6e, 0xb2, 0x54, 0x3c, 0x6c, 0x8d, 0x9b,
|
||||
0x59, 0xc5, 0x1d, 0x0c, 0x4f, 0xa0, 0x5f, 0x25, 0x77, 0xc6, 0xcd, 0x9d, 0xea, 0x55, 0x0a, 0x9e,
|
||||
0x41, 0xef, 0xfa, 0x4c, 0x2e, 0xaf, 0x78, 0x24, 0xe4, 0xa1, 0x4b, 0x05, 0xe6, 0x8a, 0x12, 0x22,
|
||||
0x3a, 0x4d, 0xa9, 0x5e, 0x94, 0x2a, 0x6b, 0x4b, 0xf5, 0x42, 0x53, 0x95, 0x34, 0x1c, 0x42, 0x67,
|
||||
0xc1, 0x93, 0x40, 0xb0, 0x68, 0xd8, 0x94, 0x8d, 0x21, 0x79, 0xe8, 0x1c, 0x83, 0xa5, 0x76, 0x3c,
|
||||
0x00, 0x73, 0xe6, 0xa9, 0xae, 0x59, 0xc4, 0x9c, 0x79, 0x32, 0x7e, 0xcd, 0xd5, 0x4d, 0xb4, 0x88,
|
||||
0xf9, 0x9a, 0x3b, 0x67, 0x00, 0xa5, 0x0d, 0xc4, 0x54, 0x95, 0x76, 0x99, 0xa4, 0x15, 0x10, 0x2c,
|
||||
0x89, 0x29, 0x4d, 0x9f, 0xa8, 0xb5, 0xf3, 0x25, 0x40, 0x69, 0xe3, 0xb1, 0x6f, 0x14, 0x15, 0x9a,
|
||||
0x5a, 0x85, 0xbb, 0x7c, 0xb0, 0xae, 0xbc, 0xe0, 0xf6, 0xfd, 0x83, 0x25, 0x19, 0x35, 0x83, 0x85,
|
||||
0x60, 0xcd, 0xbd, 0x35, 0xcb, 0xbe, 0xa3, 0xd6, 0x8e, 0xb3, 0x33, 0x36, 0x52, 0x6c, 0x37, 0x70,
|
||||
0x0f, 0x5a, 0xe9, 0x25, 0x34, 0x9c, 0x1f, 0xe1, 0x49, 0x5a, 0x77, 0x46, 0x03, 0x37, 0x5e, 0xd2,
|
||||
0x15, 0xc3, 0x2f, 0xca, 0x19, 0x35, 0xd4, 0xf5, 0xd9, 0x72, 0x50, 0x30, 0xb7, 0x07, 0x55, 0x9a,
|
||||
0x98, 0xad, 0xe9, 0x42, 0x99, 0xd8, 0x27, 0x6a, 0xed, 0xfc, 0x6a, 0x80, 0x7d, 0x91, 0xf8, 0xc2,
|
||||
0x93, 0x1b, 0xcd, 0x89, 0x63, 0xe8, 0x91, 0xbb, 0x6f, 0x93, 0x30, 0xe4, 0x91, 0x60, 0xae, 0xfa,
|
||||
0x4c, 0x97, 0xe8, 0x29, 0xc9, 0x98, 0x6b, 0x0c, 0x33, 0x65, 0x68, 0x29, 0x7c, 0x0a, 0xdd, 0x73,
|
||||
0x1a, 0x33, 0xad, 0x97, 0x45, 0x8c, 0x23, 0x80, 0x39, 0x17, 0xd4, 0xcf, 0xaf, 0x8f, 0x44, 0xb5,
|
||||
0x8c, 0xf3, 0x97, 0x09, 0x87, 0xf5, 0x9b, 0x91, 0x7b, 0x98, 0xb2, 0x48, 0x28, 0x4f, 0xfb, 0x44,
|
||||
0xad, 0xf1, 0x18, 0x06, 0xaf, 0x02, 0x4f, 0x78, 0x54, 0xf0, 0xe8, 0x55, 0xe0, 0xb2, 0xbb, 0xec,
|
||||
0xf8, 0xb7, 0xb2, 0x92, 0x47, 0x58, 0x1c, 0xf2, 0xc0, 0x65, 0x19, 0x2f, 0x35, 0xb6, 0x95, 0xc5,
|
||||
0x43, 0x68, 0x4f, 0x39, 0x5f, 0x79, 0x4c, 0x59, 0xb3, 0x48, 0x16, 0x15, 0x87, 0xd8, 0x2a, 0x0f,
|
||||
0x51, 0x36, 0x42, 0x7a, 0xb8, 0x66, 0x51, 0xec, 0xf1, 0x60, 0xd8, 0x55, 0x05, 0xf5, 0x14, 0xce,
|
||||
0x00, 0x0b, 0x1f, 0x45, 0xa7, 0xb3, 0xc9, 0x1f, 0xe6, 0x47, 0xb7, 0x7d, 0x04, 0xa4, 0x46, 0x23,
|
||||
0x2b, 0x15, 0x4e, 0xcb, 0x4a, 0x9d, 0xc7, 0x2a, 0xed, 0x6a, 0x9c, 0xdf, 0x9a, 0xd0, 0x4f, 0x1b,
|
||||
0x3c, 0xe5, 0x81, 0x88, 0xb8, 0x8f, 0x9f, 0x57, 0x2e, 0xf5, 0x27, 0xd5, 0x2b, 0x95, 0x91, 0x6a,
|
||||
0xee, 0xf5, 0x67, 0x70, 0x50, 0x18, 0x55, 0x2f, 0x8b, 0xde, 0xff, 0x3a, 0x48, 0x2a, 0x0a, 0x43,
|
||||
0x9a, 0x22, 0x3d, 0x89, 0x3a, 0x08, 0x3f, 0x85, 0x41, 0xfe, 0xd6, 0xcd, 0xb9, 0x9a, 0x78, 0xab,
|
||||
0x78, 0x57, 0xb7, 0x10, 0xfd, 0xcd, 0xfc, 0x3a, 0xe2, 0x6b, 0xc5, 0x6e, 0x15, 0xec, 0x1d, 0x0c,
|
||||
0x27, 0xd0, 0xd3, 0x0b, 0xd7, 0xbd, 0xc7, 0x3a, 0xa1, 0x78, 0x63, 0x8b, 0xe2, 0x9d, 0x1a, 0x45,
|
||||
0x95, 0xe2, 0xcc, 0xfe, 0xef, 0xe7, 0xf1, 0x10, 0x70, 0x1a, 0x31, 0x2a, 0x98, 0xe2, 0x13, 0xf6,
|
||||
0x36, 0x61, 0xb1, 0xb0, 0x0d, 0xfc, 0x08, 0x0e, 0x2a, 0x79, 0xd9, 0x92, 0x98, 0xd9, 0xe6, 0xf9,
|
||||
0xe9, 0xef, 0xf7, 0x23, 0xe3, 0xdd, 0xfd, 0xc8, 0xf8, 0xfb, 0x7e, 0x64, 0xfc, 0xf2, 0x30, 0x6a,
|
||||
0xbc, 0x7b, 0x18, 0x35, 0xfe, 0x7c, 0x18, 0x35, 0x7e, 0x38, 0xba, 0xf5, 0xc4, 0x32, 0xb9, 0x99,
|
||||
0x2c, 0xf8, 0xfa, 0x79, 0xec, 0xd3, 0xc5, 0x6a, 0xf9, 0xf6, 0x79, 0x6a, 0xe9, 0xa6, 0xad, 0xfe,
|
||||
0x25, 0x9c, 0xfe, 0x17, 0x00, 0x00, 0xff, 0xff, 0xd6, 0x71, 0x5a, 0xf8, 0x35, 0x08, 0x00, 0x00,
|
||||
// 785 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x55, 0xcd, 0x6e, 0xeb, 0x44,
|
||||
0x14, 0x8e, 0x1d, 0x27, 0x4e, 0x4f, 0x7e, 0xae, 0x39, 0x15, 0xc1, 0x41, 0x22, 0x0a, 0x5e, 0x54,
|
||||
0x57, 0x2c, 0x72, 0x51, 0x5a, 0xae, 0x58, 0x72, 0x1b, 0x84, 0xd2, 0xaa, 0x3f, 0x61, 0x54, 0x8a,
|
||||
0xc4, 0x06, 0xb9, 0xf6, 0xd0, 0x58, 0x71, 0x3c, 0xa9, 0x3d, 0x41, 0xcd, 0x5b, 0xf0, 0x30, 0x3c,
|
||||
0x04, 0xec, 0xba, 0x42, 0x2c, 0x51, 0xbb, 0x64, 0xc9, 0x0b, 0xa0, 0x19, 0xff, 0x27, 0x86, 0xbb,
|
||||
0x9b, 0x73, 0xbe, 0xef, 0x3b, 0x73, 0xe6, 0xf3, 0x9c, 0x31, 0x74, 0x02, 0x7a, 0xb7, 0xf1, 0xed,
|
||||
0xf1, 0x3a, 0x64, 0x9c, 0x61, 0x33, 0x8e, 0xac, 0xbf, 0x55, 0x80, 0x2b, 0xb9, 0xbc, 0xa4, 0xdc,
|
||||
0xc6, 0x09, 0x68, 0x37, 0xdb, 0x35, 0x35, 0x95, 0x91, 0xf2, 0xba, 0x37, 0x19, 0x8e, 0x13, 0x4d,
|
||||
0xce, 0x18, 0x5f, 0xd2, 0x28, 0xb2, 0xef, 0xa9, 0x60, 0x11, 0xc9, 0xc5, 0x63, 0xd0, 0xbf, 0xa6,
|
||||
0xdc, 0xf6, 0xfc, 0xc8, 0x54, 0x47, 0xca, 0xeb, 0xf6, 0x64, 0xb0, 0x2f, 0x4b, 0x08, 0x24, 0x65,
|
||||
0x5a, 0xff, 0x28, 0xd0, 0x2e, 0x94, 0xc2, 0x16, 0x68, 0x57, 0x2c, 0xa0, 0x46, 0x0d, 0xbb, 0x70,
|
||||
0x30, 0x63, 0x11, 0xff, 0x76, 0x43, 0xc3, 0xad, 0xa1, 0x20, 0x42, 0x2f, 0x0b, 0x09, 0x5d, 0xfb,
|
||||
0x5b, 0x43, 0xc5, 0x8f, 0xa1, 0x2f, 0x72, 0xdf, 0xad, 0x5d, 0x9b, 0xd3, 0x2b, 0xc6, 0xbd, 0x9f,
|
||||
0x3c, 0xc7, 0xe6, 0x1e, 0x0b, 0x8c, 0x3a, 0x0e, 0xe0, 0x43, 0x81, 0x5d, 0xb2, 0x9f, 0xa9, 0x5b,
|
||||
0x82, 0xb4, 0x14, 0x9a, 0x6f, 0x02, 0x67, 0x51, 0x82, 0x1a, 0xd8, 0x03, 0x10, 0xd0, 0xf7, 0x0b,
|
||||
0x66, 0xaf, 0x3c, 0xa3, 0x89, 0x87, 0xf0, 0x2a, 0x8f, 0xe3, 0x6d, 0x75, 0xd1, 0xd9, 0xdc, 0xe6,
|
||||
0x8b, 0xe9, 0x82, 0x3a, 0x4b, 0xa3, 0x25, 0x3a, 0xcb, 0xc2, 0x98, 0x72, 0x80, 0x9f, 0xc0, 0xa0,
|
||||
0xba, 0xb3, 0x77, 0xce, 0xd2, 0x00, 0xeb, 0x77, 0x15, 0x3e, 0xd8, 0x33, 0x05, 0x2d, 0x80, 0x6b,
|
||||
0xdf, 0xbd, 0x5d, 0x07, 0xef, 0x5c, 0x37, 0x94, 0xd6, 0x77, 0x4f, 0x55, 0x53, 0x21, 0x85, 0x2c,
|
||||
0x1e, 0x81, 0x9e, 0x12, 0x9a, 0xd2, 0xe4, 0x4e, 0x6a, 0xb2, 0xc8, 0x91, 0x14, 0xc4, 0x31, 0x18,
|
||||
0xd7, 0xbe, 0x4b, 0xa8, 0x6f, 0x6f, 0x93, 0x54, 0x64, 0x36, 0x46, 0xf5, 0xa4, 0xe2, 0x1e, 0x86,
|
||||
0x13, 0xe8, 0x96, 0xc9, 0xfa, 0xa8, 0xbe, 0x57, 0xbd, 0x4c, 0xc1, 0x13, 0x68, 0xdf, 0x9e, 0x88,
|
||||
0xe5, 0x9c, 0x85, 0x5c, 0x7c, 0x74, 0xa1, 0xc0, 0x54, 0x91, 0x43, 0xa4, 0x48, 0x93, 0xaa, 0xb7,
|
||||
0xb9, 0x4a, 0xdb, 0x51, 0xbd, 0x2d, 0xa8, 0x72, 0x1a, 0x9a, 0xa0, 0x3b, 0x6c, 0x13, 0x70, 0x1a,
|
||||
0x9a, 0x75, 0x61, 0x0c, 0x49, 0x43, 0xeb, 0x08, 0x34, 0x79, 0xe2, 0x1e, 0xa8, 0x33, 0x4f, 0xba,
|
||||
0xa6, 0x11, 0x75, 0xe6, 0x89, 0xf8, 0x82, 0xc9, 0x9b, 0xa8, 0x11, 0xf5, 0x82, 0x59, 0x27, 0x00,
|
||||
0x79, 0x1b, 0x88, 0xb1, 0x2a, 0x76, 0x99, 0xc4, 0x15, 0x10, 0x34, 0x81, 0x49, 0x4d, 0x97, 0xc8,
|
||||
0xb5, 0xf5, 0x15, 0x40, 0xde, 0xc6, 0xfb, 0xf6, 0xc8, 0x2a, 0xd4, 0x0b, 0x15, 0x1e, 0xd3, 0xc1,
|
||||
0x9a, 0x7b, 0xc1, 0xfd, 0xff, 0x0f, 0x96, 0x60, 0x54, 0x0c, 0x16, 0x82, 0x76, 0xe3, 0xad, 0x68,
|
||||
0xb2, 0x8f, 0x5c, 0x5b, 0xd6, 0xde, 0xd8, 0x08, 0xb1, 0x51, 0xc3, 0x03, 0x68, 0xc4, 0x97, 0x50,
|
||||
0xb1, 0x7e, 0x84, 0x57, 0x71, 0xdd, 0x99, 0x1d, 0xb8, 0xd1, 0xc2, 0x5e, 0x52, 0xfc, 0x32, 0x9f,
|
||||
0x51, 0x45, 0x5e, 0x9f, 0x9d, 0x0e, 0x32, 0xe6, 0xee, 0xa0, 0x8a, 0x26, 0x66, 0x2b, 0xdb, 0x91,
|
||||
0x4d, 0x74, 0x88, 0x5c, 0x5b, 0x7f, 0x28, 0xd0, 0xaf, 0xd6, 0x09, 0xfa, 0x94, 0x86, 0x5c, 0xee,
|
||||
0xd2, 0x21, 0x72, 0x8d, 0x47, 0xd0, 0x3b, 0x0b, 0x3c, 0xee, 0xd9, 0x9c, 0x85, 0x67, 0x81, 0x4b,
|
||||
0x1f, 0x13, 0xa7, 0x77, 0xb2, 0x82, 0x47, 0x68, 0xb4, 0x66, 0x81, 0x4b, 0x13, 0x5e, 0xec, 0xe7,
|
||||
0x4e, 0x16, 0xfb, 0xd0, 0x9c, 0x32, 0xb6, 0xf4, 0xa8, 0xa9, 0x49, 0x67, 0x92, 0x28, 0xf3, 0xab,
|
||||
0x91, 0xfb, 0x85, 0x23, 0x68, 0x8b, 0x1e, 0x6e, 0x69, 0x18, 0x79, 0x2c, 0x30, 0x5b, 0xb2, 0x60,
|
||||
0x31, 0x75, 0xae, 0xb5, 0x9a, 0x86, 0x7e, 0xae, 0xb5, 0x74, 0xa3, 0x65, 0xfd, 0x5a, 0x87, 0x6e,
|
||||
0x7c, 0xb0, 0x29, 0x0b, 0x78, 0xc8, 0x7c, 0xfc, 0xa2, 0xf4, 0xdd, 0x3e, 0x2d, 0xbb, 0x96, 0x90,
|
||||
0x2a, 0x3e, 0xdd, 0xe7, 0x70, 0x98, 0x1d, 0x4e, 0x0e, 0x4f, 0xf1, 0xdc, 0x55, 0x90, 0x50, 0x64,
|
||||
0xc7, 0x2c, 0x28, 0x62, 0x07, 0xaa, 0x20, 0xfc, 0x0c, 0x7a, 0xe9, 0x38, 0xdf, 0x30, 0x79, 0xa9,
|
||||
0xb5, 0xec, 0xe9, 0xd8, 0x41, 0x8a, 0xcf, 0xc2, 0x37, 0x21, 0x5b, 0x49, 0x76, 0x23, 0x63, 0xef,
|
||||
0x61, 0x38, 0x86, 0x76, 0xb1, 0x70, 0xd5, 0x93, 0x53, 0x24, 0x64, 0xcf, 0x48, 0x56, 0x5c, 0xaf,
|
||||
0x50, 0x94, 0x29, 0xd6, 0xec, 0xbf, 0xfe, 0x00, 0x7d, 0xc0, 0x69, 0x48, 0x6d, 0x4e, 0x25, 0x9f,
|
||||
0xd0, 0x87, 0x0d, 0x8d, 0xb8, 0xa1, 0xe0, 0x47, 0x70, 0x58, 0xca, 0x0b, 0x4b, 0x22, 0x6a, 0xa8,
|
||||
0xa7, 0xc7, 0xbf, 0x3d, 0x0f, 0x95, 0xa7, 0xe7, 0xa1, 0xf2, 0xd7, 0xf3, 0x50, 0xf9, 0xe5, 0x65,
|
||||
0x58, 0x7b, 0x7a, 0x19, 0xd6, 0xfe, 0x7c, 0x19, 0xd6, 0x7e, 0x18, 0xdc, 0x7b, 0x7c, 0xb1, 0xb9,
|
||||
0x1b, 0x3b, 0x6c, 0xf5, 0x26, 0xf2, 0x6d, 0x67, 0xb9, 0x78, 0x78, 0x13, 0xb7, 0x74, 0xd7, 0x94,
|
||||
0x3f, 0xc2, 0xe3, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xea, 0x6f, 0xbc, 0x50, 0x18, 0x07, 0x00,
|
||||
0x00,
|
||||
}
|
||||
|
||||
func (m *NebulaMeta) Marshal() (dAtA []byte, err error) {
|
||||
@@ -1203,59 +1114,6 @@ func (m *NebulaHandshake) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *MultiPortDetails) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *MultiPortDetails) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *MultiPortDetails) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.TotalPorts != 0 {
|
||||
i = encodeVarintNebula(dAtA, i, uint64(m.TotalPorts))
|
||||
i--
|
||||
dAtA[i] = 0x20
|
||||
}
|
||||
if m.BasePort != 0 {
|
||||
i = encodeVarintNebula(dAtA, i, uint64(m.BasePort))
|
||||
i--
|
||||
dAtA[i] = 0x18
|
||||
}
|
||||
if m.TxSupported {
|
||||
i--
|
||||
if m.TxSupported {
|
||||
dAtA[i] = 1
|
||||
} else {
|
||||
dAtA[i] = 0
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x10
|
||||
}
|
||||
if m.RxSupported {
|
||||
i--
|
||||
if m.RxSupported {
|
||||
dAtA[i] = 1
|
||||
} else {
|
||||
dAtA[i] = 0
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x8
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *NebulaHandshakeDetails) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
@@ -1281,30 +1139,6 @@ func (m *NebulaHandshakeDetails) MarshalToSizedBuffer(dAtA []byte) (int, error)
|
||||
i--
|
||||
dAtA[i] = 0x40
|
||||
}
|
||||
if m.ResponderMultiPort != nil {
|
||||
{
|
||||
size, err := m.ResponderMultiPort.MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintNebula(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x3a
|
||||
}
|
||||
if m.InitiatorMultiPort != nil {
|
||||
{
|
||||
size, err := m.InitiatorMultiPort.MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintNebula(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x32
|
||||
}
|
||||
if m.Time != 0 {
|
||||
i = encodeVarintNebula(dAtA, i, uint64(m.Time))
|
||||
i--
|
||||
@@ -1558,27 +1392,6 @@ func (m *NebulaHandshake) Size() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *MultiPortDetails) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.RxSupported {
|
||||
n += 2
|
||||
}
|
||||
if m.TxSupported {
|
||||
n += 2
|
||||
}
|
||||
if m.BasePort != 0 {
|
||||
n += 1 + sovNebula(uint64(m.BasePort))
|
||||
}
|
||||
if m.TotalPorts != 0 {
|
||||
n += 1 + sovNebula(uint64(m.TotalPorts))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *NebulaHandshakeDetails) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
@@ -1601,14 +1414,6 @@ func (m *NebulaHandshakeDetails) Size() (n int) {
|
||||
if m.Time != 0 {
|
||||
n += 1 + sovNebula(uint64(m.Time))
|
||||
}
|
||||
if m.InitiatorMultiPort != nil {
|
||||
l = m.InitiatorMultiPort.Size()
|
||||
n += 1 + l + sovNebula(uint64(l))
|
||||
}
|
||||
if m.ResponderMultiPort != nil {
|
||||
l = m.ResponderMultiPort.Size()
|
||||
n += 1 + l + sovNebula(uint64(l))
|
||||
}
|
||||
if m.CertVersion != 0 {
|
||||
n += 1 + sovNebula(uint64(m.CertVersion))
|
||||
}
|
||||
@@ -2551,134 +2356,6 @@ func (m *NebulaHandshake) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *MultiPortDetails) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowNebula
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: MultiPortDetails: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: MultiPortDetails: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field RxSupported", wireType)
|
||||
}
|
||||
var v int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowNebula
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
v |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
m.RxSupported = bool(v != 0)
|
||||
case 2:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field TxSupported", wireType)
|
||||
}
|
||||
var v int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowNebula
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
v |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
m.TxSupported = bool(v != 0)
|
||||
case 3:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field BasePort", wireType)
|
||||
}
|
||||
m.BasePort = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowNebula
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.BasePort |= uint32(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 4:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field TotalPorts", wireType)
|
||||
}
|
||||
m.TotalPorts = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowNebula
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.TotalPorts |= uint32(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipNebula(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthNebula
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *NebulaHandshakeDetails) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
@@ -2818,78 +2495,6 @@ func (m *NebulaHandshakeDetails) Unmarshal(dAtA []byte) error {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 6:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field InitiatorMultiPort", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowNebula
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthNebula
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthNebula
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.InitiatorMultiPort == nil {
|
||||
m.InitiatorMultiPort = &MultiPortDetails{}
|
||||
}
|
||||
if err := m.InitiatorMultiPort.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 7:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ResponderMultiPort", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowNebula
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthNebula
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthNebula
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.ResponderMultiPort == nil {
|
||||
m.ResponderMultiPort = &MultiPortDetails{}
|
||||
}
|
||||
if err := m.ResponderMultiPort.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 8:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field CertVersion", wireType)
|
||||
|
||||
12
nebula.proto
12
nebula.proto
@@ -65,13 +65,6 @@ message NebulaHandshake {
|
||||
bytes Hmac = 2;
|
||||
}
|
||||
|
||||
message MultiPortDetails {
|
||||
bool RxSupported = 1;
|
||||
bool TxSupported = 2;
|
||||
uint32 BasePort = 3;
|
||||
uint32 TotalPorts = 4;
|
||||
}
|
||||
|
||||
message NebulaHandshakeDetails {
|
||||
bytes Cert = 1;
|
||||
uint32 InitiatorIndex = 2;
|
||||
@@ -79,9 +72,8 @@ message NebulaHandshakeDetails {
|
||||
uint64 Cookie = 4;
|
||||
uint64 Time = 5;
|
||||
uint32 CertVersion = 8;
|
||||
|
||||
MultiPortDetails InitiatorMultiPort = 6;
|
||||
MultiPortDetails ResponderMultiPort = 7;
|
||||
// reserved for WIP multiport
|
||||
reserved 6, 7;
|
||||
}
|
||||
|
||||
message NebulaControl {
|
||||
|
||||
28
outside.go
28
outside.go
@@ -232,16 +232,6 @@ func (f *Interface) sendCloseTunnel(h *HostInfo) {
|
||||
|
||||
func (f *Interface) handleHostRoaming(hostinfo *HostInfo, udpAddr netip.AddrPort) {
|
||||
if udpAddr.IsValid() && hostinfo.remote != udpAddr {
|
||||
if hostinfo.multiportRx {
|
||||
// If the remote is sending with multiport, we aren't roaming unless
|
||||
// the IP has changed
|
||||
if hostinfo.remote.Addr().Compare(udpAddr.Addr()) == 0 {
|
||||
return
|
||||
}
|
||||
// Keep the port from the original hostinfo, because the remote is transmitting from multiport ports
|
||||
udpAddr = netip.AddrPortFrom(udpAddr.Addr(), hostinfo.remote.Port())
|
||||
}
|
||||
|
||||
if !f.lightHouse.GetRemoteAllowList().AllowAll(hostinfo.vpnAddrs, udpAddr.Addr()) {
|
||||
hostinfo.logger(f.l).WithField("newAddr", udpAddr).Debug("lighthouse.remote_allow_list denied roaming")
|
||||
return
|
||||
@@ -264,16 +254,18 @@ func (f *Interface) handleHostRoaming(hostinfo *HostInfo, udpAddr netip.AddrPort
|
||||
|
||||
}
|
||||
|
||||
// handleEncrypted returns true if a packet should be processed, false otherwise
|
||||
func (f *Interface) handleEncrypted(ci *ConnectionState, addr netip.AddrPort, h *header.H) bool {
|
||||
// If connectionstate exists and the replay protector allows, process packet
|
||||
// Else, send recv errors for 300 seconds after a restart to allow fast reconnection.
|
||||
if ci == nil || !ci.window.Check(f.l, h.MessageCounter) {
|
||||
// If connectionstate does not exist, send a recv error, if possible, to encourage a fast reconnect
|
||||
if ci == nil {
|
||||
if addr.IsValid() {
|
||||
f.maybeSendRecvError(addr, h.RemoteIndex)
|
||||
return false
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
// If the window check fails, refuse to process the packet, but don't send a recv error
|
||||
if !ci.window.Check(f.l, h.MessageCounter) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -547,10 +539,6 @@ func (f *Interface) handleRecvError(addr netip.AddrPort, h *header.H) {
|
||||
return
|
||||
}
|
||||
|
||||
if !hostinfo.RecvErrorExceeded() {
|
||||
return
|
||||
}
|
||||
|
||||
if hostinfo.remote.IsValid() && hostinfo.remote != addr {
|
||||
f.l.Infoln("Someone spoofing recv_errors? ", addr, hostinfo.remote)
|
||||
return
|
||||
|
||||
@@ -293,7 +293,6 @@ func (t *tun) addIPs(link netlink.Link) error {
|
||||
|
||||
//add all new addresses
|
||||
for i := range newAddrs {
|
||||
//TODO: CERT-V2 do we want to stack errors and try as many ops as possible?
|
||||
//AddrReplace still adds new IPs, but if their properties change it will change them as well
|
||||
if err := netlink.AddrReplace(link, newAddrs[i]); err != nil {
|
||||
return err
|
||||
@@ -361,6 +360,11 @@ func (t *tun) Activate() error {
|
||||
t.l.WithError(err).Error("Failed to set tun tx queue length")
|
||||
}
|
||||
|
||||
const modeNone = 1
|
||||
if err = netlink.LinkSetIP6AddrGenMode(link, modeNone); err != nil {
|
||||
t.l.WithError(err).Warn("Failed to disable link local address generation")
|
||||
}
|
||||
|
||||
if err = t.addIPs(link); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -638,6 +642,11 @@ func (t *tun) updateRoutes(r netlink.RouteUpdate) {
|
||||
return
|
||||
}
|
||||
|
||||
if r.Dst == nil {
|
||||
t.l.WithField("route", r).Debug("Ignoring route update, no destination address")
|
||||
return
|
||||
}
|
||||
|
||||
dstAddr, ok := netip.AddrFromSlice(r.Dst.IP)
|
||||
if !ok {
|
||||
t.l.WithField("route", r).Debug("Ignoring route update, invalid destination address")
|
||||
|
||||
5
pki.go
5
pki.go
@@ -173,7 +173,6 @@ func (p *PKI) reloadCerts(c *config.C, initial bool) *util.ContextualError {
|
||||
|
||||
p.cs.Store(newState)
|
||||
|
||||
//TODO: CERT-V2 newState needs a stringer that does json
|
||||
if initial {
|
||||
p.l.WithField("cert", newState).Debug("Client nebula certificate(s)")
|
||||
} else {
|
||||
@@ -359,7 +358,9 @@ func newCertState(dv cert.Version, v1, v2 cert.Certificate, pkcs11backed bool, p
|
||||
return nil, util.NewContextualError("v1 and v2 curve are not the same, ignoring", nil, nil)
|
||||
}
|
||||
|
||||
//TODO: CERT-V2 make sure v2 has v1s address
|
||||
if v1.Networks()[0] != v2.Networks()[0] {
|
||||
return nil, util.NewContextualError("v1 and v2 networks are not the same", nil, nil)
|
||||
}
|
||||
|
||||
cs.initiatingVersion = dv
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package udp
|
||||
|
||||
import mathrand "math/rand"
|
||||
|
||||
type SendPortGetter interface {
|
||||
// UDPSendPort returns the port to use
|
||||
UDPSendPort(maxPort int) uint16
|
||||
}
|
||||
|
||||
type randomSendPort struct{}
|
||||
|
||||
func (randomSendPort) UDPSendPort(maxPort int) uint16 {
|
||||
return uint16(mathrand.Intn(maxPort))
|
||||
}
|
||||
|
||||
var RandomSendPort = randomSendPort{}
|
||||
@@ -1,191 +0,0 @@
|
||||
//go:build !android && !e2e_testing
|
||||
// +build !android,!e2e_testing
|
||||
|
||||
package udp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/rcrowley/go-metrics"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/slackhq/nebula/config"
|
||||
"golang.org/x/net/ipv4"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// RawOverhead is the number of bytes that need to be reserved at the start of
|
||||
// the raw bytes passed to (*RawConn).WriteTo. This is used by WriteTo to prefix
|
||||
// the IP and UDP headers.
|
||||
const RawOverhead = 28
|
||||
|
||||
type RawConn struct {
|
||||
sysFd int
|
||||
basePort uint16
|
||||
l *logrus.Logger
|
||||
}
|
||||
|
||||
func NewRawConn(l *logrus.Logger, ip string, port int, basePort uint16) (*RawConn, error) {
|
||||
syscall.ForkLock.RLock()
|
||||
// With IPPROTO_UDP, the linux kernel tries to deliver every UDP packet
|
||||
// received in the system to our socket. This constantly overflows our
|
||||
// buffer and marks our socket as having dropped packets. This makes the
|
||||
// stats on the socket useless.
|
||||
//
|
||||
// In contrast, IPPROTO_RAW is not delivered any packets and thus our read
|
||||
// buffer will not fill up and mark as having dropped packets. The only
|
||||
// difference is that we have to assemble the IP header as well, but this
|
||||
// is fairly easy since Linux does the checksum for us.
|
||||
//
|
||||
// TODO: How to get this working with Inet6 correctly? I was having issues
|
||||
// with the source address when testing before, probably need to `bind(2)`?
|
||||
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_RAW, unix.IPPROTO_RAW)
|
||||
if err == nil {
|
||||
unix.CloseOnExec(fd)
|
||||
}
|
||||
syscall.ForkLock.RUnlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We only want to send, not recv. This will hopefully help the kernel avoid
|
||||
// wasting time on us
|
||||
if err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_RCVBUF, 0); err != nil {
|
||||
return nil, fmt.Errorf("unable to set SO_RCVBUF: %s", err)
|
||||
}
|
||||
|
||||
var lip [16]byte
|
||||
copy(lip[:], net.ParseIP(ip))
|
||||
|
||||
// TODO do we need to `bind(2)` so that we send from the correct address/interface?
|
||||
if err = unix.Bind(fd, &unix.SockaddrInet6{Addr: lip, Port: port}); err != nil {
|
||||
return nil, fmt.Errorf("unable to bind to socket: %s", err)
|
||||
}
|
||||
|
||||
return &RawConn{
|
||||
sysFd: fd,
|
||||
basePort: basePort,
|
||||
l: l,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WriteTo must be called with raw leaving the first `udp.RawOverhead` bytes empty,
|
||||
// for the IP/UDP headers.
|
||||
func (u *RawConn) WriteTo(raw []byte, fromPort uint16, ip netip.AddrPort) error {
|
||||
var rsa unix.RawSockaddrInet4
|
||||
rsa.Family = unix.AF_INET
|
||||
rsa.Addr = ip.Addr().As4()
|
||||
|
||||
totalLen := len(raw)
|
||||
udpLen := totalLen - ipv4.HeaderLen
|
||||
|
||||
// IP header
|
||||
raw[0] = byte(ipv4.Version<<4 | (ipv4.HeaderLen >> 2 & 0x0f))
|
||||
raw[1] = 0 // tos
|
||||
binary.BigEndian.PutUint16(raw[2:4], uint16(totalLen))
|
||||
binary.BigEndian.PutUint16(raw[4:6], 0) // id (linux does it for us)
|
||||
binary.BigEndian.PutUint16(raw[6:8], 0) // frag options
|
||||
raw[8] = byte(64) // ttl
|
||||
raw[9] = byte(17) // protocol
|
||||
binary.BigEndian.PutUint16(raw[10:12], 0) // checksum (linux does it for us)
|
||||
binary.BigEndian.PutUint32(raw[12:16], 0) // src (linux does it for us)
|
||||
copy(raw[16:20], rsa.Addr[:]) // dst
|
||||
|
||||
// UDP header
|
||||
fromPort = u.basePort + fromPort
|
||||
binary.BigEndian.PutUint16(raw[20:22], uint16(fromPort)) // src port
|
||||
binary.BigEndian.PutUint16(raw[22:24], uint16(ip.Port())) // dst port
|
||||
binary.BigEndian.PutUint16(raw[24:26], uint16(udpLen)) // UDP length
|
||||
binary.BigEndian.PutUint16(raw[26:28], 0) // checksum (optional)
|
||||
|
||||
for {
|
||||
_, _, err := unix.Syscall6(
|
||||
unix.SYS_SENDTO,
|
||||
uintptr(u.sysFd),
|
||||
uintptr(unsafe.Pointer(&raw[0])),
|
||||
uintptr(len(raw)),
|
||||
uintptr(0),
|
||||
uintptr(unsafe.Pointer(&rsa)),
|
||||
uintptr(unix.SizeofSockaddrInet4),
|
||||
)
|
||||
|
||||
if err != 0 {
|
||||
return &net.OpError{Op: "sendto", Err: err}
|
||||
}
|
||||
|
||||
//TODO: handle incomplete writes
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (u *RawConn) ReloadConfig(c *config.C) {
|
||||
b := c.GetInt("listen.write_buffer", 0)
|
||||
if b <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if err := u.SetSendBuffer(b); err != nil {
|
||||
u.l.WithError(err).Error("Failed to set listen.write_buffer")
|
||||
return
|
||||
}
|
||||
|
||||
s, err := u.GetSendBuffer()
|
||||
if err != nil {
|
||||
u.l.WithError(err).Warn("Failed to get listen.write_buffer")
|
||||
return
|
||||
}
|
||||
|
||||
u.l.WithField("size", s).Info("listen.write_buffer was set")
|
||||
}
|
||||
|
||||
func (u *RawConn) SetSendBuffer(n int) error {
|
||||
return unix.SetsockoptInt(u.sysFd, unix.SOL_SOCKET, unix.SO_SNDBUFFORCE, n)
|
||||
}
|
||||
|
||||
func (u *RawConn) GetSendBuffer() (int, error) {
|
||||
return unix.GetsockoptInt(u.sysFd, unix.SOL_SOCKET, unix.SO_SNDBUF)
|
||||
}
|
||||
|
||||
func (u *RawConn) getMemInfo(meminfo *[unix.SK_MEMINFO_VARS]uint32) error {
|
||||
var vallen uint32 = 4 * unix.SK_MEMINFO_VARS
|
||||
_, _, err := unix.Syscall6(unix.SYS_GETSOCKOPT, uintptr(u.sysFd), uintptr(unix.SOL_SOCKET), uintptr(unix.SO_MEMINFO), uintptr(unsafe.Pointer(meminfo)), uintptr(unsafe.Pointer(&vallen)), 0)
|
||||
if err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewRawStatsEmitter(rawConn *RawConn) func() {
|
||||
// Check if our kernel supports SO_MEMINFO before registering the gauges
|
||||
var gauges [unix.SK_MEMINFO_VARS]metrics.Gauge
|
||||
var meminfo [unix.SK_MEMINFO_VARS]uint32
|
||||
if err := rawConn.getMemInfo(&meminfo); err == nil {
|
||||
gauges = [unix.SK_MEMINFO_VARS]metrics.Gauge{
|
||||
metrics.GetOrRegisterGauge("raw.rmem_alloc", nil),
|
||||
metrics.GetOrRegisterGauge("raw.rcvbuf", nil),
|
||||
metrics.GetOrRegisterGauge("raw.wmem_alloc", nil),
|
||||
metrics.GetOrRegisterGauge("raw.sndbuf", nil),
|
||||
metrics.GetOrRegisterGauge("raw.fwd_alloc", nil),
|
||||
metrics.GetOrRegisterGauge("raw.wmem_queued", nil),
|
||||
metrics.GetOrRegisterGauge("raw.optmem", nil),
|
||||
metrics.GetOrRegisterGauge("raw.backlog", nil),
|
||||
metrics.GetOrRegisterGauge("raw.drops", nil),
|
||||
}
|
||||
} else {
|
||||
// return no-op because we don't support SO_MEMINFO
|
||||
return func() {}
|
||||
}
|
||||
|
||||
return func() {
|
||||
if err := rawConn.getMemInfo(&meminfo); err == nil {
|
||||
for j := 0; j < unix.SK_MEMINFO_VARS; j++ {
|
||||
gauges[j].Update(int64(meminfo[j]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
//go:build !linux || android || e2e_testing
|
||||
// +build !linux android e2e_testing
|
||||
|
||||
package udp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"runtime"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/slackhq/nebula/config"
|
||||
)
|
||||
|
||||
const RawOverhead = 0
|
||||
|
||||
type RawConn struct{}
|
||||
|
||||
func NewRawConn(l *logrus.Logger, ip string, port int, basePort uint16) (*RawConn, error) {
|
||||
return nil, fmt.Errorf("multiport tx is not supported on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
func (u *RawConn) WriteTo(raw []byte, fromPort uint16, addr netip.AddrPort) error {
|
||||
return fmt.Errorf("multiport tx is not supported on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
func (u *RawConn) ReloadConfig(c *config.C) {}
|
||||
|
||||
func NewRawStatsEmitter(rawConn *RawConn) func() { return func() {} }
|
||||
Reference in New Issue
Block a user