github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/p2p/nat/upnp.go (about) 1 /* 2 * Copyright (C) 2021 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU 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 * This program 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 General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package nat 19 20 import ( 21 "fmt" 22 23 "github.com/rs/zerolog/log" 24 25 "github.com/mysteriumnetwork/node/config" 26 "github.com/mysteriumnetwork/node/core/port" 27 "github.com/mysteriumnetwork/node/eventbus" 28 "github.com/mysteriumnetwork/node/nat/mapping" 29 ) 30 31 type upnpPort struct { 32 pool *port.Pool 33 portMapper mapping.PortMapper 34 } 35 36 // NewUPnPPortProvider returns a new instance of the UPnP port provider. 37 func NewUPnPPortProvider() PortProvider { 38 udpPortRange, err := port.ParseRange(config.GetString(config.FlagUDPListenPorts)) 39 if err != nil { 40 log.Warn().Err(err).Msg("Failed to parse UDP listen port range, using default value") 41 42 udpPortRange, err = port.ParseRange("10000:60000") 43 if err != nil { 44 panic(err) // This must never happen. 45 } 46 } 47 48 return &upnpPort{ 49 pool: port.NewFixedRangePool(udpPortRange), 50 portMapper: mapping.NewPortMapper(mapping.DefaultConfig(), eventbus.New()), 51 } 52 } 53 54 func (up *upnpPort) PreparePorts() (ports []int, release func(), start StartPorts, err error) { 55 localPorts, err := up.pool.AcquireMultiple(requiredConnCount) 56 if err != nil { 57 return nil, nil, nil, err 58 } 59 60 // Try to add upnp ports mapping. 61 var portsRelease []func() 62 var portMappingOk bool 63 var portRelease func() 64 65 for _, p := range localPorts { 66 portRelease, portMappingOk = up.portMapper.Map("", "UDP", p.Num(), "Myst node p2p port mapping") 67 if !portMappingOk { 68 break 69 } 70 71 portsRelease = append(portsRelease, portRelease) 72 } 73 74 if !portMappingOk { 75 for _, r := range portsRelease { 76 r() 77 } 78 return nil, nil, nil, fmt.Errorf("failed to map port via UPnP") 79 } 80 81 for _, p := range localPorts { 82 ports = append(ports, p.Num()) 83 } 84 85 if err := checkAllPorts(ports); err != nil { 86 for _, r := range portsRelease { 87 r() 88 } 89 log.Debug().Err(err).Msgf("Failed to check UPnP ports %d globally", ports) 90 return nil, nil, nil, err 91 } 92 93 return ports, func() { 94 for _, r := range portsRelease { 95 r() 96 } 97 }, nil, nil 98 }