Skip to content

Commit

Permalink
Merge 5d23e07 into 2fa2644
Browse files Browse the repository at this point in the history
  • Loading branch information
guggero committed Jun 2, 2018
2 parents 2fa2644 + 5d23e07 commit 580c22d
Show file tree
Hide file tree
Showing 7 changed files with 420 additions and 139 deletions.
12 changes: 11 additions & 1 deletion cmd/lncli/main.go
Expand Up @@ -14,6 +14,7 @@ import (

macaroon "gopkg.in/macaroon.v2"

"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/macaroons"
"github.com/roasbeef/btcutil"
Expand All @@ -26,6 +27,8 @@ import (
const (
defaultTLSCertFilename = "tls.cert"
defaultMacaroonFilename = "admin.macaroon"
defaultRpcPort = "10009"
defaultRpcHostPort = "localhost:" + defaultRpcPort
)

var (
Expand Down Expand Up @@ -143,6 +146,13 @@ func getClientConn(ctx *cli.Context, skipMacaroons bool) *grpc.ClientConn {
opts = append(opts, grpc.WithPerRPCCredentials(cred))
}

// We need to use a custom dialer so we can also connect to unix sockets
// and not just TCP addresses.
opts = append(
opts, grpc.WithDialer(
lncfg.ClientAddressDialer(defaultRpcPort),
),
)
conn, err := grpc.Dial(ctx.GlobalString("rpcserver"), opts...)
if err != nil {
fatal(err)
Expand All @@ -159,7 +169,7 @@ func main() {
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "rpcserver",
Value: "localhost:10009",
Value: defaultRpcHostPort,
Usage: "host:port of ln daemon",
},
cli.StringFlag{
Expand Down
175 changes: 79 additions & 96 deletions config.go
Expand Up @@ -21,6 +21,7 @@ import (
flags "github.com/jessevdk/go-flags"
"github.com/lightningnetwork/lnd/brontide"
"github.com/lightningnetwork/lnd/htlcswitch/hodl"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/torsvc"
"github.com/roasbeef/btcd/btcec"
Expand Down Expand Up @@ -148,25 +149,33 @@ type torConfig struct {
type config struct {
ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"`

LndDir string `long:"lnddir" description:"The base directory that contains lnd's data, logs, configuration file, etc."`
ConfigFile string `long:"C" long:"configfile" description:"Path to configuration file"`
DataDir string `short:"b" long:"datadir" description:"The directory to store lnd's data within"`
TLSCertPath string `long:"tlscertpath" description:"Path to write the TLS certificate for lnd's RPC and REST services"`
TLSKeyPath string `long:"tlskeypath" description:"Path to write the TLS private key for lnd's RPC and REST services"`
TLSExtraIP string `long:"tlsextraip" description:"Adds an extra ip to the generated certificate"`
TLSExtraDomain string `long:"tlsextradomain" description:"Adds an extra domain to the generated certificate"`
NoMacaroons bool `long:"no-macaroons" description:"Disable macaroon authentication"`
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"`
LogDir string `long:"logdir" description:"Directory to log output."`
MaxLogFiles int `long:"maxlogfiles" description:"Maximum logfiles to keep (0 for no rotation)"`
MaxLogFileSize int `long:"maxlogfilesize" description:"Maximum logfile size in MB"`
RPCListeners []string `long:"rpclisten" description:"Add an interface/port to listen for RPC connections"`
RESTListeners []string `long:"restlisten" description:"Add an interface/port to listen for REST connections"`
Listeners []string `long:"listen" description:"Add an interface/port to listen for peer connections"`
DisableListen bool `long:"nolisten" description:"Disable listening for incoming peer connections"`
ExternalIPs []string `long:"externalip" description:"Add an ip:port to the list of local addresses we claim to listen on to peers. If a port is not specified, the default (9735) will be used regardless of other parameters"`
LndDir string `long:"lnddir" description:"The base directory that contains lnd's data, logs, configuration file, etc."`
ConfigFile string `long:"C" long:"configfile" description:"Path to configuration file"`
DataDir string `short:"b" long:"datadir" description:"The directory to store lnd's data within"`
TLSCertPath string `long:"tlscertpath" description:"Path to write the TLS certificate for lnd's RPC and REST services"`
TLSKeyPath string `long:"tlskeypath" description:"Path to write the TLS private key for lnd's RPC and REST services"`
TLSExtraIP string `long:"tlsextraip" description:"Adds an extra ip to the generated certificate"`
TLSExtraDomain string `long:"tlsextradomain" description:"Adds an extra domain to the generated certificate"`
NoMacaroons bool `long:"no-macaroons" description:"Disable macaroon authentication"`
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"`
LogDir string `long:"logdir" description:"Directory to log output."`
MaxLogFiles int `long:"maxlogfiles" description:"Maximum logfiles to keep (0 for no rotation)"`
MaxLogFileSize int `long:"maxlogfilesize" description:"Maximum logfile size in MB"`

// We'll parse these 'raw' string arguments into real net.Addrs in the
// loadConfig function. We need to expose the 'raw' strings so the
// command line library can access them.
// Only the parsed net.Addrs should be used!
RawRPCListeners []string `long:"rpclisten" description:"Add an interface/port/socket to listen for RPC connections"`
RawRESTListeners []string `long:"restlisten" description:"Add an interface/port/socket to listen for REST connections"`
RawListeners []string `long:"listen" description:"Add an interface/port to listen for peer connections"`
RPCListeners []net.Addr
RESTListeners []net.Addr
Listeners []net.Addr
DisableListen bool `long:"nolisten" description:"Disable listening for incoming peer connections"`
ExternalIPs []string `long:"externalip" description:"Add an ip:port to the list of local addresses we claim to listen on to peers. If a port is not specified, the default (9735) will be used regardless of other parameters"`

DebugLevel string `short:"d" long:"debuglevel" description:"Logging level for all subsystems {trace, debug, info, warn, error, critical} -- You may also specify <subsystem>=<level>,<subsystem2>=<level>,... to set the log level for individual subsystems -- Use show to list available subsystems"`

Expand Down Expand Up @@ -673,7 +682,10 @@ func loadConfig() (*config, error) {
normalizeNetwork(activeNetParams.Name))

// Initialize logging at the default logging level.
initLogRotator(filepath.Join(cfg.LogDir, defaultLogFilename), cfg.MaxLogFileSize, cfg.MaxLogFiles)
initLogRotator(
filepath.Join(cfg.LogDir, defaultLogFilename),
cfg.MaxLogFileSize, cfg.MaxLogFiles,
)

// Parse, validate, and set debug log level(s).
if err := parseAndSetDebugLevels(cfg.DebugLevel); err != nil {
Expand All @@ -683,33 +695,39 @@ func loadConfig() (*config, error) {
return nil, err
}

// At least one RPCListener is required.
if len(cfg.RPCListeners) == 0 {
// At least one RPCListener is required. So listen on localhost per
// default.
if len(cfg.RawRPCListeners) == 0 {
addr := fmt.Sprintf("localhost:%d", defaultRPCPort)
cfg.RPCListeners = append(cfg.RPCListeners, addr)
cfg.RawRPCListeners = append(cfg.RawRPCListeners, addr)
}

// Listen on the default interface/port if no REST listeners were
// specified.
if len(cfg.RESTListeners) == 0 {
// Listen on localhost if no REST listeners were specified.
if len(cfg.RawRESTListeners) == 0 {
addr := fmt.Sprintf("localhost:%d", defaultRESTPort)
cfg.RESTListeners = append(cfg.RESTListeners, addr)
cfg.RawRESTListeners = append(cfg.RawRESTListeners, addr)
}

// Listen on the default interface/port if no listeners were specified.
if len(cfg.Listeners) == 0 {
// An empty address string means default interface/address, which on
// most unix systems is the same as 0.0.0.0.
if len(cfg.RawListeners) == 0 {
addr := fmt.Sprintf(":%d", defaultPeerPort)
cfg.Listeners = append(cfg.Listeners, addr)
cfg.RawListeners = append(cfg.RawListeners, addr)
}

// For each of the RPC listeners (REST+gRPC), we'll ensure that users
// have specified a safe combo for authentication. If not, we'll bail
// out with an error.
err := enforceSafeAuthentication(cfg.RPCListeners, !cfg.NoMacaroons)
err := lncfg.EnforceSafeAuthentication(
cfg.RPCListeners, !cfg.NoMacaroons,
)
if err != nil {
return nil, err
}
err = enforceSafeAuthentication(cfg.RESTListeners, !cfg.NoMacaroons)
err = lncfg.EnforceSafeAuthentication(
cfg.RESTListeners, !cfg.NoMacaroons,
)
if err != nil {
return nil, err
}
Expand All @@ -721,18 +739,42 @@ func loadConfig() (*config, error) {

// Add default port to all RPC listener addresses if needed and remove
// duplicate addresses.
cfg.RPCListeners = normalizeAddresses(cfg.RPCListeners,
strconv.Itoa(defaultRPCPort))
cfg.RPCListeners, err = lncfg.NormalizeAddresses(
cfg.RawRPCListeners, strconv.Itoa(defaultRPCPort),
)
if err != nil {
return nil, err
}

// Add default port to all REST listener addresses if needed and remove
// duplicate addresses.
cfg.RESTListeners = normalizeAddresses(cfg.RESTListeners,
strconv.Itoa(defaultRESTPort))
cfg.RESTListeners, err = lncfg.NormalizeAddresses(
cfg.RawRESTListeners, strconv.Itoa(defaultRESTPort),
)
if err != nil {
return nil, err
}

// Add default port to all listener addresses if needed and remove
// duplicate addresses.
cfg.Listeners = normalizeAddresses(cfg.Listeners,
strconv.Itoa(defaultPeerPort))
cfg.Listeners, err = lncfg.NormalizeAddresses(
cfg.RawListeners, strconv.Itoa(defaultPeerPort),
)
if err != nil {
return nil, err
}

// For the p2p port it makes no sense to listen to an Unix socket.
// Also, we would need to refactor the brontide listener to support
// that.
for _, p2pListener := range cfg.Listeners {
if lncfg.IsUnix(p2pListener) {
err := fmt.Errorf("unix socket addresses cannot be " +
"used for the p2p connection listener: %s",
p2pListener)
return nil, err
}
}

// Warn about missing config file only after all other configuration is
// done. This prevents the warning on help messages and invalid
Expand Down Expand Up @@ -1107,65 +1149,6 @@ func extractBitcoindRPCParams(bitcoindConfigPath string) (string, string, string
string(zmqPathSubmatches[1]), nil
}

// normalizeAddresses returns a new slice with all the passed addresses
// normalized with the given default port and all duplicates removed.
func normalizeAddresses(addrs []string, defaultPort string) []string {
result := make([]string, 0, len(addrs))
seen := map[string]struct{}{}
for _, addr := range addrs {
if _, _, err := net.SplitHostPort(addr); err != nil {
// If the address is an integer, then we assume it is *only* a
// port and default to binding to that port on localhost
if _, err := strconv.Atoi(addr); err == nil {
addr = net.JoinHostPort("localhost", addr)
} else {
addr = net.JoinHostPort(addr, defaultPort)
}
}
if _, ok := seen[addr]; !ok {
result = append(result, addr)
seen[addr] = struct{}{}
}
}
return result
}

// enforceSafeAuthentication enforces "safe" authentication taking into account
// the interfaces that the RPC servers are listening on, and if macaroons are
// activated or not. To project users from using dangerous config combinations,
// we'll prevent disabling authentication if the sever is listening on a public
// interface.
func enforceSafeAuthentication(addrs []string, macaroonsActive bool) error {
isLoopback := func(addr string) bool {
loopBackAddrs := []string{"localhost", "127.0.0.1", "[::1]"}
for _, loopback := range loopBackAddrs {
if strings.Contains(addr, loopback) {
return true
}
}

return false
}

// 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.
for _, addr := range addrs {
if isLoopback(addr) {
continue
}

if !macaroonsActive {
return fmt.Errorf("Detected RPC server listening on "+
"publicly reachable interface %v with "+
"authentication disabled! Refusing to start with "+
"--no-macaroons specified.", addr)
}
}

return nil
}

// normalizeNetwork returns the common name of a network type used to create
// file paths. This allows differently versioned networks to use the same path.
func normalizeNetwork(network string) string {
Expand Down

0 comments on commit 580c22d

Please sign in to comment.