diff --git a/core/node/groups.go b/core/node/groups.go index ad51473452e..823d9037b66 100644 --- a/core/node/groups.go +++ b/core/node/groups.go @@ -120,7 +120,7 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option { fx.Invoke(libp2p.StartListening(cfg.Addresses.Swarm)), fx.Invoke(libp2p.SetupDiscovery(cfg.Discovery.MDNS.Enabled, cfg.Discovery.MDNS.Interval)), - fx.Provide(libp2p.Security(!bcfg.DisableEncryptedConnections)), + fx.Provide(libp2p.Security(!bcfg.DisableEncryptedConnections, cfg.Experimental.OverrideSecurityTransports)), fx.Provide(libp2p.Routing), fx.Provide(libp2p.BaseRouting), diff --git a/core/node/libp2p/transport.go b/core/node/libp2p/transport.go index 7fca3b71d90..0bbc7cf01b8 100644 --- a/core/node/libp2p/transport.go +++ b/core/node/libp2p/transport.go @@ -1,8 +1,11 @@ package libp2p import ( + "fmt" + "github.com/libp2p/go-libp2p" metrics "github.com/libp2p/go-libp2p-core/metrics" + noise "github.com/libp2p/go-libp2p-noise" libp2pquic "github.com/libp2p/go-libp2p-quic-transport" secio "github.com/libp2p/go-libp2p-secio" tls "github.com/libp2p/go-libp2p-tls" @@ -10,6 +13,9 @@ import ( "go.uber.org/fx" ) +// default security transports for libp2p +var defaultSecurityTransports = []string{"tls", "secio", "noise"} + func Transports(pnet struct { fx.In Fprint PNetFingerprint `optional:"true"` @@ -21,7 +27,7 @@ func Transports(pnet struct { return opts } -func Security(enabled bool) interface{} { +func Security(enabled bool, securityTransportOverride []string) interface{} { if !enabled { return func() (opts Libp2pOpts) { // TODO: shouldn't this be Errorf to guarantee visibility? @@ -31,8 +37,28 @@ func Security(enabled bool) interface{} { return opts } } + + securityTransports := defaultSecurityTransports + if len(securityTransportOverride) > 0 { + securityTransports = securityTransportOverride + } + + var libp2pOpts []libp2p.Option + for _, tpt := range securityTransports { + switch tpt { + case "tls": + libp2pOpts = append(libp2pOpts, libp2p.Security(tls.ID, tls.New)) + case "secio": + libp2pOpts = append(libp2pOpts, libp2p.Security(secio.ID, secio.New)) + case "noise": + libp2pOpts = append(libp2pOpts, libp2p.Security(noise.ID, noise.New)) + default: + return fx.Error(fmt.Errorf("invalid security transport specified in config: %s", tpt)) + } + } + return func() (opts Libp2pOpts) { - opts.Opts = append(opts.Opts, libp2p.ChainOptions(libp2p.Security(tls.ID, tls.New), libp2p.Security(secio.ID, secio.New))) + opts.Opts = append(opts.Opts, libp2p.ChainOptions(libp2pOpts...)) return opts } } diff --git a/docs/experimental-features.md b/docs/experimental-features.md index 820fdc6ca3d..6fd639e7620 100644 --- a/docs/experimental-features.md +++ b/docs/experimental-features.md @@ -25,6 +25,7 @@ the above issue. - [AutoRelay](#autorelay) - [Strategic Providing](#strategic-providing) - [Graphsync](#graphsync) +- [Noise](#noise) --- @@ -538,3 +539,26 @@ ipfs config --json Experimental.GraphsyncEnabled true ### Road to being a real feature - [ ] We need to confirm that it can't be used to DoS a node. The server-side logic for GraphSync is quite complex and, if we're not careful, the server might end up performing unbounded work when responding to a malicious request. + +## Noise + +### State + +Experimental, enabled by default + +[Noise](https://github.com/libp2p/specs/tree/master/noise) libp2p transport based on the [Noise Protocol Framework](https://noiseprotocol.org/noise.html). While TLS remains the default transport in go-ipfs, Noise is easier to implement and will thus serve as the "interop" transport between IPFS and libp2p implementations, eventually replacing SECIO. + +### How to enable + +While the Noise transport is now shipped and enabled by default in go-ipfs, it won't be used by default for most connections because TLS and SECIO are currently preferred. If you'd like to test out the Noise transport, you can use the `Experimental.OverrideSecurityTransports` option to enable, disable, and reorder security transports. + +For example, to prefer noise over TLS and disable SECIO, run: + +``` +ipfs config --json Experimental.OverrideSecurityTransports '["noise", "tls"]' +``` + +### Road to being a real feature + +- [ ] Needs real-world testing. +- [ ] Ideally a js-ipfs and a rust-ipfs release would include support for Noise. diff --git a/go.mod b/go.mod index f3bebcd9da0..e0139b53e37 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/ipfs/go-ipfs-blockstore v0.1.4 github.com/ipfs/go-ipfs-chunker v0.0.5 github.com/ipfs/go-ipfs-cmds v0.2.9 - github.com/ipfs/go-ipfs-config v0.7.0 + github.com/ipfs/go-ipfs-config v0.7.1 github.com/ipfs/go-ipfs-ds-help v0.1.1 github.com/ipfs/go-ipfs-exchange-interface v0.0.1 github.com/ipfs/go-ipfs-exchange-offline v0.0.1 @@ -70,6 +70,7 @@ require ( github.com/libp2p/go-libp2p-kbucket v0.4.2 github.com/libp2p/go-libp2p-loggables v0.1.0 github.com/libp2p/go-libp2p-mplex v0.2.3 + github.com/libp2p/go-libp2p-noise v0.1.1 github.com/libp2p/go-libp2p-peerstore v0.2.4 github.com/libp2p/go-libp2p-pubsub v0.3.0 github.com/libp2p/go-libp2p-pubsub-router v0.3.0 diff --git a/go.sum b/go.sum index 5e6b4b75b16..eadeccbf422 100644 --- a/go.sum +++ b/go.sum @@ -115,6 +115,8 @@ github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= +github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= @@ -303,6 +305,8 @@ github.com/ipfs/go-ipfs-cmds v0.2.9 h1:zQTENe9UJrtCb2bOtRoDGjtuo3rQjmuPdPnVlqoBV github.com/ipfs/go-ipfs-cmds v0.2.9/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk= github.com/ipfs/go-ipfs-config v0.7.0 h1:cClINg8v28//KaYMwt1aSjbS8eGJjNKIEnahpT/2hYk= github.com/ipfs/go-ipfs-config v0.7.0/go.mod h1:GQUxqb0NfkZmEU92PxqqqLVVFTLpoGGUlBaTyDaAqrE= +github.com/ipfs/go-ipfs-config v0.7.1 h1:57ZzoiUIbOIT01x1RconKtCv1MElV/6+kqW8hZY9NJ4= +github.com/ipfs/go-ipfs-config v0.7.1/go.mod h1:GQUxqb0NfkZmEU92PxqqqLVVFTLpoGGUlBaTyDaAqrE= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= @@ -501,6 +505,7 @@ github.com/libp2p/go-libp2p v0.7.0 h1:qWmciout2lJclKfRlxqdepsQB7JihcbRhgcRcssP4r github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= github.com/libp2p/go-libp2p v0.7.4 h1:xVj1oSlN0C+FlxqiLuHC8WruMvq24xxfeVxmNhTG0r0= github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= +github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= github.com/libp2p/go-libp2p v0.8.2 h1:gVuk8nZGjnRagJ/mLpBCSJw7bW1yWJrq3EwOk/AC6FM= github.com/libp2p/go-libp2p v0.8.2/go.mod h1:NQDA/F/qArMHGe0J7sDScaKjW8Jh4y/ozQqBbYJ+BnA= github.com/libp2p/go-libp2p v0.8.3 h1:IFWeNzxkBaNO1N8stN9ayFGdC6RmVuSsKd5bou7qpK0= @@ -620,6 +625,8 @@ github.com/libp2p/go-libp2p-net v0.0.2/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8 github.com/libp2p/go-libp2p-netutil v0.0.1/go.mod h1:GdusFvujWZI9Vt0X5BKqwWWmZFxecf9Gt03cKxm2f/Q= github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-noise v0.1.1 h1:vqYQWvnIcHpIoWJKC7Al4D6Hgj0H012TuXRhPwSMGpQ= +github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es= github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY= diff --git a/test/sharness/lib/iptb-lib.sh b/test/sharness/lib/iptb-lib.sh index ab612ada7f2..3d2e95a4916 100644 --- a/test/sharness/lib/iptb-lib.sh +++ b/test/sharness/lib/iptb-lib.sh @@ -36,11 +36,11 @@ startup_cluster() { if test -n "$other_args"; then test_expect_success "start up nodes with additional args" " - iptb start -wait -- ${other_args[@]} + iptb start -wait [0-$bound] -- ${other_args[@]} " else test_expect_success "start up nodes" ' - iptb start -wait + iptb start -wait [0-$bound] ' fi diff --git a/test/sharness/t0125-twonode.sh b/test/sharness/t0125-twonode.sh index 424b610ff99..a3b1006a4d3 100755 --- a/test/sharness/t0125-twonode.sh +++ b/test/sharness/t0125-twonode.sh @@ -89,23 +89,38 @@ test_expect_success "set up tcp testbed" ' iptb testbed create -type localipfs -count 2 -force -init ' +# Test TCP transport +echo "Testing TCP" +tcp_addr='"[\"/ip4/127.0.0.1/tcp/0\"]"' +test_expect_success "use TCP only" ' + ipfsi 0 config --json Addresses.Swarm '${tcp_addr}' && + ipfsi 1 config --json Addresses.Swarm '${tcp_addr}' +' +run_advanced_test + # test multiplex muxer echo "Running advanced tests with mplex" export LIBP2P_MUX_PREFS="/mplex/6.7.0" run_advanced_test "--enable-mplex-experiment" unset LIBP2P_MUX_PREFS -# test default configuration -echo "Running advanced tests with default config" +# test Noise + +echo "Running advanced tests with NOISE" +noise_transports='"[\"noise\"]"' +test_expect_success "use noise only" ' + ipfsi 0 config --json Experimental.OverrideSecurityTransports '${noise_transports}' && + ipfsi 1 config --json Experimental.OverrideSecurityTransports '${noise_transports}' +' + run_advanced_test # test QUIC echo "Running advanced tests over QUIC" -addr1='"[\"/ip4/127.0.0.1/udp/0/quic/\"]"' -addr2='"[\"/ip4/127.0.0.1/udp/0/quic/\"]"' -test_expect_success "add QUIC swarm addresses" ' - ipfsi 0 config --json Addresses.Swarm '$addr1' && - ipfsi 1 config --json Addresses.Swarm '$addr2' +addr1='"[\"/ip4/127.0.0.1/udp/0/quic\"]"' +test_expect_success "use QUIC only" ' + ipfsi 0 config --json Addresses.Swarm '${quic_addr}' && + ipfsi 1 config --json Addresses.Swarm '${quic_addr}' ' run_advanced_test diff --git a/test/sharness/t0191-noise.sh b/test/sharness/t0191-noise.sh new file mode 100755 index 00000000000..4787dfc53fd --- /dev/null +++ b/test/sharness/t0191-noise.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +test_description="Test ping over NOISE command" + +. lib/test-lib.sh + +test_init_ipfs + +# start iptb + wait for peering +test_expect_success 'init iptb' ' + iptb testbed create -type localipfs -count 3 -init +' + +noise_transports='"[\"noise\"]"' +other_transports='"[\"tls\",\"secio\"]"' +tcp_addr='"[\"/ip4/127.0.0.1/tcp/0\"]"' +test_expect_success "configure security transports" ' + ipfsi 0 config --json Experimental.OverrideSecurityTransports '${noise_transports}' && + ipfsi 1 config --json Experimental.OverrideSecurityTransports '${noise_transports}' && + ipfsi 2 config --json Experimental.OverrideSecurityTransports '${other_transports}' && + iptb run -- ipfs config --json Addresses.Swarm '${tcp_addr}' +' + +startup_cluster 2 + +test_expect_success 'peer ids' ' + PEERID_0=$(iptb attr get 0 id) && + PEERID_1=$(iptb attr get 1 id) +' + +test_expect_success "test ping other" ' + ipfsi 0 ping -n2 -- "$PEERID_1" && + ipfsi 1 ping -n2 -- "$PEERID_0" +' + +test_expect_success "test tls incompatible" ' + iptb start --wait 2 && + test_must_fail iptb connect 2 0 > connect_error 2>&1 && + test_should_contain "failed to negotiate security protocol" connect_error || + test_fsh cat connect_error +' + +test_expect_success 'stop iptb' ' + iptb stop +' + +test_done