lnd: optionally listen on localhost for better security

The --profile flag now accepts both a port and a host:port string.
If profile is set to a port, then pprof debugging information will
be served over localhost. Otherwise, we will attempt to serve pprof
information on the specified host:port (if we are allowed to listen
on it.)

We default to the safe option as if the port is connectable, anybody
can connect and see debugging information.

See: https://mmcloughlin.com/posts/your-pprof-is-showing
This commit is contained in:
eugene 2021-03-02 17:08:31 -05:00
parent e7400dfb2b
commit 8b463fbc2b
No known key found for this signature in database
GPG Key ID: 118759E83439A9B1
2 changed files with 30 additions and 11 deletions

@ -239,7 +239,7 @@ type Config struct {
CPUProfile string `long:"cpuprofile" description:"Write CPU profile to the specified file"`
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65535"`
Profile string `long:"profile" description:"Enable HTTP profiling on either a port or host:port"`
UnsafeDisconnect bool `long:"unsafe-disconnect" description:"DEPRECATED: Allows the rpcserver to intentionally disconnect from peers with open channels. THIS FLAG WILL BE REMOVED IN 0.10.0"`
UnsafeReplay bool `long:"unsafe-replay" description:"Causes a link to replay the adds on its commitment txn after starting up, this enables testing of the sphinx replay logic."`
@ -1086,15 +1086,34 @@ func ValidateConfig(cfg Config, usageMessage string,
cfg.Autopilot.MaxChannelSize = int64(MaxFundingAmount)
}
// Validate profile port number.
// Validate profile port or host:port.
if cfg.Profile != "" {
profilePort, err := strconv.Atoi(cfg.Profile)
if err != nil || profilePort < 1024 || profilePort > 65535 {
str := "%s: The profile port must be between 1024 and 65535"
err := fmt.Errorf(str, funcName)
_, _ = fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, usageMessage)
return nil, err
str := "%s: The profile port must be between 1024 and 65535"
// Try to parse Profile as a host:port.
_, hostPort, err := net.SplitHostPort(cfg.Profile)
if err == nil {
// Determine if the port is valid.
profilePort, err := strconv.Atoi(hostPort)
if err != nil || profilePort < 1024 || profilePort > 65535 {
err = fmt.Errorf(str, funcName)
_, _ = fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, usageMessage)
return nil, err
}
} else {
// Try to parse Profile as a port.
profilePort, err := strconv.Atoi(cfg.Profile)
if err != nil || profilePort < 1024 || profilePort > 65535 {
err = fmt.Errorf(str, funcName)
_, _ = fmt.Fprintln(os.Stderr, err)
_, _ = fmt.Fprintln(os.Stderr, usageMessage)
return nil, err
}
// Since the user just set a port, we will serve debugging
// information over localhost.
cfg.Profile = net.JoinHostPort("127.0.0.1", cfg.Profile)
}
}

4
lnd.go

@ -227,11 +227,11 @@ func Main(cfg *Config, lisCfg ListenerCfg, interceptor signal.Interceptor) error
// Enable http profiling server if requested.
if cfg.Profile != "" {
go func() {
listenAddr := net.JoinHostPort("", cfg.Profile)
profileRedirect := http.RedirectHandler("/debug/pprof",
http.StatusSeeOther)
http.Handle("/", profileRedirect)
fmt.Println(http.ListenAndServe(listenAddr, nil))
ltndLog.Infof("Pprof listening on %v", cfg.Profile)
fmt.Println(http.ListenAndServe(cfg.Profile, nil))
}()
}