github.com/ethereum/go-ethereum@v1.16.1/p2p/server_nat_test.go (about) 1 // Copyright 2023 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package p2p 18 19 import ( 20 "net" 21 "net/netip" 22 "sync/atomic" 23 "testing" 24 "time" 25 26 "github.com/ethereum/go-ethereum/common/mclock" 27 "github.com/ethereum/go-ethereum/internal/testlog" 28 "github.com/ethereum/go-ethereum/log" 29 ) 30 31 func TestServerPortMapping(t *testing.T) { 32 clock := new(mclock.Simulated) 33 mockNAT := &mockNAT{mappedPort: 30000} 34 srv := Server{ 35 Config: Config{ 36 PrivateKey: newkey(), 37 NoDial: true, 38 ListenAddr: ":0", 39 DiscAddr: ":0", 40 NAT: mockNAT, 41 Logger: testlog.Logger(t, log.LvlTrace), 42 clock: clock, 43 }, 44 } 45 err := srv.Start() 46 if err != nil { 47 t.Fatal(err) 48 } 49 defer srv.Stop() 50 51 // Wait for the port mapping to be registered. Synchronization with the port mapping 52 // goroutine works like this: For each iteration, we allow other goroutines to run and 53 // also advance the virtual clock by 1 second. Waiting stops when the NAT interface 54 // has received some requests, or when the clock reaches a timeout. 55 deadline := clock.Now().Add(portMapRefreshInterval) 56 for clock.Now() < deadline && mockNAT.mapRequests.Load() < 2 { 57 time.Sleep(10 * time.Millisecond) 58 clock.Run(1 * time.Second) 59 } 60 61 if mockNAT.ipRequests.Load() == 0 { 62 t.Fatal("external IP was never requested") 63 } 64 reqCount := mockNAT.mapRequests.Load() 65 if reqCount != 2 { 66 t.Error("wrong request count:", reqCount) 67 } 68 enr := srv.LocalNode().Node() 69 if enr.IPAddr() != netip.MustParseAddr("192.0.2.0") { 70 t.Error("wrong IP in ENR:", enr.IPAddr()) 71 } 72 if enr.TCP() != 30000 { 73 t.Error("wrong TCP port in ENR:", enr.TCP()) 74 } 75 if enr.UDP() != 30000 { 76 t.Error("wrong UDP port in ENR:", enr.UDP()) 77 } 78 } 79 80 type mockNAT struct { 81 mappedPort uint16 82 mapRequests atomic.Int32 83 unmapRequests atomic.Int32 84 ipRequests atomic.Int32 85 } 86 87 func (m *mockNAT) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) (uint16, error) { 88 m.mapRequests.Add(1) 89 return m.mappedPort, nil 90 } 91 92 func (m *mockNAT) DeleteMapping(protocol string, extport, intport int) error { 93 m.unmapRequests.Add(1) 94 return nil 95 } 96 97 func (m *mockNAT) ExternalIP() (net.IP, error) { 98 m.ipRequests.Add(1) 99 return net.ParseIP("192.0.2.0"), nil 100 } 101 102 func (m *mockNAT) String() string { 103 return "mockNAT" 104 }