From 3a3b5413b99d258030095425291f83874bf8ba90 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 7 May 2020 18:28:52 +0800 Subject: [PATCH 1/2] lncfg: allow no auth on private addresses --- lncfg/address.go | 39 +++++++++++++++++++++++++++--- lncfg/address_test.go | 55 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/lncfg/address.go b/lncfg/address.go index 7fe2d71d..2c1770e4 100644 --- a/lncfg/address.go +++ b/lncfg/address.go @@ -54,10 +54,10 @@ func NormalizeAddresses(addrs []string, defaultPort string, // interface. func EnforceSafeAuthentication(addrs []net.Addr, macaroonsActive bool) error { // We'll now examine all addresses that this RPC server is listening - // on. If it's a localhost address, we'll skip it, otherwise, we'll - // return an error if macaroons are inactive. + // on. If it's a localhost address or a private address, we'll skip it, + // otherwise, we'll return an error if macaroons are inactive. for _, addr := range addrs { - if IsLoopback(addr.String()) || IsUnix(addr) { + if IsLoopback(addr.String()) || IsUnix(addr) || IsPrivate(addr) { continue } @@ -117,6 +117,39 @@ func IsUnix(addr net.Addr) bool { return strings.HasPrefix(addr.Network(), "unix") } +// IsPrivate returns true if the address is private. The definitions are, +// https://en.wikipedia.org/wiki/Link-local_address +// https://en.wikipedia.org/wiki/Multicast_address +// Local IPv4 addresses, https://tools.ietf.org/html/rfc1918 +// Local IPv6 addresses, https://tools.ietf.org/html/rfc4193 +func IsPrivate(addr net.Addr) bool { + switch addr := addr.(type) { + case *net.TCPAddr: + // Check 169.254.0.0/16 and fe80::/10. + if addr.IP.IsLinkLocalUnicast() { + return true + } + + // Check 224.0.0.0/4 and ff00::/8. + if addr.IP.IsLinkLocalMulticast() { + return true + } + + // Check 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. + if ip4 := addr.IP.To4(); ip4 != nil { + return ip4[0] == 10 || + (ip4[0] == 172 && ip4[1]&0xf0 == 16) || + (ip4[0] == 192 && ip4[1] == 168) + } + + // Check fc00::/7. + return len(addr.IP) == net.IPv6len && addr.IP[0]&0xfe == 0xfc + + default: + return false + } +} + // ParseAddressString converts an address in string format to a net.Addr that is // compatible with lnd. UDP is not supported because lnd needs reliable // connections. We accept a custom function to resolve any TCP addresses so diff --git a/lncfg/address_test.go b/lncfg/address_test.go index c35d7199..208b0407 100644 --- a/lncfg/address_test.go +++ b/lncfg/address_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/btcsuite/btcd/btcec" + "github.com/stretchr/testify/require" ) // addressTest defines a test vector for an address that contains the non- @@ -265,3 +266,57 @@ func validateAddr(t *testing.T, addr net.Addr, test addressTest) { ) } } + +func TestIsPrivate(t *testing.T) { + nonPrivateIPList := []net.IP{ + net.IPv4(169, 255, 0, 0), + {0xfe, 0x79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + net.IPv4(225, 0, 0, 0), + {0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + net.IPv4(11, 0, 0, 0), + net.IPv4(172, 15, 0, 0), + net.IPv4(192, 169, 0, 0), + {0xfe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + net.IPv4(8, 8, 8, 8), + {2, 0, 0, 1, 4, 8, 6, 0, 4, 8, 6, 0, 8, 8, 8, 8}, + } + privateIPList := []net.IP{ + net.IPv4(169, 254, 0, 0), + {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + net.IPv4(224, 0, 0, 0), + {0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + net.IPv4(10, 0, 0, 1), + net.IPv4(172, 16, 0, 1), + net.IPv4(172, 31, 255, 255), + net.IPv4(192, 168, 0, 1), + {0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + } + + testParams := []struct { + name string + ipList []net.IP + private bool + }{ + { + "Non-private addresses should return false", + nonPrivateIPList, false, + }, + { + "Private addresses should return true", + privateIPList, true, + }, + } + + for _, tt := range testParams { + test := tt + t.Run(test.name, func(t *testing.T) { + for _, ip := range test.ipList { + addr := &net.TCPAddr{IP: ip} + require.Equal( + t, test.private, IsPrivate(addr), + "expected IP: %s to be %v", ip, test.private, + ) + } + }) + } +} From 86d5facaa2d55594dee64e24d038ad1925461e32 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 21 Jul 2020 18:12:13 +0800 Subject: [PATCH 2/2] docs: update no-macaroons option in macaroon --- config.go | 2 +- docs/macaroons.md | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/config.go b/config.go index 368661ba..77a0ea23 100644 --- a/config.go +++ b/config.go @@ -146,7 +146,7 @@ type Config struct { TLSExtraDomains []string `long:"tlsextradomain" description:"Adds an extra domain to the generated certificate"` TLSAutoRefresh bool `long:"tlsautorefresh" description:"Re-generate TLS certificate and key if the IPs or domains are changed"` - NoMacaroons bool `long:"no-macaroons" description:"Disable macaroon authentication"` + NoMacaroons bool `long:"no-macaroons" description:"Disable macaroon authentication, can only be used if server is not listening on a public interface."` AdminMacPath string `long:"adminmacaroonpath" description:"Path to write the admin macaroon for lnd's RPC and REST services if it doesn't exist"` ReadMacPath string `long:"readonlymacaroonpath" description:"Path to write the read-only macaroon for lnd's RPC and REST services if it doesn't exist"` InvoiceMacPath string `long:"invoicemacaroonpath" description:"Path to the invoice-only macaroon for lnd's RPC and REST services if it doesn't exist"` diff --git a/docs/macaroons.md b/docs/macaroons.md index aae12d1d..b1ed988c 100644 --- a/docs/macaroons.md +++ b/docs/macaroons.md @@ -81,7 +81,14 @@ methods. This means a few important things: You can also run `lnd` with the `--no-macaroons` option, which skips the creation of the macaroon files and all macaroon checks within the RPC server. This means you can still pass a macaroon to the RPC server with a client, but -it won't be checked for validity. +it won't be checked for validity. Note that disabling authentication of a server +that's listening on a public interface is not allowed. This means the +`--no-macaroons` option is only permitted when the RPC server is in a private +network. In CIDR notation, the following IPs are considered private, +- [`169.254.0.0/16` and `fe80::/10`](https://en.wikipedia.org/wiki/Link-local_address). +- [`224.0.0.0/4` and `ff00::/8`](https://en.wikipedia.org/wiki/Multicast_address). +- [`10.0.0.0/8`, `172.16.0.0/12` and `192.168.0.0/16`](https://tools.ietf.org/html/rfc1918). +- [`fc00::/7`](https://tools.ietf.org/html/rfc4193). Since `lnd` requires macaroons by default in order to call RPC methods, `lncli` now reads a macaroon and provides it in the RPC call. Unless the path is