diff --git a/config.go b/config.go index d08e75244..f2dbce740 100644 --- a/config.go +++ b/config.go @@ -380,6 +380,8 @@ type Config struct { Cluster *lncfg.Cluster `group:"cluster" namespace:"cluster"` + RPCMiddleware *lncfg.RPCMiddleware `group:"rpcmiddleware" namespace:"rpcmiddleware"` + // LogWriter is the root logger that all of the daemon's subloggers are // hooked up to. LogWriter *build.RotatingLogWriter @@ -550,6 +552,7 @@ func DefaultConfig() Config { LogWriter: build.NewRotatingLogWriter(), DB: lncfg.DefaultDB(), Cluster: lncfg.DefaultCluster(), + RPCMiddleware: lncfg.DefaultRPCMiddleware(), registeredChains: chainreg.NewChainRegistry(), ActiveNetParams: chainreg.BitcoinTestNetParams, ChannelCommitInterval: defaultChannelCommitInterval, @@ -639,6 +642,7 @@ func LoadConfig(interceptor signal.Interceptor) (*Config, error) { // normalized. The cleaned up config is returned on success. func ValidateConfig(cfg Config, usageMessage string, interceptor signal.Interceptor) (*Config, error) { + // If the provided lnd directory is not the default, we'll modify the // path to all of the files and directories that will live within it. lndDir := CleanAndExpandPath(cfg.LndDir) @@ -1477,6 +1481,7 @@ func ValidateConfig(cfg Config, usageMessage string, cfg.DB, cfg.Cluster, cfg.HealthChecks, + cfg.RPCMiddleware, ) if err != nil { return nil, err diff --git a/lncfg/rpcmiddleware.go b/lncfg/rpcmiddleware.go new file mode 100644 index 000000000..abcc7d518 --- /dev/null +++ b/lncfg/rpcmiddleware.go @@ -0,0 +1,40 @@ +package lncfg + +import ( + "fmt" + "time" +) + +const ( + // defaultRPCMiddlewareTimeout is the time after which a request sent to + // a gRPC interception middleware times out. This value is chosen very + // low since in a worst case scenario that time is added to a request's + // full duration twice (request and response interception) if a + // middleware is very slow. + defaultRPCMiddlewareTimeout = 2 * time.Second +) + +// RPCMiddleware holds the configuration for RPC interception middleware. +type RPCMiddleware struct { + Enable bool `long:"enable" description:"Enable the RPC middleware interceptor functionality."` + InterceptTimeout time.Duration `long:"intercepttimeout" description:"Time after which a RPC middleware intercept request will time out and return an error if it hasn't yet received a response."` + Mandatory []string `long:"addmandatory" description:"Add the named middleware to the list of mandatory middlewares. All RPC requests are blocked/denied if any of the mandatory middlewares is not registered. Can be specified multiple times."` +} + +// Validate checks the values configured for the RPC middleware. +func (r *RPCMiddleware) Validate() error { + if r.InterceptTimeout < 0 { + return fmt.Errorf("RPC middleware intercept timeout cannot " + + "be negative") + } + + return nil +} + +// DefaultRPCMiddleware returns the default values for the RPC interception +// middleware configuration. +func DefaultRPCMiddleware() *RPCMiddleware { + return &RPCMiddleware{ + InterceptTimeout: defaultRPCMiddlewareTimeout, + } +} diff --git a/sample-lnd.conf b/sample-lnd.conf index 59b7231c8..d06dae4fe 100644 --- a/sample-lnd.conf +++ b/sample-lnd.conf @@ -1151,6 +1151,20 @@ litecoin.node=ltcd ; Defaults to the hostname. ; cluster.id=example.com +[rpcmiddleware] + +; Enable the RPC middleware interceptor functionality. +; rpcmiddleware.enable=true + +; Time after which a RPC middleware intercept request will time out and return +; an error if it hasn't yet received a response. +; rpcmiddleware.intercepttimeout=2s + +; Add the named middleware to the list of mandatory middlewares. All RPC +; requests are blocked/denied if any of the mandatory middlewares is not +; registered. Can be specified multiple times. +; rpcmiddleware.addmandatory=my-example-middleware +; rpcmiddleware.addmandatory=other-mandatory-middleware [bolt]