55 "context"
66 "fmt"
77 "net/netip"
8+ "sync/atomic"
89 "testing"
10+ "time"
911
1012 "github.com/google/gopacket/layers"
1113 "github.com/rs/zerolog"
@@ -16,7 +18,12 @@ import (
1618)
1719
1820var (
19- noopLogger = zerolog .Nop ()
21+ noopLogger = zerolog .Nop ()
22+ packetConfig = & GlobalRouterConfig {
23+ ICMPRouter : & mockICMPRouter {},
24+ IPv4Src : netip .MustParseAddr ("172.16.0.1" ),
25+ IPv6Src : netip .MustParseAddr ("fd51:2391:523:f4ee::1" ),
26+ }
2027)
2128
2229func TestRouterReturnTTLExceed (t * testing.T ) {
@@ -26,12 +33,9 @@ func TestRouterReturnTTLExceed(t *testing.T) {
2633 returnPipe := & mockFunnelUniPipe {
2734 uniPipe : make (chan RawPacket ),
2835 }
29- packetConfig := & GlobalRouterConfig {
30- ICMPRouter : & mockICMPRouter {},
31- IPv4Src : netip .MustParseAddr ("172.16.0.1" ),
32- IPv6Src : netip .MustParseAddr ("fd51:2391:523:f4ee::1" ),
33- }
34- router := NewRouter (packetConfig , upstream , returnPipe , & noopLogger )
36+ routerEnabled := & routerEnabledChecker {}
37+ routerEnabled .set (true )
38+ router := NewRouter (packetConfig , upstream , returnPipe , & noopLogger , routerEnabled .isEnabled )
3539 ctx , cancel := context .WithCancel (context .Background ())
3640 routerStopped := make (chan struct {})
3741 go func () {
@@ -80,12 +84,71 @@ func TestRouterReturnTTLExceed(t *testing.T) {
8084 <- routerStopped
8185}
8286
87+ func TestRouterCheckEnabled (t * testing.T ) {
88+ upstream := & mockUpstream {
89+ source : make (chan RawPacket ),
90+ }
91+ returnPipe := & mockFunnelUniPipe {
92+ uniPipe : make (chan RawPacket ),
93+ }
94+ routerEnabled := & routerEnabledChecker {}
95+ router := NewRouter (packetConfig , upstream , returnPipe , & noopLogger , routerEnabled .isEnabled )
96+ ctx , cancel := context .WithCancel (context .Background ())
97+ routerStopped := make (chan struct {})
98+ go func () {
99+ router .Serve (ctx )
100+ close (routerStopped )
101+ }()
102+
103+ pk := ICMP {
104+ IP : & IP {
105+ Src : netip .MustParseAddr ("192.168.1.1" ),
106+ Dst : netip .MustParseAddr ("10.0.0.1" ),
107+ Protocol : layers .IPProtocolICMPv4 ,
108+ TTL : 1 ,
109+ },
110+ Message : & icmp.Message {
111+ Type : ipv4 .ICMPTypeEcho ,
112+ Code : 0 ,
113+ Body : & icmp.Echo {
114+ ID : 12481 ,
115+ Seq : 8036 ,
116+ Data : []byte (t .Name ()),
117+ },
118+ },
119+ }
120+
121+ // router is disabled
122+ require .NoError (t , upstream .send (& pk ))
123+ select {
124+ case <- time .After (time .Millisecond * 10 ):
125+ case <- returnPipe .uniPipe :
126+ t .Error ("Unexpected reply when router is disabled" )
127+ }
128+ routerEnabled .set (true )
129+ // router is enabled, expects reply
130+ require .NoError (t , upstream .send (& pk ))
131+ <- returnPipe .uniPipe
132+
133+ routerEnabled .set (false )
134+ // router is disabled
135+ require .NoError (t , upstream .send (& pk ))
136+ select {
137+ case <- time .After (time .Millisecond * 10 ):
138+ case <- returnPipe .uniPipe :
139+ t .Error ("Unexpected reply when router is disabled" )
140+ }
141+
142+ cancel ()
143+ <- routerStopped
144+ }
145+
83146func assertTTLExceed (t * testing.T , originalPacket * ICMP , expectedSrc netip.Addr , upstream * mockUpstream , returnPipe * mockFunnelUniPipe ) {
84147 encoder := NewEncoder ()
85148 rawPacket , err := encoder .Encode (originalPacket )
86149 require .NoError (t , err )
87-
88150 upstream .source <- rawPacket
151+
89152 resp := <- returnPipe .uniPipe
90153 decoder := NewICMPDecoder ()
91154 decoded , err := decoder .Decode (resp )
@@ -111,6 +174,16 @@ type mockUpstream struct {
111174 source chan RawPacket
112175}
113176
177+ func (ms * mockUpstream ) send (pk Packet ) error {
178+ encoder := NewEncoder ()
179+ rawPacket , err := encoder .Encode (pk )
180+ if err != nil {
181+ return err
182+ }
183+ ms .source <- rawPacket
184+ return nil
185+ }
186+
114187func (ms * mockUpstream ) ReceivePacket (ctx context.Context ) (RawPacket , error ) {
115188 select {
116189 case <- ctx .Done ():
@@ -129,3 +202,22 @@ func (mir mockICMPRouter) Serve(ctx context.Context) error {
129202func (mir mockICMPRouter ) Request (pk * ICMP , responder FunnelUniPipe ) error {
130203 return fmt .Errorf ("Request not implemented by mockICMPRouter" )
131204}
205+
206+ type routerEnabledChecker struct {
207+ enabled uint32
208+ }
209+
210+ func (rec * routerEnabledChecker ) isEnabled () bool {
211+ if atomic .LoadUint32 (& rec .enabled ) == 0 {
212+ return false
213+ }
214+ return true
215+ }
216+
217+ func (rec * routerEnabledChecker ) set (enabled bool ) {
218+ if enabled {
219+ atomic .StoreUint32 (& rec .enabled , 1 )
220+ } else {
221+ atomic .StoreUint32 (& rec .enabled , 0 )
222+ }
223+ }
0 commit comments