@@ -7,19 +7,39 @@ import (
77 "fmt"
88 "net"
99 "net/netip"
10+ "os"
1011 "strconv"
1112 "syscall"
1213 "time"
1314 "unsafe"
1415
1516 "github.com/cenkalti/backoff/v4"
17+ "github.com/hashicorp/go-multierror"
1618 log "github.com/sirupsen/logrus"
1719 "golang.org/x/net/route"
1820 "golang.org/x/sys/unix"
1921
22+ nberrors "github.com/netbirdio/netbird/client/errors"
2023 "github.com/netbirdio/netbird/client/internal/statemanager"
2124)
2225
26+ const (
27+ envRouteProtoFlag = "NB_ROUTE_PROTO_FLAG"
28+ )
29+
30+ var routeProtoFlag int
31+
32+ func init () {
33+ switch os .Getenv (envRouteProtoFlag ) {
34+ case "2" :
35+ routeProtoFlag = unix .RTF_PROTO2
36+ case "3" :
37+ routeProtoFlag = unix .RTF_PROTO3
38+ default :
39+ routeProtoFlag = unix .RTF_PROTO1
40+ }
41+ }
42+
2343func (r * SysOps ) SetupRouting (initAddresses []net.IP , stateManager * statemanager.Manager , advancedRouting bool ) error {
2444 return r .setupRefCounter (initAddresses , stateManager )
2545}
@@ -28,6 +48,62 @@ func (r *SysOps) CleanupRouting(stateManager *statemanager.Manager, advancedRout
2848 return r .cleanupRefCounter (stateManager )
2949}
3050
51+ // FlushMarkedRoutes removes single IP exclusion routes marked with the configured RTF_PROTO flag.
52+ func (r * SysOps ) FlushMarkedRoutes () error {
53+ rib , err := retryFetchRIB ()
54+ if err != nil {
55+ return fmt .Errorf ("fetch routing table: %w" , err )
56+ }
57+
58+ msgs , err := route .ParseRIB (route .RIBTypeRoute , rib )
59+ if err != nil {
60+ return fmt .Errorf ("parse routing table: %w" , err )
61+ }
62+
63+ var merr * multierror.Error
64+ flushedCount := 0
65+
66+ for _ , msg := range msgs {
67+ rtMsg , ok := msg .(* route.RouteMessage )
68+ if ! ok {
69+ continue
70+ }
71+
72+ if rtMsg .Flags & routeProtoFlag == 0 {
73+ continue
74+ }
75+
76+ routeInfo , err := MsgToRoute (rtMsg )
77+ if err != nil {
78+ log .Debugf ("Skipping route flush: %v" , err )
79+ continue
80+ }
81+
82+ if ! routeInfo .Dst .IsValid () || ! routeInfo .Dst .IsSingleIP () {
83+ continue
84+ }
85+
86+ nexthop := Nexthop {
87+ IP : routeInfo .Gw ,
88+ Intf : routeInfo .Interface ,
89+ }
90+
91+ if err := r .removeFromRouteTable (routeInfo .Dst , nexthop ); err != nil {
92+ merr = multierror .Append (merr , fmt .Errorf ("remove route %s: %w" , routeInfo .Dst , err ))
93+ continue
94+ }
95+
96+ flushedCount ++
97+ log .Debugf ("Flushed marked route: %s" , routeInfo .Dst )
98+ }
99+
100+ if flushedCount > 0 {
101+ log .Infof ("Flushed %d residual NetBird routes from previous session" , flushedCount )
102+ }
103+
104+ return nberrors .FormatErrorOrNil (merr )
105+ }
106+
31107func (r * SysOps ) addToRouteTable (prefix netip.Prefix , nexthop Nexthop ) error {
32108 return r .routeSocket (unix .RTM_ADD , prefix , nexthop )
33109}
@@ -105,7 +181,7 @@ func (r *SysOps) routeOp(action int, prefix netip.Prefix, nexthop Nexthop) func(
105181func (r * SysOps ) buildRouteMessage (action int , prefix netip.Prefix , nexthop Nexthop ) (msg * route.RouteMessage , err error ) {
106182 msg = & route.RouteMessage {
107183 Type : action ,
108- Flags : unix .RTF_UP ,
184+ Flags : unix .RTF_UP | routeProtoFlag ,
109185 Version : unix .RTM_VERSION ,
110186 Seq : r .getSeq (),
111187 }
0 commit comments