github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/services/wireguard/resources/allocator_unix.go (about) 1 /* 2 * Copyright (C) 2018 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 resources 19 20 import ( 21 "fmt" 22 "net" 23 "runtime" 24 "strconv" 25 "strings" 26 "sync" 27 28 "github.com/pkg/errors" 29 30 "github.com/mysteriumnetwork/node/core/port" 31 ) 32 33 // MaxConnections sets the limit to the maximum number of wireguard connections. 34 var MaxConnections = 256 35 36 type portSupplier interface { 37 Acquire() (port.Port, error) 38 } 39 40 // Allocator is mock wireguard resource handler. 41 // It will manage lists of network interfaces names, IP addresses and port for endpoints. 42 type Allocator struct { 43 mu sync.Mutex 44 Ifaces map[int]struct{} 45 IPAddresses map[int]struct{} 46 47 portSupplier portSupplier 48 subnet net.IPNet 49 } 50 51 // NewAllocator creates new resource pool for wireguard connection. 52 func NewAllocator(ports portSupplier, subnet net.IPNet) *Allocator { 53 return &Allocator{ 54 Ifaces: make(map[int]struct{}), 55 IPAddresses: make(map[int]struct{}), 56 57 portSupplier: ports, 58 subnet: subnet, 59 } 60 } 61 62 // AbandonedInterfaces returns a list of abandoned interfaces that exist in the system, 63 // but was not allocated by the Allocator. 64 func (a *Allocator) AbandonedInterfaces() ([]net.Interface, error) { 65 a.mu.Lock() 66 defer a.mu.Unlock() 67 68 if runtime.GOOS == "android" { 69 list := make([]net.Interface, 0) 70 return list, nil 71 } 72 73 ifaces, err := net.Interfaces() 74 if err != nil { 75 return nil, err 76 } 77 78 list := make([]net.Interface, 0) 79 for _, iface := range ifaces { 80 if strings.HasPrefix(iface.Name, interfacePrefix) { 81 ifaceID, err := strconv.Atoi(strings.TrimPrefix(iface.Name, interfacePrefix)) 82 if err == nil { 83 if _, ok := a.Ifaces[ifaceID]; !ok { 84 list = append(list, iface) 85 } 86 } 87 } 88 } 89 90 return list, nil 91 } 92 93 // AllocateInterface provides available name for the wireguard network interface. 94 func (a *Allocator) AllocateInterface() (string, error) { 95 a.mu.Lock() 96 defer a.mu.Unlock() 97 98 if runtime.GOOS == "android" { 99 return "myst0", nil 100 } 101 102 ifaces, err := net.Interfaces() 103 if err != nil { 104 return "", err 105 } 106 107 for i := 0; i < MaxConnections; i++ { 108 if _, ok := a.Ifaces[i]; !ok { 109 a.Ifaces[i] = struct{}{} 110 if interfaceExists(ifaces, fmt.Sprintf("%s%d", interfacePrefix, i)) { 111 continue 112 } 113 114 return fmt.Sprintf("%s%d", interfacePrefix, i), nil 115 } 116 } 117 118 return "", errors.New("no more unused interfaces") 119 } 120 121 // AllocateIPNet provides available IP address for the wireguard connection. 122 func (a *Allocator) AllocateIPNet() (net.IPNet, error) { 123 a.mu.Lock() 124 defer a.mu.Unlock() 125 126 for i := 0; i < MaxConnections; i++ { 127 if _, ok := a.IPAddresses[i]; !ok { 128 a.IPAddresses[i] = struct{}{} 129 return calcIPNet(a.subnet, i), nil 130 } 131 } 132 return net.IPNet{}, errors.New("no more unused subnets") 133 } 134 135 // AllocatePort provides available UDP port for the wireguard endpoint. 136 func (a *Allocator) AllocatePort() (int, error) { 137 a.mu.Lock() 138 defer a.mu.Unlock() 139 140 port, err := a.portSupplier.Acquire() 141 if err != nil { 142 return 0, err 143 } 144 return port.Num(), nil 145 } 146 147 // ReleaseInterface releases name for the wireguard network interface. 148 func (a *Allocator) ReleaseInterface(iface string) error { 149 a.mu.Lock() 150 defer a.mu.Unlock() 151 152 i, err := strconv.Atoi(strings.TrimPrefix(iface, interfacePrefix)) 153 if err != nil { 154 return err 155 } 156 157 if _, ok := a.Ifaces[i]; !ok { 158 return errors.New("allocated interface not found") 159 } 160 161 delete(a.Ifaces, i) 162 return nil 163 } 164 165 // ReleaseIPNet releases IP address. 166 func (a *Allocator) ReleaseIPNet(ipnet net.IPNet) error { 167 a.mu.Lock() 168 defer a.mu.Unlock() 169 170 ip4 := ipnet.IP.To4() 171 if ip4 == nil { 172 return errors.New("allocated subnet not found") 173 } 174 175 i := int(ip4[2]) 176 if _, ok := a.IPAddresses[i]; !ok { 177 return errors.New("allocated subnet not found") 178 } 179 180 delete(a.IPAddresses, i) 181 return nil 182 } 183 184 func interfaceExists(ifaces []net.Interface, name string) bool { 185 for _, iface := range ifaces { 186 if iface.Name == name { 187 return true 188 } 189 } 190 return false 191 } 192 193 func calcIPNet(ipnet net.IPNet, index int) net.IPNet { 194 ip := make(net.IP, len(ipnet.IP)) 195 copy(ip, ipnet.IP) 196 ip = ip.To4() 197 ip[2] = byte(index) 198 return net.IPNet{IP: ip, Mask: net.IPv4Mask(255, 255, 255, 0)} 199 }