Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(libp2p): shared TCP listeners and AutoTLS.AutoWSS #10565

Merged
merged 30 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7833e64
feat(libp2p): enable shared TCP listeners
aschmahmann Oct 30, 2024
590bed0
chore(tmp): update go-libp2p to branch
aschmahmann Nov 12, 2024
2a33eb2
Merge branch 'master' into feat/libp2p-sharedtcp
gammazero Nov 19, 2024
bc215c2
docs: switch mentions of /ws to /tcp/4001
lidel Nov 29, 2024
6de3faa
chore: latest boxo and go-libp2p mains
lidel Dec 3, 2024
1831a3d
Merge remote-tracking branch 'origin/master' into feat/libp2p-sharedtcp
lidel Dec 3, 2024
9b887ea
feat: AutoTLS.AutoWSS
lidel Dec 4, 2024
80e8895
fix: conditional tcp sharing
lidel Dec 9, 2024
0d7ad48
test: go-libp2p#3080
lidel Dec 10, 2024
2adb2f1
chore: go-libp2p@master with go-libp2p#3080
lidel Dec 10, 2024
65d51e9
test: remove replace
lidel Dec 17, 2024
66317b4
chore: go-libp2p v0.38.1
lidel Dec 19, 2024
d178b87
Merge 'origin/master' into feat/libp2p-sharedtcp
lidel Dec 19, 2024
2d84386
docs: AutoTLS.AutoWSS and go-libp2p v0.38.x
lidel Dec 19, 2024
c841ca6
chore: p2p-forge/client v0.2.0-rc1
lidel Dec 19, 2024
0a59574
test: boxo@main (v0.26.0 pre release)
lidel Dec 19, 2024
075ed6b
chore: p2p-forge/client v0.2.0
lidel Dec 19, 2024
a436f4e
test: boxo@main (v0.26.0 pre release)
lidel Dec 19, 2024
b5cfd6d
test: sharness without tcp mux
lidel Dec 19, 2024
6caf78c
test: sharness with tcp mux
lidel Dec 19, 2024
2919d6d
Merge remote-tracking branch 'origin/master' into feat/libp2p-sharedtcp
lidel Dec 19, 2024
e150509
Merge branch 'master' into feat/libp2p-sharedtcp
gammazero Dec 20, 2024
7a4ec80
test: LIBP2P_TCP_MUX: false
lidel Dec 20, 2024
858e10a
test: LIBP2P_TCP_MUX: true
lidel Dec 20, 2024
50cd7cd
test: run sharness sequentially
lidel Dec 20, 2024
6367f64
testi: set sharness timeout to 2h
lidel Dec 20, 2024
bb87df3
fix: disable libp2p.ShareTCPListener() in PNET
lidel Dec 20, 2024
6b5b2ed
chore: restore regular sharness
lidel Dec 20, 2024
d532e58
chore: fix lint
lidel Dec 20, 2024
a1f1cb2
chore(ci): timeout sharness after 15m
lidel Dec 20, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/sharness.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
sharness-test:
if: github.repository == 'ipfs/kubo' || github.event_name == 'workflow_dispatch'
runs-on: ${{ fromJSON(github.repository == 'ipfs/kubo' && '["self-hosted", "linux", "x64", "4xlarge"]' || '"ubuntu-latest"') }}
timeout-minutes: 20
timeout-minutes: ${{ github.repository == 'ipfs/kubo' && 15 || 60 }}
defaults:
run:
shell: bash
Expand Down
18 changes: 13 additions & 5 deletions cmd/ipfs/kubo/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,13 +410,21 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
}
}

// Private setups can't leverage peers returned by default IPNIs (Routing.Type=auto)
// To avoid breaking existing setups, switch them to DHT-only.
if routingOption == routingOptionAutoKwd {
if key, _ := repo.SwarmKey(); key != nil || pnet.ForcePrivateNetwork {
if key, _ := repo.SwarmKey(); key != nil || pnet.ForcePrivateNetwork {
// Private setups can't leverage peers returned by default IPNIs (Routing.Type=auto)
// To avoid breaking existing setups, switch them to DHT-only.
if routingOption == routingOptionAutoKwd {
log.Error("Private networking (swarm.key / LIBP2P_FORCE_PNET) does not work with public HTTP IPNIs enabled by Routing.Type=auto. Kubo will use Routing.Type=dht instead. Update config to remove this message.")
routingOption = routingOptionDHTKwd
}

// Private setups should not use public AutoTLS infrastructure
// as it will leak their existence and PeerID identity to CA
// and they will show up at https://crt.sh/?q=libp2p.direct
// Below ensures we hard fail if someone tries to enable both
if cfg.AutoTLS.Enabled.WithDefault(config.DefaultAutoTLSEnabled) {
return errors.New("private networking (swarm.key / LIBP2P_FORCE_PNET) does not work with AutoTLS.Enabled=true, update config to remove this message")
}
}

switch routingOption {
Expand Down Expand Up @@ -467,7 +475,7 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
fmt.Printf("Swarm key fingerprint: %x\n", node.PNetFingerprint)
}

if (pnet.ForcePrivateNetwork || node.PNetFingerprint != nil) && routingOption == routingOptionAutoKwd {
if (pnet.ForcePrivateNetwork || node.PNetFingerprint != nil) && (routingOption == routingOptionAutoKwd || routingOption == routingOptionAutoClientKwd) {
// This should never happen, but better safe than sorry
log.Fatal("Private network does not work with Routing.Type=auto. Update your config to Routing.Type=dht (or none, and do manual peering)")
}
Expand Down
6 changes: 5 additions & 1 deletion config/autotls.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import p2pforge "github.com/ipshipyard/p2p-forge/client"
// for obtaining a domain and TLS certificate to improve connectivity for web
// browser clients. More: https://github.com/ipshipyard/p2p-forge#readme
type AutoTLS struct {
// Enables the p2p-forge feature
// Enables the p2p-forge feature and all related features.
Enabled Flag `json:",omitempty"`

// Optional, controls if Kubo should add /tls/sni/.../ws listener to every /tcp port if no explicit /ws is defined in Addresses.Swarm
AutoWSS Flag `json:",omitempty"`

// Optional override of the parent domain that will be used
DomainSuffix *OptionalString `json:",omitempty"`

Expand All @@ -27,4 +30,5 @@ const (
DefaultDomainSuffix = p2pforge.DefaultForgeDomain
DefaultRegistrationEndpoint = p2pforge.DefaultForgeEndpoint
DefaultCAEndpoint = p2pforge.DefaultCAEndpoint
DefaultAutoWSS = true // requires AutoTLS.Enabled
)
47 changes: 44 additions & 3 deletions core/node/groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"regexp"
"strings"
"time"

Expand Down Expand Up @@ -115,6 +116,8 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part
enableRelayService := cfg.Swarm.RelayService.Enabled.WithDefault(enableRelayTransport)
enableRelayClient := cfg.Swarm.RelayClient.Enabled.WithDefault(enableRelayTransport)
enableAutoTLS := cfg.AutoTLS.Enabled.WithDefault(config.DefaultAutoTLSEnabled)
enableAutoWSS := cfg.AutoTLS.AutoWSS.WithDefault(config.DefaultAutoWSS)
atlsLog := log.Logger("autotls")

// Log error when relay subsystem could not be initialized due to missing dependency
if !enableRelayTransport {
Expand All @@ -125,21 +128,59 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part
logger.Fatal("Failed to enable `Swarm.RelayClient`, it requires `Swarm.Transports.Network.Relay` to be true.")
}
}

if enableAutoTLS {
if !cfg.Swarm.Transports.Network.TCP.WithDefault(true) {
logger.Fatal("Invalid configuration: AutoTLS.Enabled=true requires Swarm.Transports.Network.TCP to be true as well.")
}
if !cfg.Swarm.Transports.Network.Websocket.WithDefault(true) {
logger.Fatal("Invalid configuration: AutoTLS.Enabled=true requires Swarm.Transports.Network.Websocket to be true as well.")
}

// AutoTLS for Secure WebSockets: ensure WSS listeners are in place (manual or automatic)
wssWildcard := fmt.Sprintf("/tls/sni/*.%s/ws", cfg.AutoTLS.DomainSuffix.WithDefault(config.DefaultDomainSuffix))
wssWildcardPresent := false
customWsPresent := false
customWsRegex := regexp.MustCompile(`/wss?$`)
tcpRegex := regexp.MustCompile(`/tcp/\d+$`)

// inspect listeners defined in config at Addresses.Swarm
var tcpListeners []string
for _, listener := range cfg.Addresses.Swarm {
// detect if user manually added /tls/sni/.../ws listener matching AutoTLS.DomainSuffix
if strings.Contains(listener, wssWildcard) {
atlsLog.Infof("found compatible wildcard listener in Addresses.Swarm. AutoTLS will be used on %s", listener)
wssWildcardPresent = true
break
}
// detect if user manually added own /ws or /wss listener that is
// not related to AutoTLS feature
if customWsRegex.MatchString(listener) {
atlsLog.Infof("found custom /ws listener set by user in Addresses.Swarm. AutoTLS will not be used on %s.", listener)
customWsPresent = true
break
}
// else, remember /tcp listeners that can be reused for /tls/sni/../ws
if tcpRegex.MatchString(listener) {
tcpListeners = append(tcpListeners, listener)
}
}
if !wssWildcardPresent {
logger.Fatal(fmt.Sprintf("Invalid configuration: AutoTLS.Enabled=true requires a catch-all Addresses.Swarm listener ending with %q to be present, see https://github.com/ipfs/kubo/blob/master/docs/config.md#autotls", wssWildcard))

// Append AutoTLS's wildcard listener
// if no manual /ws listener was set by the user
if enableAutoWSS && !wssWildcardPresent && !customWsPresent {
if len(tcpListeners) == 0 {
logger.Fatal("Invalid configuration: AutoTLS.AutoWSS=true requires at least one /tcp listener present in Addresses.Swarm, see https://github.com/ipfs/kubo/blob/master/docs/config.md#autotls")
}
for _, tcpListener := range tcpListeners {
wssListener := tcpListener + wssWildcard
cfg.Addresses.Swarm = append(cfg.Addresses.Swarm, wssListener)
atlsLog.Infof("appended AutoWSS listener: %s", wssListener)
}
}

if !wssWildcardPresent && !enableAutoWSS {
logger.Fatal(fmt.Sprintf("Invalid configuration: AutoTLS.Enabled=true requires a /tcp listener ending with %q to be present in Addresses.Swarm or AutoTLS.AutoWSS=true, see https://github.com/ipfs/kubo/blob/master/docs/config.md#autotls", wssWildcard))
}
}

Expand All @@ -152,7 +193,7 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part

// Services (resource management)
fx.Provide(libp2p.ResourceManager(bcfg.Repo.Path(), cfg.Swarm, userResourceOverrides)),
maybeProvide(libp2p.P2PForgeCertMgr(bcfg.Repo.Path(), cfg.AutoTLS), enableAutoTLS),
maybeProvide(libp2p.P2PForgeCertMgr(bcfg.Repo.Path(), cfg.AutoTLS, atlsLog), enableAutoTLS),
maybeInvoke(libp2p.StartP2PAutoTLS, enableAutoTLS),
fx.Provide(libp2p.AddrFilters(cfg.Swarm.AddrFilters)),
fx.Provide(libp2p.AddrsFactory(cfg.Addresses.Announce, cfg.Addresses.AppendAnnounce, cfg.Addresses.NoAnnounce)),
Expand Down
11 changes: 5 additions & 6 deletions core/node/libp2p/addrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,21 +133,20 @@ func ListenOn(addresses []string) interface{} {
}
}

func P2PForgeCertMgr(repoPath string, cfg config.AutoTLS) interface{} {
func P2PForgeCertMgr(repoPath string, cfg config.AutoTLS, atlsLog *logging.ZapEventLogger) interface{} {
return func() (*p2pforge.P2PForgeCertMgr, error) {
storagePath := filepath.Join(repoPath, "p2p-forge-certs")

forgeLogger := logging.Logger("autotls").Desugar()

// TODO: this should not be necessary, but we do it to help tracking
// down any race conditions causing
// https://github.com/ipshipyard/p2p-forge/issues/8
certmagic.Default.Logger = forgeLogger.Named("default_fixme")
certmagic.DefaultACME.Logger = forgeLogger.Named("default_acme_client_fixme")
rawLogger := atlsLog.Desugar()
certmagic.Default.Logger = rawLogger.Named("default_fixme")
certmagic.DefaultACME.Logger = rawLogger.Named("default_acme_client_fixme")

certStorage := &certmagic.FileStorage{Path: storagePath}
certMgr, err := p2pforge.NewP2PForgeCertMgr(
p2pforge.WithLogger(forgeLogger.Sugar()),
p2pforge.WithLogger(rawLogger.Sugar()),
p2pforge.WithForgeDomain(cfg.DomainSuffix.WithDefault(config.DefaultDomainSuffix)),
p2pforge.WithForgeRegistrationEndpoint(cfg.RegistrationEndpoint.WithDefault(config.DefaultRegistrationEndpoint)),
p2pforge.WithCAEndpoint(cfg.CAEndpoint.WithDefault(config.DefaultCAEndpoint)),
Expand Down
16 changes: 14 additions & 2 deletions core/node/libp2p/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package libp2p

import (
"fmt"
"os"

"github.com/ipfs/kubo/config"
"github.com/ipshipyard/p2p-forge/client"
"github.com/libp2p/go-libp2p"
Expand All @@ -24,19 +26,29 @@ func Transports(tptConfig config.Transports) interface{} {
) (opts Libp2pOpts, err error) {
privateNetworkEnabled := params.Fprint != nil

if tptConfig.Network.TCP.WithDefault(true) {
tcpEnabled := tptConfig.Network.TCP.WithDefault(true)
wsEnabled := tptConfig.Network.Websocket.WithDefault(true)
if tcpEnabled {
// TODO(9290): Make WithMetrics configurable
opts.Opts = append(opts.Opts, libp2p.Transport(tcp.NewTCPTransport, tcp.WithMetrics()))
}

if tptConfig.Network.Websocket.WithDefault(true) {
if wsEnabled {
if params.ForgeMgr == nil {
opts.Opts = append(opts.Opts, libp2p.Transport(websocket.New))
} else {
opts.Opts = append(opts.Opts, libp2p.Transport(websocket.New, websocket.WithTLSConfig(params.ForgeMgr.TLSConfig())))
}
}

if tcpEnabled && wsEnabled && os.Getenv("LIBP2P_TCP_MUX") != "false" {
if privateNetworkEnabled {
log.Error("libp2p.ShareTCPListener() is not supported in private networks, please disable Swarm.Transports.Network.Websocket or run with LIBP2P_TCP_MUX=false to make this message go away")
} else {
opts.Opts = append(opts.Opts, libp2p.ShareTCPListener())
}
}

if tptConfig.Network.QUIC.WithDefault(!privateNetworkEnabled) {
if privateNetworkEnabled {
return opts, fmt.Errorf(
Expand Down
28 changes: 24 additions & 4 deletions docs/changelogs/v0.33.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,40 @@

- [Overview](#overview)
- [🔦 Highlights](#-highlights)
- [Shared TCP listeners](#shared-tcp-listeners)
- [AutoTLS takes care of Secure WebSockets setup](#autotls-takes-care-of-secure-websockets-setup)
- [Bitswap improvements from Boxo](#bitswap-improvements-from-boxo)
- [Using default `libp2p_rcmgr` metrics](#using-default-libp2p_rcmgr--metrics)
- [Flatfs does not `sync` on each write](#flatfs-does-not-sync-on-each-write)
- [`ipfs add --to-files` no longer works with `--wrap`](#ipfs-add---to-files-no-longer-works-with---wrap)
- [New options for faster writes: `WriteThrough`, `BlockKeyCacheSize`, `BatchMaxNodes`, `BatchMaxSize`](#new-options-for-faster-writes-writethrough-blockkeycachesize-batchmaxnodes-batchmaxsize)
- [MFS stability with large number of writes](#mfs-stability-with-large-number-of-writes)
- [📦️ Dependency updates](#-dependency-updates)
- [📦️ Important dependency updates](#-important-dependency-updates)
- [📝 Changelog](#-changelog)
- [👨‍👩‍👧‍👦 Contributors](#-contributors)

### Overview

### 🔦 Highlights

#### Shared TCP listeners

Kubo now supports sharing the same TCP port (`4001` by default) by both [raw TCP](https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmtransportsnetworktcp) and [WebSockets](https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmtransportsnetworkwebsocket) libp2p transports.

This feature is not yet compatible with Private Networks and can be disabled by setting `LIBP2P_TCP_MUX=false` if causes any issues.

#### AutoTLS takes care of Secure WebSockets setup

It is no longer necessary to manually add `/tcp/../ws` listeners to `Addresses.Swarm` when [`AutoTLS.Enabled`](https://github.com/ipfs/kubo/blob/master/docs/config.md#autotlsenabled) is set to `true`. Kubo will detect if `/ws` listener is missing and add one on the same port as pre-existing TCP (e.g. `/tcp/4001`), removing the need for any extra configuration.
> [!TIP]
> Give it a try:
> ```console
> $ ipfs config --json AutoTLS.Enabled true
> ```
> And restart the node. If you are behind NAT, make sure your node is publicly diallable (uPnP or port forwarding), and wait a few minutes to pass all checks and for the changes to take effect.

See [`AutoTLS`](https://github.com/ipfs/kubo/blob/master/docs/config.md#autotls) for more information.

#### Bitswap improvements from Boxo

This release includes some refactorings and improvements affecting Bitswap which should improve reliability. One of the changes affects blocks providing. Previously, the bitswap layer took care itself of announcing new blocks -added or received- with the configured provider (i.e. DHT). This bypassed the "Reprovider", that is, the system that manages precisely "providing" the blocks stored by Kubo. The Reprovider knows how to take advantage of the [AcceleratedDHTClient](https://github.com/ipfs/kubo/blob/master/docs/config.md#routingaccelerateddhtclient), is able to handle priorities, logs statistics and is able to resume on daemon reboot where it left off. From now on, Bitswap will not be doing any providing on-the-side and all announcements are managed by the reprovider. In some cases, when the reproviding queue is full with other elements, this may cause additional delays, but more likely this will result in improved block-providing behaviour overall.
Expand Down Expand Up @@ -62,11 +82,11 @@ We recommend users trying Pebble as a datastore backend to disable both blocksto

We have fixed a number of issues that were triggered by writing or copying many files onto an MFS folder: increased memory usage first, then CPU, disk usage, and eventually a deadlock on write operations. The details of the fixes can be read at [#10630](https://github.com/ipfs/kubo/pull/10630) and [#10623](https://github.com/ipfs/kubo/pull/10623). The result is that writing large amounts of files to an MFS folder should now be possible without major issues. It is possible, as before, to speed up the operations using the `ipfs files --flush=false <op> ...` flag, but it is recommended to switch to `ipfs files --flush=true <op> ...` regularly, or call `ipfs files flush` on the working directory regularly, as this will flush, clear the directory cache and speed up reads.

#### 📦️ Dependency updates
#### 📦️ Important dependency updates

- update `boxo` to [v0.26.0](https://github.com/ipfs/boxo/releases/tag/v0.26.0)
- update `boxo` to [v0.26.0](https://github.com/ipfs/boxo/releases/tag/v0.26.0) (incl. [v0.25.0](https://github.com/ipfs/boxo/releases/tag/v0.25.0))
- update `go-libp2p` to [v0.38.1](https://github.com/libp2p/go-libp2p/releases/tag/v0.38.1) (incl. [v0.37.1](https://github.com/libp2p/go-libp2p/releases/tag/v0.37.1) + [v0.37.2](https://github.com/libp2p/go-libp2p/releases/tag/v0.37.2) + [v0.38.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.38.0))
- update `p2p-forge/client` to [v0.1.0](https://github.com/ipshipyard/p2p-forge/releases/tag/v0.1.0)
- update `p2p-forge/client` to [v0.2.0](https://github.com/ipshipyard/p2p-forge/releases/tag/v0.2.0) (incl. [v0.1.0](https://github.com/ipshipyard/p2p-forge/releases/tag/v0.1.0))
- update `ipfs-webui` to [v4.4.1](https://github.com/ipfs/ipfs-webui/releases/tag/v4.4.1)

### 📝 Changelog
Expand Down
Loading
Loading