-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1460 from libp2p/merge-csm
move go-conn-security-multistream here
- Loading branch information
Showing
8 changed files
with
195 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters