github.com/decred/dcrlnd@v0.7.6/lncfg/address.go (about) 1 package lncfg 2 3 import ( 4 "context" 5 "crypto/tls" 6 "encoding/hex" 7 "fmt" 8 "net" 9 "strconv" 10 "strings" 11 12 "github.com/decred/dcrd/dcrec/secp256k1/v4" 13 "github.com/decred/dcrlnd/lnwire" 14 "github.com/decred/dcrlnd/tor" 15 ) 16 17 var ( 18 loopBackAddrs = []string{"localhost", "127.0.0.1", "[::1]"} 19 ) 20 21 // TCPResolver is a function signature that resolves an address on a given 22 // network. 23 type TCPResolver = func(network, addr string) (*net.TCPAddr, error) 24 25 // NormalizeAddresses returns a new slice with all the passed addresses 26 // normalized with the given default port and all duplicates removed. 27 func NormalizeAddresses(addrs []string, defaultPort string, 28 tcpResolver TCPResolver) ([]net.Addr, error) { 29 30 result := make([]net.Addr, 0, len(addrs)) 31 seen := map[string]struct{}{} 32 33 for _, addr := range addrs { 34 parsedAddr, err := ParseAddressString( 35 addr, defaultPort, tcpResolver, 36 ) 37 if err != nil { 38 return nil, fmt.Errorf("parse address %s failed: %w", 39 addr, err) 40 } 41 42 if _, ok := seen[parsedAddr.String()]; !ok { 43 result = append(result, parsedAddr) 44 seen[parsedAddr.String()] = struct{}{} 45 } 46 } 47 48 return result, nil 49 } 50 51 // EnforceSafeAuthentication enforces "safe" authentication taking into account 52 // the interfaces that the RPC servers are listening on, and if macaroons and 53 // TLS is activated or not. To protect users from using dangerous config 54 // combinations, we'll prevent disabling authentication if the server is 55 // listening on a public interface. 56 func EnforceSafeAuthentication(addrs []net.Addr, macaroonsActive, 57 tlsActive bool) error { 58 59 // We'll now examine all addresses that this RPC server is listening 60 // on. If it's a localhost address we'll skip it, otherwise, we'll 61 // return an error if macaroons are inactive. 62 for _, addr := range addrs { 63 if IsLoopback(addr.String()) || IsUnix(addr) { 64 continue 65 } 66 67 if !macaroonsActive { 68 return fmt.Errorf("detected RPC server listening on "+ 69 "publicly reachable interface %v with "+ 70 "authentication disabled! Refusing to start "+ 71 "with --no-macaroons specified", addr) 72 } 73 74 if !tlsActive { 75 return fmt.Errorf("detected RPC server listening on "+ 76 "publicly reachable interface %v with "+ 77 "encryption disabled! Refusing to start "+ 78 "with --no-rest-tls specified", addr) 79 } 80 } 81 82 return nil 83 } 84 85 // parseNetwork parses the network type of the given address. 86 func parseNetwork(addr net.Addr) string { 87 switch addr := addr.(type) { 88 // TCP addresses resolved through net.ResolveTCPAddr give a default 89 // network of "tcp", so we'll map back the correct network for the given 90 // address. This ensures that we can listen on the correct interface 91 // (IPv4 vs IPv6). 92 case *net.TCPAddr: 93 if addr.IP.To4() != nil { 94 return "tcp4" 95 } 96 return "tcp6" 97 98 default: 99 return addr.Network() 100 } 101 } 102 103 // ListenOnAddress creates a listener that listens on the given address. 104 func ListenOnAddress(addr net.Addr) (net.Listener, error) { 105 return net.Listen(parseNetwork(addr), addr.String()) 106 } 107 108 // TLSListenOnAddress creates a TLS listener that listens on the given address. 109 func TLSListenOnAddress(addr net.Addr, 110 config *tls.Config) (net.Listener, error) { 111 return tls.Listen(parseNetwork(addr), addr.String(), config) 112 } 113 114 // IsLoopback returns true if an address describes a loopback interface. 115 func IsLoopback(addr string) bool { 116 for _, loopback := range loopBackAddrs { 117 if strings.Contains(addr, loopback) { 118 return true 119 } 120 } 121 122 return false 123 } 124 125 // isIPv6Host returns true if the host is IPV6 and false otherwise. 126 func isIPv6Host(host string) bool { 127 v6Addr := net.ParseIP(host) 128 if v6Addr == nil { 129 return false 130 } 131 132 // The documentation states that if the IP address is an IPv6 address, 133 // then To4() will return nil. 134 return v6Addr.To4() == nil 135 } 136 137 // IsUnix returns true if an address describes an Unix socket address. 138 func IsUnix(addr net.Addr) bool { 139 return strings.HasPrefix(addr.Network(), "unix") 140 } 141 142 // IsPrivate returns true if the address is private. The definitions are, 143 // 144 // https://en.wikipedia.org/wiki/Link-local_address 145 // https://en.wikipedia.org/wiki/Multicast_address 146 // Local IPv4 addresses, https://tools.ietf.org/html/rfc1918 147 // Local IPv6 addresses, https://tools.ietf.org/html/rfc4193 148 func IsPrivate(addr net.Addr) bool { 149 switch addr := addr.(type) { 150 case *net.TCPAddr: 151 // Check 169.254.0.0/16 and fe80::/10. 152 if addr.IP.IsLinkLocalUnicast() { 153 return true 154 } 155 156 // Check 224.0.0.0/4 and ff00::/8. 157 if addr.IP.IsLinkLocalMulticast() { 158 return true 159 } 160 161 // Check 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. 162 if ip4 := addr.IP.To4(); ip4 != nil { 163 return ip4[0] == 10 || 164 (ip4[0] == 172 && ip4[1]&0xf0 == 16) || 165 (ip4[0] == 192 && ip4[1] == 168) 166 } 167 168 // Check fc00::/7. 169 return len(addr.IP) == net.IPv6len && addr.IP[0]&0xfe == 0xfc 170 171 default: 172 return false 173 } 174 } 175 176 // ParseAddressString converts an address in string format to a net.Addr that is 177 // compatible with lnd. UDP is not supported because lnd needs reliable 178 // connections. We accept a custom function to resolve any TCP addresses so 179 // that caller is able control exactly how resolution is performed. 180 func ParseAddressString(strAddress string, defaultPort string, 181 tcpResolver TCPResolver) (net.Addr, error) { 182 183 var parsedNetwork, parsedAddr string 184 185 // Addresses can either be in network://address:port format, 186 // network:address:port, address:port, or just port. We want to support 187 // all possible types. 188 if strings.Contains(strAddress, "://") { 189 parts := strings.Split(strAddress, "://") 190 parsedNetwork, parsedAddr = parts[0], parts[1] 191 } else if strings.Contains(strAddress, ":") { 192 parts := strings.Split(strAddress, ":") 193 parsedNetwork = parts[0] 194 parsedAddr = strings.Join(parts[1:], ":") 195 } 196 197 // Only TCP and Unix socket addresses are valid. We can't use IP or 198 // UDP only connections for anything we do in lnd. 199 switch parsedNetwork { 200 case "unix", "unixpacket": 201 return net.ResolveUnixAddr(parsedNetwork, parsedAddr) 202 203 case "tcp", "tcp4", "tcp6": 204 return tcpResolver( 205 parsedNetwork, verifyPort(parsedAddr, defaultPort), 206 ) 207 208 case "ip", "ip4", "ip6", "udp", "udp4", "udp6", "unixgram": 209 return nil, fmt.Errorf("only TCP or unix socket "+ 210 "addresses are supported: %s", parsedAddr) 211 212 default: 213 // We'll now possibly apply the default port, use the local 214 // host short circuit, or parse out an all interfaces listen. 215 addrWithPort := verifyPort(strAddress, defaultPort) 216 rawHost, rawPort, _ := net.SplitHostPort(addrWithPort) 217 218 // If we reach this point, then we'll check to see if we have 219 // an onion addresses, if so, we can directly pass the raw 220 // address and port to create the proper address. 221 if tor.IsOnionHost(rawHost) { 222 portNum, err := strconv.Atoi(rawPort) 223 if err != nil { 224 return nil, err 225 } 226 227 return &tor.OnionAddr{ 228 OnionService: rawHost, 229 Port: portNum, 230 }, nil 231 } 232 233 // Otherwise, we'll attempt the resolve the host. The Tor 234 // resolver is unable to resolve local or IPv6 addresses, so 235 // we'll use the system resolver instead. 236 if rawHost == "" || IsLoopback(rawHost) || 237 isIPv6Host(rawHost) { 238 239 return net.ResolveTCPAddr("tcp", addrWithPort) 240 } 241 242 // If we've reached this point, then it's possible that this 243 // resolve returns an error if it isn't able to resolve the 244 // host. For eaxmple, local entries in /etc/hosts will fail to 245 // be resolved by Tor. In order to handle this case, we'll fall 246 // back to the normal system resolver if we fail with an 247 // identifiable error. 248 addr, err := tcpResolver("tcp", addrWithPort) 249 if err != nil { 250 torErrStr := "tor host is unreachable" 251 if strings.Contains(err.Error(), torErrStr) { 252 return net.ResolveTCPAddr("tcp", addrWithPort) 253 } 254 255 return nil, err 256 } 257 258 return addr, nil 259 } 260 } 261 262 // ParseLNAddressString converts a string of the form <pubkey>@<addr> into an 263 // lnwire.NetAddress. The <pubkey> must be presented in hex, and result in a 264 // 33-byte, compressed public key that lies on the secp256k1 curve. The <addr> 265 // may be any address supported by ParseAddressString. If no port is specified, 266 // the defaultPort will be used. Any tcp addresses that need resolving will be 267 // resolved using the custom TCPResolver. 268 func ParseLNAddressString(strAddress string, defaultPort string, 269 tcpResolver TCPResolver) (*lnwire.NetAddress, error) { 270 271 // Split the address string around the @ sign. 272 parts := strings.Split(strAddress, "@") 273 274 // The string is malformed if there are not exactly two parts. 275 if len(parts) != 2 { 276 return nil, fmt.Errorf("invalid lightning address %s: "+ 277 "must be of the form <pubkey-hex>@<addr>", strAddress) 278 } 279 280 // Now, take the first portion as the hex pubkey, and the latter as the 281 // address string. 282 parsedPubKey, parsedAddr := parts[0], parts[1] 283 284 // Decode the hex pubkey to get the raw compressed pubkey bytes. 285 pubKeyBytes, err := hex.DecodeString(parsedPubKey) 286 if err != nil { 287 return nil, fmt.Errorf("invalid lightning address pubkey: %v", err) 288 } 289 290 // The compressed pubkey should have a length of exactly 33 bytes. 291 if len(pubKeyBytes) != 33 { 292 return nil, fmt.Errorf("invalid lightning address pubkey: "+ 293 "length must be 33 bytes, found %d", len(pubKeyBytes)) 294 } 295 296 // Parse the pubkey bytes to verify that it corresponds to valid public 297 // key on the secp256k1 curve. 298 pubKey, err := secp256k1.ParsePubKey(pubKeyBytes) 299 if err != nil { 300 return nil, fmt.Errorf("invalid lightning address pubkey: %v", err) 301 } 302 303 // Finally, parse the address string using our generic address parser. 304 addr, err := ParseAddressString(parsedAddr, defaultPort, tcpResolver) 305 if err != nil { 306 return nil, fmt.Errorf("invalid lightning address address: %v", err) 307 } 308 309 return &lnwire.NetAddress{ 310 IdentityKey: pubKey, 311 Address: addr, 312 }, nil 313 } 314 315 // verifyPort makes sure that an address string has both a host and a port. If 316 // there is no port found, the default port is appended. If the address is just 317 // a port, then we'll assume that the user is using the short cut to specify a 318 // localhost:port address. 319 func verifyPort(address string, defaultPort string) string { 320 host, port, err := net.SplitHostPort(address) 321 if err != nil { 322 // If the address itself is just an integer, then we'll assume 323 // that we're mapping this directly to a localhost:port pair. 324 // This ensures we maintain the legacy behavior. 325 if _, err := strconv.Atoi(address); err == nil { 326 return net.JoinHostPort("localhost", address) 327 } 328 329 // Otherwise, we'll assume that the address just failed to 330 // attach its own port, so we'll use the default port. In the 331 // case of IPv6 addresses, if the host is already surrounded by 332 // brackets, then we'll avoid using the JoinHostPort function, 333 // since it will always add a pair of brackets. 334 if strings.HasPrefix(address, "[") { 335 return address + ":" + defaultPort 336 } 337 return net.JoinHostPort(address, defaultPort) 338 } 339 340 // In the case that both the host and port are empty, we'll use the 341 // default port. 342 if host == "" && port == "" { 343 return ":" + defaultPort 344 } 345 346 return address 347 } 348 349 // ClientAddressDialer creates a gRPC dialer that can also dial unix socket 350 // addresses instead of just TCP addresses. 351 func ClientAddressDialer(defaultPort string) func(context.Context, 352 string) (net.Conn, error) { 353 354 return func(ctx context.Context, addr string) (net.Conn, error) { 355 parsedAddr, err := ParseAddressString( 356 addr, defaultPort, net.ResolveTCPAddr, 357 ) 358 if err != nil { 359 return nil, err 360 } 361 362 d := net.Dialer{} 363 return d.DialContext( 364 ctx, parsedAddr.Network(), parsedAddr.String(), 365 ) 366 } 367 }