Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions chanbackup/single_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ var (
addr1, _ = net.ResolveTCPAddr("tcp", "10.0.0.2:9000")
addr2, _ = net.ResolveTCPAddr("tcp", "10.0.0.3:9000")
addr3 = &tor.OnionAddr{
OnionService: "3g2upl4pq6kufc4m.onion",
Port: 9735,
OnionService: "vww6ybal4bd7szmgncyruucpgfkqahzd" +
"di37ktceo3ah7ngmcopnpyyd.onion",
Port: 9735,
}
addr4 = &lnwire.DNSAddress{
Hostname: "example.com",
Expand Down
14 changes: 11 additions & 3 deletions channeldb/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,16 +189,24 @@ func WriteElement(w io.Writer, element interface{}) error {
}

case net.Addr:
if err := graphdb.SerializeAddr(w, e); err != nil {
// Route through the filter so a stale v2 onion address is
// dropped (with a warning) rather than failing the whole
// write with "unknown onion service length".
filtered := graphdb.FilterSerializableAddrs([]net.Addr{e})
if len(filtered) == 0 {
return nil
}
if err := graphdb.SerializeAddr(w, filtered[0]); err != nil {
return err
}

case []net.Addr:
if err := WriteElement(w, uint32(len(e))); err != nil {
addrs := graphdb.FilterSerializableAddrs(e)
if err := WriteElement(w, uint32(len(addrs))); err != nil {
return err
}

for _, addr := range e {
for _, addr := range addrs {
if err := graphdb.SerializeAddr(w, addr); err != nil {
return err
}
Expand Down
5 changes: 3 additions & 2 deletions channeldb/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,13 +358,14 @@ func serializeLinkNode(w io.Writer, l *LinkNode) error {
return err
}

numAddrs := uint32(len(l.Addresses))
addresses := graphdb.FilterSerializableAddrs(l.Addresses)
numAddrs := uint32(len(addresses))
byteOrder.PutUint32(buf[:4], numAddrs)
if _, err := w.Write(buf[:4]); err != nil {
return err
}

for _, addr := range l.Addresses {
for _, addr := range addresses {
if err := graphdb.SerializeAddr(w, addr); err != nil {
return err
}
Expand Down
40 changes: 10 additions & 30 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ const (
defaultTorDNSHost = "soa.nodes.lightning.directory"
defaultTorDNSPort = 53
defaultTorControlPort = 9051
defaultTorV2PrivateKeyFilename = "v2_onion_private_key"
defaultTorV3PrivateKeyFilename = "v3_onion_private_key"

// defaultZMQReadDeadline is the default read deadline to be used for
Expand Down Expand Up @@ -1239,41 +1238,22 @@ func ValidateConfig(cfg Config, interceptor signal.Interceptor, fileParser,
return nil, mkErr(str)
}

switch {
case cfg.Tor.V2 && cfg.Tor.V3:
return nil, mkErr("either tor.v2 or tor.v3 can be set, " +
"but not both")
case cfg.DisableListen && (cfg.Tor.V2 || cfg.Tor.V3):
if cfg.DisableListen && cfg.Tor.V3 {
return nil, mkErr("listening must be enabled when enabling " +
"inbound connections over Tor")
}

if cfg.Tor.PrivateKeyPath == "" {
switch {
case cfg.Tor.V2:
cfg.Tor.PrivateKeyPath = filepath.Join(
lndDir, defaultTorV2PrivateKeyFilename,
)
case cfg.Tor.V3:
cfg.Tor.PrivateKeyPath = filepath.Join(
lndDir, defaultTorV3PrivateKeyFilename,
)
}
if cfg.Tor.PrivateKeyPath == "" && cfg.Tor.V3 {
cfg.Tor.PrivateKeyPath = filepath.Join(
lndDir, defaultTorV3PrivateKeyFilename,
)
}

if cfg.Tor.WatchtowerKeyPath == "" {
switch {
case cfg.Tor.V2:
cfg.Tor.WatchtowerKeyPath = filepath.Join(
cfg.Watchtower.TowerDir,
defaultTorV2PrivateKeyFilename,
)
case cfg.Tor.V3:
cfg.Tor.WatchtowerKeyPath = filepath.Join(
cfg.Watchtower.TowerDir,
defaultTorV3PrivateKeyFilename,
)
}
if cfg.Tor.WatchtowerKeyPath == "" && cfg.Tor.V3 {
cfg.Tor.WatchtowerKeyPath = filepath.Join(
cfg.Watchtower.TowerDir,
defaultTorV3PrivateKeyFilename,
)
}

// Set up the network-related functions that will be used throughout
Expand Down
2 changes: 0 additions & 2 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,12 @@ func TestConfigToFlatMap(t *testing.T) {

// Set deprecated fields.
cfg.Bitcoin.Active = true
cfg.Tor.V2 = true

result, deprecated, err := configToFlatMap(cfg)
require.NoError(t, err)

// Check that the deprecated option has been parsed out.
require.Contains(t, deprecated, "bitcoin.active")
require.Contains(t, deprecated, "tor.v2")

// Pick a couple of random values to check.
require.Equal(t, DefaultLndDir, result["lnddir"])
Expand Down
39 changes: 16 additions & 23 deletions docs/configuring_tor.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ by using Tor for anonymous networking to establish connections.

With widespread usage of Onion Services within the network, concerns about the
difficulty of proper NAT traversal are alleviated, as usage of onion services
allows nodes to accept inbound connections even if they're behind a NAT. At the
time of writing this documentation, `lnd` supports both types of onion services:
v2 and v3.
allows nodes to accept inbound connections even if they're behind a NAT. `lnd`
supports v3 onion services only; legacy v2 onion service support has been
removed.

Before following the remainder of this documentation, you should ensure that you
already have Tor installed locally. **If you want to run v3 Onion Services, make
sure that you run at least version 0.3.3.6.**
Before following the remainder of this documentation, you should ensure that
you already have Tor installed locally. **Make sure that you run at least
version 0.3.3.6 of Tor in order to use v3 Onion Services.**
Official instructions to install the latest release of Tor can be found
[here](https://www.torproject.org/docs/tor-doc-unix.html.en).

Expand Down Expand Up @@ -81,7 +81,6 @@ Tor:
--tor.control= The host:port that Tor is listening on for Tor control connections (default: localhost:9051)
--tor.targetipaddress= IP address that Tor should use as the target of the hidden service
--tor.password= The password used to arrive at the HashedControlPassword for the control port. If provided, the HASHEDPASSWORD authentication method will be used instead of the SAFECOOKIE one.
--tor.v2 Automatically set up a v2 onion service to listen for inbound connections
--tor.v3 Automatically set up a v3 onion service to listen for inbound connections
--tor.privatekeypath= The path to the private key of the onion service being created
```
Expand All @@ -103,11 +102,8 @@ service. A path to save the onion service's private key can be specified with
the `--tor.privatekeypath` flag.

Most of these arguments have defaults, so as long as they apply to you, routing
all outbound and inbound connections through Tor can simply be done with either
v2 or v3 onion services:
```shell
$ ./lnd --tor.active --tor.v2
```
all outbound and inbound connections through Tor can simply be done with v3
Comment thread
erickcestari marked this conversation as resolved.
onion services:
```shell
$ ./lnd --tor.active --tor.v3
```
Expand Down Expand Up @@ -159,15 +155,13 @@ authentication methods (arguably, from most to least secure):
## Listening for Inbound Connections

In order to listen for inbound connections through Tor, an onion service must be
created. There are two types of onion services: v2 and v3. v3 onion services
are the latest generation of onion services, and they provide a number of
advantages over the legacy v2 onion services. To learn more about these
benefits, see [Intro to Next Gen Onion Services](https://trac.torproject.org/projects/tor/wiki/doc/NextGenOnions).
created. `lnd` supports v3 onion services, the latest generation of onion
services. To learn more about these, see
[Intro to Next Gen Onion Services](https://trac.torproject.org/projects/tor/wiki/doc/NextGenOnions).

Both types can be created and used automatically by `lnd`. Specifying which type
should be used can easily be done by either using the `tor.v2` or `tor.v3` flag.
To prevent unintentional leaking of identifying information, it is also necessary
to add the flag `listen=localhost`.
v3 onion services are created and used automatically by `lnd` via the `tor.v3`
flag. To prevent unintentional leaking of identifying information, it is also
necessary to add the flag `listen=localhost`.

For example, v3 onion services can be used with the following flags:
```shell
Expand All @@ -176,9 +170,8 @@ $ ./lnd --tor.active --tor.v3 --listen=localhost

This will automatically create a hidden service for your node to use to listen
for inbound connections and advertise itself to the network. The onion service's
private key is saved to a file named `v2_onion_private_key` or
`v3_onion_private_key` depending on the type of onion service used in `lnd`'s
base directory. This will allow `lnd` to recreate the same hidden service upon
private key is saved to a file named `v3_onion_private_key` in `lnd`'s base
directory. This will allow `lnd` to recreate the same hidden service upon
restart. If you wish to generate a new onion service, you can simply delete this
file. The path to this private key file can also be modified with the
`--tor.privatekeypath` argument.
Expand Down
42 changes: 41 additions & 1 deletion docs/release-notes/release-notes-0.21.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,46 @@
`lncli getdebuginfo` and `lncli encryptdebugpackage` commands similarly
require the `--include_log` flag to include logs in the output.

* [Removed the deprecated payment and tracking
RPCs](https://github.com/lightningnetwork/lnd/pull/10795) that were
[announced for removal in 0.21](https://github.com/lightningnetwork/lnd/blob/master/docs/release-notes/release-notes-0.20.0.md#deprecations)
via the 0.20 release notes. Callers must migrate to the V2 equivalents:

| Removed RPC | Replacement |
|-------------|-------------|
| `lnrpc.SendPayment` (streaming) | `routerrpc.SendPaymentV2` |
| `lnrpc.SendPaymentSync` | `routerrpc.SendPaymentV2` |
| `lnrpc.SendToRoute` (streaming) | `routerrpc.SendToRouteV2` |
| `lnrpc.SendToRouteSync` | `routerrpc.SendToRouteV2` |
| `routerrpc.SendPayment` (streaming) | `routerrpc.SendPaymentV2` |
| `routerrpc.SendToRoute` | `routerrpc.SendToRouteV2` |
| `routerrpc.TrackPayment` (streaming) | `routerrpc.TrackPaymentV2` |

This also removes the corresponding REST routes
`POST /v1/channels/transaction-stream`, `POST /v1/channels/transactions`,
Comment thread
erickcestari marked this conversation as resolved.
and `POST /v1/channels/transactions/route`. The orphan
`routerrpc.SendToRouteResponse` message (only used by the removed
`routerrpc.SendToRoute` RPC) is also dropped.

* [Removed the deprecated `outgoing_chan_id`
field](https://github.com/lightningnetwork/lnd/pull/10795) from
`lnrpc.QueryRoutesRequest` and `routerrpc.SendPaymentRequest`. Proto tags
14 and 8 respectively are now reserved. Callers must use the multi-channel
`outgoing_chan_ids` field introduced in 0.20.

* [Removed the deprecated `--tor.v2` configuration
Comment thread
erickcestari marked this conversation as resolved.
flag](https://github.com/lightningnetwork/lnd/pull/10795). Tor v2 onion
services have been obsolete since October 2021 when the Tor network dropped
support for them; only v3 is supported now. Incoming
`NodeAnnouncement` messages still decode successfully, but any v2 onion
addresses they carry are stripped post-decode so they are never relayed
onward or persisted to the graph DB. The wire/storage encoders for v2
onion addresses (in
`lnwire`, `graph/db`) and the `tor.OnionHostToFakeIP` helper have been
removed. The `lnwire` and `graph/db` v2 decoders themselves are
retained so legacy graph databases (and the existing KV-to-SQL graph
migration that re-parses opaque address payloads) continue to load.

## Performance Improvements

* Let the [channel graph cache be populated
Expand Down Expand Up @@ -331,7 +371,7 @@

### ⚠️ **Warning:** Deprecated fields in `lnrpc.Hop` will be removed in release version **0.22**

The following deprecated fields in the [`lnrpc.Hop`](https://lightning.engineering/api-docs/api/lnd/lightning/send-to-route-sync/#lnrpchop)
The following deprecated fields in the [`lnrpc.Hop`](https://lightning.engineering/api-docs/api/lnd/lightning/query-routes/#lnrpchop)
message will be removed:

| Field | Deprecated Since | Replacement |
Expand Down
4 changes: 2 additions & 2 deletions docs/rest/websockets.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ ws.on('open', function() {
// This empty message will be ignored by the channel acceptor though, this
// is just for telling the grpc-gateway library that it can forward the
// request to the gRPC interface now. If this were an RPC where the client
// always sends the first message (for example the streaming payment RPC
// /v1/channels/transaction-stream), we'd simply send the first "real"
// always sends the first message (for example the HTLC interceptor RPC
// /v2/router/htlcinterceptor), we'd simply send the first "real"
// message here when needed.
ws.send('{}');
});
Expand Down
35 changes: 24 additions & 11 deletions graph/db/addr.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,6 @@ func encodeOnionAddr(w io.Writer, addr *tor.OnionAddr) error {
var suffixIndex int
hostLen := len(addr.OnionService)
switch hostLen {
case tor.V2Len:
Comment thread
erickcestari marked this conversation as resolved.
if _, err := w.Write([]byte{byte(v2OnionAddr)}); err != nil {
return err
}
suffixIndex = tor.V2Len - tor.OnionSuffixLen
case tor.V3Len:
if _, err := w.Write([]byte{byte(v3OnionAddr)}); err != nil {
return err
Expand All @@ -131,12 +126,7 @@ func encodeOnionAddr(w io.Writer, addr *tor.OnionAddr) error {
}

// Sanity check the decoded length.
switch {
case hostLen == tor.V2Len && len(host) != tor.V2DecodedLen:
return fmt.Errorf("onion service %v decoded to invalid host %x",
addr.OnionService, host)

case hostLen == tor.V3Len && len(host) != tor.V3DecodedLen:
if hostLen == tor.V3Len && len(host) != tor.V3DecodedLen {
return fmt.Errorf("onion service %v decoded to invalid host %x",
addr.OnionService, host)
}
Expand Down Expand Up @@ -322,3 +312,26 @@ func SerializeAddr(w io.Writer, address net.Addr) error {
return ErrUnknownAddressType
}
}

// FilterSerializableAddrs returns the subset of addresses that this package
// can currently serialize. Legacy Tor v2 onion addresses are dropped (with a
// warning) since lnd no longer persists them; pre-existing v2 addresses on
// disk can still be deserialized, but any rewrite path must call this helper
// before counting and encoding the address slice so that node updates do not
// fail when a stale v2 address is present.
func FilterSerializableAddrs(addrs []net.Addr) []net.Addr {
out := make([]net.Addr, 0, len(addrs))
for _, a := range addrs {
onion, ok := a.(*tor.OnionAddr)
if ok && len(onion.OnionService) == tor.V2Len {
log.Warnf("Dropping legacy v2 onion address %v "+
"during serialization; v2 is no longer "+
"supported", onion)

continue
}
out = append(out, a)
}

return out
}
8 changes: 0 additions & 8 deletions graph/db/addr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ var (
Port: 65535,
}

testOnionV2Addr = &tor.OnionAddr{
OnionService: "3g2upl4pq6kufc4m.onion",
Port: 9735,
}

testOnionV3Addr = &tor.OnionAddr{
OnionService: "vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd.onion", //nolint:ll
Port: 80,
Expand Down Expand Up @@ -63,9 +58,6 @@ var addrTests = []struct {
{
expAddr: testIPV6Addr,
},
{
expAddr: testOnionV2Addr,
},
{
expAddr: testOnionV3Addr,
},
Expand Down
4 changes: 1 addition & 3 deletions graph/db/graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,8 +400,7 @@ func testNodeInsertionAndDeletion(t *testing.T, v lnwire.GossipVersion) {
// Add 2 IPV6 addresses.
testIPV6Addr,
anotherAddr,
// Add one v2 and one v3 onion address.
testOnionV2Addr,
// Add a v3 onion address.
testOnionV3Addr,
// Add a DNS host address.
testDNSAddr,
Expand Down Expand Up @@ -439,7 +438,6 @@ func testNodeInsertionAndDeletion(t *testing.T, v lnwire.GossipVersion) {

// Finally, update the set to only contain the Tor addresses.
expAddrs = []net.Addr{
testOnionV2Addr,
testOnionV3Addr,
}
node = nodeWithAddrs(expAddrs)
Expand Down
5 changes: 3 additions & 2 deletions graph/db/kv_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -4699,13 +4699,14 @@ func putLightningNode(nodeBucket, aliasBucket, updateIndex kvdb.RwBucket,
return err
}

numAddresses := uint16(len(node.Addresses))
addresses := FilterSerializableAddrs(node.Addresses)
numAddresses := uint16(len(addresses))
byteOrder.PutUint16(scratch[:2], numAddresses)
if _, err := b.Write(scratch[:2]); err != nil {
return err
}

for _, address := range node.Addresses {
for _, address := range addresses {
if err := SerializeAddr(&b, address); err != nil {
return err
}
Expand Down
Loading
Loading