//go:build !android package routemanager import ( "context" "fmt" "sync" log "github.com/sirupsen/logrus" "github.com/netbirdio/netbird/iface" "github.com/netbirdio/netbird/route" ) type defaultServerRouter struct { mux sync.Mutex ctx context.Context routes map[string]*route.Route firewall firewallManager wgInterface *iface.WGIface } func newServerRouter(ctx context.Context, wgInterface *iface.WGIface) (serverRouter, error) { firewall, err := newFirewall(ctx) if err != nil { return nil, err } return &defaultServerRouter{ ctx: ctx, routes: make(map[string]*route.Route), firewall: firewall, wgInterface: wgInterface, }, nil } func (m *defaultServerRouter) updateRoutes(routesMap map[string]*route.Route) error { serverRoutesToRemove := make([]string, 0) if len(routesMap) > 0 { err := m.firewall.RestoreOrCreateContainers() if err != nil { return fmt.Errorf("couldn't initialize firewall containers, got err: %v", err) } } for routeID := range m.routes { update, found := routesMap[routeID] if !found || !update.IsEqual(m.routes[routeID]) { serverRoutesToRemove = append(serverRoutesToRemove, routeID) } } for _, routeID := range serverRoutesToRemove { oldRoute := m.routes[routeID] err := m.removeFromServerNetwork(oldRoute) if err != nil { log.Errorf("unable to remove route id: %s, network %s, from server, got: %v", oldRoute.ID, oldRoute.Network, err) } delete(m.routes, routeID) } for id, newRoute := range routesMap { _, found := m.routes[id] if found { continue } err := m.addToServerNetwork(newRoute) if err != nil { log.Errorf("unable to add route %s from server, got: %v", newRoute.ID, err) continue } m.routes[id] = newRoute } if len(m.routes) > 0 { err := enableIPForwarding() if err != nil { return err } } return nil } func (m *defaultServerRouter) removeFromServerNetwork(route *route.Route) error { select { case <-m.ctx.Done(): log.Infof("not removing from server network because context is done") return m.ctx.Err() default: m.mux.Lock() defer m.mux.Unlock() err := m.firewall.RemoveRoutingRules(routeToRouterPair(m.wgInterface.Address().String(), route)) if err != nil { return err } delete(m.routes, route.ID) return nil } } func (m *defaultServerRouter) addToServerNetwork(route *route.Route) error { select { case <-m.ctx.Done(): log.Infof("not adding to server network because context is done") return m.ctx.Err() default: m.mux.Lock() defer m.mux.Unlock() err := m.firewall.InsertRoutingRules(routeToRouterPair(m.wgInterface.Address().String(), route)) if err != nil { return err } m.routes[route.ID] = route return nil } } func (m *defaultServerRouter) cleanUp() { m.firewall.CleanRoutingRules() }