mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-20 17:26:40 +00:00
Merge branch 'main' into ssh-rewrite
This commit is contained in:
@@ -43,7 +43,7 @@ jobs:
|
||||
- name: gomobile init
|
||||
run: gomobile init
|
||||
- name: build android netbird lib
|
||||
run: PATH=$PATH:$(go env GOPATH) gomobile bind -o $GITHUB_WORKSPACE/netbird.aar -javapkg=io.netbird.gomobile -ldflags="-X golang.zx2c4.com/wireguard/ipc.socketDirectory=/data/data/io.netbird.client/cache/wireguard -X github.com/netbirdio/netbird/version.version=buildtest" $GITHUB_WORKSPACE/client/android
|
||||
run: PATH=$PATH:$(go env GOPATH) gomobile bind -o $GITHUB_WORKSPACE/netbird.aar -javapkg=io.netbird.gomobile -ldflags="-checklinkname=0 -X golang.zx2c4.com/wireguard/ipc.socketDirectory=/data/data/io.netbird.client/cache/wireguard -X github.com/netbirdio/netbird/version.version=buildtest" $GITHUB_WORKSPACE/client/android
|
||||
env:
|
||||
CGO_ENABLED: 0
|
||||
ANDROID_NDK_HOME: /usr/local/lib/android/sdk/ndk/23.1.7779620
|
||||
|
||||
@@ -50,10 +50,9 @@
|
||||
|
||||
**Secure.** NetBird enables secure remote access by applying granular access policies while allowing you to manage them intuitively from a single place. Works universally on any infrastructure.
|
||||
|
||||
### Open-Source Network Security in a Single Platform
|
||||
### Open Source Network Security in a Single Platform
|
||||
|
||||
|
||||

|
||||
<img width="1188" alt="centralized-network-management 1" src="https://github.com/user-attachments/assets/c28cc8e4-15d2-4d2f-bb97-a6433db39d56" />
|
||||
|
||||
### NetBird on Lawrence Systems (Video)
|
||||
[](https://www.youtube.com/watch?v=Kwrff6h0rEw)
|
||||
|
||||
@@ -64,7 +64,9 @@ type Client struct {
|
||||
}
|
||||
|
||||
// NewClient instantiate a new Client
|
||||
func NewClient(cfgFile, deviceName string, uiVersion string, tunAdapter TunAdapter, iFaceDiscover IFaceDiscover, networkChangeListener NetworkChangeListener) *Client {
|
||||
func NewClient(cfgFile string, androidSDKVersion int, deviceName string, uiVersion string, tunAdapter TunAdapter, iFaceDiscover IFaceDiscover, networkChangeListener NetworkChangeListener) *Client {
|
||||
execWorkaround(androidSDKVersion)
|
||||
|
||||
net.SetAndroidProtectSocketFn(tunAdapter.ProtectSocket)
|
||||
return &Client{
|
||||
cfgFile: cfgFile,
|
||||
|
||||
26
client/android/exec.go
Normal file
26
client/android/exec.go
Normal file
@@ -0,0 +1,26 @@
|
||||
//go:build android
|
||||
|
||||
package android
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
// https://github.com/golang/go/pull/69543/commits/aad6b3b32c81795f86bc4a9e81aad94899daf520
|
||||
// In Android version 11 and earlier, pidfd-related system calls
|
||||
// are not allowed by the seccomp policy, which causes crashes due
|
||||
// to SIGSYS signals.
|
||||
|
||||
//go:linkname checkPidfdOnce os.checkPidfdOnce
|
||||
var checkPidfdOnce func() error
|
||||
|
||||
func execWorkaround(androidSDKVersion int) {
|
||||
if androidSDKVersion > 30 { // above Android 11
|
||||
return
|
||||
}
|
||||
|
||||
checkPidfdOnce = func() error {
|
||||
return fmt.Errorf("unsupported Android version")
|
||||
}
|
||||
}
|
||||
@@ -17,10 +17,18 @@ import (
|
||||
"github.com/netbirdio/netbird/client/server"
|
||||
nbstatus "github.com/netbirdio/netbird/client/status"
|
||||
mgmProto "github.com/netbirdio/netbird/management/proto"
|
||||
"github.com/netbirdio/netbird/upload-server/types"
|
||||
)
|
||||
|
||||
const errCloseConnection = "Failed to close connection: %v"
|
||||
|
||||
var (
|
||||
logFileCount uint32
|
||||
systemInfoFlag bool
|
||||
uploadBundleFlag bool
|
||||
uploadBundleURLFlag string
|
||||
)
|
||||
|
||||
var debugCmd = &cobra.Command{
|
||||
Use: "debug",
|
||||
Short: "Debugging commands",
|
||||
@@ -88,12 +96,13 @@ func debugBundle(cmd *cobra.Command, _ []string) error {
|
||||
|
||||
client := proto.NewDaemonServiceClient(conn)
|
||||
request := &proto.DebugBundleRequest{
|
||||
Anonymize: anonymizeFlag,
|
||||
Status: getStatusOutput(cmd, anonymizeFlag),
|
||||
SystemInfo: debugSystemInfoFlag,
|
||||
Anonymize: anonymizeFlag,
|
||||
Status: getStatusOutput(cmd, anonymizeFlag),
|
||||
SystemInfo: systemInfoFlag,
|
||||
LogFileCount: logFileCount,
|
||||
}
|
||||
if debugUploadBundle {
|
||||
request.UploadURL = debugUploadBundleURL
|
||||
if uploadBundleFlag {
|
||||
request.UploadURL = uploadBundleURLFlag
|
||||
}
|
||||
resp, err := client.DebugBundle(cmd.Context(), request)
|
||||
if err != nil {
|
||||
@@ -105,7 +114,7 @@ func debugBundle(cmd *cobra.Command, _ []string) error {
|
||||
return fmt.Errorf("upload failed: %s", resp.GetUploadFailureReason())
|
||||
}
|
||||
|
||||
if debugUploadBundle {
|
||||
if uploadBundleFlag {
|
||||
cmd.Printf("Upload file key:\n%s\n", resp.GetUploadedKey())
|
||||
}
|
||||
|
||||
@@ -223,12 +232,13 @@ func runForDuration(cmd *cobra.Command, args []string) error {
|
||||
headerPreDown := fmt.Sprintf("----- Netbird pre-down - Timestamp: %s - Duration: %s", time.Now().Format(time.RFC3339), duration)
|
||||
statusOutput = fmt.Sprintf("%s\n%s\n%s", statusOutput, headerPreDown, getStatusOutput(cmd, anonymizeFlag))
|
||||
request := &proto.DebugBundleRequest{
|
||||
Anonymize: anonymizeFlag,
|
||||
Status: statusOutput,
|
||||
SystemInfo: debugSystemInfoFlag,
|
||||
Anonymize: anonymizeFlag,
|
||||
Status: statusOutput,
|
||||
SystemInfo: systemInfoFlag,
|
||||
LogFileCount: logFileCount,
|
||||
}
|
||||
if debugUploadBundle {
|
||||
request.UploadURL = debugUploadBundleURL
|
||||
if uploadBundleFlag {
|
||||
request.UploadURL = uploadBundleURLFlag
|
||||
}
|
||||
resp, err := client.DebugBundle(cmd.Context(), request)
|
||||
if err != nil {
|
||||
@@ -255,7 +265,7 @@ func runForDuration(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("upload failed: %s", resp.GetUploadFailureReason())
|
||||
}
|
||||
|
||||
if debugUploadBundle {
|
||||
if uploadBundleFlag {
|
||||
cmd.Printf("Upload file key:\n%s\n", resp.GetUploadedKey())
|
||||
}
|
||||
|
||||
@@ -375,3 +385,15 @@ func generateDebugBundle(config *internal.Config, recorder *peer.Status, connect
|
||||
}
|
||||
log.Infof("Generated debug bundle from SIGUSR1 at: %s", path)
|
||||
}
|
||||
|
||||
func init() {
|
||||
debugBundleCmd.Flags().Uint32VarP(&logFileCount, "log-file-count", "C", 1, "Number of rotated log files to include in debug bundle")
|
||||
debugBundleCmd.Flags().BoolVarP(&systemInfoFlag, "system-info", "S", true, "Adds system information to the debug bundle")
|
||||
debugBundleCmd.Flags().BoolVarP(&uploadBundleFlag, "upload-bundle", "U", false, "Uploads the debug bundle to a server")
|
||||
debugBundleCmd.Flags().StringVar(&uploadBundleURLFlag, "upload-bundle-url", types.DefaultBundleURL, "Service URL to get an URL to upload the debug bundle")
|
||||
|
||||
forCmd.Flags().Uint32VarP(&logFileCount, "log-file-count", "C", 1, "Number of rotated log files to include in debug bundle")
|
||||
forCmd.Flags().BoolVarP(&systemInfoFlag, "system-info", "S", true, "Adds system information to the debug bundle")
|
||||
forCmd.Flags().BoolVarP(&uploadBundleFlag, "upload-bundle", "U", false, "Uploads the debug bundle to a server")
|
||||
forCmd.Flags().StringVar(&uploadBundleURLFlag, "upload-bundle-url", types.DefaultBundleURL, "Service URL to get an URL to upload the debug bundle")
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal"
|
||||
"github.com/netbirdio/netbird/upload-server/types"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -37,10 +36,7 @@ const (
|
||||
disableAutoConnectFlag = "disable-auto-connect"
|
||||
extraIFaceBlackListFlag = "extra-iface-blacklist"
|
||||
dnsRouteIntervalFlag = "dns-router-interval"
|
||||
systemInfoFlag = "system-info"
|
||||
enableLazyConnectionFlag = "enable-lazy-connection"
|
||||
uploadBundle = "upload-bundle"
|
||||
uploadBundleURL = "upload-bundle-url"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -73,10 +69,7 @@ var (
|
||||
autoConnectDisabled bool
|
||||
extraIFaceBlackList []string
|
||||
anonymizeFlag bool
|
||||
debugSystemInfoFlag bool
|
||||
dnsRouteInterval time.Duration
|
||||
debugUploadBundle bool
|
||||
debugUploadBundleURL string
|
||||
lazyConnEnabled bool
|
||||
|
||||
rootCmd = &cobra.Command{
|
||||
@@ -181,11 +174,8 @@ func init() {
|
||||
upCmd.PersistentFlags().BoolVar(&rosenpassEnabled, enableRosenpassFlag, false, "[Experimental] Enable Rosenpass feature. If enabled, the connection will be post-quantum secured via Rosenpass.")
|
||||
upCmd.PersistentFlags().BoolVar(&rosenpassPermissive, rosenpassPermissiveFlag, false, "[Experimental] Enable Rosenpass in permissive mode to allow this peer to accept WireGuard connections without requiring Rosenpass functionality from peers that do not have Rosenpass enabled.")
|
||||
upCmd.PersistentFlags().BoolVar(&autoConnectDisabled, disableAutoConnectFlag, false, "Disables auto-connect feature. If enabled, then the client won't connect automatically when the service starts.")
|
||||
upCmd.PersistentFlags().BoolVar(&lazyConnEnabled, enableLazyConnectionFlag, false, "[Experimental] Enable the lazy connection feature. If enabled, the client will establish connections on-demand.")
|
||||
upCmd.PersistentFlags().BoolVar(&lazyConnEnabled, enableLazyConnectionFlag, false, "[Experimental] Enable the lazy connection feature. If enabled, the client will establish connections on-demand. Note: this setting may be overridden by management configuration.")
|
||||
|
||||
debugCmd.PersistentFlags().BoolVarP(&debugSystemInfoFlag, systemInfoFlag, "S", true, "Adds system information to the debug bundle")
|
||||
debugCmd.PersistentFlags().BoolVarP(&debugUploadBundle, uploadBundle, "U", false, fmt.Sprintf("Uploads the debug bundle to a server from URL defined by %s", uploadBundleURL))
|
||||
debugCmd.PersistentFlags().StringVar(&debugUploadBundleURL, uploadBundleURL, types.DefaultBundleURL, "Service URL to get an URL to upload the debug bundle")
|
||||
}
|
||||
|
||||
// SetupCloseHandler handles SIGTERM signal and exits with success
|
||||
|
||||
94
client/iface/bind/activity.go
Normal file
94
client/iface/bind/activity.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package bind
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/monotime"
|
||||
)
|
||||
|
||||
const (
|
||||
saveFrequency = int64(5 * time.Second)
|
||||
)
|
||||
|
||||
type PeerRecord struct {
|
||||
Address netip.AddrPort
|
||||
LastActivity atomic.Int64 // UnixNano timestamp
|
||||
}
|
||||
|
||||
type ActivityRecorder struct {
|
||||
mu sync.RWMutex
|
||||
peers map[string]*PeerRecord // publicKey to PeerRecord map
|
||||
addrToPeer map[netip.AddrPort]*PeerRecord // address to PeerRecord map
|
||||
}
|
||||
|
||||
func NewActivityRecorder() *ActivityRecorder {
|
||||
return &ActivityRecorder{
|
||||
peers: make(map[string]*PeerRecord),
|
||||
addrToPeer: make(map[netip.AddrPort]*PeerRecord),
|
||||
}
|
||||
}
|
||||
|
||||
// GetLastActivities returns a snapshot of peer last activity
|
||||
func (r *ActivityRecorder) GetLastActivities() map[string]time.Time {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
activities := make(map[string]time.Time, len(r.peers))
|
||||
for key, record := range r.peers {
|
||||
unixNano := record.LastActivity.Load()
|
||||
activities[key] = time.Unix(0, unixNano)
|
||||
}
|
||||
return activities
|
||||
}
|
||||
|
||||
// UpsertAddress adds or updates the address for a publicKey
|
||||
func (r *ActivityRecorder) UpsertAddress(publicKey string, address netip.AddrPort) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if pr, exists := r.peers[publicKey]; exists {
|
||||
delete(r.addrToPeer, pr.Address)
|
||||
pr.Address = address
|
||||
} else {
|
||||
record := &PeerRecord{
|
||||
Address: address,
|
||||
}
|
||||
record.LastActivity.Store(monotime.Now())
|
||||
r.peers[publicKey] = record
|
||||
}
|
||||
|
||||
r.addrToPeer[address] = r.peers[publicKey]
|
||||
}
|
||||
|
||||
func (r *ActivityRecorder) Remove(publicKey string) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if record, exists := r.peers[publicKey]; exists {
|
||||
delete(r.addrToPeer, record.Address)
|
||||
delete(r.peers, publicKey)
|
||||
}
|
||||
}
|
||||
|
||||
// record updates LastActivity for the given address using atomic store
|
||||
func (r *ActivityRecorder) record(address netip.AddrPort) {
|
||||
r.mu.RLock()
|
||||
record, ok := r.addrToPeer[address]
|
||||
r.mu.RUnlock()
|
||||
if !ok {
|
||||
log.Warnf("could not find record for address %s", address)
|
||||
return
|
||||
}
|
||||
|
||||
now := monotime.Now()
|
||||
last := record.LastActivity.Load()
|
||||
if now-last < saveFrequency {
|
||||
return
|
||||
}
|
||||
|
||||
_ = record.LastActivity.CompareAndSwap(last, now)
|
||||
}
|
||||
27
client/iface/bind/activity_test.go
Normal file
27
client/iface/bind/activity_test.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package bind
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestActivityRecorder_GetLastActivities(t *testing.T) {
|
||||
peer := "peer1"
|
||||
ar := NewActivityRecorder()
|
||||
ar.UpsertAddress("peer1", netip.MustParseAddrPort("192.168.0.5:51820"))
|
||||
activities := ar.GetLastActivities()
|
||||
|
||||
p, ok := activities[peer]
|
||||
if !ok {
|
||||
t.Fatalf("Expected activity for peer %s, but got none", peer)
|
||||
}
|
||||
|
||||
if p.IsZero() {
|
||||
t.Fatalf("Expected activity for peer %s, but got zero", peer)
|
||||
}
|
||||
|
||||
if p.Before(time.Now().Add(-2 * time.Minute)) {
|
||||
t.Fatalf("Expected activity for peer %s to be recent, but got %v", peer, p)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package bind
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
@@ -51,22 +52,24 @@ type ICEBind struct {
|
||||
closedChanMu sync.RWMutex // protect the closeChan recreation from reading from it.
|
||||
closed bool
|
||||
|
||||
muUDPMux sync.Mutex
|
||||
udpMux *UniversalUDPMuxDefault
|
||||
address wgaddr.Address
|
||||
muUDPMux sync.Mutex
|
||||
udpMux *UniversalUDPMuxDefault
|
||||
address wgaddr.Address
|
||||
activityRecorder *ActivityRecorder
|
||||
}
|
||||
|
||||
func NewICEBind(transportNet transport.Net, filterFn FilterFn, address wgaddr.Address) *ICEBind {
|
||||
b, _ := wgConn.NewStdNetBind().(*wgConn.StdNetBind)
|
||||
ib := &ICEBind{
|
||||
StdNetBind: b,
|
||||
RecvChan: make(chan RecvMessage, 1),
|
||||
transportNet: transportNet,
|
||||
filterFn: filterFn,
|
||||
endpoints: make(map[netip.Addr]net.Conn),
|
||||
closedChan: make(chan struct{}),
|
||||
closed: true,
|
||||
address: address,
|
||||
StdNetBind: b,
|
||||
RecvChan: make(chan RecvMessage, 1),
|
||||
transportNet: transportNet,
|
||||
filterFn: filterFn,
|
||||
endpoints: make(map[netip.Addr]net.Conn),
|
||||
closedChan: make(chan struct{}),
|
||||
closed: true,
|
||||
address: address,
|
||||
activityRecorder: NewActivityRecorder(),
|
||||
}
|
||||
|
||||
rc := receiverCreator{
|
||||
@@ -100,6 +103,10 @@ func (s *ICEBind) Close() error {
|
||||
return s.StdNetBind.Close()
|
||||
}
|
||||
|
||||
func (s *ICEBind) ActivityRecorder() *ActivityRecorder {
|
||||
return s.activityRecorder
|
||||
}
|
||||
|
||||
// GetICEMux returns the ICE UDPMux that was created and used by ICEBind
|
||||
func (s *ICEBind) GetICEMux() (*UniversalUDPMuxDefault, error) {
|
||||
s.muUDPMux.Lock()
|
||||
@@ -199,6 +206,11 @@ func (s *ICEBind) createIPv4ReceiverFn(pc *ipv4.PacketConn, conn *net.UDPConn, r
|
||||
continue
|
||||
}
|
||||
addrPort := msg.Addr.(*net.UDPAddr).AddrPort()
|
||||
|
||||
if isTransportPkg(msg.Buffers, msg.N) {
|
||||
s.activityRecorder.record(addrPort)
|
||||
}
|
||||
|
||||
ep := &wgConn.StdNetEndpoint{AddrPort: addrPort} // TODO: remove allocation
|
||||
wgConn.GetSrcFromControl(msg.OOB[:msg.NN], ep)
|
||||
eps[i] = ep
|
||||
@@ -257,6 +269,13 @@ func (c *ICEBind) receiveRelayed(buffs [][]byte, sizes []int, eps []wgConn.Endpo
|
||||
copy(buffs[0], msg.Buffer)
|
||||
sizes[0] = len(msg.Buffer)
|
||||
eps[0] = wgConn.Endpoint(msg.Endpoint)
|
||||
|
||||
if isTransportPkg(buffs, sizes[0]) {
|
||||
if ep, ok := eps[0].(*Endpoint); ok {
|
||||
c.activityRecorder.record(ep.AddrPort)
|
||||
}
|
||||
}
|
||||
|
||||
return 1, nil
|
||||
}
|
||||
}
|
||||
@@ -272,3 +291,19 @@ func putMessages(msgs *[]ipv6.Message, msgsPool *sync.Pool) {
|
||||
}
|
||||
msgsPool.Put(msgs)
|
||||
}
|
||||
|
||||
func isTransportPkg(buffers [][]byte, n int) bool {
|
||||
// The first buffer should contain at least 4 bytes for type
|
||||
if len(buffers[0]) < 4 {
|
||||
return true
|
||||
}
|
||||
|
||||
// WireGuard packet type is a little-endian uint32 at start
|
||||
packetType := binary.LittleEndian.Uint32(buffers[0][:4])
|
||||
|
||||
// Check if packetType matches known WireGuard message types
|
||||
if packetType == 4 && n > 32 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -276,3 +276,7 @@ func (c *KernelConfigurer) GetStats() (map[string]WGStats, error) {
|
||||
}
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func (c *KernelConfigurer) LastActivities() map[string]time.Time {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
|
||||
"github.com/netbirdio/netbird/client/iface/bind"
|
||||
nbnet "github.com/netbirdio/netbird/util/net"
|
||||
)
|
||||
|
||||
@@ -36,16 +37,18 @@ const (
|
||||
var ErrAllowedIPNotFound = fmt.Errorf("allowed IP not found")
|
||||
|
||||
type WGUSPConfigurer struct {
|
||||
device *device.Device
|
||||
deviceName string
|
||||
device *device.Device
|
||||
deviceName string
|
||||
activityRecorder *bind.ActivityRecorder
|
||||
|
||||
uapiListener net.Listener
|
||||
}
|
||||
|
||||
func NewUSPConfigurer(device *device.Device, deviceName string) *WGUSPConfigurer {
|
||||
func NewUSPConfigurer(device *device.Device, deviceName string, activityRecorder *bind.ActivityRecorder) *WGUSPConfigurer {
|
||||
wgCfg := &WGUSPConfigurer{
|
||||
device: device,
|
||||
deviceName: deviceName,
|
||||
device: device,
|
||||
deviceName: deviceName,
|
||||
activityRecorder: activityRecorder,
|
||||
}
|
||||
wgCfg.startUAPI()
|
||||
return wgCfg
|
||||
@@ -87,7 +90,19 @@ func (c *WGUSPConfigurer) UpdatePeer(peerKey string, allowedIps []netip.Prefix,
|
||||
Peers: []wgtypes.PeerConfig{peer},
|
||||
}
|
||||
|
||||
return c.device.IpcSet(toWgUserspaceString(config))
|
||||
if ipcErr := c.device.IpcSet(toWgUserspaceString(config)); ipcErr != nil {
|
||||
return ipcErr
|
||||
}
|
||||
|
||||
if endpoint != nil {
|
||||
addr, err := netip.ParseAddr(endpoint.IP.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse endpoint address: %w", err)
|
||||
}
|
||||
addrPort := netip.AddrPortFrom(addr, uint16(endpoint.Port))
|
||||
c.activityRecorder.UpsertAddress(peerKey, addrPort)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *WGUSPConfigurer) RemovePeer(peerKey string) error {
|
||||
@@ -104,7 +119,10 @@ func (c *WGUSPConfigurer) RemovePeer(peerKey string) error {
|
||||
config := wgtypes.Config{
|
||||
Peers: []wgtypes.PeerConfig{peer},
|
||||
}
|
||||
return c.device.IpcSet(toWgUserspaceString(config))
|
||||
ipcErr := c.device.IpcSet(toWgUserspaceString(config))
|
||||
|
||||
c.activityRecorder.Remove(peerKey)
|
||||
return ipcErr
|
||||
}
|
||||
|
||||
func (c *WGUSPConfigurer) AddAllowedIP(peerKey string, allowedIP netip.Prefix) error {
|
||||
@@ -205,6 +223,10 @@ func (c *WGUSPConfigurer) FullStats() (*Stats, error) {
|
||||
return parseStatus(c.deviceName, ipcStr)
|
||||
}
|
||||
|
||||
func (c *WGUSPConfigurer) LastActivities() map[string]time.Time {
|
||||
return c.activityRecorder.GetLastActivities()
|
||||
}
|
||||
|
||||
// startUAPI starts the UAPI listener for managing the WireGuard interface via external tool
|
||||
func (t *WGUSPConfigurer) startUAPI() {
|
||||
var err error
|
||||
|
||||
@@ -79,7 +79,7 @@ func (t *WGTunDevice) Create(routes []string, dns string, searchDomains []string
|
||||
// this helps with support for the older NetBird clients that had a hardcoded direct mode
|
||||
// t.device.DisableSomeRoamingForBrokenMobileSemantics()
|
||||
|
||||
t.configurer = configurer.NewUSPConfigurer(t.device, t.name)
|
||||
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder())
|
||||
err = t.configurer.ConfigureInterface(t.key, t.port)
|
||||
if err != nil {
|
||||
t.device.Close()
|
||||
|
||||
@@ -61,7 +61,7 @@ func (t *TunDevice) Create() (WGConfigurer, error) {
|
||||
return nil, fmt.Errorf("error assigning ip: %s", err)
|
||||
}
|
||||
|
||||
t.configurer = configurer.NewUSPConfigurer(t.device, t.name)
|
||||
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder())
|
||||
err = t.configurer.ConfigureInterface(t.key, t.port)
|
||||
if err != nil {
|
||||
t.device.Close()
|
||||
|
||||
@@ -71,7 +71,7 @@ func (t *TunDevice) Create() (WGConfigurer, error) {
|
||||
// this helps with support for the older NetBird clients that had a hardcoded direct mode
|
||||
// t.device.DisableSomeRoamingForBrokenMobileSemantics()
|
||||
|
||||
t.configurer = configurer.NewUSPConfigurer(t.device, t.name)
|
||||
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder())
|
||||
err = t.configurer.ConfigureInterface(t.key, t.port)
|
||||
if err != nil {
|
||||
t.device.Close()
|
||||
|
||||
@@ -72,7 +72,7 @@ func (t *TunNetstackDevice) Create() (WGConfigurer, error) {
|
||||
device.NewLogger(wgLogLevel(), "[netbird] "),
|
||||
)
|
||||
|
||||
t.configurer = configurer.NewUSPConfigurer(t.device, t.name)
|
||||
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder())
|
||||
err = t.configurer.ConfigureInterface(t.key, t.port)
|
||||
if err != nil {
|
||||
_ = tunIface.Close()
|
||||
|
||||
@@ -64,7 +64,7 @@ func (t *USPDevice) Create() (WGConfigurer, error) {
|
||||
return nil, fmt.Errorf("error assigning ip: %s", err)
|
||||
}
|
||||
|
||||
t.configurer = configurer.NewUSPConfigurer(t.device, t.name)
|
||||
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder())
|
||||
err = t.configurer.ConfigureInterface(t.key, t.port)
|
||||
if err != nil {
|
||||
t.device.Close()
|
||||
|
||||
@@ -94,7 +94,7 @@ func (t *TunDevice) Create() (WGConfigurer, error) {
|
||||
return nil, fmt.Errorf("error assigning ip: %s", err)
|
||||
}
|
||||
|
||||
t.configurer = configurer.NewUSPConfigurer(t.device, t.name)
|
||||
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder())
|
||||
err = t.configurer.ConfigureInterface(t.key, t.port)
|
||||
if err != nil {
|
||||
t.device.Close()
|
||||
|
||||
@@ -19,4 +19,5 @@ type WGConfigurer interface {
|
||||
Close()
|
||||
GetStats() (map[string]configurer.WGStats, error)
|
||||
FullStats() (*configurer.Stats, error)
|
||||
LastActivities() map[string]time.Time
|
||||
}
|
||||
|
||||
@@ -29,6 +29,11 @@ const (
|
||||
WgInterfaceDefault = configurer.WgInterfaceDefault
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrIfaceNotFound is returned when the WireGuard interface is not found
|
||||
ErrIfaceNotFound = fmt.Errorf("wireguard interface not found")
|
||||
)
|
||||
|
||||
type wgProxyFactory interface {
|
||||
GetProxy() wgproxy.Proxy
|
||||
Free() error
|
||||
@@ -117,6 +122,9 @@ func (w *WGIface) UpdateAddr(newAddr string) error {
|
||||
func (w *WGIface) UpdatePeer(peerKey string, allowedIps []netip.Prefix, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
if w.configurer == nil {
|
||||
return ErrIfaceNotFound
|
||||
}
|
||||
|
||||
log.Debugf("updating interface %s peer %s, endpoint %s, allowedIPs %v", w.tun.DeviceName(), peerKey, endpoint, allowedIps)
|
||||
return w.configurer.UpdatePeer(peerKey, allowedIps, keepAlive, endpoint, preSharedKey)
|
||||
@@ -126,6 +134,9 @@ func (w *WGIface) UpdatePeer(peerKey string, allowedIps []netip.Prefix, keepAliv
|
||||
func (w *WGIface) RemovePeer(peerKey string) error {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
if w.configurer == nil {
|
||||
return ErrIfaceNotFound
|
||||
}
|
||||
|
||||
log.Debugf("Removing peer %s from interface %s ", peerKey, w.tun.DeviceName())
|
||||
return w.configurer.RemovePeer(peerKey)
|
||||
@@ -135,6 +146,9 @@ func (w *WGIface) RemovePeer(peerKey string) error {
|
||||
func (w *WGIface) AddAllowedIP(peerKey string, allowedIP netip.Prefix) error {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
if w.configurer == nil {
|
||||
return ErrIfaceNotFound
|
||||
}
|
||||
|
||||
log.Debugf("Adding allowed IP to interface %s and peer %s: allowed IP %s ", w.tun.DeviceName(), peerKey, allowedIP)
|
||||
return w.configurer.AddAllowedIP(peerKey, allowedIP)
|
||||
@@ -144,6 +158,9 @@ func (w *WGIface) AddAllowedIP(peerKey string, allowedIP netip.Prefix) error {
|
||||
func (w *WGIface) RemoveAllowedIP(peerKey string, allowedIP netip.Prefix) error {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
if w.configurer == nil {
|
||||
return ErrIfaceNotFound
|
||||
}
|
||||
|
||||
log.Debugf("Removing allowed IP from interface %s and peer %s: allowed IP %s ", w.tun.DeviceName(), peerKey, allowedIP)
|
||||
return w.configurer.RemoveAllowedIP(peerKey, allowedIP)
|
||||
@@ -214,10 +231,29 @@ func (w *WGIface) GetWGDevice() *wgdevice.Device {
|
||||
|
||||
// GetStats returns the last handshake time, rx and tx bytes
|
||||
func (w *WGIface) GetStats() (map[string]configurer.WGStats, error) {
|
||||
if w.configurer == nil {
|
||||
return nil, ErrIfaceNotFound
|
||||
}
|
||||
return w.configurer.GetStats()
|
||||
}
|
||||
|
||||
func (w *WGIface) LastActivities() map[string]time.Time {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
if w.configurer == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return w.configurer.LastActivities()
|
||||
|
||||
}
|
||||
|
||||
func (w *WGIface) FullStats() (*configurer.Stats, error) {
|
||||
if w.configurer == nil {
|
||||
return nil, ErrIfaceNotFound
|
||||
}
|
||||
|
||||
return w.configurer.FullStats()
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/netbirdio/netbird/client/internal/lazyconn"
|
||||
"github.com/netbirdio/netbird/client/internal/lazyconn/manager"
|
||||
"github.com/netbirdio/netbird/client/internal/peer"
|
||||
"github.com/netbirdio/netbird/client/internal/peer/dispatcher"
|
||||
"github.com/netbirdio/netbird/client/internal/peerstore"
|
||||
"github.com/netbirdio/netbird/route"
|
||||
)
|
||||
@@ -26,11 +25,11 @@ import (
|
||||
//
|
||||
// The implementation is not thread-safe; it is protected by engine.syncMsgMux.
|
||||
type ConnMgr struct {
|
||||
peerStore *peerstore.Store
|
||||
statusRecorder *peer.Status
|
||||
iface lazyconn.WGIface
|
||||
dispatcher *dispatcher.ConnectionDispatcher
|
||||
enabledLocally bool
|
||||
peerStore *peerstore.Store
|
||||
statusRecorder *peer.Status
|
||||
iface lazyconn.WGIface
|
||||
enabledLocally bool
|
||||
rosenpassEnabled bool
|
||||
|
||||
lazyConnMgr *manager.Manager
|
||||
|
||||
@@ -39,12 +38,12 @@ type ConnMgr struct {
|
||||
lazyCtxCancel context.CancelFunc
|
||||
}
|
||||
|
||||
func NewConnMgr(engineConfig *EngineConfig, statusRecorder *peer.Status, peerStore *peerstore.Store, iface lazyconn.WGIface, dispatcher *dispatcher.ConnectionDispatcher) *ConnMgr {
|
||||
func NewConnMgr(engineConfig *EngineConfig, statusRecorder *peer.Status, peerStore *peerstore.Store, iface lazyconn.WGIface) *ConnMgr {
|
||||
e := &ConnMgr{
|
||||
peerStore: peerStore,
|
||||
statusRecorder: statusRecorder,
|
||||
iface: iface,
|
||||
dispatcher: dispatcher,
|
||||
peerStore: peerStore,
|
||||
statusRecorder: statusRecorder,
|
||||
iface: iface,
|
||||
rosenpassEnabled: engineConfig.RosenpassEnabled,
|
||||
}
|
||||
if engineConfig.LazyConnectionEnabled || lazyconn.IsLazyConnEnabledByEnv() {
|
||||
e.enabledLocally = true
|
||||
@@ -64,6 +63,11 @@ func (e *ConnMgr) Start(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if e.rosenpassEnabled {
|
||||
log.Warnf("rosenpass connection manager is enabled, lazy connection manager will not be started")
|
||||
return
|
||||
}
|
||||
|
||||
e.initLazyManager(ctx)
|
||||
e.statusRecorder.UpdateLazyConnection(true)
|
||||
}
|
||||
@@ -83,7 +87,12 @@ func (e *ConnMgr) UpdatedRemoteFeatureFlag(ctx context.Context, enabled bool) er
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infof("lazy connection manager is enabled by management feature flag")
|
||||
if e.rosenpassEnabled {
|
||||
log.Infof("rosenpass connection manager is enabled, lazy connection manager will not be started")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Warnf("lazy connection manager is enabled by management feature flag")
|
||||
e.initLazyManager(ctx)
|
||||
e.statusRecorder.UpdateLazyConnection(true)
|
||||
return e.addPeersToLazyConnManager()
|
||||
@@ -133,7 +142,7 @@ func (e *ConnMgr) SetExcludeList(ctx context.Context, peerIDs map[string]bool) {
|
||||
excludedPeers = append(excludedPeers, lazyPeerCfg)
|
||||
}
|
||||
|
||||
added := e.lazyConnMgr.ExcludePeer(e.lazyCtx, excludedPeers)
|
||||
added := e.lazyConnMgr.ExcludePeer(excludedPeers)
|
||||
for _, peerID := range added {
|
||||
var peerConn *peer.Conn
|
||||
var exists bool
|
||||
@@ -175,7 +184,7 @@ func (e *ConnMgr) AddPeerConn(ctx context.Context, peerKey string, conn *peer.Co
|
||||
PeerConnID: conn.ConnID(),
|
||||
Log: conn.Log,
|
||||
}
|
||||
excluded, err := e.lazyConnMgr.AddPeer(e.lazyCtx, lazyPeerCfg)
|
||||
excluded, err := e.lazyConnMgr.AddPeer(lazyPeerCfg)
|
||||
if err != nil {
|
||||
conn.Log.Errorf("failed to add peer to lazyconn manager: %v", err)
|
||||
if err := conn.Open(ctx); err != nil {
|
||||
@@ -201,7 +210,7 @@ func (e *ConnMgr) RemovePeerConn(peerKey string) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
defer conn.Close(false)
|
||||
|
||||
if !e.isStartedWithLazyMgr() {
|
||||
return
|
||||
@@ -211,23 +220,28 @@ func (e *ConnMgr) RemovePeerConn(peerKey string) {
|
||||
conn.Log.Infof("removed peer from lazy conn manager")
|
||||
}
|
||||
|
||||
func (e *ConnMgr) OnSignalMsg(ctx context.Context, peerKey string) (*peer.Conn, bool) {
|
||||
conn, ok := e.peerStore.PeerConn(peerKey)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (e *ConnMgr) ActivatePeer(ctx context.Context, conn *peer.Conn) {
|
||||
if !e.isStartedWithLazyMgr() {
|
||||
return conn, true
|
||||
return
|
||||
}
|
||||
|
||||
if found := e.lazyConnMgr.ActivatePeer(e.lazyCtx, peerKey); found {
|
||||
if found := e.lazyConnMgr.ActivatePeer(conn.GetKey()); found {
|
||||
conn.Log.Infof("activated peer from inactive state")
|
||||
if err := conn.Open(ctx); err != nil {
|
||||
conn.Log.Errorf("failed to open connection: %v", err)
|
||||
}
|
||||
}
|
||||
return conn, true
|
||||
}
|
||||
|
||||
// DeactivatePeer deactivates a peer connection in the lazy connection manager.
|
||||
// If locally the lazy connection is disabled, we force the peer connection open.
|
||||
func (e *ConnMgr) DeactivatePeer(conn *peer.Conn) {
|
||||
if !e.isStartedWithLazyMgr() {
|
||||
return
|
||||
}
|
||||
|
||||
conn.Log.Infof("closing peer connection: remote peer initiated inactive, idle lazy state and sent GOAWAY")
|
||||
e.lazyConnMgr.DeactivatePeer(conn.ConnID())
|
||||
}
|
||||
|
||||
func (e *ConnMgr) Close() {
|
||||
@@ -244,7 +258,7 @@ func (e *ConnMgr) initLazyManager(engineCtx context.Context) {
|
||||
cfg := manager.Config{
|
||||
InactivityThreshold: inactivityThresholdEnv(),
|
||||
}
|
||||
e.lazyConnMgr = manager.NewManager(cfg, engineCtx, e.peerStore, e.iface, e.dispatcher)
|
||||
e.lazyConnMgr = manager.NewManager(cfg, engineCtx, e.peerStore, e.iface)
|
||||
|
||||
e.lazyCtx, e.lazyCtxCancel = context.WithCancel(engineCtx)
|
||||
|
||||
@@ -275,7 +289,7 @@ func (e *ConnMgr) addPeersToLazyConnManager() error {
|
||||
lazyPeerCfgs = append(lazyPeerCfgs, lazyPeerCfg)
|
||||
}
|
||||
|
||||
return e.lazyConnMgr.AddActivePeers(e.lazyCtx, lazyPeerCfgs)
|
||||
return e.lazyConnMgr.AddActivePeers(lazyPeerCfgs)
|
||||
}
|
||||
|
||||
func (e *ConnMgr) closeManager(ctx context.Context) {
|
||||
|
||||
@@ -167,6 +167,7 @@ type BundleGenerator struct {
|
||||
anonymize bool
|
||||
clientStatus string
|
||||
includeSystemInfo bool
|
||||
logFileCount uint32
|
||||
|
||||
archive *zip.Writer
|
||||
}
|
||||
@@ -175,6 +176,7 @@ type BundleConfig struct {
|
||||
Anonymize bool
|
||||
ClientStatus string
|
||||
IncludeSystemInfo bool
|
||||
LogFileCount uint32
|
||||
}
|
||||
|
||||
type GeneratorDependencies struct {
|
||||
@@ -185,6 +187,12 @@ type GeneratorDependencies struct {
|
||||
}
|
||||
|
||||
func NewBundleGenerator(deps GeneratorDependencies, cfg BundleConfig) *BundleGenerator {
|
||||
// Default to 1 log file for backward compatibility when 0 is provided
|
||||
logFileCount := cfg.LogFileCount
|
||||
if logFileCount == 0 {
|
||||
logFileCount = 1
|
||||
}
|
||||
|
||||
return &BundleGenerator{
|
||||
anonymizer: anonymize.NewAnonymizer(anonymize.DefaultAddresses()),
|
||||
|
||||
@@ -196,6 +204,7 @@ func NewBundleGenerator(deps GeneratorDependencies, cfg BundleConfig) *BundleGen
|
||||
anonymize: cfg.Anonymize,
|
||||
clientStatus: cfg.ClientStatus,
|
||||
includeSystemInfo: cfg.IncludeSystemInfo,
|
||||
logFileCount: logFileCount,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -573,32 +582,8 @@ func (g *BundleGenerator) addLogfile() error {
|
||||
return fmt.Errorf("add client log file to zip: %w", err)
|
||||
}
|
||||
|
||||
// add latest rotated log file
|
||||
pattern := filepath.Join(logDir, "client-*.log.gz")
|
||||
files, err := filepath.Glob(pattern)
|
||||
if err != nil {
|
||||
log.Warnf("failed to glob rotated logs: %v", err)
|
||||
} else if len(files) > 0 {
|
||||
// pick the file with the latest ModTime
|
||||
sort.Slice(files, func(i, j int) bool {
|
||||
fi, err := os.Stat(files[i])
|
||||
if err != nil {
|
||||
log.Warnf("failed to stat rotated log %s: %v", files[i], err)
|
||||
return false
|
||||
}
|
||||
fj, err := os.Stat(files[j])
|
||||
if err != nil {
|
||||
log.Warnf("failed to stat rotated log %s: %v", files[j], err)
|
||||
return false
|
||||
}
|
||||
return fi.ModTime().Before(fj.ModTime())
|
||||
})
|
||||
latest := files[len(files)-1]
|
||||
name := filepath.Base(latest)
|
||||
if err := g.addSingleLogFileGz(latest, name); err != nil {
|
||||
log.Warnf("failed to add rotated log %s: %v", name, err)
|
||||
}
|
||||
}
|
||||
// add rotated log files based on logFileCount
|
||||
g.addRotatedLogFiles(logDir)
|
||||
|
||||
stdErrLogPath := filepath.Join(logDir, errorLogFile)
|
||||
stdoutLogPath := filepath.Join(logDir, stdoutLogFile)
|
||||
@@ -682,6 +667,52 @@ func (g *BundleGenerator) addSingleLogFileGz(logPath, targetName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// addRotatedLogFiles adds rotated log files to the bundle based on logFileCount
|
||||
func (g *BundleGenerator) addRotatedLogFiles(logDir string) {
|
||||
if g.logFileCount == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
pattern := filepath.Join(logDir, "client-*.log.gz")
|
||||
files, err := filepath.Glob(pattern)
|
||||
if err != nil {
|
||||
log.Warnf("failed to glob rotated logs: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// sort files by modification time (newest first)
|
||||
sort.Slice(files, func(i, j int) bool {
|
||||
fi, err := os.Stat(files[i])
|
||||
if err != nil {
|
||||
log.Warnf("failed to stat rotated log %s: %v", files[i], err)
|
||||
return false
|
||||
}
|
||||
fj, err := os.Stat(files[j])
|
||||
if err != nil {
|
||||
log.Warnf("failed to stat rotated log %s: %v", files[j], err)
|
||||
return false
|
||||
}
|
||||
return fi.ModTime().After(fj.ModTime())
|
||||
})
|
||||
|
||||
// include up to logFileCount rotated files
|
||||
maxFiles := int(g.logFileCount)
|
||||
if maxFiles > len(files) {
|
||||
maxFiles = len(files)
|
||||
}
|
||||
|
||||
for i := 0; i < maxFiles; i++ {
|
||||
name := filepath.Base(files[i])
|
||||
if err := g.addSingleLogFileGz(files[i], name); err != nil {
|
||||
log.Warnf("failed to add rotated log %s: %v", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *BundleGenerator) addFileToZip(reader io.Reader, filename string) error {
|
||||
header := &zip.FileHeader{
|
||||
Name: filename,
|
||||
|
||||
@@ -36,7 +36,6 @@ import (
|
||||
nftypes "github.com/netbirdio/netbird/client/internal/netflow/types"
|
||||
"github.com/netbirdio/netbird/client/internal/networkmonitor"
|
||||
"github.com/netbirdio/netbird/client/internal/peer"
|
||||
"github.com/netbirdio/netbird/client/internal/peer/dispatcher"
|
||||
"github.com/netbirdio/netbird/client/internal/peer/guard"
|
||||
icemaker "github.com/netbirdio/netbird/client/internal/peer/ice"
|
||||
"github.com/netbirdio/netbird/client/internal/peerstore"
|
||||
@@ -175,8 +174,7 @@ type Engine struct {
|
||||
|
||||
sshServer sshServer
|
||||
|
||||
statusRecorder *peer.Status
|
||||
peerConnDispatcher *dispatcher.ConnectionDispatcher
|
||||
statusRecorder *peer.Status
|
||||
|
||||
firewall firewallManager.Manager
|
||||
routeManager routemanager.Manager
|
||||
@@ -463,9 +461,7 @@ func (e *Engine) Start() error {
|
||||
NATExternalIPs: e.parseNATExternalIPMappings(),
|
||||
}
|
||||
|
||||
e.peerConnDispatcher = dispatcher.NewConnectionDispatcher()
|
||||
|
||||
e.connMgr = NewConnMgr(e.config, e.statusRecorder, e.peerStore, wgIface, e.peerConnDispatcher)
|
||||
e.connMgr = NewConnMgr(e.config, e.statusRecorder, e.peerStore, wgIface)
|
||||
e.connMgr.Start(e.ctx)
|
||||
|
||||
e.srWatcher = guard.NewSRWatcher(e.signal, e.relayManager, e.mobileDep.IFaceDiscover, iceCfg)
|
||||
@@ -1222,7 +1218,7 @@ func (e *Engine) addNewPeer(peerConfig *mgmProto.RemotePeerConfig) error {
|
||||
}
|
||||
|
||||
if exists := e.connMgr.AddPeerConn(e.ctx, peerKey, conn); exists {
|
||||
conn.Close()
|
||||
conn.Close(false)
|
||||
return fmt.Errorf("peer already exists: %s", peerKey)
|
||||
}
|
||||
|
||||
@@ -1270,13 +1266,12 @@ func (e *Engine) createPeerConn(pubKey string, allowedIPs []netip.Prefix, agentV
|
||||
}
|
||||
|
||||
serviceDependencies := peer.ServiceDependencies{
|
||||
StatusRecorder: e.statusRecorder,
|
||||
Signaler: e.signaler,
|
||||
IFaceDiscover: e.mobileDep.IFaceDiscover,
|
||||
RelayManager: e.relayManager,
|
||||
SrWatcher: e.srWatcher,
|
||||
Semaphore: e.connSemaphore,
|
||||
PeerConnDispatcher: e.peerConnDispatcher,
|
||||
StatusRecorder: e.statusRecorder,
|
||||
Signaler: e.signaler,
|
||||
IFaceDiscover: e.mobileDep.IFaceDiscover,
|
||||
RelayManager: e.relayManager,
|
||||
SrWatcher: e.srWatcher,
|
||||
Semaphore: e.connSemaphore,
|
||||
}
|
||||
peerConn, err := peer.NewConn(config, serviceDependencies)
|
||||
if err != nil {
|
||||
@@ -1299,11 +1294,16 @@ func (e *Engine) receiveSignalEvents() {
|
||||
e.syncMsgMux.Lock()
|
||||
defer e.syncMsgMux.Unlock()
|
||||
|
||||
conn, ok := e.connMgr.OnSignalMsg(e.ctx, msg.Key)
|
||||
conn, ok := e.peerStore.PeerConn(msg.Key)
|
||||
if !ok {
|
||||
return fmt.Errorf("wrongly addressed message %s", msg.Key)
|
||||
}
|
||||
|
||||
msgType := msg.GetBody().GetType()
|
||||
if msgType != sProto.Body_GO_IDLE {
|
||||
e.connMgr.ActivatePeer(e.ctx, conn)
|
||||
}
|
||||
|
||||
switch msg.GetBody().Type {
|
||||
case sProto.Body_OFFER:
|
||||
remoteCred, err := signal.UnMarshalCredential(msg)
|
||||
@@ -1360,6 +1360,8 @@ func (e *Engine) receiveSignalEvents() {
|
||||
|
||||
go conn.OnRemoteCandidate(candidate, e.routeManager.GetClientRoutes())
|
||||
case sProto.Body_MODE:
|
||||
case sProto.Body_GO_IDLE:
|
||||
e.connMgr.DeactivatePeer(conn)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -36,7 +36,6 @@ import (
|
||||
"github.com/netbirdio/netbird/client/iface/wgproxy"
|
||||
"github.com/netbirdio/netbird/client/internal/dns"
|
||||
"github.com/netbirdio/netbird/client/internal/peer"
|
||||
"github.com/netbirdio/netbird/client/internal/peer/dispatcher"
|
||||
"github.com/netbirdio/netbird/client/internal/peer/guard"
|
||||
icemaker "github.com/netbirdio/netbird/client/internal/peer/ice"
|
||||
"github.com/netbirdio/netbird/client/internal/routemanager"
|
||||
@@ -97,6 +96,7 @@ type MockWGIface struct {
|
||||
GetInterfaceGUIDStringFunc func() (string, error)
|
||||
GetProxyFunc func() wgproxy.Proxy
|
||||
GetNetFunc func() *netstack.Net
|
||||
LastActivitiesFunc func() map[string]time.Time
|
||||
}
|
||||
|
||||
func (m *MockWGIface) FullStats() (*configurer.Stats, error) {
|
||||
@@ -187,6 +187,13 @@ func (m *MockWGIface) GetNet() *netstack.Net {
|
||||
return m.GetNetFunc()
|
||||
}
|
||||
|
||||
func (m *MockWGIface) LastActivities() map[string]time.Time {
|
||||
if m.LastActivitiesFunc != nil {
|
||||
return m.LastActivitiesFunc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
_ = util.InitLog("debug", "console")
|
||||
code := m.Run()
|
||||
@@ -430,7 +437,7 @@ func TestEngine_UpdateNetworkMap(t *testing.T) {
|
||||
engine.udpMux = bind.NewUniversalUDPMuxDefault(bind.UniversalUDPMuxParams{UDPConn: conn})
|
||||
engine.ctx = ctx
|
||||
engine.srWatcher = guard.NewSRWatcher(nil, nil, nil, icemaker.Config{})
|
||||
engine.connMgr = NewConnMgr(engine.config, engine.statusRecorder, engine.peerStore, wgIface, dispatcher.NewConnectionDispatcher())
|
||||
engine.connMgr = NewConnMgr(engine.config, engine.statusRecorder, engine.peerStore, wgIface)
|
||||
engine.connMgr.Start(ctx)
|
||||
|
||||
type testCase struct {
|
||||
@@ -819,7 +826,7 @@ func TestEngine_UpdateNetworkMapWithRoutes(t *testing.T) {
|
||||
|
||||
engine.routeManager = mockRouteManager
|
||||
engine.dnsServer = &dns.MockServer{}
|
||||
engine.connMgr = NewConnMgr(engine.config, engine.statusRecorder, engine.peerStore, engine.wgInterface, dispatcher.NewConnectionDispatcher())
|
||||
engine.connMgr = NewConnMgr(engine.config, engine.statusRecorder, engine.peerStore, engine.wgInterface)
|
||||
engine.connMgr.Start(ctx)
|
||||
|
||||
defer func() {
|
||||
@@ -1017,7 +1024,7 @@ func TestEngine_UpdateNetworkMapWithDNSUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
engine.dnsServer = mockDNSServer
|
||||
engine.connMgr = NewConnMgr(engine.config, engine.statusRecorder, engine.peerStore, engine.wgInterface, dispatcher.NewConnectionDispatcher())
|
||||
engine.connMgr = NewConnMgr(engine.config, engine.statusRecorder, engine.peerStore, engine.wgInterface)
|
||||
engine.connMgr.Start(ctx)
|
||||
|
||||
defer func() {
|
||||
|
||||
@@ -38,4 +38,5 @@ type wgIfaceBase interface {
|
||||
GetStats() (map[string]configurer.WGStats, error)
|
||||
GetNet() *netstack.Net
|
||||
FullStats() (*configurer.Stats, error)
|
||||
LastActivities() map[string]time.Time
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
// Listener it is not a thread safe implementation, do not call Close before ReadPackets. It will cause blocking
|
||||
type Listener struct {
|
||||
wgIface lazyconn.WGIface
|
||||
wgIface WgInterface
|
||||
peerCfg lazyconn.PeerConfig
|
||||
conn *net.UDPConn
|
||||
endpoint *net.UDPAddr
|
||||
@@ -22,7 +22,7 @@ type Listener struct {
|
||||
isClosed atomic.Bool // use to avoid error log when closing the listener
|
||||
}
|
||||
|
||||
func NewListener(wgIface lazyconn.WGIface, cfg lazyconn.PeerConfig) (*Listener, error) {
|
||||
func NewListener(wgIface WgInterface, cfg lazyconn.PeerConfig) (*Listener, error) {
|
||||
d := &Listener{
|
||||
wgIface: wgIface,
|
||||
peerCfg: cfg,
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
package activity
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/lazyconn"
|
||||
peerid "github.com/netbirdio/netbird/client/internal/peer/id"
|
||||
)
|
||||
|
||||
type WgInterface interface {
|
||||
RemovePeer(peerKey string) error
|
||||
UpdatePeer(peerKey string, allowedIps []netip.Prefix, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error
|
||||
}
|
||||
|
||||
type Manager struct {
|
||||
OnActivityChan chan peerid.ConnID
|
||||
|
||||
wgIface lazyconn.WGIface
|
||||
wgIface WgInterface
|
||||
|
||||
peers map[peerid.ConnID]*Listener
|
||||
done chan struct{}
|
||||
@@ -20,7 +29,7 @@ type Manager struct {
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func NewManager(wgIface lazyconn.WGIface) *Manager {
|
||||
func NewManager(wgIface WgInterface) *Manager {
|
||||
m := &Manager{
|
||||
OnActivityChan: make(chan peerid.ConnID, 1),
|
||||
wgIface: wgIface,
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
package inactivity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
peer "github.com/netbirdio/netbird/client/internal/peer/id"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultInactivityThreshold = 60 * time.Minute // idle after 1 hour inactivity
|
||||
MinimumInactivityThreshold = 3 * time.Minute
|
||||
)
|
||||
|
||||
type Monitor struct {
|
||||
id peer.ConnID
|
||||
timer *time.Timer
|
||||
cancel context.CancelFunc
|
||||
inactivityThreshold time.Duration
|
||||
}
|
||||
|
||||
func NewInactivityMonitor(peerID peer.ConnID, threshold time.Duration) *Monitor {
|
||||
i := &Monitor{
|
||||
id: peerID,
|
||||
timer: time.NewTimer(0),
|
||||
inactivityThreshold: threshold,
|
||||
}
|
||||
i.timer.Stop()
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *Monitor) Start(ctx context.Context, timeoutChan chan peer.ConnID) {
|
||||
i.timer.Reset(i.inactivityThreshold)
|
||||
defer i.timer.Stop()
|
||||
|
||||
ctx, i.cancel = context.WithCancel(ctx)
|
||||
defer func() {
|
||||
defer i.cancel()
|
||||
select {
|
||||
case <-i.timer.C:
|
||||
default:
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-i.timer.C:
|
||||
select {
|
||||
case timeoutChan <- i.id:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Monitor) Stop() {
|
||||
if i.cancel == nil {
|
||||
return
|
||||
}
|
||||
i.cancel()
|
||||
}
|
||||
|
||||
func (i *Monitor) PauseTimer() {
|
||||
i.timer.Stop()
|
||||
}
|
||||
|
||||
func (i *Monitor) ResetTimer() {
|
||||
i.timer.Reset(i.inactivityThreshold)
|
||||
}
|
||||
|
||||
func (i *Monitor) ResetMonitor(ctx context.Context, timeoutChan chan peer.ConnID) {
|
||||
i.Stop()
|
||||
go i.Start(ctx, timeoutChan)
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
package inactivity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
peerid "github.com/netbirdio/netbird/client/internal/peer/id"
|
||||
)
|
||||
|
||||
type MocPeer struct {
|
||||
}
|
||||
|
||||
func (m *MocPeer) ConnID() peerid.ConnID {
|
||||
return peerid.ConnID(m)
|
||||
}
|
||||
|
||||
func TestInactivityMonitor(t *testing.T) {
|
||||
tCtx, testTimeoutCancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
defer testTimeoutCancel()
|
||||
|
||||
p := &MocPeer{}
|
||||
im := NewInactivityMonitor(p.ConnID(), time.Second*2)
|
||||
|
||||
timeoutChan := make(chan peerid.ConnID)
|
||||
|
||||
exitChan := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(exitChan)
|
||||
im.Start(tCtx, timeoutChan)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-timeoutChan:
|
||||
case <-tCtx.Done():
|
||||
t.Fatal("timeout")
|
||||
}
|
||||
|
||||
select {
|
||||
case <-exitChan:
|
||||
case <-tCtx.Done():
|
||||
t.Fatal("timeout")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReuseInactivityMonitor(t *testing.T) {
|
||||
p := &MocPeer{}
|
||||
im := NewInactivityMonitor(p.ConnID(), time.Second*2)
|
||||
|
||||
timeoutChan := make(chan peerid.ConnID)
|
||||
|
||||
for i := 2; i > 0; i-- {
|
||||
exitChan := make(chan struct{})
|
||||
|
||||
testTimeoutCtx, testTimeoutCancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
|
||||
go func() {
|
||||
defer close(exitChan)
|
||||
im.Start(testTimeoutCtx, timeoutChan)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-timeoutChan:
|
||||
case <-testTimeoutCtx.Done():
|
||||
t.Fatal("timeout")
|
||||
}
|
||||
|
||||
select {
|
||||
case <-exitChan:
|
||||
case <-testTimeoutCtx.Done():
|
||||
t.Fatal("timeout")
|
||||
}
|
||||
testTimeoutCancel()
|
||||
}
|
||||
}
|
||||
|
||||
func TestStopInactivityMonitor(t *testing.T) {
|
||||
tCtx, testTimeoutCancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
defer testTimeoutCancel()
|
||||
|
||||
p := &MocPeer{}
|
||||
im := NewInactivityMonitor(p.ConnID(), DefaultInactivityThreshold)
|
||||
|
||||
timeoutChan := make(chan peerid.ConnID)
|
||||
|
||||
exitChan := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(exitChan)
|
||||
im.Start(tCtx, timeoutChan)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
time.Sleep(3 * time.Second)
|
||||
im.Stop()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-timeoutChan:
|
||||
t.Fatal("unexpected timeout")
|
||||
case <-exitChan:
|
||||
case <-tCtx.Done():
|
||||
t.Fatal("timeout")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPauseInactivityMonitor(t *testing.T) {
|
||||
tCtx, testTimeoutCancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer testTimeoutCancel()
|
||||
|
||||
p := &MocPeer{}
|
||||
trashHold := time.Second * 3
|
||||
im := NewInactivityMonitor(p.ConnID(), trashHold)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
timeoutChan := make(chan peerid.ConnID)
|
||||
|
||||
exitChan := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(exitChan)
|
||||
im.Start(ctx, timeoutChan)
|
||||
}()
|
||||
|
||||
time.Sleep(1 * time.Second) // grant time to start the monitor
|
||||
im.PauseTimer()
|
||||
|
||||
// check to do not receive timeout
|
||||
thresholdCtx, thresholdCancel := context.WithTimeout(context.Background(), trashHold+time.Second)
|
||||
defer thresholdCancel()
|
||||
select {
|
||||
case <-exitChan:
|
||||
t.Fatal("unexpected exit")
|
||||
case <-timeoutChan:
|
||||
t.Fatal("unexpected timeout")
|
||||
case <-thresholdCtx.Done():
|
||||
// test ok
|
||||
case <-tCtx.Done():
|
||||
t.Fatal("test timed out")
|
||||
}
|
||||
|
||||
// test reset timer
|
||||
im.ResetTimer()
|
||||
|
||||
select {
|
||||
case <-tCtx.Done():
|
||||
t.Fatal("test timed out")
|
||||
case <-exitChan:
|
||||
t.Fatal("unexpected exit")
|
||||
case <-timeoutChan:
|
||||
// expected timeout
|
||||
}
|
||||
}
|
||||
152
client/internal/lazyconn/inactivity/manager.go
Normal file
152
client/internal/lazyconn/inactivity/manager.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package inactivity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/lazyconn"
|
||||
)
|
||||
|
||||
const (
|
||||
checkInterval = 1 * time.Minute
|
||||
|
||||
DefaultInactivityThreshold = 15 * time.Minute
|
||||
MinimumInactivityThreshold = 1 * time.Minute
|
||||
)
|
||||
|
||||
type WgInterface interface {
|
||||
LastActivities() map[string]time.Time
|
||||
}
|
||||
|
||||
type Manager struct {
|
||||
inactivePeersChan chan map[string]struct{}
|
||||
|
||||
iface WgInterface
|
||||
interestedPeers map[string]*lazyconn.PeerConfig
|
||||
inactivityThreshold time.Duration
|
||||
}
|
||||
|
||||
func NewManager(iface WgInterface, configuredThreshold *time.Duration) *Manager {
|
||||
inactivityThreshold, err := validateInactivityThreshold(configuredThreshold)
|
||||
if err != nil {
|
||||
inactivityThreshold = DefaultInactivityThreshold
|
||||
log.Warnf("invalid inactivity threshold configured: %v, using default: %v", err, DefaultInactivityThreshold)
|
||||
}
|
||||
|
||||
log.Infof("inactivity threshold configured: %v", inactivityThreshold)
|
||||
return &Manager{
|
||||
inactivePeersChan: make(chan map[string]struct{}, 1),
|
||||
iface: iface,
|
||||
interestedPeers: make(map[string]*lazyconn.PeerConfig),
|
||||
inactivityThreshold: inactivityThreshold,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) InactivePeersChan() chan map[string]struct{} {
|
||||
if m == nil {
|
||||
// return a nil channel that blocks forever
|
||||
return nil
|
||||
}
|
||||
|
||||
return m.inactivePeersChan
|
||||
}
|
||||
|
||||
func (m *Manager) AddPeer(peerCfg *lazyconn.PeerConfig) {
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _, exists := m.interestedPeers[peerCfg.PublicKey]; exists {
|
||||
return
|
||||
}
|
||||
|
||||
peerCfg.Log.Infof("adding peer to inactivity manager")
|
||||
m.interestedPeers[peerCfg.PublicKey] = peerCfg
|
||||
}
|
||||
|
||||
func (m *Manager) RemovePeer(peer string) {
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
|
||||
pi, ok := m.interestedPeers[peer]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
pi.Log.Debugf("remove peer from inactivity manager")
|
||||
delete(m.interestedPeers, peer)
|
||||
}
|
||||
|
||||
func (m *Manager) Start(ctx context.Context) {
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := newTicker(checkInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C():
|
||||
idlePeers, err := m.checkStats()
|
||||
if err != nil {
|
||||
log.Errorf("error checking stats: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(idlePeers) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
m.notifyInactivePeers(ctx, idlePeers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) notifyInactivePeers(ctx context.Context, inactivePeers map[string]struct{}) {
|
||||
select {
|
||||
case m.inactivePeersChan <- inactivePeers:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) checkStats() (map[string]struct{}, error) {
|
||||
lastActivities := m.iface.LastActivities()
|
||||
|
||||
idlePeers := make(map[string]struct{})
|
||||
|
||||
for peerID, peerCfg := range m.interestedPeers {
|
||||
lastActive, ok := lastActivities[peerID]
|
||||
if !ok {
|
||||
// when peer is in connecting state
|
||||
peerCfg.Log.Warnf("peer not found in wg stats")
|
||||
continue
|
||||
}
|
||||
|
||||
if time.Since(lastActive) > m.inactivityThreshold {
|
||||
peerCfg.Log.Infof("peer is inactive since: %v", lastActive)
|
||||
idlePeers[peerID] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return idlePeers, nil
|
||||
}
|
||||
|
||||
func validateInactivityThreshold(configuredThreshold *time.Duration) (time.Duration, error) {
|
||||
if configuredThreshold == nil {
|
||||
return DefaultInactivityThreshold, nil
|
||||
}
|
||||
if *configuredThreshold < MinimumInactivityThreshold {
|
||||
return 0, fmt.Errorf("configured inactivity threshold %v is too low, using %v", *configuredThreshold, MinimumInactivityThreshold)
|
||||
}
|
||||
return *configuredThreshold, nil
|
||||
}
|
||||
113
client/internal/lazyconn/inactivity/manager_test.go
Normal file
113
client/internal/lazyconn/inactivity/manager_test.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package inactivity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/lazyconn"
|
||||
)
|
||||
|
||||
type mockWgInterface struct {
|
||||
lastActivities map[string]time.Time
|
||||
}
|
||||
|
||||
func (m *mockWgInterface) LastActivities() map[string]time.Time {
|
||||
return m.lastActivities
|
||||
}
|
||||
|
||||
func TestPeerTriggersInactivity(t *testing.T) {
|
||||
peerID := "peer1"
|
||||
|
||||
wgMock := &mockWgInterface{
|
||||
lastActivities: map[string]time.Time{
|
||||
peerID: time.Now().Add(-20 * time.Minute),
|
||||
},
|
||||
}
|
||||
|
||||
fakeTick := make(chan time.Time, 1)
|
||||
newTicker = func(d time.Duration) Ticker {
|
||||
return &fakeTickerMock{CChan: fakeTick}
|
||||
}
|
||||
|
||||
peerLog := log.WithField("peer", peerID)
|
||||
peerCfg := &lazyconn.PeerConfig{
|
||||
PublicKey: peerID,
|
||||
Log: peerLog,
|
||||
}
|
||||
|
||||
manager := NewManager(wgMock, nil)
|
||||
manager.AddPeer(peerCfg)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Start the manager in a goroutine
|
||||
go manager.Start(ctx)
|
||||
|
||||
// Send a tick to simulate time passage
|
||||
fakeTick <- time.Now()
|
||||
|
||||
// Check if peer appears on inactivePeersChan
|
||||
select {
|
||||
case inactivePeers := <-manager.inactivePeersChan:
|
||||
assert.Contains(t, inactivePeers, peerID, "expected peer to be marked inactive")
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatal("expected inactivity event, but none received")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPeerTriggersActivity(t *testing.T) {
|
||||
peerID := "peer1"
|
||||
|
||||
wgMock := &mockWgInterface{
|
||||
lastActivities: map[string]time.Time{
|
||||
peerID: time.Now().Add(-5 * time.Minute),
|
||||
},
|
||||
}
|
||||
|
||||
fakeTick := make(chan time.Time, 1)
|
||||
newTicker = func(d time.Duration) Ticker {
|
||||
return &fakeTickerMock{CChan: fakeTick}
|
||||
}
|
||||
|
||||
peerLog := log.WithField("peer", peerID)
|
||||
peerCfg := &lazyconn.PeerConfig{
|
||||
PublicKey: peerID,
|
||||
Log: peerLog,
|
||||
}
|
||||
|
||||
manager := NewManager(wgMock, nil)
|
||||
manager.AddPeer(peerCfg)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Start the manager in a goroutine
|
||||
go manager.Start(ctx)
|
||||
|
||||
// Send a tick to simulate time passage
|
||||
fakeTick <- time.Now()
|
||||
|
||||
// Check if peer appears on inactivePeersChan
|
||||
select {
|
||||
case <-manager.inactivePeersChan:
|
||||
t.Fatal("expected inactive peer to be marked inactive")
|
||||
case <-time.After(1 * time.Second):
|
||||
// No inactivity event should be received
|
||||
}
|
||||
}
|
||||
|
||||
// fakeTickerMock implements Ticker interface for testing
|
||||
type fakeTickerMock struct {
|
||||
CChan chan time.Time
|
||||
}
|
||||
|
||||
func (f *fakeTickerMock) C() <-chan time.Time {
|
||||
return f.CChan
|
||||
}
|
||||
|
||||
func (f *fakeTickerMock) Stop() {}
|
||||
24
client/internal/lazyconn/inactivity/ticker.go
Normal file
24
client/internal/lazyconn/inactivity/ticker.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package inactivity
|
||||
|
||||
import "time"
|
||||
|
||||
var newTicker = func(d time.Duration) Ticker {
|
||||
return &realTicker{t: time.NewTicker(d)}
|
||||
}
|
||||
|
||||
type Ticker interface {
|
||||
C() <-chan time.Time
|
||||
Stop()
|
||||
}
|
||||
|
||||
type realTicker struct {
|
||||
t *time.Ticker
|
||||
}
|
||||
|
||||
func (r *realTicker) C() <-chan time.Time {
|
||||
return r.t.C
|
||||
}
|
||||
|
||||
func (r *realTicker) Stop() {
|
||||
r.t.Stop()
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/netbirdio/netbird/client/internal/lazyconn"
|
||||
"github.com/netbirdio/netbird/client/internal/lazyconn/activity"
|
||||
"github.com/netbirdio/netbird/client/internal/lazyconn/inactivity"
|
||||
"github.com/netbirdio/netbird/client/internal/peer/dispatcher"
|
||||
peerid "github.com/netbirdio/netbird/client/internal/peer/id"
|
||||
"github.com/netbirdio/netbird/client/internal/peerstore"
|
||||
"github.com/netbirdio/netbird/route"
|
||||
@@ -43,60 +42,46 @@ type Config struct {
|
||||
type Manager struct {
|
||||
engineCtx context.Context
|
||||
peerStore *peerstore.Store
|
||||
connStateDispatcher *dispatcher.ConnectionDispatcher
|
||||
inactivityThreshold time.Duration
|
||||
|
||||
connStateListener *dispatcher.ConnectionListener
|
||||
managedPeers map[string]*lazyconn.PeerConfig
|
||||
managedPeersByConnID map[peerid.ConnID]*managedPeer
|
||||
excludes map[string]lazyconn.PeerConfig
|
||||
managedPeersMu sync.Mutex
|
||||
|
||||
activityManager *activity.Manager
|
||||
inactivityMonitors map[peerid.ConnID]*inactivity.Monitor
|
||||
activityManager *activity.Manager
|
||||
inactivityManager *inactivity.Manager
|
||||
|
||||
// Route HA group management
|
||||
// If any peer in the same HA group is active, all peers in that group should prevent going idle
|
||||
peerToHAGroups map[string][]route.HAUniqueID // peer ID -> HA groups they belong to
|
||||
haGroupToPeers map[route.HAUniqueID][]string // HA group -> peer IDs in the group
|
||||
routesMu sync.RWMutex
|
||||
|
||||
onInactive chan peerid.ConnID
|
||||
}
|
||||
|
||||
// NewManager creates a new lazy connection manager
|
||||
// engineCtx is the context for creating peer Connection
|
||||
func NewManager(config Config, engineCtx context.Context, peerStore *peerstore.Store, wgIface lazyconn.WGIface, connStateDispatcher *dispatcher.ConnectionDispatcher) *Manager {
|
||||
func NewManager(config Config, engineCtx context.Context, peerStore *peerstore.Store, wgIface lazyconn.WGIface) *Manager {
|
||||
log.Infof("setup lazy connection service")
|
||||
|
||||
m := &Manager{
|
||||
engineCtx: engineCtx,
|
||||
peerStore: peerStore,
|
||||
connStateDispatcher: connStateDispatcher,
|
||||
inactivityThreshold: inactivity.DefaultInactivityThreshold,
|
||||
managedPeers: make(map[string]*lazyconn.PeerConfig),
|
||||
managedPeersByConnID: make(map[peerid.ConnID]*managedPeer),
|
||||
excludes: make(map[string]lazyconn.PeerConfig),
|
||||
activityManager: activity.NewManager(wgIface),
|
||||
inactivityMonitors: make(map[peerid.ConnID]*inactivity.Monitor),
|
||||
peerToHAGroups: make(map[string][]route.HAUniqueID),
|
||||
haGroupToPeers: make(map[route.HAUniqueID][]string),
|
||||
onInactive: make(chan peerid.ConnID),
|
||||
}
|
||||
|
||||
if config.InactivityThreshold != nil {
|
||||
if *config.InactivityThreshold >= inactivity.MinimumInactivityThreshold {
|
||||
m.inactivityThreshold = *config.InactivityThreshold
|
||||
} else {
|
||||
log.Warnf("inactivity threshold is too low, using %v", m.inactivityThreshold)
|
||||
}
|
||||
if wgIface.IsUserspaceBind() {
|
||||
m.inactivityManager = inactivity.NewManager(wgIface, config.InactivityThreshold)
|
||||
} else {
|
||||
log.Warnf("inactivity manager not supported for kernel mode, wait for remote peer to close the connection")
|
||||
}
|
||||
|
||||
m.connStateListener = &dispatcher.ConnectionListener{
|
||||
OnConnected: m.onPeerConnected,
|
||||
OnDisconnected: m.onPeerDisconnected,
|
||||
}
|
||||
|
||||
connStateDispatcher.AddListener(m.connStateListener)
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -131,24 +116,28 @@ func (m *Manager) UpdateRouteHAMap(haMap route.HAMap) {
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf("updated route HA mappings: %d HA groups, %d peers with routes",
|
||||
len(m.haGroupToPeers), len(m.peerToHAGroups))
|
||||
log.Debugf("updated route HA mappings: %d HA groups, %d peers with routes", len(m.haGroupToPeers), len(m.peerToHAGroups))
|
||||
}
|
||||
|
||||
// Start starts the manager and listens for peer activity and inactivity events
|
||||
func (m *Manager) Start(ctx context.Context) {
|
||||
defer m.close()
|
||||
|
||||
if m.inactivityManager != nil {
|
||||
go m.inactivityManager.Start(ctx)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case peerConnID := <-m.activityManager.OnActivityChan:
|
||||
m.onPeerActivity(ctx, peerConnID)
|
||||
case peerConnID := <-m.onInactive:
|
||||
m.onPeerInactivityTimedOut(ctx, peerConnID)
|
||||
m.onPeerActivity(peerConnID)
|
||||
case peerIDs := <-m.inactivityManager.InactivePeersChan():
|
||||
m.onPeerInactivityTimedOut(peerIDs)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ExcludePeer marks peers for a permanent connection
|
||||
@@ -156,7 +145,7 @@ func (m *Manager) Start(ctx context.Context) {
|
||||
// Adds them back to the managed list and start the inactivity listener if they are removed from the exclude list. In
|
||||
// this case, we suppose that the connection status is connected or connecting.
|
||||
// If the peer is not exists yet in the managed list then the responsibility is the upper layer to call the AddPeer function
|
||||
func (m *Manager) ExcludePeer(ctx context.Context, peerConfigs []lazyconn.PeerConfig) []string {
|
||||
func (m *Manager) ExcludePeer(peerConfigs []lazyconn.PeerConfig) []string {
|
||||
m.managedPeersMu.Lock()
|
||||
defer m.managedPeersMu.Unlock()
|
||||
|
||||
@@ -187,7 +176,7 @@ func (m *Manager) ExcludePeer(ctx context.Context, peerConfigs []lazyconn.PeerCo
|
||||
|
||||
peerCfg.Log.Infof("peer removed from lazy connection exclude list")
|
||||
|
||||
if err := m.addActivePeer(ctx, peerCfg); err != nil {
|
||||
if err := m.addActivePeer(&peerCfg); err != nil {
|
||||
log.Errorf("failed to add peer to lazy connection manager: %s", err)
|
||||
continue
|
||||
}
|
||||
@@ -197,7 +186,7 @@ func (m *Manager) ExcludePeer(ctx context.Context, peerConfigs []lazyconn.PeerCo
|
||||
return added
|
||||
}
|
||||
|
||||
func (m *Manager) AddPeer(ctx context.Context, peerCfg lazyconn.PeerConfig) (bool, error) {
|
||||
func (m *Manager) AddPeer(peerCfg lazyconn.PeerConfig) (bool, error) {
|
||||
m.managedPeersMu.Lock()
|
||||
defer m.managedPeersMu.Unlock()
|
||||
|
||||
@@ -217,9 +206,6 @@ func (m *Manager) AddPeer(ctx context.Context, peerCfg lazyconn.PeerConfig) (boo
|
||||
return false, err
|
||||
}
|
||||
|
||||
im := inactivity.NewInactivityMonitor(peerCfg.PeerConnID, m.inactivityThreshold)
|
||||
m.inactivityMonitors[peerCfg.PeerConnID] = im
|
||||
|
||||
m.managedPeers[peerCfg.PublicKey] = &peerCfg
|
||||
m.managedPeersByConnID[peerCfg.PeerConnID] = &managedPeer{
|
||||
peerCfg: &peerCfg,
|
||||
@@ -229,7 +215,7 @@ func (m *Manager) AddPeer(ctx context.Context, peerCfg lazyconn.PeerConfig) (boo
|
||||
// Check if this peer should be activated because its HA group peers are active
|
||||
if group, ok := m.shouldActivateNewPeer(peerCfg.PublicKey); ok {
|
||||
peerCfg.Log.Debugf("peer belongs to active HA group %s, will activate immediately", group)
|
||||
m.activateNewPeerInActiveGroup(ctx, peerCfg)
|
||||
m.activateNewPeerInActiveGroup(peerCfg)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
@@ -237,7 +223,7 @@ func (m *Manager) AddPeer(ctx context.Context, peerCfg lazyconn.PeerConfig) (boo
|
||||
|
||||
// AddActivePeers adds a list of peers to the lazy connection manager
|
||||
// suppose these peers was in connected or in connecting states
|
||||
func (m *Manager) AddActivePeers(ctx context.Context, peerCfg []lazyconn.PeerConfig) error {
|
||||
func (m *Manager) AddActivePeers(peerCfg []lazyconn.PeerConfig) error {
|
||||
m.managedPeersMu.Lock()
|
||||
defer m.managedPeersMu.Unlock()
|
||||
|
||||
@@ -247,7 +233,7 @@ func (m *Manager) AddActivePeers(ctx context.Context, peerCfg []lazyconn.PeerCon
|
||||
continue
|
||||
}
|
||||
|
||||
if err := m.addActivePeer(ctx, cfg); err != nil {
|
||||
if err := m.addActivePeer(&cfg); err != nil {
|
||||
cfg.Log.Errorf("failed to add peer to lazy connection manager: %v", err)
|
||||
return err
|
||||
}
|
||||
@@ -264,7 +250,7 @@ func (m *Manager) RemovePeer(peerID string) {
|
||||
|
||||
// ActivatePeer activates a peer connection when a signal message is received
|
||||
// Also activates all peers in the same HA groups as this peer
|
||||
func (m *Manager) ActivatePeer(ctx context.Context, peerID string) (found bool) {
|
||||
func (m *Manager) ActivatePeer(peerID string) (found bool) {
|
||||
m.managedPeersMu.Lock()
|
||||
defer m.managedPeersMu.Unlock()
|
||||
cfg, mp := m.getPeerForActivation(peerID)
|
||||
@@ -272,15 +258,42 @@ func (m *Manager) ActivatePeer(ctx context.Context, peerID string) (found bool)
|
||||
return false
|
||||
}
|
||||
|
||||
if !m.activateSinglePeer(ctx, cfg, mp) {
|
||||
if !m.activateSinglePeer(cfg, mp) {
|
||||
return false
|
||||
}
|
||||
|
||||
m.activateHAGroupPeers(ctx, peerID)
|
||||
m.activateHAGroupPeers(cfg)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *Manager) DeactivatePeer(peerID peerid.ConnID) {
|
||||
m.managedPeersMu.Lock()
|
||||
defer m.managedPeersMu.Unlock()
|
||||
|
||||
mp, ok := m.managedPeersByConnID[peerID]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if mp.expectedWatcher != watcherInactivity {
|
||||
return
|
||||
}
|
||||
|
||||
m.peerStore.PeerConnClose(mp.peerCfg.PublicKey)
|
||||
|
||||
mp.peerCfg.Log.Infof("start activity monitor")
|
||||
|
||||
mp.expectedWatcher = watcherActivity
|
||||
|
||||
m.inactivityManager.RemovePeer(mp.peerCfg.PublicKey)
|
||||
|
||||
if err := m.activityManager.MonitorPeerActivity(*mp.peerCfg); err != nil {
|
||||
mp.peerCfg.Log.Errorf("failed to create activity monitor: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// getPeerForActivation checks if a peer can be activated and returns the necessary structs
|
||||
// Returns nil values if the peer should be skipped
|
||||
func (m *Manager) getPeerForActivation(peerID string) (*lazyconn.PeerConfig, *managedPeer) {
|
||||
@@ -302,41 +315,36 @@ func (m *Manager) getPeerForActivation(peerID string) (*lazyconn.PeerConfig, *ma
|
||||
return cfg, mp
|
||||
}
|
||||
|
||||
// activateSinglePeer activates a single peer (internal method)
|
||||
func (m *Manager) activateSinglePeer(ctx context.Context, cfg *lazyconn.PeerConfig, mp *managedPeer) bool {
|
||||
mp.expectedWatcher = watcherInactivity
|
||||
|
||||
m.activityManager.RemovePeer(cfg.Log, cfg.PeerConnID)
|
||||
|
||||
im, ok := m.inactivityMonitors[cfg.PeerConnID]
|
||||
if !ok {
|
||||
cfg.Log.Errorf("inactivity monitor not found for peer")
|
||||
// activateSinglePeer activates a single peer
|
||||
// return true if the peer was activated, false if it was already active
|
||||
func (m *Manager) activateSinglePeer(cfg *lazyconn.PeerConfig, mp *managedPeer) bool {
|
||||
if mp.expectedWatcher == watcherInactivity {
|
||||
return false
|
||||
}
|
||||
|
||||
cfg.Log.Infof("starting inactivity monitor")
|
||||
go im.Start(ctx, m.onInactive)
|
||||
|
||||
mp.expectedWatcher = watcherInactivity
|
||||
m.activityManager.RemovePeer(cfg.Log, cfg.PeerConnID)
|
||||
m.inactivityManager.AddPeer(cfg)
|
||||
return true
|
||||
}
|
||||
|
||||
// activateHAGroupPeers activates all peers in HA groups that the given peer belongs to
|
||||
func (m *Manager) activateHAGroupPeers(ctx context.Context, triggerPeerID string) {
|
||||
func (m *Manager) activateHAGroupPeers(triggeredPeerCfg *lazyconn.PeerConfig) {
|
||||
var peersToActivate []string
|
||||
|
||||
m.routesMu.RLock()
|
||||
haGroups := m.peerToHAGroups[triggerPeerID]
|
||||
haGroups := m.peerToHAGroups[triggeredPeerCfg.PublicKey]
|
||||
|
||||
if len(haGroups) == 0 {
|
||||
m.routesMu.RUnlock()
|
||||
log.Debugf("peer %s is not part of any HA groups", triggerPeerID)
|
||||
triggeredPeerCfg.Log.Debugf("peer is not part of any HA groups")
|
||||
return
|
||||
}
|
||||
|
||||
for _, haGroup := range haGroups {
|
||||
peers := m.haGroupToPeers[haGroup]
|
||||
for _, peerID := range peers {
|
||||
if peerID != triggerPeerID {
|
||||
if peerID != triggeredPeerCfg.PublicKey {
|
||||
peersToActivate = append(peersToActivate, peerID)
|
||||
}
|
||||
}
|
||||
@@ -350,16 +358,16 @@ func (m *Manager) activateHAGroupPeers(ctx context.Context, triggerPeerID string
|
||||
continue
|
||||
}
|
||||
|
||||
if m.activateSinglePeer(ctx, cfg, mp) {
|
||||
if m.activateSinglePeer(cfg, mp) {
|
||||
activatedCount++
|
||||
cfg.Log.Infof("activated peer as part of HA group (triggered by %s)", triggerPeerID)
|
||||
cfg.Log.Infof("activated peer as part of HA group (triggered by %s)", triggeredPeerCfg.PublicKey)
|
||||
m.peerStore.PeerConnOpen(m.engineCtx, cfg.PublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
if activatedCount > 0 {
|
||||
log.Infof("activated %d additional peers in HA groups for peer %s (groups: %v)",
|
||||
activatedCount, triggerPeerID, haGroups)
|
||||
activatedCount, triggeredPeerCfg.PublicKey, haGroups)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,13 +402,13 @@ func (m *Manager) shouldActivateNewPeer(peerID string) (route.HAUniqueID, bool)
|
||||
}
|
||||
|
||||
// activateNewPeerInActiveGroup activates a newly added peer that should be active due to HA group
|
||||
func (m *Manager) activateNewPeerInActiveGroup(ctx context.Context, peerCfg lazyconn.PeerConfig) {
|
||||
func (m *Manager) activateNewPeerInActiveGroup(peerCfg lazyconn.PeerConfig) {
|
||||
mp, ok := m.managedPeersByConnID[peerCfg.PeerConnID]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if !m.activateSinglePeer(ctx, &peerCfg, mp) {
|
||||
if !m.activateSinglePeer(&peerCfg, mp) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -408,23 +416,19 @@ func (m *Manager) activateNewPeerInActiveGroup(ctx context.Context, peerCfg lazy
|
||||
m.peerStore.PeerConnOpen(m.engineCtx, peerCfg.PublicKey)
|
||||
}
|
||||
|
||||
func (m *Manager) addActivePeer(ctx context.Context, peerCfg lazyconn.PeerConfig) error {
|
||||
func (m *Manager) addActivePeer(peerCfg *lazyconn.PeerConfig) error {
|
||||
if _, ok := m.managedPeers[peerCfg.PublicKey]; ok {
|
||||
peerCfg.Log.Warnf("peer already managed")
|
||||
return nil
|
||||
}
|
||||
|
||||
im := inactivity.NewInactivityMonitor(peerCfg.PeerConnID, m.inactivityThreshold)
|
||||
m.inactivityMonitors[peerCfg.PeerConnID] = im
|
||||
|
||||
m.managedPeers[peerCfg.PublicKey] = &peerCfg
|
||||
m.managedPeers[peerCfg.PublicKey] = peerCfg
|
||||
m.managedPeersByConnID[peerCfg.PeerConnID] = &managedPeer{
|
||||
peerCfg: &peerCfg,
|
||||
peerCfg: peerCfg,
|
||||
expectedWatcher: watcherInactivity,
|
||||
}
|
||||
|
||||
peerCfg.Log.Infof("starting inactivity monitor on peer that has been removed from exclude list")
|
||||
go im.Start(ctx, m.onInactive)
|
||||
m.inactivityManager.AddPeer(peerCfg)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -436,12 +440,7 @@ func (m *Manager) removePeer(peerID string) {
|
||||
|
||||
cfg.Log.Infof("removing lazy peer")
|
||||
|
||||
if im, ok := m.inactivityMonitors[cfg.PeerConnID]; ok {
|
||||
im.Stop()
|
||||
delete(m.inactivityMonitors, cfg.PeerConnID)
|
||||
cfg.Log.Debugf("inactivity monitor stopped")
|
||||
}
|
||||
|
||||
m.inactivityManager.RemovePeer(cfg.PublicKey)
|
||||
m.activityManager.RemovePeer(cfg.Log, cfg.PeerConnID)
|
||||
delete(m.managedPeers, peerID)
|
||||
delete(m.managedPeersByConnID, cfg.PeerConnID)
|
||||
@@ -451,12 +450,8 @@ func (m *Manager) close() {
|
||||
m.managedPeersMu.Lock()
|
||||
defer m.managedPeersMu.Unlock()
|
||||
|
||||
m.connStateDispatcher.RemoveListener(m.connStateListener)
|
||||
m.activityManager.Close()
|
||||
for _, iw := range m.inactivityMonitors {
|
||||
iw.Stop()
|
||||
}
|
||||
m.inactivityMonitors = make(map[peerid.ConnID]*inactivity.Monitor)
|
||||
|
||||
m.managedPeers = make(map[string]*lazyconn.PeerConfig)
|
||||
m.managedPeersByConnID = make(map[peerid.ConnID]*managedPeer)
|
||||
|
||||
@@ -470,7 +465,7 @@ func (m *Manager) close() {
|
||||
}
|
||||
|
||||
// shouldDeferIdleForHA checks if peer should stay connected due to HA group requirements
|
||||
func (m *Manager) shouldDeferIdleForHA(peerID string) bool {
|
||||
func (m *Manager) shouldDeferIdleForHA(inactivePeers map[string]struct{}, peerID string) bool {
|
||||
m.routesMu.RLock()
|
||||
defer m.routesMu.RUnlock()
|
||||
|
||||
@@ -480,38 +475,45 @@ func (m *Manager) shouldDeferIdleForHA(peerID string) bool {
|
||||
}
|
||||
|
||||
for _, haGroup := range haGroups {
|
||||
groupPeers := m.haGroupToPeers[haGroup]
|
||||
|
||||
for _, groupPeerID := range groupPeers {
|
||||
if groupPeerID == peerID {
|
||||
continue
|
||||
}
|
||||
|
||||
cfg, ok := m.managedPeers[groupPeerID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
groupMp, ok := m.managedPeersByConnID[cfg.PeerConnID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if groupMp.expectedWatcher != watcherInactivity {
|
||||
continue
|
||||
}
|
||||
|
||||
// Other member is still connected, defer idle
|
||||
if peer, ok := m.peerStore.PeerConn(groupPeerID); ok && peer.IsConnected() {
|
||||
return true
|
||||
}
|
||||
if active := m.checkHaGroupActivity(haGroup, peerID, inactivePeers); active {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Manager) onPeerActivity(ctx context.Context, peerConnID peerid.ConnID) {
|
||||
func (m *Manager) checkHaGroupActivity(haGroup route.HAUniqueID, peerID string, inactivePeers map[string]struct{}) bool {
|
||||
groupPeers := m.haGroupToPeers[haGroup]
|
||||
for _, groupPeerID := range groupPeers {
|
||||
|
||||
if groupPeerID == peerID {
|
||||
continue
|
||||
}
|
||||
|
||||
cfg, ok := m.managedPeers[groupPeerID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
groupMp, ok := m.managedPeersByConnID[cfg.PeerConnID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if groupMp.expectedWatcher != watcherInactivity {
|
||||
continue
|
||||
}
|
||||
|
||||
// If any peer in the group is active, do defer idle
|
||||
if _, isInactive := inactivePeers[groupPeerID]; !isInactive {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Manager) onPeerActivity(peerConnID peerid.ConnID) {
|
||||
m.managedPeersMu.Lock()
|
||||
defer m.managedPeersMu.Unlock()
|
||||
|
||||
@@ -528,100 +530,56 @@ func (m *Manager) onPeerActivity(ctx context.Context, peerConnID peerid.ConnID)
|
||||
|
||||
mp.peerCfg.Log.Infof("detected peer activity")
|
||||
|
||||
if !m.activateSinglePeer(ctx, mp.peerCfg, mp) {
|
||||
if !m.activateSinglePeer(mp.peerCfg, mp) {
|
||||
return
|
||||
}
|
||||
|
||||
m.activateHAGroupPeers(ctx, mp.peerCfg.PublicKey)
|
||||
m.activateHAGroupPeers(mp.peerCfg)
|
||||
|
||||
m.peerStore.PeerConnOpen(m.engineCtx, mp.peerCfg.PublicKey)
|
||||
}
|
||||
|
||||
func (m *Manager) onPeerInactivityTimedOut(ctx context.Context, peerConnID peerid.ConnID) {
|
||||
func (m *Manager) onPeerInactivityTimedOut(peerIDs map[string]struct{}) {
|
||||
m.managedPeersMu.Lock()
|
||||
defer m.managedPeersMu.Unlock()
|
||||
|
||||
mp, ok := m.managedPeersByConnID[peerConnID]
|
||||
if !ok {
|
||||
log.Errorf("peer not found by id: %v", peerConnID)
|
||||
return
|
||||
}
|
||||
|
||||
if mp.expectedWatcher != watcherInactivity {
|
||||
mp.peerCfg.Log.Warnf("ignore inactivity event")
|
||||
return
|
||||
}
|
||||
|
||||
if m.shouldDeferIdleForHA(mp.peerCfg.PublicKey) {
|
||||
iw, ok := m.inactivityMonitors[peerConnID]
|
||||
if ok {
|
||||
mp.peerCfg.Log.Debugf("resetting inactivity timer due to HA group requirements")
|
||||
iw.ResetMonitor(ctx, m.onInactive)
|
||||
} else {
|
||||
mp.peerCfg.Log.Errorf("inactivity monitor not found for HA defer reset")
|
||||
for peerID := range peerIDs {
|
||||
peerCfg, ok := m.managedPeers[peerID]
|
||||
if !ok {
|
||||
log.Errorf("peer not found by peerId: %v", peerID)
|
||||
continue
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
mp.peerCfg.Log.Infof("connection timed out")
|
||||
mp, ok := m.managedPeersByConnID[peerCfg.PeerConnID]
|
||||
if !ok {
|
||||
log.Errorf("peer not found by conn id: %v", peerCfg.PeerConnID)
|
||||
continue
|
||||
}
|
||||
|
||||
// this is blocking operation, potentially can be optimized
|
||||
m.peerStore.PeerConnClose(mp.peerCfg.PublicKey)
|
||||
if mp.expectedWatcher != watcherInactivity {
|
||||
mp.peerCfg.Log.Warnf("ignore inactivity event")
|
||||
continue
|
||||
}
|
||||
|
||||
mp.peerCfg.Log.Infof("start activity monitor")
|
||||
if m.shouldDeferIdleForHA(peerIDs, mp.peerCfg.PublicKey) {
|
||||
mp.peerCfg.Log.Infof("defer inactivity due to active HA group peers")
|
||||
continue
|
||||
}
|
||||
|
||||
mp.expectedWatcher = watcherActivity
|
||||
mp.peerCfg.Log.Infof("connection timed out")
|
||||
|
||||
// just in case free up
|
||||
m.inactivityMonitors[peerConnID].PauseTimer()
|
||||
// this is blocking operation, potentially can be optimized
|
||||
m.peerStore.PeerConnIdle(mp.peerCfg.PublicKey)
|
||||
|
||||
if err := m.activityManager.MonitorPeerActivity(*mp.peerCfg); err != nil {
|
||||
mp.peerCfg.Log.Errorf("failed to create activity monitor: %v", err)
|
||||
return
|
||||
mp.peerCfg.Log.Infof("start activity monitor")
|
||||
|
||||
mp.expectedWatcher = watcherActivity
|
||||
|
||||
m.inactivityManager.RemovePeer(mp.peerCfg.PublicKey)
|
||||
|
||||
if err := m.activityManager.MonitorPeerActivity(*mp.peerCfg); err != nil {
|
||||
mp.peerCfg.Log.Errorf("failed to create activity monitor: %v", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) onPeerConnected(peerConnID peerid.ConnID) {
|
||||
m.managedPeersMu.Lock()
|
||||
defer m.managedPeersMu.Unlock()
|
||||
|
||||
mp, ok := m.managedPeersByConnID[peerConnID]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if mp.expectedWatcher != watcherInactivity {
|
||||
return
|
||||
}
|
||||
|
||||
iw, ok := m.inactivityMonitors[mp.peerCfg.PeerConnID]
|
||||
if !ok {
|
||||
mp.peerCfg.Log.Warnf("inactivity monitor not found for peer")
|
||||
return
|
||||
}
|
||||
|
||||
mp.peerCfg.Log.Infof("peer connected, pausing inactivity monitor while connection is not disconnected")
|
||||
iw.PauseTimer()
|
||||
}
|
||||
|
||||
func (m *Manager) onPeerDisconnected(peerConnID peerid.ConnID) {
|
||||
m.managedPeersMu.Lock()
|
||||
defer m.managedPeersMu.Unlock()
|
||||
|
||||
mp, ok := m.managedPeersByConnID[peerConnID]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if mp.expectedWatcher != watcherInactivity {
|
||||
return
|
||||
}
|
||||
|
||||
iw, ok := m.inactivityMonitors[mp.peerCfg.PeerConnID]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
mp.peerCfg.Log.Infof("reset inactivity monitor timer")
|
||||
iw.ResetTimer()
|
||||
}
|
||||
|
||||
@@ -11,4 +11,6 @@ import (
|
||||
type WGIface interface {
|
||||
RemovePeer(peerKey string) error
|
||||
UpdatePeer(peerKey string, allowedIps []netip.Prefix, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error
|
||||
IsUserspaceBind() bool
|
||||
LastActivities() map[string]time.Time
|
||||
}
|
||||
|
||||
@@ -117,10 +117,9 @@ type Conn struct {
|
||||
wgProxyRelay wgproxy.Proxy
|
||||
handshaker *Handshaker
|
||||
|
||||
guard *guard.Guard
|
||||
semaphore *semaphoregroup.SemaphoreGroup
|
||||
peerConnDispatcher *dispatcher.ConnectionDispatcher
|
||||
wg sync.WaitGroup
|
||||
guard *guard.Guard
|
||||
semaphore *semaphoregroup.SemaphoreGroup
|
||||
wg sync.WaitGroup
|
||||
|
||||
// debug purpose
|
||||
dumpState *stateDump
|
||||
@@ -136,18 +135,17 @@ func NewConn(config ConnConfig, services ServiceDependencies) (*Conn, error) {
|
||||
connLog := log.WithField("peer", config.Key)
|
||||
|
||||
var conn = &Conn{
|
||||
Log: connLog,
|
||||
config: config,
|
||||
statusRecorder: services.StatusRecorder,
|
||||
signaler: services.Signaler,
|
||||
iFaceDiscover: services.IFaceDiscover,
|
||||
relayManager: services.RelayManager,
|
||||
srWatcher: services.SrWatcher,
|
||||
semaphore: services.Semaphore,
|
||||
peerConnDispatcher: services.PeerConnDispatcher,
|
||||
statusRelay: worker.NewAtomicStatus(),
|
||||
statusICE: worker.NewAtomicStatus(),
|
||||
dumpState: newStateDump(config.Key, connLog, services.StatusRecorder),
|
||||
Log: connLog,
|
||||
config: config,
|
||||
statusRecorder: services.StatusRecorder,
|
||||
signaler: services.Signaler,
|
||||
iFaceDiscover: services.IFaceDiscover,
|
||||
relayManager: services.RelayManager,
|
||||
srWatcher: services.SrWatcher,
|
||||
semaphore: services.Semaphore,
|
||||
statusRelay: worker.NewAtomicStatus(),
|
||||
statusICE: worker.NewAtomicStatus(),
|
||||
dumpState: newStateDump(config.Key, connLog, services.StatusRecorder),
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
@@ -226,7 +224,7 @@ func (conn *Conn) Open(engineCtx context.Context) error {
|
||||
}
|
||||
|
||||
// Close closes this peer Conn issuing a close event to the Conn closeCh
|
||||
func (conn *Conn) Close() {
|
||||
func (conn *Conn) Close(signalToRemote bool) {
|
||||
conn.mu.Lock()
|
||||
defer conn.wgWatcherWg.Wait()
|
||||
defer conn.mu.Unlock()
|
||||
@@ -236,6 +234,12 @@ func (conn *Conn) Close() {
|
||||
return
|
||||
}
|
||||
|
||||
if signalToRemote {
|
||||
if err := conn.signaler.SignalIdle(conn.config.Key); err != nil {
|
||||
conn.Log.Errorf("failed to signal idle state to peer: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
conn.Log.Infof("close peer connection")
|
||||
conn.ctxCancel()
|
||||
|
||||
@@ -404,15 +408,10 @@ func (conn *Conn) onICEConnectionIsReady(priority conntype.ConnPriority, iceConn
|
||||
}
|
||||
wgConfigWorkaround()
|
||||
|
||||
oldState := conn.currentConnPriority
|
||||
conn.currentConnPriority = priority
|
||||
conn.statusICE.SetConnected()
|
||||
conn.updateIceState(iceConnInfo)
|
||||
conn.doOnConnected(iceConnInfo.RosenpassPubKey, iceConnInfo.RosenpassAddr)
|
||||
|
||||
if oldState == conntype.None {
|
||||
conn.peerConnDispatcher.NotifyConnected(conn.ConnID())
|
||||
}
|
||||
}
|
||||
|
||||
func (conn *Conn) onICEStateDisconnected() {
|
||||
@@ -450,7 +449,6 @@ func (conn *Conn) onICEStateDisconnected() {
|
||||
} else {
|
||||
conn.Log.Infof("ICE disconnected, do not switch to Relay. Reset priority to: %s", conntype.None.String())
|
||||
conn.currentConnPriority = conntype.None
|
||||
conn.peerConnDispatcher.NotifyDisconnected(conn.ConnID())
|
||||
}
|
||||
|
||||
changed := conn.statusICE.Get() != worker.StatusDisconnected
|
||||
@@ -530,7 +528,6 @@ func (conn *Conn) onRelayConnectionIsReady(rci RelayConnInfo) {
|
||||
conn.updateRelayStatus(rci.relayedConn.RemoteAddr().String(), rci.rosenpassPubKey)
|
||||
conn.Log.Infof("start to communicate with peer via relay")
|
||||
conn.doOnConnected(rci.rosenpassPubKey, rci.rosenpassAddr)
|
||||
conn.peerConnDispatcher.NotifyConnected(conn.ConnID())
|
||||
}
|
||||
|
||||
func (conn *Conn) onRelayDisconnected() {
|
||||
@@ -545,11 +542,7 @@ func (conn *Conn) onRelayDisconnected() {
|
||||
|
||||
if conn.currentConnPriority == conntype.Relay {
|
||||
conn.Log.Debugf("clean up WireGuard config")
|
||||
if err := conn.removeWgPeer(); err != nil {
|
||||
conn.Log.Errorf("failed to remove wg endpoint: %v", err)
|
||||
}
|
||||
conn.currentConnPriority = conntype.None
|
||||
conn.peerConnDispatcher.NotifyDisconnected(conn.ConnID())
|
||||
}
|
||||
|
||||
if conn.wgProxyRelay != nil {
|
||||
|
||||
@@ -68,3 +68,13 @@ func (s *Signaler) signalOfferAnswer(offerAnswer OfferAnswer, remoteKey string,
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Signaler) SignalIdle(remoteKey string) error {
|
||||
return s.signal.Send(&sProto.Message{
|
||||
Key: s.wgPrivateKey.PublicKey().String(),
|
||||
RemoteKey: remoteKey,
|
||||
Body: &sProto.Body{
|
||||
Type: sProto.Body_GO_IDLE,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -95,6 +95,17 @@ func (s *Store) PeerConnOpen(ctx context.Context, pubKey string) {
|
||||
|
||||
}
|
||||
|
||||
func (s *Store) PeerConnIdle(pubKey string) {
|
||||
s.peerConnsMu.RLock()
|
||||
defer s.peerConnsMu.RUnlock()
|
||||
|
||||
p, ok := s.peerConns[pubKey]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
p.Close(true)
|
||||
}
|
||||
|
||||
func (s *Store) PeerConnClose(pubKey string) {
|
||||
s.peerConnsMu.RLock()
|
||||
defer s.peerConnsMu.RUnlock()
|
||||
@@ -103,7 +114,7 @@ func (s *Store) PeerConnClose(pubKey string) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
p.Close()
|
||||
p.Close(false)
|
||||
}
|
||||
|
||||
func (s *Store) PeersPubKey() []string {
|
||||
|
||||
@@ -2430,7 +2430,17 @@ func (x *ForwardingRulesResponse) GetRules() []*ForwardingRule {
|
||||
|
||||
// DebugBundler
|
||||
type DebugBundleRequest struct {
|
||||
<<<<<<< HEAD
|
||||
state protoimpl.MessageState
|
||||
=======
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Anonymize bool `protobuf:"varint,1,opt,name=anonymize,proto3" json:"anonymize,omitempty"`
|
||||
Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"`
|
||||
SystemInfo bool `protobuf:"varint,3,opt,name=systemInfo,proto3" json:"systemInfo,omitempty"`
|
||||
UploadURL string `protobuf:"bytes,4,opt,name=uploadURL,proto3" json:"uploadURL,omitempty"`
|
||||
LogFileCount uint32 `protobuf:"varint,5,opt,name=logFileCount,proto3" json:"logFileCount,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
>>>>>>> main
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
@@ -2500,6 +2510,13 @@ func (x *DebugBundleRequest) GetUploadURL() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DebugBundleRequest) GetLogFileCount() uint32 {
|
||||
if x != nil {
|
||||
return x.LogFileCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type DebugBundleResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -3885,6 +3902,7 @@ func (x *PortInfo_Range) GetEnd() uint32 {
|
||||
|
||||
var File_daemon_proto protoreflect.FileDescriptor
|
||||
|
||||
<<<<<<< HEAD
|
||||
var file_daemon_proto_rawDesc = []byte{
|
||||
0x0a, 0x0c, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06,
|
||||
0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
|
||||
@@ -4568,6 +4586,337 @@ var file_daemon_proto_rawDesc = []byte{
|
||||
0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
=======
|
||||
const file_daemon_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\fdaemon.proto\x12\x06daemon\x1a google/protobuf/descriptor.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/duration.proto\"\x0e\n" +
|
||||
"\fEmptyRequest\"\xbf\r\n" +
|
||||
"\fLoginRequest\x12\x1a\n" +
|
||||
"\bsetupKey\x18\x01 \x01(\tR\bsetupKey\x12&\n" +
|
||||
"\fpreSharedKey\x18\x02 \x01(\tB\x02\x18\x01R\fpreSharedKey\x12$\n" +
|
||||
"\rmanagementUrl\x18\x03 \x01(\tR\rmanagementUrl\x12\x1a\n" +
|
||||
"\badminURL\x18\x04 \x01(\tR\badminURL\x12&\n" +
|
||||
"\x0enatExternalIPs\x18\x05 \x03(\tR\x0enatExternalIPs\x120\n" +
|
||||
"\x13cleanNATExternalIPs\x18\x06 \x01(\bR\x13cleanNATExternalIPs\x12*\n" +
|
||||
"\x10customDNSAddress\x18\a \x01(\fR\x10customDNSAddress\x120\n" +
|
||||
"\x13isUnixDesktopClient\x18\b \x01(\bR\x13isUnixDesktopClient\x12\x1a\n" +
|
||||
"\bhostname\x18\t \x01(\tR\bhostname\x12/\n" +
|
||||
"\x10rosenpassEnabled\x18\n" +
|
||||
" \x01(\bH\x00R\x10rosenpassEnabled\x88\x01\x01\x12)\n" +
|
||||
"\rinterfaceName\x18\v \x01(\tH\x01R\rinterfaceName\x88\x01\x01\x12)\n" +
|
||||
"\rwireguardPort\x18\f \x01(\x03H\x02R\rwireguardPort\x88\x01\x01\x127\n" +
|
||||
"\x14optionalPreSharedKey\x18\r \x01(\tH\x03R\x14optionalPreSharedKey\x88\x01\x01\x123\n" +
|
||||
"\x12disableAutoConnect\x18\x0e \x01(\bH\x04R\x12disableAutoConnect\x88\x01\x01\x12/\n" +
|
||||
"\x10serverSSHAllowed\x18\x0f \x01(\bH\x05R\x10serverSSHAllowed\x88\x01\x01\x125\n" +
|
||||
"\x13rosenpassPermissive\x18\x10 \x01(\bH\x06R\x13rosenpassPermissive\x88\x01\x01\x120\n" +
|
||||
"\x13extraIFaceBlacklist\x18\x11 \x03(\tR\x13extraIFaceBlacklist\x12+\n" +
|
||||
"\x0enetworkMonitor\x18\x12 \x01(\bH\aR\x0enetworkMonitor\x88\x01\x01\x12J\n" +
|
||||
"\x10dnsRouteInterval\x18\x13 \x01(\v2\x19.google.protobuf.DurationH\bR\x10dnsRouteInterval\x88\x01\x01\x127\n" +
|
||||
"\x15disable_client_routes\x18\x14 \x01(\bH\tR\x13disableClientRoutes\x88\x01\x01\x127\n" +
|
||||
"\x15disable_server_routes\x18\x15 \x01(\bH\n" +
|
||||
"R\x13disableServerRoutes\x88\x01\x01\x12$\n" +
|
||||
"\vdisable_dns\x18\x16 \x01(\bH\vR\n" +
|
||||
"disableDns\x88\x01\x01\x12.\n" +
|
||||
"\x10disable_firewall\x18\x17 \x01(\bH\fR\x0fdisableFirewall\x88\x01\x01\x12-\n" +
|
||||
"\x10block_lan_access\x18\x18 \x01(\bH\rR\x0eblockLanAccess\x88\x01\x01\x128\n" +
|
||||
"\x15disable_notifications\x18\x19 \x01(\bH\x0eR\x14disableNotifications\x88\x01\x01\x12\x1d\n" +
|
||||
"\n" +
|
||||
"dns_labels\x18\x1a \x03(\tR\tdnsLabels\x12&\n" +
|
||||
"\x0ecleanDNSLabels\x18\x1b \x01(\bR\x0ecleanDNSLabels\x129\n" +
|
||||
"\x15lazyConnectionEnabled\x18\x1c \x01(\bH\x0fR\x15lazyConnectionEnabled\x88\x01\x01\x12(\n" +
|
||||
"\rblock_inbound\x18\x1d \x01(\bH\x10R\fblockInbound\x88\x01\x01B\x13\n" +
|
||||
"\x11_rosenpassEnabledB\x10\n" +
|
||||
"\x0e_interfaceNameB\x10\n" +
|
||||
"\x0e_wireguardPortB\x17\n" +
|
||||
"\x15_optionalPreSharedKeyB\x15\n" +
|
||||
"\x13_disableAutoConnectB\x13\n" +
|
||||
"\x11_serverSSHAllowedB\x16\n" +
|
||||
"\x14_rosenpassPermissiveB\x11\n" +
|
||||
"\x0f_networkMonitorB\x13\n" +
|
||||
"\x11_dnsRouteIntervalB\x18\n" +
|
||||
"\x16_disable_client_routesB\x18\n" +
|
||||
"\x16_disable_server_routesB\x0e\n" +
|
||||
"\f_disable_dnsB\x13\n" +
|
||||
"\x11_disable_firewallB\x13\n" +
|
||||
"\x11_block_lan_accessB\x18\n" +
|
||||
"\x16_disable_notificationsB\x18\n" +
|
||||
"\x16_lazyConnectionEnabledB\x10\n" +
|
||||
"\x0e_block_inbound\"\xb5\x01\n" +
|
||||
"\rLoginResponse\x12$\n" +
|
||||
"\rneedsSSOLogin\x18\x01 \x01(\bR\rneedsSSOLogin\x12\x1a\n" +
|
||||
"\buserCode\x18\x02 \x01(\tR\buserCode\x12(\n" +
|
||||
"\x0fverificationURI\x18\x03 \x01(\tR\x0fverificationURI\x128\n" +
|
||||
"\x17verificationURIComplete\x18\x04 \x01(\tR\x17verificationURIComplete\"M\n" +
|
||||
"\x13WaitSSOLoginRequest\x12\x1a\n" +
|
||||
"\buserCode\x18\x01 \x01(\tR\buserCode\x12\x1a\n" +
|
||||
"\bhostname\x18\x02 \x01(\tR\bhostname\"\x16\n" +
|
||||
"\x14WaitSSOLoginResponse\"\v\n" +
|
||||
"\tUpRequest\"\f\n" +
|
||||
"\n" +
|
||||
"UpResponse\"g\n" +
|
||||
"\rStatusRequest\x12,\n" +
|
||||
"\x11getFullPeerStatus\x18\x01 \x01(\bR\x11getFullPeerStatus\x12(\n" +
|
||||
"\x0fshouldRunProbes\x18\x02 \x01(\bR\x0fshouldRunProbes\"\x82\x01\n" +
|
||||
"\x0eStatusResponse\x12\x16\n" +
|
||||
"\x06status\x18\x01 \x01(\tR\x06status\x122\n" +
|
||||
"\n" +
|
||||
"fullStatus\x18\x02 \x01(\v2\x12.daemon.FullStatusR\n" +
|
||||
"fullStatus\x12$\n" +
|
||||
"\rdaemonVersion\x18\x03 \x01(\tR\rdaemonVersion\"\r\n" +
|
||||
"\vDownRequest\"\x0e\n" +
|
||||
"\fDownResponse\"\x12\n" +
|
||||
"\x10GetConfigRequest\"\xa3\x06\n" +
|
||||
"\x11GetConfigResponse\x12$\n" +
|
||||
"\rmanagementUrl\x18\x01 \x01(\tR\rmanagementUrl\x12\x1e\n" +
|
||||
"\n" +
|
||||
"configFile\x18\x02 \x01(\tR\n" +
|
||||
"configFile\x12\x18\n" +
|
||||
"\alogFile\x18\x03 \x01(\tR\alogFile\x12\"\n" +
|
||||
"\fpreSharedKey\x18\x04 \x01(\tR\fpreSharedKey\x12\x1a\n" +
|
||||
"\badminURL\x18\x05 \x01(\tR\badminURL\x12$\n" +
|
||||
"\rinterfaceName\x18\x06 \x01(\tR\rinterfaceName\x12$\n" +
|
||||
"\rwireguardPort\x18\a \x01(\x03R\rwireguardPort\x12.\n" +
|
||||
"\x12disableAutoConnect\x18\t \x01(\bR\x12disableAutoConnect\x12*\n" +
|
||||
"\x10serverSSHAllowed\x18\n" +
|
||||
" \x01(\bR\x10serverSSHAllowed\x12*\n" +
|
||||
"\x10rosenpassEnabled\x18\v \x01(\bR\x10rosenpassEnabled\x120\n" +
|
||||
"\x13rosenpassPermissive\x18\f \x01(\bR\x13rosenpassPermissive\x123\n" +
|
||||
"\x15disable_notifications\x18\r \x01(\bR\x14disableNotifications\x124\n" +
|
||||
"\x15lazyConnectionEnabled\x18\x0e \x01(\bR\x15lazyConnectionEnabled\x12\"\n" +
|
||||
"\fblockInbound\x18\x0f \x01(\bR\fblockInbound\x12&\n" +
|
||||
"\x0enetworkMonitor\x18\x10 \x01(\bR\x0enetworkMonitor\x12\x1f\n" +
|
||||
"\vdisable_dns\x18\x11 \x01(\bR\n" +
|
||||
"disableDns\x122\n" +
|
||||
"\x15disable_client_routes\x18\x12 \x01(\bR\x13disableClientRoutes\x122\n" +
|
||||
"\x15disable_server_routes\x18\x13 \x01(\bR\x13disableServerRoutes\x12(\n" +
|
||||
"\x10block_lan_access\x18\x14 \x01(\bR\x0eblockLanAccess\"\xde\x05\n" +
|
||||
"\tPeerState\x12\x0e\n" +
|
||||
"\x02IP\x18\x01 \x01(\tR\x02IP\x12\x16\n" +
|
||||
"\x06pubKey\x18\x02 \x01(\tR\x06pubKey\x12\x1e\n" +
|
||||
"\n" +
|
||||
"connStatus\x18\x03 \x01(\tR\n" +
|
||||
"connStatus\x12F\n" +
|
||||
"\x10connStatusUpdate\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\x10connStatusUpdate\x12\x18\n" +
|
||||
"\arelayed\x18\x05 \x01(\bR\arelayed\x124\n" +
|
||||
"\x15localIceCandidateType\x18\a \x01(\tR\x15localIceCandidateType\x126\n" +
|
||||
"\x16remoteIceCandidateType\x18\b \x01(\tR\x16remoteIceCandidateType\x12\x12\n" +
|
||||
"\x04fqdn\x18\t \x01(\tR\x04fqdn\x12<\n" +
|
||||
"\x19localIceCandidateEndpoint\x18\n" +
|
||||
" \x01(\tR\x19localIceCandidateEndpoint\x12>\n" +
|
||||
"\x1aremoteIceCandidateEndpoint\x18\v \x01(\tR\x1aremoteIceCandidateEndpoint\x12R\n" +
|
||||
"\x16lastWireguardHandshake\x18\f \x01(\v2\x1a.google.protobuf.TimestampR\x16lastWireguardHandshake\x12\x18\n" +
|
||||
"\abytesRx\x18\r \x01(\x03R\abytesRx\x12\x18\n" +
|
||||
"\abytesTx\x18\x0e \x01(\x03R\abytesTx\x12*\n" +
|
||||
"\x10rosenpassEnabled\x18\x0f \x01(\bR\x10rosenpassEnabled\x12\x1a\n" +
|
||||
"\bnetworks\x18\x10 \x03(\tR\bnetworks\x123\n" +
|
||||
"\alatency\x18\x11 \x01(\v2\x19.google.protobuf.DurationR\alatency\x12\"\n" +
|
||||
"\frelayAddress\x18\x12 \x01(\tR\frelayAddress\"\xf0\x01\n" +
|
||||
"\x0eLocalPeerState\x12\x0e\n" +
|
||||
"\x02IP\x18\x01 \x01(\tR\x02IP\x12\x16\n" +
|
||||
"\x06pubKey\x18\x02 \x01(\tR\x06pubKey\x12(\n" +
|
||||
"\x0fkernelInterface\x18\x03 \x01(\bR\x0fkernelInterface\x12\x12\n" +
|
||||
"\x04fqdn\x18\x04 \x01(\tR\x04fqdn\x12*\n" +
|
||||
"\x10rosenpassEnabled\x18\x05 \x01(\bR\x10rosenpassEnabled\x120\n" +
|
||||
"\x13rosenpassPermissive\x18\x06 \x01(\bR\x13rosenpassPermissive\x12\x1a\n" +
|
||||
"\bnetworks\x18\a \x03(\tR\bnetworks\"S\n" +
|
||||
"\vSignalState\x12\x10\n" +
|
||||
"\x03URL\x18\x01 \x01(\tR\x03URL\x12\x1c\n" +
|
||||
"\tconnected\x18\x02 \x01(\bR\tconnected\x12\x14\n" +
|
||||
"\x05error\x18\x03 \x01(\tR\x05error\"W\n" +
|
||||
"\x0fManagementState\x12\x10\n" +
|
||||
"\x03URL\x18\x01 \x01(\tR\x03URL\x12\x1c\n" +
|
||||
"\tconnected\x18\x02 \x01(\bR\tconnected\x12\x14\n" +
|
||||
"\x05error\x18\x03 \x01(\tR\x05error\"R\n" +
|
||||
"\n" +
|
||||
"RelayState\x12\x10\n" +
|
||||
"\x03URI\x18\x01 \x01(\tR\x03URI\x12\x1c\n" +
|
||||
"\tavailable\x18\x02 \x01(\bR\tavailable\x12\x14\n" +
|
||||
"\x05error\x18\x03 \x01(\tR\x05error\"r\n" +
|
||||
"\fNSGroupState\x12\x18\n" +
|
||||
"\aservers\x18\x01 \x03(\tR\aservers\x12\x18\n" +
|
||||
"\adomains\x18\x02 \x03(\tR\adomains\x12\x18\n" +
|
||||
"\aenabled\x18\x03 \x01(\bR\aenabled\x12\x14\n" +
|
||||
"\x05error\x18\x04 \x01(\tR\x05error\"\xef\x03\n" +
|
||||
"\n" +
|
||||
"FullStatus\x12A\n" +
|
||||
"\x0fmanagementState\x18\x01 \x01(\v2\x17.daemon.ManagementStateR\x0fmanagementState\x125\n" +
|
||||
"\vsignalState\x18\x02 \x01(\v2\x13.daemon.SignalStateR\vsignalState\x12>\n" +
|
||||
"\x0elocalPeerState\x18\x03 \x01(\v2\x16.daemon.LocalPeerStateR\x0elocalPeerState\x12'\n" +
|
||||
"\x05peers\x18\x04 \x03(\v2\x11.daemon.PeerStateR\x05peers\x12*\n" +
|
||||
"\x06relays\x18\x05 \x03(\v2\x12.daemon.RelayStateR\x06relays\x125\n" +
|
||||
"\vdns_servers\x18\x06 \x03(\v2\x14.daemon.NSGroupStateR\n" +
|
||||
"dnsServers\x128\n" +
|
||||
"\x17NumberOfForwardingRules\x18\b \x01(\x05R\x17NumberOfForwardingRules\x12+\n" +
|
||||
"\x06events\x18\a \x03(\v2\x13.daemon.SystemEventR\x06events\x124\n" +
|
||||
"\x15lazyConnectionEnabled\x18\t \x01(\bR\x15lazyConnectionEnabled\"\x15\n" +
|
||||
"\x13ListNetworksRequest\"?\n" +
|
||||
"\x14ListNetworksResponse\x12'\n" +
|
||||
"\x06routes\x18\x01 \x03(\v2\x0f.daemon.NetworkR\x06routes\"a\n" +
|
||||
"\x15SelectNetworksRequest\x12\x1e\n" +
|
||||
"\n" +
|
||||
"networkIDs\x18\x01 \x03(\tR\n" +
|
||||
"networkIDs\x12\x16\n" +
|
||||
"\x06append\x18\x02 \x01(\bR\x06append\x12\x10\n" +
|
||||
"\x03all\x18\x03 \x01(\bR\x03all\"\x18\n" +
|
||||
"\x16SelectNetworksResponse\"\x1a\n" +
|
||||
"\x06IPList\x12\x10\n" +
|
||||
"\x03ips\x18\x01 \x03(\tR\x03ips\"\xf9\x01\n" +
|
||||
"\aNetwork\x12\x0e\n" +
|
||||
"\x02ID\x18\x01 \x01(\tR\x02ID\x12\x14\n" +
|
||||
"\x05range\x18\x02 \x01(\tR\x05range\x12\x1a\n" +
|
||||
"\bselected\x18\x03 \x01(\bR\bselected\x12\x18\n" +
|
||||
"\adomains\x18\x04 \x03(\tR\adomains\x12B\n" +
|
||||
"\vresolvedIPs\x18\x05 \x03(\v2 .daemon.Network.ResolvedIPsEntryR\vresolvedIPs\x1aN\n" +
|
||||
"\x10ResolvedIPsEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12$\n" +
|
||||
"\x05value\x18\x02 \x01(\v2\x0e.daemon.IPListR\x05value:\x028\x01\"\x92\x01\n" +
|
||||
"\bPortInfo\x12\x14\n" +
|
||||
"\x04port\x18\x01 \x01(\rH\x00R\x04port\x12.\n" +
|
||||
"\x05range\x18\x02 \x01(\v2\x16.daemon.PortInfo.RangeH\x00R\x05range\x1a/\n" +
|
||||
"\x05Range\x12\x14\n" +
|
||||
"\x05start\x18\x01 \x01(\rR\x05start\x12\x10\n" +
|
||||
"\x03end\x18\x02 \x01(\rR\x03endB\x0f\n" +
|
||||
"\rportSelection\"\x80\x02\n" +
|
||||
"\x0eForwardingRule\x12\x1a\n" +
|
||||
"\bprotocol\x18\x01 \x01(\tR\bprotocol\x12:\n" +
|
||||
"\x0fdestinationPort\x18\x02 \x01(\v2\x10.daemon.PortInfoR\x0fdestinationPort\x12,\n" +
|
||||
"\x11translatedAddress\x18\x03 \x01(\tR\x11translatedAddress\x12.\n" +
|
||||
"\x12translatedHostname\x18\x04 \x01(\tR\x12translatedHostname\x128\n" +
|
||||
"\x0etranslatedPort\x18\x05 \x01(\v2\x10.daemon.PortInfoR\x0etranslatedPort\"G\n" +
|
||||
"\x17ForwardingRulesResponse\x12,\n" +
|
||||
"\x05rules\x18\x01 \x03(\v2\x16.daemon.ForwardingRuleR\x05rules\"\xac\x01\n" +
|
||||
"\x12DebugBundleRequest\x12\x1c\n" +
|
||||
"\tanonymize\x18\x01 \x01(\bR\tanonymize\x12\x16\n" +
|
||||
"\x06status\x18\x02 \x01(\tR\x06status\x12\x1e\n" +
|
||||
"\n" +
|
||||
"systemInfo\x18\x03 \x01(\bR\n" +
|
||||
"systemInfo\x12\x1c\n" +
|
||||
"\tuploadURL\x18\x04 \x01(\tR\tuploadURL\x12\"\n" +
|
||||
"\flogFileCount\x18\x05 \x01(\rR\flogFileCount\"}\n" +
|
||||
"\x13DebugBundleResponse\x12\x12\n" +
|
||||
"\x04path\x18\x01 \x01(\tR\x04path\x12 \n" +
|
||||
"\vuploadedKey\x18\x02 \x01(\tR\vuploadedKey\x120\n" +
|
||||
"\x13uploadFailureReason\x18\x03 \x01(\tR\x13uploadFailureReason\"\x14\n" +
|
||||
"\x12GetLogLevelRequest\"=\n" +
|
||||
"\x13GetLogLevelResponse\x12&\n" +
|
||||
"\x05level\x18\x01 \x01(\x0e2\x10.daemon.LogLevelR\x05level\"<\n" +
|
||||
"\x12SetLogLevelRequest\x12&\n" +
|
||||
"\x05level\x18\x01 \x01(\x0e2\x10.daemon.LogLevelR\x05level\"\x15\n" +
|
||||
"\x13SetLogLevelResponse\"\x1b\n" +
|
||||
"\x05State\x12\x12\n" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name\"\x13\n" +
|
||||
"\x11ListStatesRequest\";\n" +
|
||||
"\x12ListStatesResponse\x12%\n" +
|
||||
"\x06states\x18\x01 \x03(\v2\r.daemon.StateR\x06states\"D\n" +
|
||||
"\x11CleanStateRequest\x12\x1d\n" +
|
||||
"\n" +
|
||||
"state_name\x18\x01 \x01(\tR\tstateName\x12\x10\n" +
|
||||
"\x03all\x18\x02 \x01(\bR\x03all\";\n" +
|
||||
"\x12CleanStateResponse\x12%\n" +
|
||||
"\x0ecleaned_states\x18\x01 \x01(\x05R\rcleanedStates\"E\n" +
|
||||
"\x12DeleteStateRequest\x12\x1d\n" +
|
||||
"\n" +
|
||||
"state_name\x18\x01 \x01(\tR\tstateName\x12\x10\n" +
|
||||
"\x03all\x18\x02 \x01(\bR\x03all\"<\n" +
|
||||
"\x13DeleteStateResponse\x12%\n" +
|
||||
"\x0edeleted_states\x18\x01 \x01(\x05R\rdeletedStates\";\n" +
|
||||
"\x1fSetNetworkMapPersistenceRequest\x12\x18\n" +
|
||||
"\aenabled\x18\x01 \x01(\bR\aenabled\"\"\n" +
|
||||
" SetNetworkMapPersistenceResponse\"v\n" +
|
||||
"\bTCPFlags\x12\x10\n" +
|
||||
"\x03syn\x18\x01 \x01(\bR\x03syn\x12\x10\n" +
|
||||
"\x03ack\x18\x02 \x01(\bR\x03ack\x12\x10\n" +
|
||||
"\x03fin\x18\x03 \x01(\bR\x03fin\x12\x10\n" +
|
||||
"\x03rst\x18\x04 \x01(\bR\x03rst\x12\x10\n" +
|
||||
"\x03psh\x18\x05 \x01(\bR\x03psh\x12\x10\n" +
|
||||
"\x03urg\x18\x06 \x01(\bR\x03urg\"\x80\x03\n" +
|
||||
"\x12TracePacketRequest\x12\x1b\n" +
|
||||
"\tsource_ip\x18\x01 \x01(\tR\bsourceIp\x12%\n" +
|
||||
"\x0edestination_ip\x18\x02 \x01(\tR\rdestinationIp\x12\x1a\n" +
|
||||
"\bprotocol\x18\x03 \x01(\tR\bprotocol\x12\x1f\n" +
|
||||
"\vsource_port\x18\x04 \x01(\rR\n" +
|
||||
"sourcePort\x12)\n" +
|
||||
"\x10destination_port\x18\x05 \x01(\rR\x0fdestinationPort\x12\x1c\n" +
|
||||
"\tdirection\x18\x06 \x01(\tR\tdirection\x122\n" +
|
||||
"\ttcp_flags\x18\a \x01(\v2\x10.daemon.TCPFlagsH\x00R\btcpFlags\x88\x01\x01\x12 \n" +
|
||||
"\ticmp_type\x18\b \x01(\rH\x01R\bicmpType\x88\x01\x01\x12 \n" +
|
||||
"\ticmp_code\x18\t \x01(\rH\x02R\bicmpCode\x88\x01\x01B\f\n" +
|
||||
"\n" +
|
||||
"_tcp_flagsB\f\n" +
|
||||
"\n" +
|
||||
"_icmp_typeB\f\n" +
|
||||
"\n" +
|
||||
"_icmp_code\"\x9f\x01\n" +
|
||||
"\n" +
|
||||
"TraceStage\x12\x12\n" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name\x12\x18\n" +
|
||||
"\amessage\x18\x02 \x01(\tR\amessage\x12\x18\n" +
|
||||
"\aallowed\x18\x03 \x01(\bR\aallowed\x122\n" +
|
||||
"\x12forwarding_details\x18\x04 \x01(\tH\x00R\x11forwardingDetails\x88\x01\x01B\x15\n" +
|
||||
"\x13_forwarding_details\"n\n" +
|
||||
"\x13TracePacketResponse\x12*\n" +
|
||||
"\x06stages\x18\x01 \x03(\v2\x12.daemon.TraceStageR\x06stages\x12+\n" +
|
||||
"\x11final_disposition\x18\x02 \x01(\bR\x10finalDisposition\"\x12\n" +
|
||||
"\x10SubscribeRequest\"\x93\x04\n" +
|
||||
"\vSystemEvent\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\tR\x02id\x128\n" +
|
||||
"\bseverity\x18\x02 \x01(\x0e2\x1c.daemon.SystemEvent.SeverityR\bseverity\x128\n" +
|
||||
"\bcategory\x18\x03 \x01(\x0e2\x1c.daemon.SystemEvent.CategoryR\bcategory\x12\x18\n" +
|
||||
"\amessage\x18\x04 \x01(\tR\amessage\x12 \n" +
|
||||
"\vuserMessage\x18\x05 \x01(\tR\vuserMessage\x128\n" +
|
||||
"\ttimestamp\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\x12=\n" +
|
||||
"\bmetadata\x18\a \x03(\v2!.daemon.SystemEvent.MetadataEntryR\bmetadata\x1a;\n" +
|
||||
"\rMetadataEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\":\n" +
|
||||
"\bSeverity\x12\b\n" +
|
||||
"\x04INFO\x10\x00\x12\v\n" +
|
||||
"\aWARNING\x10\x01\x12\t\n" +
|
||||
"\x05ERROR\x10\x02\x12\f\n" +
|
||||
"\bCRITICAL\x10\x03\"R\n" +
|
||||
"\bCategory\x12\v\n" +
|
||||
"\aNETWORK\x10\x00\x12\a\n" +
|
||||
"\x03DNS\x10\x01\x12\x12\n" +
|
||||
"\x0eAUTHENTICATION\x10\x02\x12\x10\n" +
|
||||
"\fCONNECTIVITY\x10\x03\x12\n" +
|
||||
"\n" +
|
||||
"\x06SYSTEM\x10\x04\"\x12\n" +
|
||||
"\x10GetEventsRequest\"@\n" +
|
||||
"\x11GetEventsResponse\x12+\n" +
|
||||
"\x06events\x18\x01 \x03(\v2\x13.daemon.SystemEventR\x06events*b\n" +
|
||||
"\bLogLevel\x12\v\n" +
|
||||
"\aUNKNOWN\x10\x00\x12\t\n" +
|
||||
"\x05PANIC\x10\x01\x12\t\n" +
|
||||
"\x05FATAL\x10\x02\x12\t\n" +
|
||||
"\x05ERROR\x10\x03\x12\b\n" +
|
||||
"\x04WARN\x10\x04\x12\b\n" +
|
||||
"\x04INFO\x10\x05\x12\t\n" +
|
||||
"\x05DEBUG\x10\x06\x12\t\n" +
|
||||
"\x05TRACE\x10\a2\xb3\v\n" +
|
||||
"\rDaemonService\x126\n" +
|
||||
"\x05Login\x12\x14.daemon.LoginRequest\x1a\x15.daemon.LoginResponse\"\x00\x12K\n" +
|
||||
"\fWaitSSOLogin\x12\x1b.daemon.WaitSSOLoginRequest\x1a\x1c.daemon.WaitSSOLoginResponse\"\x00\x12-\n" +
|
||||
"\x02Up\x12\x11.daemon.UpRequest\x1a\x12.daemon.UpResponse\"\x00\x129\n" +
|
||||
"\x06Status\x12\x15.daemon.StatusRequest\x1a\x16.daemon.StatusResponse\"\x00\x123\n" +
|
||||
"\x04Down\x12\x13.daemon.DownRequest\x1a\x14.daemon.DownResponse\"\x00\x12B\n" +
|
||||
"\tGetConfig\x12\x18.daemon.GetConfigRequest\x1a\x19.daemon.GetConfigResponse\"\x00\x12K\n" +
|
||||
"\fListNetworks\x12\x1b.daemon.ListNetworksRequest\x1a\x1c.daemon.ListNetworksResponse\"\x00\x12Q\n" +
|
||||
"\x0eSelectNetworks\x12\x1d.daemon.SelectNetworksRequest\x1a\x1e.daemon.SelectNetworksResponse\"\x00\x12S\n" +
|
||||
"\x10DeselectNetworks\x12\x1d.daemon.SelectNetworksRequest\x1a\x1e.daemon.SelectNetworksResponse\"\x00\x12J\n" +
|
||||
"\x0fForwardingRules\x12\x14.daemon.EmptyRequest\x1a\x1f.daemon.ForwardingRulesResponse\"\x00\x12H\n" +
|
||||
"\vDebugBundle\x12\x1a.daemon.DebugBundleRequest\x1a\x1b.daemon.DebugBundleResponse\"\x00\x12H\n" +
|
||||
"\vGetLogLevel\x12\x1a.daemon.GetLogLevelRequest\x1a\x1b.daemon.GetLogLevelResponse\"\x00\x12H\n" +
|
||||
"\vSetLogLevel\x12\x1a.daemon.SetLogLevelRequest\x1a\x1b.daemon.SetLogLevelResponse\"\x00\x12E\n" +
|
||||
"\n" +
|
||||
"ListStates\x12\x19.daemon.ListStatesRequest\x1a\x1a.daemon.ListStatesResponse\"\x00\x12E\n" +
|
||||
"\n" +
|
||||
"CleanState\x12\x19.daemon.CleanStateRequest\x1a\x1a.daemon.CleanStateResponse\"\x00\x12H\n" +
|
||||
"\vDeleteState\x12\x1a.daemon.DeleteStateRequest\x1a\x1b.daemon.DeleteStateResponse\"\x00\x12o\n" +
|
||||
"\x18SetNetworkMapPersistence\x12'.daemon.SetNetworkMapPersistenceRequest\x1a(.daemon.SetNetworkMapPersistenceResponse\"\x00\x12H\n" +
|
||||
"\vTracePacket\x12\x1a.daemon.TracePacketRequest\x1a\x1b.daemon.TracePacketResponse\"\x00\x12D\n" +
|
||||
"\x0fSubscribeEvents\x12\x18.daemon.SubscribeRequest\x1a\x13.daemon.SystemEvent\"\x000\x01\x12B\n" +
|
||||
"\tGetEvents\x12\x18.daemon.GetEventsRequest\x1a\x19.daemon.GetEventsResponse\"\x00B\bZ\x06/protob\x06proto3"
|
||||
>>>>>>> main
|
||||
|
||||
var (
|
||||
file_daemon_proto_rawDescOnce sync.Once
|
||||
|
||||
@@ -372,6 +372,7 @@ message DebugBundleRequest {
|
||||
string status = 2;
|
||||
bool systemInfo = 3;
|
||||
string uploadURL = 4;
|
||||
uint32 logFileCount = 5;
|
||||
}
|
||||
|
||||
message DebugBundleResponse {
|
||||
|
||||
@@ -264,6 +264,7 @@ func (x *daemonServiceSubscribeEventsClient) Recv() (*SystemEvent, error) {
|
||||
func (c *daemonServiceClient) GetEvents(ctx context.Context, in *GetEventsRequest, opts ...grpc.CallOption) (*GetEventsResponse, error) {
|
||||
out := new(GetEventsResponse)
|
||||
err := c.cc.Invoke(ctx, "/daemon.DaemonService/GetEvents", in, out, opts...)
|
||||
<<<<<<< HEAD
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -273,6 +274,8 @@ func (c *daemonServiceClient) GetEvents(ctx context.Context, in *GetEventsReques
|
||||
func (c *daemonServiceClient) GetPeerSSHHostKey(ctx context.Context, in *GetPeerSSHHostKeyRequest, opts ...grpc.CallOption) (*GetPeerSSHHostKeyResponse, error) {
|
||||
out := new(GetPeerSSHHostKeyResponse)
|
||||
err := c.cc.Invoke(ctx, "/daemon.DaemonService/GetPeerSSHHostKey", in, out, opts...)
|
||||
=======
|
||||
>>>>>>> main
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ fi
|
||||
old_pwd=$(pwd)
|
||||
script_path=$(dirname $(realpath "$0"))
|
||||
cd "$script_path"
|
||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
|
||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.6
|
||||
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
|
||||
protoc -I ./ ./daemon.proto --go_out=../ --go-grpc_out=../ --experimental_allow_proto3_optional
|
||||
cd "$old_pwd"
|
||||
@@ -42,6 +42,7 @@ func (s *Server) DebugBundle(_ context.Context, req *proto.DebugBundleRequest) (
|
||||
Anonymize: req.GetAnonymize(),
|
||||
ClientStatus: req.GetStatus(),
|
||||
IncludeSystemInfo: req.GetSystemInfo(),
|
||||
LogFileCount: req.GetLogFileCount(),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
2
go.mod
2
go.mod
@@ -25,7 +25,7 @@ require (
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3
|
||||
google.golang.org/grpc v1.64.1
|
||||
google.golang.org/protobuf v1.36.5
|
||||
google.golang.org/protobuf v1.36.6
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
)
|
||||
|
||||
|
||||
4
go.sum
4
go.sum
@@ -1195,8 +1195,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -87,6 +87,12 @@ func startManagement(t *testing.T) (*grpc.Server, net.Listener) {
|
||||
).
|
||||
Return(&types.Settings{}, nil).
|
||||
AnyTimes()
|
||||
settingsMockManager.
|
||||
EXPECT().
|
||||
GetExtraSettings(gomock.Any(), gomock.Any()).
|
||||
Return(&types.ExtraSettings{}, nil).
|
||||
AnyTimes()
|
||||
|
||||
permissionsManagerMock := permissions.NewMockManager(ctrl)
|
||||
permissionsManagerMock.
|
||||
EXPECT().
|
||||
|
||||
@@ -16,7 +16,7 @@ type AccountsAPI struct {
|
||||
// List list all accounts, only returns one account always
|
||||
// See more: https://docs.netbird.io/api/resources/accounts#list-all-accounts
|
||||
func (a *AccountsAPI) List(ctx context.Context) ([]api.Account, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/accounts", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/accounts", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -34,7 +34,7 @@ func (a *AccountsAPI) Update(ctx context.Context, accountID string, request api.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/accounts/"+accountID, bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/accounts/"+accountID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func (a *AccountsAPI) Update(ctx context.Context, accountID string, request api.
|
||||
// Delete delete account
|
||||
// See more: https://docs.netbird.io/api/resources/accounts#delete-an-account
|
||||
func (a *AccountsAPI) Delete(ctx context.Context, accountID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/accounts/"+accountID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/accounts/"+accountID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ func (c *Client) initialize() {
|
||||
}
|
||||
|
||||
// NewRequest creates and executes new management API request
|
||||
func (c *Client) NewRequest(ctx context.Context, method, path string, body io.Reader) (*http.Response, error) {
|
||||
func (c *Client) NewRequest(ctx context.Context, method, path string, body io.Reader, query map[string]string) (*http.Response, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, method, c.managementURL+path, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -129,6 +129,14 @@ func (c *Client) NewRequest(ctx context.Context, method, path string, body io.Re
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
if len(query) != 0 {
|
||||
q := req.URL.Query()
|
||||
for k, v := range query {
|
||||
q.Add(k, v)
|
||||
}
|
||||
req.URL.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -16,7 +16,7 @@ type DNSAPI struct {
|
||||
// ListNameserverGroups list all nameserver groups
|
||||
// See more: https://docs.netbird.io/api/resources/dns#list-all-nameserver-groups
|
||||
func (a *DNSAPI) ListNameserverGroups(ctx context.Context) ([]api.NameserverGroup, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/dns/nameservers", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/dns/nameservers", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func (a *DNSAPI) ListNameserverGroups(ctx context.Context) ([]api.NameserverGrou
|
||||
// GetNameserverGroup get nameserver group info
|
||||
// See more: https://docs.netbird.io/api/resources/dns#retrieve-a-nameserver-group
|
||||
func (a *DNSAPI) GetNameserverGroup(ctx context.Context, nameserverGroupID string) (*api.NameserverGroup, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/dns/nameservers/"+nameserverGroupID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/dns/nameservers/"+nameserverGroupID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func (a *DNSAPI) CreateNameserverGroup(ctx context.Context, request api.PostApiD
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/dns/nameservers", bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/dns/nameservers", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func (a *DNSAPI) UpdateNameserverGroup(ctx context.Context, nameserverGroupID st
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/dns/nameservers/"+nameserverGroupID, bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/dns/nameservers/"+nameserverGroupID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func (a *DNSAPI) UpdateNameserverGroup(ctx context.Context, nameserverGroupID st
|
||||
// DeleteNameserverGroup delete nameserver group
|
||||
// See more: https://docs.netbird.io/api/resources/dns#delete-a-nameserver-group
|
||||
func (a *DNSAPI) DeleteNameserverGroup(ctx context.Context, nameserverGroupID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/dns/nameservers/"+nameserverGroupID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/dns/nameservers/"+nameserverGroupID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -94,7 +94,7 @@ func (a *DNSAPI) DeleteNameserverGroup(ctx context.Context, nameserverGroupID st
|
||||
// GetSettings get DNS settings
|
||||
// See more: https://docs.netbird.io/api/resources/dns#retrieve-dns-settings
|
||||
func (a *DNSAPI) GetSettings(ctx context.Context) (*api.DNSSettings, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/dns/settings", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/dns/settings", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -112,7 +112,7 @@ func (a *DNSAPI) UpdateSettings(ctx context.Context, request api.PutApiDnsSettin
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/dns/settings", bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/dns/settings", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ type EventsAPI struct {
|
||||
// List list all events
|
||||
// See more: https://docs.netbird.io/api/resources/events#list-all-events
|
||||
func (a *EventsAPI) List(ctx context.Context) ([]api.Event, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/events", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/events", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ type GeoLocationAPI struct {
|
||||
// ListCountries list all country codes
|
||||
// See more: https://docs.netbird.io/api/resources/geo-locations#list-all-country-codes
|
||||
func (a *GeoLocationAPI) ListCountries(ctx context.Context) ([]api.Country, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/locations/countries", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/locations/countries", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -28,7 +28,7 @@ func (a *GeoLocationAPI) ListCountries(ctx context.Context) ([]api.Country, erro
|
||||
// ListCountryCities Get a list of all English city names for a given country code
|
||||
// See more: https://docs.netbird.io/api/resources/geo-locations#list-all-city-names-by-country
|
||||
func (a *GeoLocationAPI) ListCountryCities(ctx context.Context, countryCode string) ([]api.City, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/locations/countries/"+countryCode+"/cities", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/locations/countries/"+countryCode+"/cities", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ type GroupsAPI struct {
|
||||
// List list all groups
|
||||
// See more: https://docs.netbird.io/api/resources/groups#list-all-groups
|
||||
func (a *GroupsAPI) List(ctx context.Context) ([]api.Group, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/groups", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/groups", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func (a *GroupsAPI) List(ctx context.Context) ([]api.Group, error) {
|
||||
// Get get group info
|
||||
// See more: https://docs.netbird.io/api/resources/groups#retrieve-a-group
|
||||
func (a *GroupsAPI) Get(ctx context.Context, groupID string) (*api.Group, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/groups/"+groupID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/groups/"+groupID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func (a *GroupsAPI) Create(ctx context.Context, request api.PostApiGroupsJSONReq
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/groups", bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/groups", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func (a *GroupsAPI) Update(ctx context.Context, groupID string, request api.PutA
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/groups/"+groupID, bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/groups/"+groupID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func (a *GroupsAPI) Update(ctx context.Context, groupID string, request api.PutA
|
||||
// Delete delete group
|
||||
// See more: https://docs.netbird.io/api/resources/groups#delete-a-group
|
||||
func (a *GroupsAPI) Delete(ctx context.Context, groupID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/groups/"+groupID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/groups/"+groupID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ type NetworksAPI struct {
|
||||
// List list all networks
|
||||
// See more: https://docs.netbird.io/api/resources/networks#list-all-networks
|
||||
func (a *NetworksAPI) List(ctx context.Context) ([]api.Network, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/networks", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/networks", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func (a *NetworksAPI) List(ctx context.Context) ([]api.Network, error) {
|
||||
// Get get network info
|
||||
// See more: https://docs.netbird.io/api/resources/networks#retrieve-a-network
|
||||
func (a *NetworksAPI) Get(ctx context.Context, networkID string) (*api.Network, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/networks/"+networkID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/networks/"+networkID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func (a *NetworksAPI) Create(ctx context.Context, request api.PostApiNetworksJSO
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/networks", bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/networks", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func (a *NetworksAPI) Update(ctx context.Context, networkID string, request api.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/networks/"+networkID, bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/networks/"+networkID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func (a *NetworksAPI) Update(ctx context.Context, networkID string, request api.
|
||||
// Delete delete network
|
||||
// See more: https://docs.netbird.io/api/resources/networks#delete-a-network
|
||||
func (a *NetworksAPI) Delete(ctx context.Context, networkID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/networks/"+networkID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/networks/"+networkID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -108,7 +108,7 @@ func (a *NetworksAPI) Resources(networkID string) *NetworkResourcesAPI {
|
||||
// List list all resources in networks
|
||||
// See more: https://docs.netbird.io/api/resources/networks#list-all-network-resources
|
||||
func (a *NetworkResourcesAPI) List(ctx context.Context) ([]api.NetworkResource, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/networks/"+a.networkID+"/resources", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/networks/"+a.networkID+"/resources", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -122,7 +122,7 @@ func (a *NetworkResourcesAPI) List(ctx context.Context) ([]api.NetworkResource,
|
||||
// Get get network resource info
|
||||
// See more: https://docs.netbird.io/api/resources/networks#retrieve-a-network-resource
|
||||
func (a *NetworkResourcesAPI) Get(ctx context.Context, networkResourceID string) (*api.NetworkResource, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/networks/"+a.networkID+"/resources/"+networkResourceID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/networks/"+a.networkID+"/resources/"+networkResourceID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -140,7 +140,7 @@ func (a *NetworkResourcesAPI) Create(ctx context.Context, request api.PostApiNet
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/networks/"+a.networkID+"/resources", bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/networks/"+a.networkID+"/resources", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -158,7 +158,7 @@ func (a *NetworkResourcesAPI) Update(ctx context.Context, networkResourceID stri
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/networks/"+a.networkID+"/resources/"+networkResourceID, bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/networks/"+a.networkID+"/resources/"+networkResourceID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -172,7 +172,7 @@ func (a *NetworkResourcesAPI) Update(ctx context.Context, networkResourceID stri
|
||||
// Delete delete network resource
|
||||
// See more: https://docs.netbird.io/api/resources/networks#delete-a-network-resource
|
||||
func (a *NetworkResourcesAPI) Delete(ctx context.Context, networkResourceID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/networks/"+a.networkID+"/resources/"+networkResourceID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/networks/"+a.networkID+"/resources/"+networkResourceID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -200,7 +200,7 @@ func (a *NetworksAPI) Routers(networkID string) *NetworkRoutersAPI {
|
||||
// List list all routers in networks
|
||||
// See more: https://docs.netbird.io/api/routers/networks#list-all-network-routers
|
||||
func (a *NetworkRoutersAPI) List(ctx context.Context) ([]api.NetworkRouter, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/networks/"+a.networkID+"/routers", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/networks/"+a.networkID+"/routers", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -214,7 +214,7 @@ func (a *NetworkRoutersAPI) List(ctx context.Context) ([]api.NetworkRouter, erro
|
||||
// Get get network router info
|
||||
// See more: https://docs.netbird.io/api/routers/networks#retrieve-a-network-router
|
||||
func (a *NetworkRoutersAPI) Get(ctx context.Context, networkRouterID string) (*api.NetworkRouter, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/networks/"+a.networkID+"/routers/"+networkRouterID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/networks/"+a.networkID+"/routers/"+networkRouterID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -232,7 +232,7 @@ func (a *NetworkRoutersAPI) Create(ctx context.Context, request api.PostApiNetwo
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/networks/"+a.networkID+"/routers", bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/networks/"+a.networkID+"/routers", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -250,7 +250,7 @@ func (a *NetworkRoutersAPI) Update(ctx context.Context, networkRouterID string,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/networks/"+a.networkID+"/routers/"+networkRouterID, bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/networks/"+a.networkID+"/routers/"+networkRouterID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -264,7 +264,7 @@ func (a *NetworkRoutersAPI) Update(ctx context.Context, networkRouterID string,
|
||||
// Delete delete network router
|
||||
// See more: https://docs.netbird.io/api/routers/networks#delete-a-network-router
|
||||
func (a *NetworkRoutersAPI) Delete(ctx context.Context, networkRouterID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/networks/"+a.networkID+"/routers/"+networkRouterID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/networks/"+a.networkID+"/routers/"+networkRouterID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -13,10 +13,30 @@ type PeersAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// PeersListOption options for Peers List API
|
||||
type PeersListOption func() (string, string)
|
||||
|
||||
func PeerNameFilter(name string) PeersListOption {
|
||||
return func() (string, string) {
|
||||
return "name", name
|
||||
}
|
||||
}
|
||||
|
||||
func PeerIPFilter(ip string) PeersListOption {
|
||||
return func() (string, string) {
|
||||
return "ip", ip
|
||||
}
|
||||
}
|
||||
|
||||
// List list all peers
|
||||
// See more: https://docs.netbird.io/api/resources/peers#list-all-peers
|
||||
func (a *PeersAPI) List(ctx context.Context) ([]api.Peer, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/peers", nil)
|
||||
func (a *PeersAPI) List(ctx context.Context, opts ...PeersListOption) ([]api.Peer, error) {
|
||||
query := make(map[string]string)
|
||||
for _, o := range opts {
|
||||
k, v := o()
|
||||
query[k] = v
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/peers", nil, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -30,7 +50,7 @@ func (a *PeersAPI) List(ctx context.Context) ([]api.Peer, error) {
|
||||
// Get retrieve a peer
|
||||
// See more: https://docs.netbird.io/api/resources/peers#retrieve-a-peer
|
||||
func (a *PeersAPI) Get(ctx context.Context, peerID string) (*api.Peer, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/peers/"+peerID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/peers/"+peerID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -48,7 +68,7 @@ func (a *PeersAPI) Update(ctx context.Context, peerID string, request api.PutApi
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/peers/"+peerID, bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/peers/"+peerID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -62,7 +82,7 @@ func (a *PeersAPI) Update(ctx context.Context, peerID string, request api.PutApi
|
||||
// Delete delete a peer
|
||||
// See more: https://docs.netbird.io/api/resources/peers#delete-a-peer
|
||||
func (a *PeersAPI) Delete(ctx context.Context, peerID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/peers/"+peerID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/peers/"+peerID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -76,7 +96,7 @@ func (a *PeersAPI) Delete(ctx context.Context, peerID string) error {
|
||||
// ListAccessiblePeers list all peers that the specified peer can connect to within the network
|
||||
// See more: https://docs.netbird.io/api/resources/peers#list-accessible-peers
|
||||
func (a *PeersAPI) ListAccessiblePeers(ctx context.Context, peerID string) ([]api.Peer, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/peers/"+peerID+"/accessible-peers", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/peers/"+peerID+"/accessible-peers", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -184,6 +184,10 @@ func TestPeers_Integration(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, peers)
|
||||
|
||||
filteredPeers, err := c.Peers.List(context.Background(), rest.PeerIPFilter("192.168.10.0"))
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, filteredPeers)
|
||||
|
||||
peer, err := c.Peers.Get(context.Background(), peers[0].Id)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, peers[0].Id, peer.Id)
|
||||
|
||||
@@ -18,7 +18,7 @@ type PoliciesAPI struct {
|
||||
func (a *PoliciesAPI) List(ctx context.Context) ([]api.Policy, error) {
|
||||
path := "/api/policies"
|
||||
|
||||
resp, err := a.c.NewRequest(ctx, "GET", path, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", path, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -32,7 +32,7 @@ func (a *PoliciesAPI) List(ctx context.Context) ([]api.Policy, error) {
|
||||
// Get get policy info
|
||||
// See more: https://docs.netbird.io/api/resources/policies#retrieve-a-policy
|
||||
func (a *PoliciesAPI) Get(ctx context.Context, policyID string) (*api.Policy, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/policies/"+policyID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/policies/"+policyID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -50,7 +50,7 @@ func (a *PoliciesAPI) Create(ctx context.Context, request api.PostApiPoliciesJSO
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/policies", bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/policies", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -70,7 +70,7 @@ func (a *PoliciesAPI) Update(ctx context.Context, policyID string, request api.P
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", path, bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", path, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -84,7 +84,7 @@ func (a *PoliciesAPI) Update(ctx context.Context, policyID string, request api.P
|
||||
// Delete delete policy
|
||||
// See more: https://docs.netbird.io/api/resources/policies#delete-a-policy
|
||||
func (a *PoliciesAPI) Delete(ctx context.Context, policyID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/policies/"+policyID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/policies/"+policyID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ type PostureChecksAPI struct {
|
||||
// List list all posture checks
|
||||
// See more: https://docs.netbird.io/api/resources/posture-checks#list-all-posture-checks
|
||||
func (a *PostureChecksAPI) List(ctx context.Context) ([]api.PostureCheck, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/posture-checks", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/posture-checks", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func (a *PostureChecksAPI) List(ctx context.Context) ([]api.PostureCheck, error)
|
||||
// Get get posture check info
|
||||
// See more: https://docs.netbird.io/api/resources/posture-checks#retrieve-a-posture-check
|
||||
func (a *PostureChecksAPI) Get(ctx context.Context, postureCheckID string) (*api.PostureCheck, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/posture-checks/"+postureCheckID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/posture-checks/"+postureCheckID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func (a *PostureChecksAPI) Create(ctx context.Context, request api.PostApiPostur
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/posture-checks", bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/posture-checks", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func (a *PostureChecksAPI) Update(ctx context.Context, postureCheckID string, re
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/posture-checks/"+postureCheckID, bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/posture-checks/"+postureCheckID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func (a *PostureChecksAPI) Update(ctx context.Context, postureCheckID string, re
|
||||
// Delete delete posture check
|
||||
// See more: https://docs.netbird.io/api/resources/posture-checks#delete-a-posture-check
|
||||
func (a *PostureChecksAPI) Delete(ctx context.Context, postureCheckID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/posture-checks/"+postureCheckID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/posture-checks/"+postureCheckID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ type RoutesAPI struct {
|
||||
// List list all routes
|
||||
// See more: https://docs.netbird.io/api/resources/routes#list-all-routes
|
||||
func (a *RoutesAPI) List(ctx context.Context) ([]api.Route, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/routes", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/routes", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func (a *RoutesAPI) List(ctx context.Context) ([]api.Route, error) {
|
||||
// Get get route info
|
||||
// See more: https://docs.netbird.io/api/resources/routes#retrieve-a-route
|
||||
func (a *RoutesAPI) Get(ctx context.Context, routeID string) (*api.Route, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/routes/"+routeID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/routes/"+routeID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func (a *RoutesAPI) Create(ctx context.Context, request api.PostApiRoutesJSONReq
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/routes", bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/routes", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func (a *RoutesAPI) Update(ctx context.Context, routeID string, request api.PutA
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/routes/"+routeID, bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/routes/"+routeID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func (a *RoutesAPI) Update(ctx context.Context, routeID string, request api.PutA
|
||||
// Delete delete route
|
||||
// See more: https://docs.netbird.io/api/resources/routes#delete-a-route
|
||||
func (a *RoutesAPI) Delete(ctx context.Context, routeID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/routes/"+routeID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/routes/"+routeID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ type SetupKeysAPI struct {
|
||||
// List list all setup keys
|
||||
// See more: https://docs.netbird.io/api/resources/setup-keys#list-all-setup-keys
|
||||
func (a *SetupKeysAPI) List(ctx context.Context) ([]api.SetupKey, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/setup-keys", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/setup-keys", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func (a *SetupKeysAPI) List(ctx context.Context) ([]api.SetupKey, error) {
|
||||
// Get get setup key info
|
||||
// See more: https://docs.netbird.io/api/resources/setup-keys#retrieve-a-setup-key
|
||||
func (a *SetupKeysAPI) Get(ctx context.Context, setupKeyID string) (*api.SetupKey, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/setup-keys/"+setupKeyID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/setup-keys/"+setupKeyID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -50,7 +50,7 @@ func (a *SetupKeysAPI) Create(ctx context.Context, request api.PostApiSetupKeysJ
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", path, bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "POST", path, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -68,7 +68,7 @@ func (a *SetupKeysAPI) Update(ctx context.Context, setupKeyID string, request ap
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/setup-keys/"+setupKeyID, bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/setup-keys/"+setupKeyID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -82,7 +82,7 @@ func (a *SetupKeysAPI) Update(ctx context.Context, setupKeyID string, request ap
|
||||
// Delete delete setup key
|
||||
// See more: https://docs.netbird.io/api/resources/setup-keys#delete-a-setup-key
|
||||
func (a *SetupKeysAPI) Delete(ctx context.Context, setupKeyID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/setup-keys/"+setupKeyID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/setup-keys/"+setupKeyID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ type TokensAPI struct {
|
||||
// List list user tokens
|
||||
// See more: https://docs.netbird.io/api/resources/tokens#list-all-tokens
|
||||
func (a *TokensAPI) List(ctx context.Context, userID string) ([]api.PersonalAccessToken, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/users/"+userID+"/tokens", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/users/"+userID+"/tokens", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func (a *TokensAPI) List(ctx context.Context, userID string) ([]api.PersonalAcce
|
||||
// Get get user token info
|
||||
// See more: https://docs.netbird.io/api/resources/tokens#retrieve-a-token
|
||||
func (a *TokensAPI) Get(ctx context.Context, userID, tokenID string) (*api.PersonalAccessToken, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/users/"+userID+"/tokens/"+tokenID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/users/"+userID+"/tokens/"+tokenID, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func (a *TokensAPI) Create(ctx context.Context, userID string, request api.PostA
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/users/"+userID+"/tokens", bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/users/"+userID+"/tokens", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -62,7 +62,7 @@ func (a *TokensAPI) Create(ctx context.Context, userID string, request api.PostA
|
||||
// Delete delete user token
|
||||
// See more: https://docs.netbird.io/api/resources/tokens#delete-a-token
|
||||
func (a *TokensAPI) Delete(ctx context.Context, userID, tokenID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/users/"+userID+"/tokens/"+tokenID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/users/"+userID+"/tokens/"+tokenID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ type UsersAPI struct {
|
||||
// List list all users, only returns one user always
|
||||
// See more: https://docs.netbird.io/api/resources/users#list-all-users
|
||||
func (a *UsersAPI) List(ctx context.Context) ([]api.User, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/users", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/users", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -34,7 +34,7 @@ func (a *UsersAPI) Create(ctx context.Context, request api.PostApiUsersJSONReque
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/users", bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/users", bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -52,7 +52,7 @@ func (a *UsersAPI) Update(ctx context.Context, userID string, request api.PutApi
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/users/"+userID, bytes.NewReader(requestBytes))
|
||||
resp, err := a.c.NewRequest(ctx, "PUT", "/api/users/"+userID, bytes.NewReader(requestBytes), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func (a *UsersAPI) Update(ctx context.Context, userID string, request api.PutApi
|
||||
// Delete delete user
|
||||
// See more: https://docs.netbird.io/api/resources/users#delete-a-user
|
||||
func (a *UsersAPI) Delete(ctx context.Context, userID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/users/"+userID, nil)
|
||||
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/users/"+userID, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func (a *UsersAPI) Delete(ctx context.Context, userID string) error {
|
||||
// ResendInvitation resend user invitation
|
||||
// See more: https://docs.netbird.io/api/resources/users#resend-user-invitation
|
||||
func (a *UsersAPI) ResendInvitation(ctx context.Context, userID string) error {
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/users/"+userID+"/invite", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "POST", "/api/users/"+userID+"/invite", nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -94,7 +94,7 @@ func (a *UsersAPI) ResendInvitation(ctx context.Context, userID string) error {
|
||||
// Current gets the current user info
|
||||
// See more: https://docs.netbird.io/api/resources/users#retrieve-current-user
|
||||
func (a *UsersAPI) Current(ctx context.Context) (*api.User, error) {
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/users/current", nil)
|
||||
resp, err := a.c.NewRequest(ctx, "GET", "/api/users/current", nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ type Manager interface {
|
||||
GetAccountSettings(ctx context.Context, accountID string, userID string) (*types.Settings, error)
|
||||
DeleteSetupKey(ctx context.Context, accountID, userID, keyID string) error
|
||||
UpdateAccountPeers(ctx context.Context, accountID string)
|
||||
BufferUpdateAccountPeers(ctx context.Context, accountID string)
|
||||
BuildUserInfosForAccount(ctx context.Context, accountID, initiatorUserID string, accountUsers []*types.User) (map[string]*types.UserInfo, error)
|
||||
SyncUserJWTGroups(ctx context.Context, userAuth nbcontext.UserAuth) error
|
||||
GetStore() store.Store
|
||||
|
||||
@@ -216,6 +216,8 @@ func createDNSManager(t *testing.T) (*DefaultAccountManager, error) {
|
||||
t.Cleanup(ctrl.Finish)
|
||||
|
||||
settingsMockManager := settings.NewMockManager(ctrl)
|
||||
// return empty extra settings for expected calls to UpdateAccountPeers
|
||||
settingsMockManager.EXPECT().GetExtraSettings(gomock.Any(), gomock.Any()).Return(&types.ExtraSettings{}, nil).AnyTimes()
|
||||
permissionsManager := permissions.NewManager(store)
|
||||
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.test", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ import (
|
||||
|
||||
const (
|
||||
ephemeralLifeTime = 10 * time.Minute
|
||||
// cleanupWindow is the time window to wait after nearest peer deadline to start the cleanup procedure.
|
||||
cleanupWindow = 1 * time.Minute
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -41,6 +43,9 @@ type EphemeralManager struct {
|
||||
tailPeer *ephemeralPeer
|
||||
peersLock sync.Mutex
|
||||
timer *time.Timer
|
||||
|
||||
lifeTime time.Duration
|
||||
cleanupWindow time.Duration
|
||||
}
|
||||
|
||||
// NewEphemeralManager instantiate new EphemeralManager
|
||||
@@ -48,6 +53,9 @@ func NewEphemeralManager(store store.Store, accountManager nbAccount.Manager) *E
|
||||
return &EphemeralManager{
|
||||
store: store,
|
||||
accountManager: accountManager,
|
||||
|
||||
lifeTime: ephemeralLifeTime,
|
||||
cleanupWindow: cleanupWindow,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +68,7 @@ func (e *EphemeralManager) LoadInitialPeers(ctx context.Context) {
|
||||
|
||||
e.loadEphemeralPeers(ctx)
|
||||
if e.headPeer != nil {
|
||||
e.timer = time.AfterFunc(ephemeralLifeTime, func() {
|
||||
e.timer = time.AfterFunc(e.lifeTime, func() {
|
||||
e.cleanup(ctx)
|
||||
})
|
||||
}
|
||||
@@ -113,9 +121,13 @@ func (e *EphemeralManager) OnPeerDisconnected(ctx context.Context, peer *nbpeer.
|
||||
return
|
||||
}
|
||||
|
||||
e.addPeer(peer.AccountID, peer.ID, newDeadLine())
|
||||
e.addPeer(peer.AccountID, peer.ID, e.newDeadLine())
|
||||
if e.timer == nil {
|
||||
e.timer = time.AfterFunc(e.headPeer.deadline.Sub(timeNow()), func() {
|
||||
delay := e.headPeer.deadline.Sub(timeNow()) + e.cleanupWindow
|
||||
if delay < 0 {
|
||||
delay = 0
|
||||
}
|
||||
e.timer = time.AfterFunc(delay, func() {
|
||||
e.cleanup(ctx)
|
||||
})
|
||||
}
|
||||
@@ -128,7 +140,7 @@ func (e *EphemeralManager) loadEphemeralPeers(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
t := newDeadLine()
|
||||
t := e.newDeadLine()
|
||||
for _, p := range peers {
|
||||
e.addPeer(p.AccountID, p.ID, t)
|
||||
}
|
||||
@@ -155,7 +167,11 @@ func (e *EphemeralManager) cleanup(ctx context.Context) {
|
||||
}
|
||||
|
||||
if e.headPeer != nil {
|
||||
e.timer = time.AfterFunc(e.headPeer.deadline.Sub(timeNow()), func() {
|
||||
delay := e.headPeer.deadline.Sub(timeNow()) + e.cleanupWindow
|
||||
if delay < 0 {
|
||||
delay = 0
|
||||
}
|
||||
e.timer = time.AfterFunc(delay, func() {
|
||||
e.cleanup(ctx)
|
||||
})
|
||||
} else {
|
||||
@@ -164,13 +180,20 @@ func (e *EphemeralManager) cleanup(ctx context.Context) {
|
||||
|
||||
e.peersLock.Unlock()
|
||||
|
||||
bufferAccountCall := make(map[string]struct{})
|
||||
|
||||
for id, p := range deletePeers {
|
||||
log.WithContext(ctx).Debugf("delete ephemeral peer: %s", id)
|
||||
err := e.accountManager.DeletePeer(ctx, p.accountID, id, activity.SystemInitiator)
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Errorf("failed to delete ephemeral peer: %s", err)
|
||||
} else {
|
||||
bufferAccountCall[p.accountID] = struct{}{}
|
||||
}
|
||||
}
|
||||
for accountID := range bufferAccountCall {
|
||||
e.accountManager.BufferUpdateAccountPeers(ctx, accountID)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EphemeralManager) addPeer(accountID string, peerID string, deadline time.Time) {
|
||||
@@ -223,6 +246,6 @@ func (e *EphemeralManager) isPeerOnList(id string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func newDeadLine() time.Time {
|
||||
return timeNow().Add(ephemeralLifeTime)
|
||||
func (e *EphemeralManager) newDeadLine() time.Time {
|
||||
return timeNow().Add(e.lifeTime)
|
||||
}
|
||||
|
||||
@@ -3,9 +3,12 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
nbAccount "github.com/netbirdio/netbird/management/server/account"
|
||||
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
||||
"github.com/netbirdio/netbird/management/server/store"
|
||||
@@ -27,28 +30,65 @@ func (s *MockStore) GetAllEphemeralPeers(_ context.Context, _ store.LockingStren
|
||||
return peers, nil
|
||||
}
|
||||
|
||||
type MocAccountManager struct {
|
||||
type MockAccountManager struct {
|
||||
mu sync.Mutex
|
||||
nbAccount.Manager
|
||||
store *MockStore
|
||||
store *MockStore
|
||||
deletePeerCalls int
|
||||
bufferUpdateCalls map[string]int
|
||||
wg *sync.WaitGroup
|
||||
}
|
||||
|
||||
func (a MocAccountManager) DeletePeer(_ context.Context, accountID, peerID, userID string) error {
|
||||
func (a *MockAccountManager) DeletePeer(_ context.Context, accountID, peerID, userID string) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
a.deletePeerCalls++
|
||||
if a.wg != nil {
|
||||
a.wg.Done()
|
||||
}
|
||||
delete(a.store.account.Peers, peerID)
|
||||
return nil //nolint:nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a MocAccountManager) GetStore() store.Store {
|
||||
func (a *MockAccountManager) GetDeletePeerCalls() int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.deletePeerCalls
|
||||
}
|
||||
|
||||
func (a *MockAccountManager) BufferUpdateAccountPeers(ctx context.Context, accountID string) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if a.bufferUpdateCalls == nil {
|
||||
a.bufferUpdateCalls = make(map[string]int)
|
||||
}
|
||||
a.bufferUpdateCalls[accountID]++
|
||||
}
|
||||
|
||||
func (a *MockAccountManager) GetBufferUpdateCalls(accountID string) int {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if a.bufferUpdateCalls == nil {
|
||||
return 0
|
||||
}
|
||||
return a.bufferUpdateCalls[accountID]
|
||||
}
|
||||
|
||||
func (a *MockAccountManager) GetStore() store.Store {
|
||||
return a.store
|
||||
}
|
||||
|
||||
func TestNewManager(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
timeNow = time.Now
|
||||
})
|
||||
startTime := time.Now()
|
||||
timeNow = func() time.Time {
|
||||
return startTime
|
||||
}
|
||||
|
||||
store := &MockStore{}
|
||||
am := MocAccountManager{
|
||||
am := MockAccountManager{
|
||||
store: store,
|
||||
}
|
||||
|
||||
@@ -56,7 +96,7 @@ func TestNewManager(t *testing.T) {
|
||||
numberOfEphemeralPeers := 3
|
||||
seedPeers(store, numberOfPeers, numberOfEphemeralPeers)
|
||||
|
||||
mgr := NewEphemeralManager(store, am)
|
||||
mgr := NewEphemeralManager(store, &am)
|
||||
mgr.loadEphemeralPeers(context.Background())
|
||||
startTime = startTime.Add(ephemeralLifeTime + 1)
|
||||
mgr.cleanup(context.Background())
|
||||
@@ -67,13 +107,16 @@ func TestNewManager(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewManagerPeerConnected(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
timeNow = time.Now
|
||||
})
|
||||
startTime := time.Now()
|
||||
timeNow = func() time.Time {
|
||||
return startTime
|
||||
}
|
||||
|
||||
store := &MockStore{}
|
||||
am := MocAccountManager{
|
||||
am := MockAccountManager{
|
||||
store: store,
|
||||
}
|
||||
|
||||
@@ -81,7 +124,7 @@ func TestNewManagerPeerConnected(t *testing.T) {
|
||||
numberOfEphemeralPeers := 3
|
||||
seedPeers(store, numberOfPeers, numberOfEphemeralPeers)
|
||||
|
||||
mgr := NewEphemeralManager(store, am)
|
||||
mgr := NewEphemeralManager(store, &am)
|
||||
mgr.loadEphemeralPeers(context.Background())
|
||||
mgr.OnPeerConnected(context.Background(), store.account.Peers["ephemeral_peer_0"])
|
||||
|
||||
@@ -95,13 +138,16 @@ func TestNewManagerPeerConnected(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewManagerPeerDisconnected(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
timeNow = time.Now
|
||||
})
|
||||
startTime := time.Now()
|
||||
timeNow = func() time.Time {
|
||||
return startTime
|
||||
}
|
||||
|
||||
store := &MockStore{}
|
||||
am := MocAccountManager{
|
||||
am := MockAccountManager{
|
||||
store: store,
|
||||
}
|
||||
|
||||
@@ -109,7 +155,7 @@ func TestNewManagerPeerDisconnected(t *testing.T) {
|
||||
numberOfEphemeralPeers := 3
|
||||
seedPeers(store, numberOfPeers, numberOfEphemeralPeers)
|
||||
|
||||
mgr := NewEphemeralManager(store, am)
|
||||
mgr := NewEphemeralManager(store, &am)
|
||||
mgr.loadEphemeralPeers(context.Background())
|
||||
for _, v := range store.account.Peers {
|
||||
mgr.OnPeerConnected(context.Background(), v)
|
||||
@@ -126,6 +172,36 @@ func TestNewManagerPeerDisconnected(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanupSchedulingBehaviorIsBatched(t *testing.T) {
|
||||
const (
|
||||
ephemeralPeers = 10
|
||||
testLifeTime = 1 * time.Second
|
||||
testCleanupWindow = 100 * time.Millisecond
|
||||
)
|
||||
mockStore := &MockStore{}
|
||||
mockAM := &MockAccountManager{
|
||||
store: mockStore,
|
||||
}
|
||||
mockAM.wg = &sync.WaitGroup{}
|
||||
mockAM.wg.Add(ephemeralPeers)
|
||||
mgr := NewEphemeralManager(mockStore, mockAM)
|
||||
mgr.lifeTime = testLifeTime
|
||||
mgr.cleanupWindow = testCleanupWindow
|
||||
|
||||
account := newAccountWithId(context.Background(), "account", "", "", false)
|
||||
mockStore.account = account
|
||||
for i := range ephemeralPeers {
|
||||
p := &nbpeer.Peer{ID: fmt.Sprintf("peer-%d", i), AccountID: account.Id, Ephemeral: true}
|
||||
mockStore.account.Peers[p.ID] = p
|
||||
time.Sleep(testCleanupWindow / ephemeralPeers)
|
||||
mgr.OnPeerDisconnected(context.Background(), p)
|
||||
}
|
||||
mockAM.wg.Wait()
|
||||
assert.Len(t, mockStore.account.Peers, 0, "all ephemeral peers should be cleaned up after the lifetime")
|
||||
assert.Equal(t, 1, mockAM.GetBufferUpdateCalls(account.Id), "buffer update should be called once")
|
||||
assert.Equal(t, ephemeralPeers, mockAM.GetDeletePeerCalls(), "should have deleted all peers")
|
||||
}
|
||||
|
||||
func seedPeers(store *MockStore, numberOfPeers int, numberOfEphemeralPeers int) {
|
||||
store.account = newAccountWithId(context.Background(), "my account", "", "", false)
|
||||
|
||||
|
||||
@@ -440,7 +440,11 @@ func startManagementForTest(t *testing.T, testFile string, config *types.Config)
|
||||
GetSettings(gomock.Any(), gomock.Any(), gomock.Any()).
|
||||
AnyTimes().
|
||||
Return(&types.Settings{}, nil)
|
||||
|
||||
settingsMockManager.
|
||||
EXPECT().
|
||||
GetExtraSettings(gomock.Any(), gomock.Any()).
|
||||
Return(&types.ExtraSettings{}, nil).
|
||||
AnyTimes()
|
||||
permissionsManager := permissions.NewManager(store)
|
||||
|
||||
accountManager, err := BuildManager(ctx, store, peersUpdateManager, nil, "", "netbird.selfhosted",
|
||||
|
||||
@@ -120,10 +120,20 @@ type MockAccountManager struct {
|
||||
GetAccountOnboardingFunc func(ctx context.Context, accountID, userID string) (*types.AccountOnboarding, error)
|
||||
UpdateAccountOnboardingFunc func(ctx context.Context, accountID, userID string, onboarding *types.AccountOnboarding) (*types.AccountOnboarding, error)
|
||||
GetOrCreateAccountByPrivateDomainFunc func(ctx context.Context, initiatorId, domain string) (*types.Account, bool, error)
|
||||
UpdateAccountPeersFunc func(ctx context.Context, accountID string)
|
||||
BufferUpdateAccountPeersFunc func(ctx context.Context, accountID string)
|
||||
}
|
||||
|
||||
func (am *MockAccountManager) UpdateAccountPeers(ctx context.Context, accountID string) {
|
||||
// do nothing
|
||||
if am.UpdateAccountPeersFunc != nil {
|
||||
am.UpdateAccountPeersFunc(ctx, accountID)
|
||||
}
|
||||
}
|
||||
|
||||
func (am *MockAccountManager) BufferUpdateAccountPeers(ctx context.Context, accountID string) {
|
||||
if am.BufferUpdateAccountPeersFunc != nil {
|
||||
am.BufferUpdateAccountPeersFunc(ctx, accountID)
|
||||
}
|
||||
}
|
||||
|
||||
func (am *MockAccountManager) DeleteSetupKey(ctx context.Context, accountID, userID, keyID string) error {
|
||||
|
||||
@@ -778,6 +778,12 @@ func createNSManager(t *testing.T) (*DefaultAccountManager, error) {
|
||||
ctrl := gomock.NewController(t)
|
||||
t.Cleanup(ctrl.Finish)
|
||||
settingsMockManager := settings.NewMockManager(ctrl)
|
||||
settingsMockManager.
|
||||
EXPECT().
|
||||
GetExtraSettings(gomock.Any(), gomock.Any()).
|
||||
Return(&types.ExtraSettings{}, nil).
|
||||
AnyTimes()
|
||||
|
||||
permissionsManager := permissions.NewManager(store)
|
||||
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/rs/xid"
|
||||
@@ -236,11 +237,23 @@ func (am *DefaultAccountManager) UpdatePeer(ctx context.Context, accountID, user
|
||||
|
||||
if peer.Name != update.Name {
|
||||
var newLabel string
|
||||
newLabel, err = getPeerIPDNSLabel(ctx, transaction, peer.IP, accountID, update.Name)
|
||||
|
||||
newLabel, err = nbdns.GetParsedDomainLabel(update.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get free DNS label: %w", err)
|
||||
newLabel = ""
|
||||
} else {
|
||||
_, err := transaction.GetPeerIdByLabel(ctx, store.LockingStrengthNone, accountID, update.Name)
|
||||
if err == nil {
|
||||
newLabel = ""
|
||||
}
|
||||
}
|
||||
|
||||
if newLabel == "" {
|
||||
newLabel, err = getPeerIPDNSLabel(peer.IP, update.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get free DNS label: %w", err)
|
||||
}
|
||||
}
|
||||
peer.Name = update.Name
|
||||
peer.DNSLabel = newLabel
|
||||
peerLabelChanged = true
|
||||
@@ -364,19 +377,6 @@ func (am *DefaultAccountManager) DeletePeer(ctx context.Context, accountID, peer
|
||||
return err
|
||||
}
|
||||
|
||||
groups, err := transaction.GetPeerGroups(ctx, store.LockingStrengthUpdate, accountID, peerID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get peer groups: %w", err)
|
||||
}
|
||||
|
||||
for _, group := range groups {
|
||||
group.RemovePeer(peerID)
|
||||
err = transaction.SaveGroup(ctx, store.LockingStrengthUpdate, group)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to save group: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
eventsToStore, err = deletePeers(ctx, am, transaction, accountID, userID, []*nbpeer.Peer{peer})
|
||||
return err
|
||||
})
|
||||
@@ -388,7 +388,7 @@ func (am *DefaultAccountManager) DeletePeer(ctx context.Context, accountID, peer
|
||||
storeEvent()
|
||||
}
|
||||
|
||||
if updateAccountPeers {
|
||||
if updateAccountPeers && userID != activity.SystemInitiator {
|
||||
am.BufferUpdateAccountPeers(ctx, accountID)
|
||||
}
|
||||
|
||||
@@ -485,6 +485,7 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, setupKey, userID s
|
||||
var groupsToAdd []string
|
||||
var allowExtraDNSLabels bool
|
||||
var accountID string
|
||||
var isEphemeral bool
|
||||
if addedByUser {
|
||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthNone, userID)
|
||||
if err != nil {
|
||||
@@ -514,7 +515,7 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, setupKey, userID s
|
||||
setupKeyName = sk.Name
|
||||
allowExtraDNSLabels = sk.AllowExtraDNSLabels
|
||||
accountID = sk.AccountID
|
||||
|
||||
isEphemeral = sk.Ephemeral
|
||||
if !sk.AllowExtraDNSLabels && len(peer.ExtraDNSLabels) > 0 {
|
||||
return nil, nil, nil, status.Errorf(status.PreconditionFailed, "couldn't add peer: setup key doesn't allow extra DNS labels")
|
||||
}
|
||||
@@ -586,11 +587,17 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, setupKey, userID s
|
||||
}
|
||||
|
||||
var freeLabel string
|
||||
freeLabel, err = getPeerIPDNSLabel(ctx, am.Store, freeIP, accountID, peer.Meta.Hostname)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("failed to get free DNS label: %w", err)
|
||||
if isEphemeral || attempt > 1 {
|
||||
freeLabel, err = getPeerIPDNSLabel(freeIP, peer.Meta.Hostname)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("failed to get free DNS label: %w", err)
|
||||
}
|
||||
} else {
|
||||
freeLabel, err = nbdns.GetParsedDomainLabel(peer.Meta.Hostname)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("failed to get free DNS label: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
newPeer.DNSLabel = freeLabel
|
||||
newPeer.IP = freeIP
|
||||
|
||||
@@ -660,7 +667,7 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, setupKey, userID s
|
||||
if isUniqueConstraintError(err) {
|
||||
unlock()
|
||||
unlock = nil
|
||||
log.WithContext(ctx).Debugf("Failed to add peer in attempt %d, retrying: %v", attempt, err)
|
||||
log.WithContext(ctx).WithFields(log.Fields{"dns_label": freeLabel, "ip": freeIP}).Tracef("Failed to add peer in attempt %d, retrying: %v", attempt, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -694,7 +701,7 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, setupKey, userID s
|
||||
return am.getValidatedPeerWithMap(ctx, false, accountID, newPeer)
|
||||
}
|
||||
|
||||
func getPeerIPDNSLabel(ctx context.Context, tx store.Store, ip net.IP, accountID, peerHostName string) (string, error) {
|
||||
func getPeerIPDNSLabel(ip net.IP, peerHostName string) (string, error) {
|
||||
ip = ip.To4()
|
||||
|
||||
dnsName, err := nbdns.GetParsedDomainLabel(peerHostName)
|
||||
@@ -702,12 +709,6 @@ func getPeerIPDNSLabel(ctx context.Context, tx store.Store, ip net.IP, accountID
|
||||
return "", fmt.Errorf("failed to parse peer host name %s: %w", peerHostName, err)
|
||||
}
|
||||
|
||||
_, err = tx.GetPeerIdByLabel(ctx, store.LockingStrengthNone, accountID, dnsName)
|
||||
if err != nil {
|
||||
//nolint:nilerr
|
||||
return dnsName, nil
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s-%d-%d", dnsName, ip[2], ip[3]), nil
|
||||
}
|
||||
|
||||
@@ -1190,6 +1191,19 @@ func (am *DefaultAccountManager) UpdateAccountPeers(ctx context.Context, account
|
||||
|
||||
globalStart := time.Now()
|
||||
|
||||
hasPeersConnected := false
|
||||
for _, peer := range account.Peers {
|
||||
if am.peersUpdateManager.HasChannel(peer.ID) {
|
||||
hasPeersConnected = true
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if !hasPeersConnected {
|
||||
return
|
||||
}
|
||||
|
||||
approvedPeersMap, err := am.integratedPeerValidator.GetValidatedPeers(account.Id, maps.Values(account.Groups), maps.Values(account.Peers), account.Settings.Extra)
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Errorf("failed to send out updates to peers, failed to get validate peers: %v", err)
|
||||
@@ -1211,6 +1225,12 @@ func (am *DefaultAccountManager) UpdateAccountPeers(ctx context.Context, account
|
||||
return
|
||||
}
|
||||
|
||||
extraSetting, err := am.settingsManager.GetExtraSettings(ctx, accountID)
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Errorf("failed to get flow enabled status: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, peer := range account.Peers {
|
||||
if !am.peersUpdateManager.HasChannel(peer.ID) {
|
||||
log.WithContext(ctx).Tracef("peer %s doesn't have a channel, skipping network map update", peer.ID)
|
||||
@@ -1245,12 +1265,6 @@ func (am *DefaultAccountManager) UpdateAccountPeers(ctx context.Context, account
|
||||
}
|
||||
am.metrics.UpdateChannelMetrics().CountMergeNetworkMapDuration(time.Since(start))
|
||||
|
||||
extraSetting, err := am.settingsManager.GetExtraSettings(ctx, accountID)
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Errorf("failed to get flow enabled status: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
start = time.Now()
|
||||
update := toSyncResponse(ctx, nil, p, nil, nil, remotePeerNetworkMap, dnsDomain, postureChecks, dnsCache, account.Settings, extraSetting)
|
||||
am.metrics.UpdateChannelMetrics().CountToSyncResponseDuration(time.Since(start))
|
||||
@@ -1267,18 +1281,39 @@ func (am *DefaultAccountManager) UpdateAccountPeers(ctx context.Context, account
|
||||
}
|
||||
}
|
||||
|
||||
func (am *DefaultAccountManager) BufferUpdateAccountPeers(ctx context.Context, accountID string) {
|
||||
mu, _ := am.accountUpdateLocks.LoadOrStore(accountID, &sync.Mutex{})
|
||||
lock := mu.(*sync.Mutex)
|
||||
type bufferUpdate struct {
|
||||
mu sync.Mutex
|
||||
next *time.Timer
|
||||
update atomic.Bool
|
||||
}
|
||||
|
||||
if !lock.TryLock() {
|
||||
func (am *DefaultAccountManager) BufferUpdateAccountPeers(ctx context.Context, accountID string) {
|
||||
bufUpd, _ := am.accountUpdateLocks.LoadOrStore(accountID, &bufferUpdate{})
|
||||
b := bufUpd.(*bufferUpdate)
|
||||
|
||||
if !b.mu.TryLock() {
|
||||
b.update.Store(true)
|
||||
return
|
||||
}
|
||||
|
||||
if b.next != nil {
|
||||
b.next.Stop()
|
||||
}
|
||||
|
||||
go func() {
|
||||
time.Sleep(time.Duration(am.updateAccountPeersBufferInterval.Load()))
|
||||
lock.Unlock()
|
||||
defer b.mu.Unlock()
|
||||
am.UpdateAccountPeers(ctx, accountID)
|
||||
if !b.update.Load() {
|
||||
return
|
||||
}
|
||||
b.update.Store(false)
|
||||
if b.next == nil {
|
||||
b.next = time.AfterFunc(time.Duration(am.updateAccountPeersBufferInterval.Load()), func() {
|
||||
am.UpdateAccountPeers(ctx, accountID)
|
||||
})
|
||||
return
|
||||
}
|
||||
b.next.Reset(time.Duration(am.updateAccountPeersBufferInterval.Load()))
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -1517,13 +1552,26 @@ func deletePeers(ctx context.Context, am *DefaultAccountManager, transaction sto
|
||||
}
|
||||
dnsDomain := am.GetDNSDomain(settings)
|
||||
|
||||
network, err := transaction.GetAccountNetwork(ctx, store.LockingStrengthShare, accountID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, peer := range peers {
|
||||
if err := am.integratedPeerValidator.PeerDeleted(ctx, accountID, peer.ID); err != nil {
|
||||
return nil, err
|
||||
groups, err := transaction.GetPeerGroups(ctx, store.LockingStrengthUpdate, accountID, peer.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get peer groups: %w", err)
|
||||
}
|
||||
|
||||
network, err := transaction.GetAccountNetwork(ctx, store.LockingStrengthShare, accountID)
|
||||
if err != nil {
|
||||
for _, group := range groups {
|
||||
group.RemovePeer(peer.ID)
|
||||
err = transaction.SaveGroup(ctx, store.LockingStrengthUpdate, group)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to save group: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := am.integratedPeerValidator.PeerDeleted(ctx, accountID, peer.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -25,6 +26,7 @@ import (
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
|
||||
"github.com/netbirdio/netbird/management/server/mock_server"
|
||||
"github.com/netbirdio/netbird/management/server/permissions"
|
||||
"github.com/netbirdio/netbird/management/server/settings"
|
||||
"github.com/netbirdio/netbird/management/server/status"
|
||||
@@ -1344,6 +1346,11 @@ func Test_RegisterPeerBySetupKey(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
t.Cleanup(ctrl.Finish)
|
||||
settingsMockManager := settings.NewMockManager(ctrl)
|
||||
settingsMockManager.
|
||||
EXPECT().
|
||||
GetExtraSettings(gomock.Any(), gomock.Any()).
|
||||
Return(&types.ExtraSettings{}, nil).
|
||||
AnyTimes()
|
||||
permissionsManager := permissions.NewManager(s)
|
||||
|
||||
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
@@ -1556,6 +1563,11 @@ func Test_LoginPeer(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
t.Cleanup(ctrl.Finish)
|
||||
settingsMockManager := settings.NewMockManager(ctrl)
|
||||
settingsMockManager.
|
||||
EXPECT().
|
||||
GetExtraSettings(gomock.Any(), gomock.Any()).
|
||||
Return(&types.ExtraSettings{}, nil).
|
||||
AnyTimes()
|
||||
permissionsManager := permissions.NewManager(s)
|
||||
|
||||
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false)
|
||||
@@ -2241,3 +2253,131 @@ func Test_AddPeer(t *testing.T) {
|
||||
assert.Equal(t, totalPeers, maps.Values(account.SetupKeys)[0].UsedTimes)
|
||||
assert.Equal(t, uint64(totalPeers), account.Network.Serial)
|
||||
}
|
||||
|
||||
func TestBufferUpdateAccountPeers(t *testing.T) {
|
||||
const (
|
||||
peersCount = 1000
|
||||
updateAccountInterval = 50 * time.Millisecond
|
||||
)
|
||||
|
||||
var (
|
||||
deletedPeers, updatePeersDeleted, updatePeersRuns atomic.Int32
|
||||
uapLastRun, dpLastRun atomic.Int64
|
||||
|
||||
totalNewRuns, totalOldRuns int
|
||||
)
|
||||
|
||||
uap := func(ctx context.Context, accountID string) {
|
||||
updatePeersDeleted.Store(deletedPeers.Load())
|
||||
updatePeersRuns.Add(1)
|
||||
uapLastRun.Store(time.Now().UnixMilli())
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
t.Run("new approach", func(t *testing.T) {
|
||||
updatePeersRuns.Store(0)
|
||||
updatePeersDeleted.Store(0)
|
||||
deletedPeers.Store(0)
|
||||
|
||||
var mustore sync.Map
|
||||
bufupd := func(ctx context.Context, accountID string) {
|
||||
mu, _ := mustore.LoadOrStore(accountID, &bufferUpdate{})
|
||||
b := mu.(*bufferUpdate)
|
||||
|
||||
if !b.mu.TryLock() {
|
||||
b.update.Store(true)
|
||||
return
|
||||
}
|
||||
|
||||
if b.next != nil {
|
||||
b.next.Stop()
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer b.mu.Unlock()
|
||||
uap(ctx, accountID)
|
||||
if !b.update.Load() {
|
||||
return
|
||||
}
|
||||
b.update.Store(false)
|
||||
b.next = time.AfterFunc(updateAccountInterval, func() {
|
||||
uap(ctx, accountID)
|
||||
})
|
||||
}()
|
||||
}
|
||||
dp := func(ctx context.Context, accountID, peerID, userID string) error {
|
||||
deletedPeers.Add(1)
|
||||
dpLastRun.Store(time.Now().UnixMilli())
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
bufupd(ctx, accountID)
|
||||
return nil
|
||||
}
|
||||
|
||||
am := mock_server.MockAccountManager{
|
||||
UpdateAccountPeersFunc: uap,
|
||||
BufferUpdateAccountPeersFunc: bufupd,
|
||||
DeletePeerFunc: dp,
|
||||
}
|
||||
empty := ""
|
||||
for range peersCount {
|
||||
//nolint
|
||||
am.DeletePeer(context.Background(), empty, empty, empty)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
assert.Equal(t, peersCount, int(deletedPeers.Load()), "Expected all peers to be deleted")
|
||||
assert.Equal(t, peersCount, int(updatePeersDeleted.Load()), "Expected all peers to be updated in the buffer")
|
||||
assert.GreaterOrEqual(t, uapLastRun.Load(), dpLastRun.Load(), "Expected update account peers to run after delete peer")
|
||||
|
||||
totalNewRuns = int(updatePeersRuns.Load())
|
||||
})
|
||||
|
||||
t.Run("old approach", func(t *testing.T) {
|
||||
updatePeersRuns.Store(0)
|
||||
updatePeersDeleted.Store(0)
|
||||
deletedPeers.Store(0)
|
||||
|
||||
var mustore sync.Map
|
||||
bufupd := func(ctx context.Context, accountID string) {
|
||||
mu, _ := mustore.LoadOrStore(accountID, &sync.Mutex{})
|
||||
b := mu.(*sync.Mutex)
|
||||
|
||||
if !b.TryLock() {
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
time.Sleep(updateAccountInterval)
|
||||
b.Unlock()
|
||||
uap(ctx, accountID)
|
||||
}()
|
||||
}
|
||||
dp := func(ctx context.Context, accountID, peerID, userID string) error {
|
||||
deletedPeers.Add(1)
|
||||
dpLastRun.Store(time.Now().UnixMilli())
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
bufupd(ctx, accountID)
|
||||
return nil
|
||||
}
|
||||
|
||||
am := mock_server.MockAccountManager{
|
||||
UpdateAccountPeersFunc: uap,
|
||||
BufferUpdateAccountPeersFunc: bufupd,
|
||||
DeletePeerFunc: dp,
|
||||
}
|
||||
empty := ""
|
||||
for range peersCount {
|
||||
//nolint
|
||||
am.DeletePeer(context.Background(), empty, empty, empty)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
assert.Equal(t, peersCount, int(deletedPeers.Load()), "Expected all peers to be deleted")
|
||||
assert.Equal(t, peersCount, int(updatePeersDeleted.Load()), "Expected all peers to be updated in the buffer")
|
||||
assert.GreaterOrEqual(t, uapLastRun.Load(), dpLastRun.Load(), "Expected update account peers to run after delete peer")
|
||||
|
||||
totalOldRuns = int(updatePeersRuns.Load())
|
||||
})
|
||||
assert.Less(t, totalNewRuns, totalOldRuns, "Expected new approach to run less than old approach. New runs: %d, Old runs: %d", totalNewRuns, totalOldRuns)
|
||||
t.Logf("New runs: %d, Old runs: %d", totalNewRuns, totalOldRuns)
|
||||
}
|
||||
|
||||
29
monotime/time.go
Normal file
29
monotime/time.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package monotime
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
baseWallTime time.Time
|
||||
baseWallNano int64
|
||||
)
|
||||
|
||||
func init() {
|
||||
baseWallTime = time.Now()
|
||||
baseWallNano = baseWallTime.UnixNano()
|
||||
}
|
||||
|
||||
// Now returns the current time as Unix nanoseconds (int64).
|
||||
// It uses monotonic time measurement from the base time to ensure
|
||||
// the returned value increases monotonically and is not affected
|
||||
// by system clock adjustments.
|
||||
//
|
||||
// Performance optimization: By capturing the base wall time once at startup
|
||||
// and using time.Since() for elapsed calculation, this avoids repeated
|
||||
// time.Now() calls and leverages Go's internal monotonic clock for
|
||||
// efficient duration measurement.
|
||||
func Now() int64 {
|
||||
elapsed := time.Since(baseWallTime)
|
||||
return baseWallNano + int64(elapsed)
|
||||
}
|
||||
20
monotime/time_test.go
Normal file
20
monotime/time_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package monotime
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func BenchmarkMonotimeNow(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = Now()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTimeNow(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = time.Now()
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ const (
|
||||
Body_ANSWER Body_Type = 1
|
||||
Body_CANDIDATE Body_Type = 2
|
||||
Body_MODE Body_Type = 4
|
||||
Body_GO_IDLE Body_Type = 5
|
||||
)
|
||||
|
||||
// Enum value maps for Body_Type.
|
||||
@@ -38,12 +39,14 @@ var (
|
||||
1: "ANSWER",
|
||||
2: "CANDIDATE",
|
||||
4: "MODE",
|
||||
5: "GO_IDLE",
|
||||
}
|
||||
Body_Type_value = map[string]int32{
|
||||
"OFFER": 0,
|
||||
"ANSWER": 1,
|
||||
"CANDIDATE": 2,
|
||||
"MODE": 4,
|
||||
"GO_IDLE": 5,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -225,7 +228,7 @@ type Body struct {
|
||||
FeaturesSupported []uint32 `protobuf:"varint,6,rep,packed,name=featuresSupported,proto3" json:"featuresSupported,omitempty"`
|
||||
// RosenpassConfig is a Rosenpass config of the remote peer our peer tries to connect to
|
||||
RosenpassConfig *RosenpassConfig `protobuf:"bytes,7,opt,name=rosenpassConfig,proto3" json:"rosenpassConfig,omitempty"`
|
||||
// relayServerAddress is an IP:port of the relay server
|
||||
// relayServerAddress is url of the relay server
|
||||
RelayServerAddress string `protobuf:"bytes,8,opt,name=relayServerAddress,proto3" json:"relayServerAddress,omitempty"`
|
||||
}
|
||||
|
||||
@@ -440,7 +443,7 @@ var file_signalexchange_proto_rawDesc = []byte{
|
||||
0x52, 0x09, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x04, 0x62,
|
||||
0x6f, 0x64, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x69, 0x67, 0x6e,
|
||||
0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52,
|
||||
0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0xa6, 0x03, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2d,
|
||||
0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0xb3, 0x03, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2d,
|
||||
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x73,
|
||||
0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x42, 0x6f,
|
||||
0x64, 0x79, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a,
|
||||
@@ -463,33 +466,34 @@ var file_signalexchange_proto_rawDesc = []byte{
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x53,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41,
|
||||
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x36, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09,
|
||||
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x43, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09,
|
||||
0x0a, 0x05, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x53,
|
||||
0x57, 0x45, 0x52, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x41, 0x4e, 0x44, 0x49, 0x44, 0x41,
|
||||
0x54, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x4f, 0x44, 0x45, 0x10, 0x04, 0x22, 0x2e,
|
||||
0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x06, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x06, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
|
||||
0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x22, 0x6d,
|
||||
0x0a, 0x0f, 0x52, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x50, 0x75,
|
||||
0x62, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x72, 0x6f, 0x73, 0x65,
|
||||
0x6e, 0x70, 0x61, 0x73, 0x73, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x13, 0x72,
|
||||
0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64,
|
||||
0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70,
|
||||
0x61, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x32, 0xb9, 0x01,
|
||||
0x0a, 0x0e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
|
||||
0x12, 0x4c, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61,
|
||||
0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70,
|
||||
0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x20, 0x2e, 0x73, 0x69, 0x67,
|
||||
0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72,
|
||||
0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x59,
|
||||
0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12,
|
||||
0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
|
||||
0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x1a, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e,
|
||||
0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x54, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x4f, 0x44, 0x45, 0x10, 0x04, 0x12, 0x0b,
|
||||
0x0a, 0x07, 0x47, 0x4f, 0x5f, 0x49, 0x44, 0x4c, 0x45, 0x10, 0x05, 0x22, 0x2e, 0x0a, 0x04, 0x4d,
|
||||
0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x06, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x06, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x88, 0x01, 0x01,
|
||||
0x42, 0x09, 0x0a, 0x07, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x22, 0x6d, 0x0a, 0x0f, 0x52,
|
||||
0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28,
|
||||
0x0a, 0x0f, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x50, 0x75, 0x62, 0x4b, 0x65,
|
||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61,
|
||||
0x73, 0x73, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x13, 0x72, 0x6f, 0x73, 0x65,
|
||||
0x6e, 0x70, 0x61, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73,
|
||||
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x32, 0xb9, 0x01, 0x0a, 0x0e, 0x53,
|
||||
0x69, 0x67, 0x6e, 0x61, 0x6c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x4c, 0x0a,
|
||||
0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78,
|
||||
0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64,
|
||||
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c,
|
||||
0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74,
|
||||
0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x0d, 0x43,
|
||||
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x20, 0x2e, 0x73,
|
||||
0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e,
|
||||
0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x20,
|
||||
0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e,
|
||||
0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -47,6 +47,7 @@ message Body {
|
||||
ANSWER = 1;
|
||||
CANDIDATE = 2;
|
||||
MODE = 4;
|
||||
GO_IDLE = 5;
|
||||
}
|
||||
Type type = 1;
|
||||
string payload = 2;
|
||||
@@ -74,4 +75,4 @@ message RosenpassConfig {
|
||||
bytes rosenpassPubKey = 1;
|
||||
// rosenpassServerAddr is an IP:port of the rosenpass service
|
||||
string rosenpassServerAddr = 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/netbirdio/netbird/formatter"
|
||||
)
|
||||
|
||||
const defaultLogSize = 5
|
||||
const defaultLogSize = 15
|
||||
|
||||
// InitLog parses and sets log-level input
|
||||
func InitLog(logLevel string, logPath string) error {
|
||||
|
||||
Reference in New Issue
Block a user