package libp2ptls
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"os"
"runtime/debug"
"github.com/libp2p/go-libp2p/core/canonicallog"
ci "github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/protocol"
"github.com/libp2p/go-libp2p/core/sec"
tptu "github.com/libp2p/go-libp2p/p2p/net/upgrader"
manet "github.com/multiformats/go-multiaddr/net"
)
const ID = "/tls/1.0.0"
type Transport struct {
identity *Identity
localPeer peer .ID
privKey ci .PrivKey
muxers []protocol .ID
protocolID protocol .ID
}
var _ sec .SecureTransport = &Transport {}
func New (id protocol .ID , key ci .PrivKey , muxers []tptu .StreamMuxer ) (*Transport , error ) {
localPeer , err := peer .IDFromPrivateKey (key )
if err != nil {
return nil , err
}
muxerIDs := make ([]protocol .ID , 0 , len (muxers ))
for _ , m := range muxers {
muxerIDs = append (muxerIDs , m .ID )
}
t := &Transport {
protocolID : id ,
localPeer : localPeer ,
privKey : key ,
muxers : muxerIDs ,
}
identity , err := NewIdentity (key )
if err != nil {
return nil , err
}
t .identity = identity
return t , nil
}
func (t *Transport ) SecureInbound (ctx context .Context , insecure net .Conn , p peer .ID ) (sec .SecureConn , error ) {
config , keyCh := t .identity .ConfigForPeer (p )
muxers := make ([]string , 0 , len (t .muxers ))
for _ , muxer := range t .muxers {
muxers = append (muxers , string (muxer ))
}
getConfigForClient := config .GetConfigForClient
config .GetConfigForClient = func (info *tls .ClientHelloInfo ) (*tls .Config , error ) {
alpnLoop :
for _ , proto := range info .SupportedProtos {
for _ , m := range muxers {
if m == proto {
config .NextProtos = []string {proto }
break alpnLoop
}
}
}
if getConfigForClient != nil {
return getConfigForClient (info )
}
return config , nil
}
config .NextProtos = append (muxers , config .NextProtos ...)
cs , err := t .handshake (ctx , tls .Server (insecure , config ), keyCh )
if err != nil {
addr , maErr := manet .FromNetAddr (insecure .RemoteAddr ())
if maErr == nil {
canonicallog .LogPeerStatus (100 , p , addr , "handshake_failure" , "tls" , "err" , err .Error())
}
insecure .Close ()
}
return cs , err
}
func (t *Transport ) SecureOutbound (ctx context .Context , insecure net .Conn , p peer .ID ) (sec .SecureConn , error ) {
config , keyCh := t .identity .ConfigForPeer (p )
muxers := make ([]string , 0 , len (t .muxers ))
for _ , muxer := range t .muxers {
muxers = append (muxers , (string )(muxer ))
}
config .NextProtos = append (muxers , config .NextProtos ...)
cs , err := t .handshake (ctx , tls .Client (insecure , config ), keyCh )
if err != nil {
insecure .Close ()
}
return cs , err
}
func (t *Transport ) handshake (ctx context .Context , tlsConn *tls .Conn , keyCh <-chan ci .PubKey ) (_sconn sec .SecureConn , err error ) {
defer func () {
if rerr := recover (); rerr != nil {
fmt .Fprintf (os .Stderr , "panic in TLS handshake: %s\n%s\n" , rerr , debug .Stack ())
err = fmt .Errorf ("panic in TLS handshake: %s" , rerr )
}
}()
if err := tlsConn .HandshakeContext (ctx ); err != nil {
return nil , err
}
var remotePubKey ci .PubKey
select {
case remotePubKey = <- keyCh :
default :
}
if remotePubKey == nil {
return nil , errors .New ("go-libp2p tls BUG: expected remote pub key to be set" )
}
return t .setupConn (tlsConn , remotePubKey )
}
func (t *Transport ) setupConn (tlsConn *tls .Conn , remotePubKey ci .PubKey ) (sec .SecureConn , error ) {
remotePeerID , err := peer .IDFromPublicKey (remotePubKey )
if err != nil {
return nil , err
}
nextProto := tlsConn .ConnectionState ().NegotiatedProtocol
if nextProto == "libp2p" {
nextProto = ""
}
return &conn {
Conn : tlsConn ,
localPeer : t .localPeer ,
remotePeer : remotePeerID ,
remotePubKey : remotePubKey ,
connectionState : network .ConnectionState {
StreamMultiplexer : protocol .ID (nextProto ),
UsedEarlyMuxerNegotiation : nextProto != "" ,
},
}, nil
}
func (t *Transport ) ID () protocol .ID {
return t .protocolID
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .