Builder's Guide
  • Welcome to the Builder's Guide to the LND Galaxy!
  • The Lightning Network
    • Overview
    • Payment Channels
      • Lifecycle of a Payment Channel
      • Watchtowers
      • Understanding Sweeping
      • Etymology
    • The Gossip Network
      • Identifying Good Peers on the Lightning Network
    • Pathfinding
      • Finding routes in the Lightning Network
      • Channel Fees
      • Multipath Payments (MPP)
    • Lightning Network Invoices
      • Understanding Lightning Invoices
    • Making Payments
      • The Payment Cycle
      • Timelocks
      • ⭐Hashed Timelock Contract (HTLC)
      • Payment Etymology
      • ⭐What Makes a Good Routing Node
      • Understanding Submarine Swaps
      • Instant Submarine Swaps
    • Liquidity
      • ⭐Understanding Liquidity
      • Managing Liquidity on the Lightning Network
      • Liquidity Management for Lightning Merchants
      • How to Get Inbound Capacity on the Lightning Network
      • Lightning Service Provider
    • L402: Lightning HTTP 402 Protocol
      • Macaroons
      • L402
      • 📋Protocol Specification
      • Implementations and Links
    • Taproot Assets
      • Taproot Assets Protocol
      • Taproot Assets on Lightning
      • Edge Nodes
      • Taproot Assets Trustless Swap
      • FAQ
      • Glossary
  • Lightning Network Tools
    • LND
      • 🛠️Get Started
      • lnd.conf
      • First Steps With LND
      • Wallet Management
      • Sending Payments
      • Atomic Multi-path Payments (AMP)
      • Receiving Payments
      • Unconfirmed Bitcoin Transactions
      • Channel Fees
      • Inbound Channel Fees
      • Macaroons
      • Configuring Watchtowers
      • Pathfinding
      • Blinded Paths
      • Key Import
      • Secure Your Lightning Network Node
      • Configuration of a Routing Node
      • Quick Tor Setup
      • Configuring Tor
      • Enable ‘Neutrino mode’ in Bitcoin Core
      • Send Messages With Keysend
      • Partially Signed Bitcoin Transactions
      • Bulk onchain actions with PSBTs
      • Sweeper
      • Debugging LND
      • Fuzzing LND
      • LND API documentation
      • Channel Acceptor
      • RPC Middleware Interceptor
      • HTLC Interceptor
      • NAT Traversal
      • Recovery: Planning for Failure
      • Migrating LND
      • Disaster recovery
      • Contribute to LND
    • Lightning Terminal
      • What is Lightning Terminal?
      • 🛠️Get litd
      • Run litd
      • Integrating litd
      • Demo: Litd Speed Run
      • Connect to Terminal
      • Recommended Channels
      • Rankings
      • Health Checks
      • Liquidity Report
      • Opening Lightning Network Channels
      • Managing Channel Liquidity
      • Autofees
      • AutoOpen
      • LND Accounts
      • Loop and Lightning Terminal
      • Loop Fees
      • Pool and Lightning Terminal
      • Command Line Interface
      • Troubleshooting
      • Lightning Node Connect: Under the hood
      • LNC Node Package
      • LITD API Documentation
      • Privacy and Security
      • Privacy Policy
      • Terms of Use
    • Loop
      • 🛠️Get Started
      • The Loop CLI
      • Autoloop
      • Static Loop In Addresses
      • Instant Loop Outs
      • Peer with Loop
      • Loop API Documentation
    • Pool
      • Overview
      • Quickstart
      • 🛠️Installation
      • First Steps
      • Accounts
      • Orders and Asks
      • Sidecar Channels
      • Zero-confirmation Channels
      • Channel Leases
      • Batch Execution
      • Account Recovery
      • Pool API Documentation
      • FAQs
    • Taproot Assets
      • Get Started
      • First Steps
      • Taproot Assets Channels
      • Asset Decimal Display
      • Become an Edge Node
      • RFQ
      • Collectibles
      • Universes
      • Asset Loop
      • Debugging Tapd
      • Multisignature
      • Minting Assets With an External Signer
      • Lightning Polar
      • Operational Safety Guidelines
      • Taproot Assets API Documentation
    • Aperture
      • ⚒️Get Aperture
      • LNC Backend
      • LNC Mailbox
      • Pricing
    • Faraday
      • 🛠️Get Started
      • The Faraday CLI
      • Faraday API Documentation
  • LAPPs
    • Guides
      • Use Polar to Build Your First LAPP
        • Setup: Local Cluster with Polar
        • Setup: Run the Completed App
        • Setup: Run the App Without LND
      • Add Features
        • Feature 1: Connect to LND
        • Feature 2: Display Node Alias and Balance
        • Feature 3: Sign and Verify Posts
        • Feature 4: Modify Upvote Action
      • Make Your own LNC-powered Application
    • Next Steps
  • Community Resources
    • Resource List
    • Lightning Bulb 💡
    • Glossary
    • FAQ
Powered by GitBook
On this page
  • Enable the RPC Middleware Interceptor
  • Code examples:
  • Lightning Terminal
  • lndclient:

Was this helpful?

  1. Lightning Network Tools
  2. LND

RPC Middleware Interceptor

The RPC middleware interceptor allows interception and modification of any RPC call made to LND.

PreviousChannel AcceptorNextHTLC Interceptor

Last updated 8 months ago

Was this helpful?

The RPC middleware interceptor is a powerful feature of LND. Once enabled, it intercepts all incoming RPC requests to LND and forwards them, allowing these requests to be inspected, validated and modified before they are sent back to LND for execution.

This interceptor is used by Lightning Terminal to enable the Accounts feature, which allows a node operator to virtually segregate funds in their Lightning Network node between multiple accounts, enforced by Macaroons.

Enable the RPC Middleware Interceptor

To enable the interceptor, add this line to your lnd.conf file and restart your node.

rpcmiddleware.enable=true

Any software attempting to inspect, validate or even modify is required to authenticate itself to LND with a custom macaroon indicating which caveats it wants to be responsible for. Only requests pertaining to these specific caveats will then be forwarded to the middleware.

Multiple connections to the RPC Middleware are possible, though when replacing calls, each interceptor should be limited to their exclusive caveats only, as each call can only be replaced once.

Code examples:

Lightning Terminal

// Intercept processes an RPC middleware interception request and returns the
// interception result which either accepts or rejects the intercepted message.
func (s *InterceptorService) Intercept(ctx context.Context,
	req *lnrpc.RPCMiddlewareRequest) (*lnrpc.RPCMiddlewareResponse, error) {

	// We only allow a single request or response to be handled at the same
	// time. This should already be serialized by the RPC stream itself, but
	// with the lock we prevent a new request to be handled before we finish
	// handling the previous one.
	s.requestMtx.Lock()
	defer s.requestMtx.Unlock()

	mac := &macaroon.Macaroon{}
	err := mac.UnmarshalBinary(req.RawMacaroon)
	if err != nil {
		return mid.RPCErrString(req, "error parsing macaroon: %v", err)
	}

	acctID, err := accountFromMacaroon(mac)
	if err != nil {
		return mid.RPCErrString(
			req, "error parsing account from macaroon: %v", err,
		)
	}

	// No account lock in the macaroon, something's weird. The interceptor
	// wouldn't have been triggered if there was no caveat, so we do expect
	// a macaroon here.
	if acctID == nil {
		return mid.RPCErrString(req, "expected account ID in "+
			"macaroon caveat")
	}

	acct, err := s.Account(*acctID)
	if err != nil {
		return mid.RPCErrString(
			req, "error getting account %x: %v", acctID[:], err,
		)
	}

	log.Debugf("Account auth intercepted, ID=%x, balance_sat=%d, "+
		"expired=%v", acct.ID[:], acct.CurrentBalanceSats(),
		acct.HasExpired())

	if acct.HasExpired() {
		return mid.RPCErrString(
			req, "account %x has expired", acct.ID[:],
		)
	}

	// We now add the account to the incoming context to give each checker
	// access to it if required.
	ctxAccount := AddToContext(ctx, KeyAccount, acct)

	switch r := req.InterceptType.(type) {
	// In the authentication phase we just check that the account hasn't
	// expired yet (which we already did). This is only be used for
	// establishing streams, so we don't see a request yet.
	case *lnrpc.RPCMiddlewareRequest_StreamAuth:
		return mid.RPCOk(req)

	// Parse incoming requests and act on them.
	case *lnrpc.RPCMiddlewareRequest_Request:
		msg, err := parseRPCMessage(r.Request)
		if err != nil {
			return mid.RPCErr(req, err)
		}

		return mid.RPCErr(req, s.checkers.checkIncomingRequest(
			ctxAccount, r.Request.MethodFullUri, msg,
		))

	// Parse and possibly manipulate outgoing responses.
	case *lnrpc.RPCMiddlewareRequest_Response:
		msg, err := parseRPCMessage(r.Response)
		if err != nil {
			return mid.RPCErr(req, err)
		}

		replacement, err := s.checkers.replaceOutgoingResponse(
			ctxAccount, r.Response.MethodFullUri, msg,
		)
		if err != nil {
			return mid.RPCErr(req, err)
		}

		// No error occurred but the response should be replaced with
		// the given custom response. Wrap it in the correct RPC
		// response of the interceptor now.
		if replacement != nil {
			return mid.RPCReplacement(req, replacement)
		}

		// No error and no replacement, just return an empty response of
		// the correct type.
		return mid.RPCOk(req)

	default:
		return mid.RPCErrString(req, "invalid intercept type: %v", r)
	}
}

lndclient:

	// RegisterRPCMiddleware adds a new gRPC middleware to the interceptor
	// chain. A gRPC middleware is software component external to lnd that
	// aims to add additional business logic to lnd by observing/
	// intercepting/validating incoming gRPC client requests and (if needed)
	// replacing/overwriting outgoing messages before they're sent to the
	// client.
	RegisterRPCMiddleware(ctx context.Context, middlewareName,
		customCaveatName string, readOnly bool, timeout time.Duration,
		intercept InterceptFunction) (chan error, error)

	// SendCustomMessage sends a custom message to a peer.
	SendCustomMessage(ctx context.Context, msg CustomMessage) error

	// SubscribeCustomMessages creates a subscription to custom messages
	// received from our peers.
	SubscribeCustomMessages(ctx context.Context) (<-chan CustomMessage,
		<-chan error, error)
}

https://github.com/lightninglabs/lightning-terminal/blob/master/accounts/interceptor.go#L45
https://github.com/lightninglabs/lndclient/blob/master/lightning_client.go
RegisterRPCMiddleware | Lightning Labs API Reference
Read the API documentation: Middleware
Logo