Skip to content

Commit

Permalink
Merge pull request #1460 from libp2p/merge-csm
Browse files Browse the repository at this point in the history
move go-conn-security-multistream here
  • Loading branch information
marten-seemann authored Apr 26, 2022
2 parents d6c72fe + de5875f commit 4b7059c
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 7 deletions.
4 changes: 2 additions & 2 deletions config/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ package config
import (
"fmt"

csms "github.com/libp2p/go-libp2p/p2p/net/conn-security-multistream"

"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-core/sec"
"github.com/libp2p/go-libp2p-core/sec/insecure"

csms "github.com/libp2p/go-conn-security-multistream"
)

// SecC is a security transport constructor.
Expand Down
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ require (
github.com/ipfs/go-log/v2 v2.5.1
github.com/klauspost/compress v1.15.1
github.com/libp2p/go-buffer-pool v0.0.2
github.com/libp2p/go-conn-security-multistream v0.3.0
github.com/libp2p/go-eventbus v0.2.1
github.com/libp2p/go-libp2p-asn-util v0.1.0
github.com/libp2p/go-libp2p-circuit v0.6.0
Expand Down
109 changes: 109 additions & 0 deletions p2p/net/conn-security-multistream/ssms.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package csms

import (
"context"
"fmt"
"log"
"net"

"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-core/sec"
mss "github.com/multiformats/go-multistream"
)

// SSMuxer is a multistream stream security transport multiplexer.
//
// SSMuxer is safe to use without initialization. However, it's not safe to move
// after use.
type SSMuxer struct {
mux mss.MultistreamMuxer
tpts map[string]sec.SecureTransport
OrderPreference []string
}

var _ sec.SecureMuxer = (*SSMuxer)(nil)

// AddTransport adds a stream security transport to this multistream muxer.
//
// This method is *not* thread-safe. It should be called only when initializing
// the SSMuxer.
func (sm *SSMuxer) AddTransport(path string, transport sec.SecureTransport) {
if sm.tpts == nil {
sm.tpts = make(map[string]sec.SecureTransport, 1)
}

sm.mux.AddHandler(path, nil)
sm.tpts[path] = transport
sm.OrderPreference = append(sm.OrderPreference, path)
}

// SecureInbound secures an inbound connection using this multistream
// multiplexed stream security transport.
func (sm *SSMuxer) SecureInbound(ctx context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, bool, error) {
tpt, _, err := sm.selectProto(ctx, insecure, true)
if err != nil {
return nil, false, err
}
sconn, err := tpt.SecureInbound(ctx, insecure, p)
return sconn, true, err
}

// SecureOutbound secures an outbound connection using this multistream
// multiplexed stream security transport.
func (sm *SSMuxer) SecureOutbound(ctx context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, bool, error) {
tpt, server, err := sm.selectProto(ctx, insecure, false)
if err != nil {
return nil, false, err
}

var sconn sec.SecureConn
if server {
sconn, err = tpt.SecureInbound(ctx, insecure, p)
if err != nil {
return nil, false, fmt.Errorf("failed to secure inbound connection: %s", err)
}
// ensure the correct peer connected to us
if sconn.RemotePeer() != p {
sconn.Close()
log.Printf("Handshake failed to properly authenticate peer. Authenticated %s, expected %s.", sconn.RemotePeer(), p)
return nil, false, fmt.Errorf("unexpected peer")
}
} else {
sconn, err = tpt.SecureOutbound(ctx, insecure, p)
}

return sconn, server, err
}

func (sm *SSMuxer) selectProto(ctx context.Context, insecure net.Conn, server bool) (sec.SecureTransport, bool, error) {
var proto string
var err error
var iamserver bool
done := make(chan struct{})
go func() {
defer close(done)
if server {
iamserver = true
proto, _, err = sm.mux.Negotiate(insecure)
} else {
proto, iamserver, err = mss.SelectWithSimopenOrFail(sm.OrderPreference, insecure)
}
}()

select {
case <-done:
if err != nil {
return nil, false, err
}
if tpt, ok := sm.tpts[proto]; ok {
return tpt, iamserver, nil
}
return nil, false, fmt.Errorf("selected unknown security transport")
case <-ctx.Done():
// We *must* do this. We have outstanding work on the connection
// and it's no longer safe to use.
insecure.Close()
<-done // wait to stop using the connection.
return nil, false, ctx.Err()
}
}
79 changes: 79 additions & 0 deletions p2p/net/conn-security-multistream/ssms_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package csms

import (
"context"
"net"
"sync"
"testing"

"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-core/sec"
"github.com/libp2p/go-libp2p-core/sec/insecure"
tnet "github.com/libp2p/go-libp2p-testing/net"
sst "github.com/libp2p/go-libp2p-testing/suites/sec"
)

type TransportAdapter struct {
mux *SSMuxer
}

func (sm *TransportAdapter) SecureInbound(ctx context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
sconn, _, err := sm.mux.SecureInbound(ctx, insecure, p)
return sconn, err
}

func (sm *TransportAdapter) SecureOutbound(ctx context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
sconn, _, err := sm.mux.SecureOutbound(ctx, insecure, p)
return sconn, err
}

func TestCommonProto(t *testing.T) {
idA := tnet.RandIdentityOrFatal(t)
idB := tnet.RandIdentityOrFatal(t)

var at, bt SSMuxer

atInsecure := insecure.NewWithIdentity(idA.ID(), idA.PrivateKey())
btInsecure := insecure.NewWithIdentity(idB.ID(), idB.PrivateKey())
at.AddTransport("/plaintext/1.0.0", atInsecure)
bt.AddTransport("/plaintext/1.1.0", btInsecure)
bt.AddTransport("/plaintext/1.0.0", btInsecure)
sst.SubtestRW(t, &TransportAdapter{mux: &at}, &TransportAdapter{mux: &bt}, idA.ID(), idB.ID())
}

func TestNoCommonProto(t *testing.T) {
idA := tnet.RandIdentityOrFatal(t)
idB := tnet.RandIdentityOrFatal(t)

var at, bt SSMuxer
atInsecure := insecure.NewWithIdentity(idA.ID(), idA.PrivateKey())
btInsecure := insecure.NewWithIdentity(idB.ID(), idB.PrivateKey())

at.AddTransport("/plaintext/1.0.0", atInsecure)
bt.AddTransport("/plaintext/1.1.0", btInsecure)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()
a, b := net.Pipe()

var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
defer a.Close()
_, _, err := at.SecureInbound(ctx, a, "")
if err == nil {
t.Error("connection should have failed")
}
}()

go func() {
defer wg.Done()
defer b.Close()
_, _, err := bt.SecureOutbound(ctx, b, "peerA")
if err == nil {
t.Error("connection should have failed")
}
}()
wg.Wait()
}
2 changes: 1 addition & 1 deletion p2p/net/swarm/dial_worker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import (
"time"

"github.com/libp2p/go-libp2p/p2p/muxer/yamux"
csms "github.com/libp2p/go-libp2p/p2p/net/conn-security-multistream"
quic "github.com/libp2p/go-libp2p/p2p/transport/quic"
"github.com/libp2p/go-libp2p/p2p/transport/tcp"

"github.com/libp2p/go-libp2p-core/peerstore"
"github.com/libp2p/go-libp2p-core/sec/insecure"
"github.com/libp2p/go-libp2p-core/transport"

csms "github.com/libp2p/go-conn-security-multistream"
"github.com/libp2p/go-libp2p-peerstore/pstoremem"
tnet "github.com/libp2p/go-libp2p-testing/net"
tptu "github.com/libp2p/go-libp2p-transport-upgrader"
Expand Down
2 changes: 1 addition & 1 deletion p2p/net/swarm/testing/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"time"

"github.com/libp2p/go-libp2p/p2p/muxer/yamux"
csms "github.com/libp2p/go-libp2p/p2p/net/conn-security-multistream"
"github.com/libp2p/go-libp2p/p2p/net/swarm"
quic "github.com/libp2p/go-libp2p/p2p/transport/quic"
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
Expand All @@ -19,7 +20,6 @@ import (
"github.com/libp2p/go-libp2p-core/sec/insecure"
"github.com/libp2p/go-libp2p-core/transport"

csms "github.com/libp2p/go-conn-security-multistream"
"github.com/libp2p/go-libp2p-peerstore/pstoremem"
tnet "github.com/libp2p/go-libp2p-testing/net"
tptu "github.com/libp2p/go-libp2p-transport-upgrader"
Expand Down
2 changes: 1 addition & 1 deletion p2p/transport/tcp/tcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"

"github.com/libp2p/go-libp2p/p2p/muxer/yamux"
csms "github.com/libp2p/go-libp2p/p2p/net/conn-security-multistream"

"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/network"
Expand All @@ -14,7 +15,6 @@ import (
"github.com/libp2p/go-libp2p-core/sec/insecure"
"github.com/libp2p/go-libp2p-core/transport"

csms "github.com/libp2p/go-conn-security-multistream"
mocknetwork "github.com/libp2p/go-libp2p-testing/mocks/network"
ttransport "github.com/libp2p/go-libp2p-testing/suites/transport"
tptu "github.com/libp2p/go-libp2p-transport-upgrader"
Expand Down
3 changes: 2 additions & 1 deletion p2p/transport/websocket/websocket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"testing"
"time"

csms "github.com/libp2p/go-libp2p/p2p/net/conn-security-multistream"

"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
Expand All @@ -24,7 +26,6 @@ import (
"github.com/libp2p/go-libp2p-core/transport"
"github.com/libp2p/go-libp2p/p2p/muxer/yamux"

csms "github.com/libp2p/go-conn-security-multistream"
ttransport "github.com/libp2p/go-libp2p-testing/suites/transport"
tptu "github.com/libp2p/go-libp2p-transport-upgrader"

Expand Down

0 comments on commit 4b7059c

Please sign in to comment.