mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-07 05:59:06 +02:00
@@ -0,0 +1,105 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/netflow/store"
|
||||
"github.com/netbirdio/netbird/client/internal/netflow/types"
|
||||
)
|
||||
|
||||
type rcvChan chan *types.EventFields
|
||||
type Logger struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
enabled atomic.Bool
|
||||
rcvChan atomic.Pointer[rcvChan]
|
||||
stopChan chan struct{}
|
||||
Store types.Store
|
||||
}
|
||||
|
||||
func New(ctx context.Context) *Logger {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
return &Logger{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
Store: store.NewMemoryStore(),
|
||||
stopChan: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) StoreEvent(flowEvent types.EventFields) {
|
||||
if !l.enabled.Load() {
|
||||
return
|
||||
}
|
||||
|
||||
c := l.rcvChan.Load()
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case *c <- &flowEvent:
|
||||
default:
|
||||
// todo: we should collect or log on this
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Enable() {
|
||||
go l.startReceiver()
|
||||
}
|
||||
|
||||
func (l *Logger) startReceiver() {
|
||||
if l.enabled.Load() {
|
||||
return
|
||||
}
|
||||
|
||||
c := make(rcvChan, 100)
|
||||
l.rcvChan.Swap(&c)
|
||||
l.enabled.Store(true)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-l.ctx.Done():
|
||||
log.Info("flow Memory store receiver stopped")
|
||||
return
|
||||
case eventFields := <-c:
|
||||
id := uuid.NewString()
|
||||
event := types.Event{
|
||||
ID: id,
|
||||
EventFields: *eventFields,
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
l.Store.StoreEvent(&event)
|
||||
case <-l.stopChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Disable() {
|
||||
l.stop()
|
||||
l.Store.Close()
|
||||
}
|
||||
|
||||
func (l *Logger) stop() {
|
||||
if !l.enabled.Load() {
|
||||
return
|
||||
}
|
||||
|
||||
l.enabled.Store(false)
|
||||
l.stopChan <- struct{}{}
|
||||
}
|
||||
|
||||
func (l *Logger) GetEvents() []*types.Event {
|
||||
return l.Store.GetEvents()
|
||||
}
|
||||
|
||||
func (l *Logger) Close() {
|
||||
l.stop()
|
||||
l.cancel()
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package logger_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/netflow/logger"
|
||||
"github.com/netbirdio/netbird/client/internal/netflow/types"
|
||||
)
|
||||
|
||||
func TestStore(t *testing.T) {
|
||||
logger := logger.New(context.Background())
|
||||
logger.Enable()
|
||||
|
||||
event := types.EventFields{
|
||||
FlowID: uuid.New(),
|
||||
Type: types.TypeStart,
|
||||
Direction: types.Ingress,
|
||||
Protocol: 6,
|
||||
}
|
||||
time.Sleep(time.Millisecond)
|
||||
logger.StoreEvent(event)
|
||||
time.Sleep(time.Millisecond)
|
||||
|
||||
allEvents := logger.GetEvents()
|
||||
matched := false
|
||||
for _, e := range allEvents {
|
||||
if e.EventFields.FlowID == event.FlowID {
|
||||
matched = true
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
t.Errorf("didn't match any event")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package netflow
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/netflow/logger"
|
||||
"github.com/netbirdio/netbird/client/internal/netflow/types"
|
||||
)
|
||||
|
||||
type Manager struct {
|
||||
mux sync.Mutex
|
||||
logger types.FlowLogger
|
||||
flowConfig *types.FlowConfig
|
||||
}
|
||||
|
||||
func NewManager(ctx context.Context) *Manager {
|
||||
return &Manager{
|
||||
logger: logger.New(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) Update(update *types.FlowConfig) error {
|
||||
m.mux.Lock()
|
||||
defer m.mux.Unlock()
|
||||
if update == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
m.flowConfig = update
|
||||
|
||||
if update.Enabled {
|
||||
m.logger.Enable()
|
||||
return nil
|
||||
}
|
||||
|
||||
m.logger.Disable()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Close() {
|
||||
m.logger.Close()
|
||||
}
|
||||
|
||||
func (m *Manager) GetLogger() types.FlowLogger {
|
||||
return m.logger
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/netflow/types"
|
||||
)
|
||||
|
||||
func NewMemoryStore() *Memory {
|
||||
return &Memory{
|
||||
events: make(map[string]*types.Event),
|
||||
}
|
||||
}
|
||||
|
||||
type Memory struct {
|
||||
mux sync.Mutex
|
||||
events map[string]*types.Event
|
||||
}
|
||||
|
||||
func (m *Memory) StoreEvent(event *types.Event) {
|
||||
m.mux.Lock()
|
||||
defer m.mux.Unlock()
|
||||
m.events[event.ID] = event
|
||||
}
|
||||
|
||||
func (m *Memory) Close() {
|
||||
m.mux.Lock()
|
||||
defer m.mux.Unlock()
|
||||
m.events = make(map[string]*types.Event)
|
||||
}
|
||||
|
||||
func (m *Memory) GetEvents() []*types.Event {
|
||||
m.mux.Lock()
|
||||
defer m.mux.Unlock()
|
||||
events := make([]*types.Event, 0, len(m.events))
|
||||
for _, event := range m.events {
|
||||
events = append(events, event)
|
||||
}
|
||||
return events
|
||||
}
|
||||
|
||||
func (m *Memory) DeleteEvents(ids []string) {
|
||||
m.mux.Lock()
|
||||
defer m.mux.Unlock()
|
||||
for _, id := range ids {
|
||||
delete(m.events, id)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Type int
|
||||
|
||||
const (
|
||||
TypeStart = iota
|
||||
TypeEnd
|
||||
)
|
||||
|
||||
type Direction int
|
||||
|
||||
const (
|
||||
Ingress = iota
|
||||
Egress
|
||||
)
|
||||
|
||||
type Event struct {
|
||||
ID string
|
||||
Timestamp time.Time
|
||||
EventFields
|
||||
}
|
||||
|
||||
type EventFields struct {
|
||||
FlowID uuid.UUID
|
||||
Type Type
|
||||
Direction Direction
|
||||
Protocol uint8
|
||||
SourceIP netip.Addr
|
||||
DestIP netip.Addr
|
||||
SourcePort uint16
|
||||
DestPort uint16
|
||||
ICMPType uint8
|
||||
ICMPCode uint8
|
||||
}
|
||||
|
||||
type FlowConfig struct {
|
||||
URL string
|
||||
Interval time.Duration
|
||||
Enabled bool
|
||||
TokenPayload string
|
||||
TokenSignature string
|
||||
}
|
||||
|
||||
type FlowManager interface {
|
||||
// FlowConfig handles network map updates
|
||||
Update(update *FlowConfig) error
|
||||
// Close closes the manager
|
||||
Close()
|
||||
// GetLogger returns a flow logger
|
||||
GetLogger() FlowLogger
|
||||
}
|
||||
|
||||
type FlowLogger interface {
|
||||
// StoreEvent stores a flow event
|
||||
StoreEvent(flowEvent EventFields)
|
||||
// GetEvents returns all stored events
|
||||
GetEvents() []*Event
|
||||
// Close closes the logger
|
||||
Close()
|
||||
// Enable enables the flow logger receiver
|
||||
Enable()
|
||||
// Disable disables the flow logger receiver
|
||||
Disable()
|
||||
}
|
||||
|
||||
type Store interface {
|
||||
// StoreEvent stores a flow event
|
||||
StoreEvent(event *Event)
|
||||
// GetEvents returns all stored events
|
||||
GetEvents() []*Event
|
||||
// DeleteEvents deletes events from the store
|
||||
DeleteEvents([]string)
|
||||
// Close closes the store
|
||||
Close()
|
||||
}
|
||||
Reference in New Issue
Block a user