mirror of
https://github.com/slackhq/nebula.git
synced 2025-11-09 00:13:57 +01:00
add listen.send_recv_error config option (#670)
By default, Nebula replies to packets it has no tunnel for with a `recv_error` packet. This packet helps speed up re-connection in the case that Nebula on either side did not shut down cleanly. This response can be abused as a way to discover if Nebula is running on a host though. This option lets you configure if you want to send `recv_error` packets always, never, or only to private network remotes. valid values: always, never, private This setting is reloadable with SIGHUP.
This commit is contained in:
parent
85ec807b7e
commit
7b9287709c
@ -76,6 +76,11 @@ func (c *C) RegisterReloadCallback(f func(*C)) {
|
|||||||
c.callbacks = append(c.callbacks, f)
|
c.callbacks = append(c.callbacks, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InitialLoad returns true if this is the first load of the config, and ReloadConfig has not been called yet.
|
||||||
|
func (c *C) InitialLoad() bool {
|
||||||
|
return c.oldSettings == nil
|
||||||
|
}
|
||||||
|
|
||||||
// HasChanged checks if the underlying structure of the provided key has changed after a config reload. The value of
|
// HasChanged checks if the underlying structure of the provided key has changed after a config reload. The value of
|
||||||
// k in both the old and new settings will be serialized, the result of the string comparison is returned.
|
// k in both the old and new settings will be serialized, the result of the string comparison is returned.
|
||||||
// If k is an empty string the entire config is tested.
|
// If k is an empty string the entire config is tested.
|
||||||
|
|||||||
@ -105,6 +105,12 @@ listen:
|
|||||||
# max, net.core.rmem_max and net.core.wmem_max
|
# max, net.core.rmem_max and net.core.wmem_max
|
||||||
#read_buffer: 10485760
|
#read_buffer: 10485760
|
||||||
#write_buffer: 10485760
|
#write_buffer: 10485760
|
||||||
|
# By default, Nebula replies to packets it has no tunnel for with a "recv_error" packet. This packet helps speed up reconnection
|
||||||
|
# in the case that Nebula on either side did not shut down cleanly. This response can be abused as a way to discover if Nebula is running
|
||||||
|
# on a host though. This option lets you configure if you want to send "recv_error" packets always, never, or only to private network remotes.
|
||||||
|
# valid values: always, never, private
|
||||||
|
# This setting is reloadable.
|
||||||
|
#send_recv_error: always
|
||||||
|
|
||||||
# EXPERIMENTAL: This option is currently only supported on linux and may
|
# EXPERIMENTAL: This option is currently only supported on linux and may
|
||||||
# change in future minor releases.
|
# change in future minor releases.
|
||||||
|
|||||||
63
interface.go
63
interface.go
@ -3,7 +3,9 @@ package nebula
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@ -68,6 +70,8 @@ type Interface struct {
|
|||||||
closed int32
|
closed int32
|
||||||
relayManager *relayManager
|
relayManager *relayManager
|
||||||
|
|
||||||
|
sendRecvErrorConfig sendRecvErrorConfig
|
||||||
|
|
||||||
// rebindCount is used to decide if an active tunnel should trigger a punch notification through a lighthouse
|
// rebindCount is used to decide if an active tunnel should trigger a punch notification through a lighthouse
|
||||||
rebindCount int8
|
rebindCount int8
|
||||||
version string
|
version string
|
||||||
@ -84,6 +88,40 @@ type Interface struct {
|
|||||||
l *logrus.Logger
|
l *logrus.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type sendRecvErrorConfig uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
sendRecvErrorAlways sendRecvErrorConfig = iota
|
||||||
|
sendRecvErrorNever
|
||||||
|
sendRecvErrorPrivate
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s sendRecvErrorConfig) ShouldSendRecvError(ip net.IP) bool {
|
||||||
|
switch s {
|
||||||
|
case sendRecvErrorPrivate:
|
||||||
|
return ip.IsPrivate()
|
||||||
|
case sendRecvErrorAlways:
|
||||||
|
return true
|
||||||
|
case sendRecvErrorNever:
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("invalid sendRecvErrorConfig value: %d", s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s sendRecvErrorConfig) String() string {
|
||||||
|
switch s {
|
||||||
|
case sendRecvErrorAlways:
|
||||||
|
return "always"
|
||||||
|
case sendRecvErrorNever:
|
||||||
|
return "never"
|
||||||
|
case sendRecvErrorPrivate:
|
||||||
|
return "private"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("invalid(%d)", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func NewInterface(ctx context.Context, c *InterfaceConfig) (*Interface, error) {
|
func NewInterface(ctx context.Context, c *InterfaceConfig) (*Interface, error) {
|
||||||
if c.Outside == nil {
|
if c.Outside == nil {
|
||||||
return nil, errors.New("no outside connection")
|
return nil, errors.New("no outside connection")
|
||||||
@ -232,6 +270,7 @@ func (f *Interface) RegisterConfigChangeCallbacks(c *config.C) {
|
|||||||
c.RegisterReloadCallback(f.reloadCA)
|
c.RegisterReloadCallback(f.reloadCA)
|
||||||
c.RegisterReloadCallback(f.reloadCertKey)
|
c.RegisterReloadCallback(f.reloadCertKey)
|
||||||
c.RegisterReloadCallback(f.reloadFirewall)
|
c.RegisterReloadCallback(f.reloadFirewall)
|
||||||
|
c.RegisterReloadCallback(f.reloadSendRecvError)
|
||||||
for _, udpConn := range f.writers {
|
for _, udpConn := range f.writers {
|
||||||
c.RegisterReloadCallback(udpConn.ReloadConfig)
|
c.RegisterReloadCallback(udpConn.ReloadConfig)
|
||||||
}
|
}
|
||||||
@ -309,6 +348,30 @@ func (f *Interface) reloadFirewall(c *config.C) {
|
|||||||
Info("New firewall has been installed")
|
Info("New firewall has been installed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Interface) reloadSendRecvError(c *config.C) {
|
||||||
|
if c.InitialLoad() || c.HasChanged("listen.send_recv_error") {
|
||||||
|
stringValue := c.GetString("listen.send_recv_error", "always")
|
||||||
|
|
||||||
|
switch stringValue {
|
||||||
|
case "always":
|
||||||
|
f.sendRecvErrorConfig = sendRecvErrorAlways
|
||||||
|
case "never":
|
||||||
|
f.sendRecvErrorConfig = sendRecvErrorNever
|
||||||
|
case "private":
|
||||||
|
f.sendRecvErrorConfig = sendRecvErrorPrivate
|
||||||
|
default:
|
||||||
|
if c.GetBool("listen.send_recv_error", true) {
|
||||||
|
f.sendRecvErrorConfig = sendRecvErrorAlways
|
||||||
|
} else {
|
||||||
|
f.sendRecvErrorConfig = sendRecvErrorNever
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.l.WithField("sendRecvError", f.sendRecvErrorConfig.String()).
|
||||||
|
Info("Loaded send_recv_error config")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f *Interface) emitStats(ctx context.Context, i time.Duration) {
|
func (f *Interface) emitStats(ctx context.Context, i time.Duration) {
|
||||||
ticker := time.NewTicker(i)
|
ticker := time.NewTicker(i)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|||||||
2
main.go
2
main.go
@ -306,6 +306,8 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg
|
|||||||
|
|
||||||
ifce.RegisterConfigChangeCallbacks(c)
|
ifce.RegisterConfigChangeCallbacks(c)
|
||||||
|
|
||||||
|
ifce.reloadSendRecvError(c)
|
||||||
|
|
||||||
go handshakeManager.Run(ctx, ifce)
|
go handshakeManager.Run(ctx, ifce)
|
||||||
go lightHouse.LhUpdateWorker(ctx, ifce)
|
go lightHouse.LhUpdateWorker(ctx, ifce)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -273,7 +273,7 @@ func (f *Interface) handleEncrypted(ci *ConnectionState, addr *udp.Addr, h *head
|
|||||||
// Else, send recv errors for 300 seconds after a restart to allow fast reconnection.
|
// 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 ci == nil || !ci.window.Check(f.l, h.MessageCounter) {
|
||||||
if addr != nil {
|
if addr != nil {
|
||||||
f.sendRecvError(addr, h.RemoteIndex)
|
f.maybeSendRecvError(addr, h.RemoteIndex)
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -402,6 +402,12 @@ func (f *Interface) decryptToTun(hostinfo *HostInfo, messageCounter uint64, out
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Interface) maybeSendRecvError(endpoint *udp.Addr, index uint32) {
|
||||||
|
if f.sendRecvErrorConfig.ShouldSendRecvError(endpoint.IP) {
|
||||||
|
f.sendRecvError(endpoint, index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f *Interface) sendRecvError(endpoint *udp.Addr, index uint32) {
|
func (f *Interface) sendRecvError(endpoint *udp.Addr, index uint32) {
|
||||||
f.messageMetrics.Tx(header.RecvError, 0, 1)
|
f.messageMetrics.Tx(header.RecvError, 0, 1)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user