Merge pull request #4473 from yyforyongyu/allow-no-auth-private-addr

lncfg: allow no auth on private addresses
This commit is contained in:
Olaoluwa Osuntokun 2020-09-14 19:03:27 -07:00 committed by GitHub
commit ffe7c3e626
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 5 deletions

@ -170,7 +170,7 @@ type Config struct {
TLSAutoRefresh bool `long:"tlsautorefresh" description:"Re-generate TLS certificate and key if the IPs or domains are changed"` TLSAutoRefresh bool `long:"tlsautorefresh" description:"Re-generate TLS certificate and key if the IPs or domains are changed"`
TLSDisableAutofill bool `long:"tlsdisableautofill" description:"Do not include the interface IPs or the system hostname in TLS certificate, use first --tlsextradomain as Common Name instead, if set"` TLSDisableAutofill bool `long:"tlsdisableautofill" description:"Do not include the interface IPs or the system hostname in TLS certificate, use first --tlsextradomain as Common Name instead, if set"`
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"` 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"` 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"` InvoiceMacPath string `long:"invoicemacaroonpath" description:"Path to the invoice-only macaroon for lnd's RPC and REST services if it doesn't exist"`

@ -81,7 +81,14 @@ methods. This means a few important things:
You can also run `lnd` with the `--no-macaroons` option, which skips the 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. 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 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` 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 now reads a macaroon and provides it in the RPC call. Unless the path is

@ -54,10 +54,10 @@ func NormalizeAddresses(addrs []string, defaultPort string,
// interface. // interface.
func EnforceSafeAuthentication(addrs []net.Addr, macaroonsActive bool) error { func EnforceSafeAuthentication(addrs []net.Addr, macaroonsActive bool) error {
// We'll now examine all addresses that this RPC server is listening // 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 // on. If it's a localhost address or a private address, we'll skip it,
// return an error if macaroons are inactive. // otherwise, we'll return an error if macaroons are inactive.
for _, addr := range addrs { for _, addr := range addrs {
if IsLoopback(addr.String()) || IsUnix(addr) { if IsLoopback(addr.String()) || IsUnix(addr) || IsPrivate(addr) {
continue continue
} }
@ -117,6 +117,39 @@ func IsUnix(addr net.Addr) bool {
return strings.HasPrefix(addr.Network(), "unix") 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 // ParseAddressString converts an address in string format to a net.Addr that is
// compatible with lnd. UDP is not supported because lnd needs reliable // compatible with lnd. UDP is not supported because lnd needs reliable
// connections. We accept a custom function to resolve any TCP addresses so // connections. We accept a custom function to resolve any TCP addresses so

@ -9,6 +9,7 @@ import (
"testing" "testing"
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/stretchr/testify/require"
) )
// addressTest defines a test vector for an address that contains the non- // 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,
)
}
})
}
}