diff --git a/lnd.go b/lnd.go index c6d77a0f..56ab23c5 100644 --- a/lnd.go +++ b/lnd.go @@ -177,29 +177,15 @@ func lndMain() error { ctx, cancel := context.WithCancel(ctx) defer cancel() - // Ensure we create TLS key and certificate if they don't exist - if !fileExists(cfg.TLSCertPath) && !fileExists(cfg.TLSKeyPath) { - if err := genCertPair(cfg.TLSCertPath, cfg.TLSKeyPath); err != nil { - return err - } + tlsCfg, restCreds, restProxyDest, err := getTLSConfig(cfg) + if err != nil { + return err } - cert, err := tls.LoadX509KeyPair(cfg.TLSCertPath, cfg.TLSKeyPath) - if err != nil { - return err - } - tlsConf := &tls.Config{ - Certificates: []tls.Certificate{cert}, - CipherSuites: tlsCipherSuites, - MinVersion: tls.VersionTLS12, - } - sCreds := credentials.NewTLS(tlsConf) - serverOpts := []grpc.ServerOption{grpc.Creds(sCreds)} - cCreds, err := credentials.NewClientTLSFromFile(cfg.TLSCertPath, "") - if err != nil { - return err - } - proxyOpts := []grpc.DialOption{grpc.WithTransportCredentials(cCreds)} + serverCreds := credentials.NewTLS(tlsCfg) + serverOpts := []grpc.ServerOption{grpc.Creds(serverCreds)} + + restDialOpts := []grpc.DialOption{grpc.WithTransportCredentials(*restCreds)} // Before starting the wallet, we'll create and start our Neutrino // light client instance, if enabled, in order to allow it to sync @@ -237,7 +223,7 @@ func lndMain() error { if !cfg.NoSeedBackup { params, err := waitForWalletPassword( cfg.RPCListeners, cfg.RESTListeners, serverOpts, - proxyOpts, tlsConf, + restDialOpts, restProxyDest, tlsCfg, ) if err != nil { return err @@ -364,7 +350,8 @@ func lndMain() error { // exported by the rpcServer. rpcServer, err := newRPCServer( server, macaroonService, cfg.SubRPCServers, serverOpts, - proxyOpts, atplManager, server.invoices, tlsConf, + restDialOpts, restProxyDest, atplManager, server.invoices, + tlsCfg, ) if err != nil { srvrLog.Errorf("unable to start RPC server: %v", err) @@ -439,6 +426,51 @@ func lndMain() error { return nil } +// getTLSConfig returns a TLS configuration for the gRPC server and credentials +// and a proxy destination for the REST reverse proxy. +func getTLSConfig(cfg *config) (*tls.Config, *credentials.TransportCredentials, + string, error) { + + // Ensure we create TLS key and certificate if they don't exist + if !fileExists(cfg.TLSCertPath) && !fileExists(cfg.TLSKeyPath) { + err := genCertPair(cfg.TLSCertPath, cfg.TLSKeyPath) + if err != nil { + return nil, nil, "", err + } + } + + cert, err := tls.LoadX509KeyPair(cfg.TLSCertPath, cfg.TLSKeyPath) + if err != nil { + return nil, nil, "", err + } + + tlsCfg := &tls.Config{ + Certificates: []tls.Certificate{cert}, + CipherSuites: tlsCipherSuites, + MinVersion: tls.VersionTLS12, + } + + restCreds, err := credentials.NewClientTLSFromFile(cfg.TLSCertPath, "") + if err != nil { + return nil, nil, "", err + } + + restProxyDest := cfg.RPCListeners[0].String() + switch { + case strings.Contains(restProxyDest, "0.0.0.0"): + restProxyDest = strings.Replace( + restProxyDest, "0.0.0.0", "127.0.0.1", 1, + ) + + case strings.Contains(restProxyDest, "[::]"): + restProxyDest = strings.Replace( + restProxyDest, "[::]", "[::1]", 1, + ) + } + + return tlsCfg, &restCreds, restProxyDest, nil +} + func main() { // Call the "real" main in a nested manner so the defers will properly // be executed in the case of a graceful shutdown. @@ -689,8 +721,8 @@ type WalletUnlockParams struct { // WalletUnlocker server, and block until a password is provided by // the user to this RPC server. func waitForWalletPassword(grpcEndpoints, restEndpoints []net.Addr, - serverOpts []grpc.ServerOption, proxyOpts []grpc.DialOption, - tlsConf *tls.Config) (*WalletUnlockParams, error) { + serverOpts []grpc.ServerOption, restDialOpts []grpc.DialOption, + restProxyDest string, tlsConf *tls.Config) (*WalletUnlockParams, error) { // Set up a new PasswordService, which will listen for passwords // provided over RPC. @@ -750,7 +782,7 @@ func waitForWalletPassword(grpcEndpoints, restEndpoints []net.Addr, mux := proxy.NewServeMux() err := lnrpc.RegisterWalletUnlockerHandlerFromEndpoint( - ctx, mux, grpcEndpoints[0].String(), proxyOpts, + ctx, mux, restProxyDest, restDialOpts, ) if err != nil { return nil, err diff --git a/rpcserver.go b/rpcserver.go index e79b4d67..70d5406d 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -409,9 +409,12 @@ type rpcServer struct { // server. listenerCleanUp []func() - // restServerOpts are a set of gRPC dial options that the REST server + // restDialOpts are a set of gRPC dial options that the REST server // proxy will use to connect to the main gRPC server. - restServerOpts []grpc.DialOption + restDialOpts []grpc.DialOption + + // restProxyDest is the address to forward REST requests to. + restProxyDest string // tlsCfg is the TLS config that allows the REST server proxy to // connect to the main gRPC server to proxy all incoming requests. @@ -435,8 +438,8 @@ var _ lnrpc.LightningServer = (*rpcServer)(nil) // like requiring TLS, etc. func newRPCServer(s *server, macService *macaroons.Service, subServerCgs *subRPCServerConfigs, serverOpts []grpc.ServerOption, - restServerOpts []grpc.DialOption, atpl *autopilot.Manager, - invoiceRegistry *invoices.InvoiceRegistry, + restDialOpts []grpc.DialOption, restProxyDest string, + atpl *autopilot.Manager, invoiceRegistry *invoices.InvoiceRegistry, tlsCfg *tls.Config) (*rpcServer, error) { // Set up router rpc backend. @@ -531,13 +534,14 @@ func newRPCServer(s *server, macService *macaroons.Service, // gRPC server, and register the main lnrpc server along side. grpcServer := grpc.NewServer(serverOpts...) rootRPCServer := &rpcServer{ - restServerOpts: restServerOpts, - subServers: subServers, - tlsCfg: tlsCfg, - grpcServer: grpcServer, - server: s, - routerBackend: routerBackend, - quit: make(chan struct{}, 1), + restDialOpts: restDialOpts, + restProxyDest: restProxyDest, + subServers: subServers, + tlsCfg: tlsCfg, + grpcServer: grpcServer, + server: s, + routerBackend: routerBackend, + quit: make(chan struct{}, 1), } lnrpc.RegisterLightningServer(grpcServer, rootRPCServer) @@ -604,17 +608,10 @@ func (r *rpcServer) Start() error { // TODO(roasbeef): eventually also allow the sub-servers to themselves // have a REST proxy. mux := proxy.NewServeMux() - grpcEndpoint := cfg.RPCListeners[0].String() - switch { - case strings.Contains(grpcEndpoint, "0.0.0.0"): - grpcEndpoint = strings.Replace( - grpcEndpoint, "0.0.0.0", "127.0.0.1", 1, - ) - case strings.Contains(grpcEndpoint, "[::]"): - grpcEndpoint = strings.Replace(grpcEndpoint, "[::]", "[::1]", 1) - } + err := lnrpc.RegisterLightningHandlerFromEndpoint( - context.Background(), mux, grpcEndpoint, r.restServerOpts, + context.Background(), mux, r.restProxyDest, + r.restDialOpts, ) if err != nil { return err