Skip to content

Commit ff365af

Browse files
authored
p2p/nat: remove forceful port mapping in upnp (#30265)
Here we are modifying the port mapping logic so that existing port mappings will only be removed when they were previously created by geth. The AddAnyPortMapping functionality has been adapted to work consistently between the IGDv1 and IGDv2 backends.
1 parent 9f83e9e commit ff365af

File tree

3 files changed

+30
-22
lines changed

3 files changed

+30
-22
lines changed

p2p/nat/natpmp.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ func (n *pmp) AddMapping(protocol string, extport, intport int, name string, lif
4949
if lifetime <= 0 {
5050
return 0, errors.New("lifetime must not be <= 0")
5151
}
52+
if extport == 0 {
53+
extport = intport
54+
}
5255
// Note order of port arguments is switched between our
5356
// AddMapping and the client's AddPortMapping.
5457
res, err := n.c.AddPortMapping(strings.ToLower(protocol), intport, extport, int(lifetime/time.Second))

p2p/nat/natupnp.go

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,15 @@ func (n *upnp) AddMapping(protocol string, extport, intport int, desc string, li
8686
}
8787
protocol = strings.ToUpper(protocol)
8888
lifetimeS := uint32(lifetime / time.Second)
89-
n.DeleteMapping(protocol, extport, intport)
9089

91-
err = n.withRateLimit(func() error {
92-
return n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS)
93-
})
94-
if err == nil {
95-
return uint16(extport), nil
90+
if extport == 0 {
91+
extport = intport
92+
} else {
93+
// Only delete port mapping if the external port was already used by geth.
94+
n.DeleteMapping(protocol, extport, intport)
9695
}
97-
// Try addAnyPortMapping if mapping specified port didn't work.
96+
97+
// Try to add port mapping, preferring the specified external port.
9898
err = n.withRateLimit(func() error {
9999
p, err := n.addAnyPortMapping(protocol, extport, intport, ip, desc, lifetimeS)
100100
if err == nil {
@@ -105,18 +105,28 @@ func (n *upnp) AddMapping(protocol string, extport, intport int, desc string, li
105105
return uint16(extport), err
106106
}
107107

108+
// addAnyPortMapping tries to add a port mapping with the specified external port.
109+
// If the external port is already in use, it will try to assign another port.
108110
func (n *upnp) addAnyPortMapping(protocol string, extport, intport int, ip net.IP, desc string, lifetimeS uint32) (uint16, error) {
109111
if client, ok := n.client.(*internetgateway2.WANIPConnection2); ok {
110112
return client.AddAnyPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS)
111113
}
112-
// It will retry with a random port number if the client does
113-
// not support AddAnyPortMapping.
114-
extport = n.randomPort()
114+
// For IGDv1 and v1 services we should first try to add with extport.
115115
err := n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS)
116-
if err != nil {
117-
return 0, err
116+
if err == nil {
117+
return uint16(extport), nil
118+
}
119+
120+
// If above fails, we retry with a random port.
121+
// We retry several times because of possible port conflicts.
122+
for i := 0; i < 3; i++ {
123+
extport = n.randomPort()
124+
err := n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS)
125+
if err == nil {
126+
return uint16(extport), nil
127+
}
118128
}
119-
return uint16(extport), nil
129+
return 0, err
120130
}
121131

122132
func (n *upnp) randomPort() int {

p2p/server_nat.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,9 @@ func (srv *Server) portMappingLoop() {
150150
continue
151151
}
152152

153-
external := m.port
154-
if m.extPort != 0 {
155-
external = m.extPort
156-
}
157-
log := newLogger(m.protocol, external, m.port)
158-
153+
log := newLogger(m.protocol, m.extPort, m.port)
159154
log.Trace("Attempting port mapping")
160-
p, err := srv.NAT.AddMapping(m.protocol, external, m.port, m.name, portMapDuration)
155+
p, err := srv.NAT.AddMapping(m.protocol, m.extPort, m.port, m.name, portMapDuration)
161156
if err != nil {
162157
log.Debug("Couldn't add port mapping", "err", err)
163158
m.extPort = 0
@@ -167,8 +162,8 @@ func (srv *Server) portMappingLoop() {
167162
// It was mapped!
168163
m.extPort = int(p)
169164
m.nextTime = srv.clock.Now().Add(portMapRefreshInterval)
170-
if external != m.extPort {
171-
log = newLogger(m.protocol, m.extPort, m.port)
165+
log = newLogger(m.protocol, m.extPort, m.port)
166+
if m.port != m.extPort {
172167
log.Info("NAT mapped alternative port")
173168
} else {
174169
log.Info("NAT mapped port")

0 commit comments

Comments
 (0)