Swarm.DialAddr -> Transport.Dial -> Tpt.Upgrader.UpgradeOutbound
call stack:
github.com/libp2p/go-libp2p-secio.(*secureSession).runHandshake at protocol.go:119
github.com/libp2p/go-libp2p-secio.newSecureSession at protocol.go:95
github.com/libp2p/go-libp2p-secio.(*Transport).SecureOutbound at transport.go:40
github.com/libp2p/go-conn-security-multistream.(*SSMuxer).SecureOutbound at ssms.go:56
github.com/libp2p/go-libp2p-transport-upgrader.(*Upgrader).setupSecurity at upgrader.go:108
github.com/libp2p/go-libp2p-transport-upgrader.(*Upgrader).upgrade at upgrader.go:86
github.com/libp2p/go-libp2p-transport-upgrader.(*Upgrader).UpgradeOutbound at upgrader.go:57
github.com/libp2p/go-tcp-transport.(*TcpTransport).Dial at tcp.go:107
github.com/libp2p/go-libp2p-swarm.(*Swarm).dialAddr at swarm_dial.go:462
github.com/libp2p/go-libp2p-swarm.(*Swarm).dialAddr-fm at swarm_dial.go:450
github.com/libp2p/go-libp2p-swarm.(*dialLimiter).executeDial at limiter.go:218
runtime.goexit at asm_amd64.s:1357
- Async stack trace
github.com/libp2p/go-libp2p-swarm.(*dialLimiter).addCheckFdLimit at limiter.go:168
After dialing, try to upgrade…
func (t *TcpTransport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (transport.CapableConn, error) {
conn, err := t.maDial(ctx, raddr)
if err != nil {
return nil, err
}
// Set linger to 0 so we never get stuck in the TIME-WAIT state. When
// linger is 0, connections are _reset_ instead of closed with a FIN.
// This means we can immediately reuse the 5-tuple and reconnect.
tryLinger(conn, 0)
return t.Upgrader.UpgradeOutbound(ctx, t, conn, p)
}
In upgrade, upgrader might Protect and then setupSecurity/setupMuxer
func (u *Upgrader) upgrade(ctx context.Context, t transport.Transport, maconn manet.Conn, p peer.ID) (transport.CapableConn, error) {
if u.Filters != nil && u.Filters.AddrBlocked(maconn.RemoteMultiaddr()) {
log.Debugf("blocked connection from %s", maconn.RemoteMultiaddr())
maconn.Close()
return nil, fmt.Errorf("blocked connection from %s", maconn.RemoteMultiaddr())
}
var conn net.Conn = maconn
if u.Protector != nil {
pconn, err := u.Protector.Protect(conn)
if err != nil {
conn.Close()
return nil, fmt.Errorf("failed to setup private network protector: %s", err)
}
conn = pconn
} else if pnet.ForcePrivateNetwork {
log.Error("tried to dial with no Private Network Protector but usage" +
" of Private Networks is forced by the enviroment")
return nil, pnet.ErrNotInPrivateNetwork
}
sconn, err := u.setupSecurity(ctx, conn, p)
if err != nil {
conn.Close()
return nil, fmt.Errorf("failed to negotiate security protocol: %s", err)
}
smconn, err := u.setupMuxer(ctx, sconn, p)
if err != nil {
sconn.Close()
return nil, fmt.Errorf("failed to negotiate security stream multiplexer: %s", err)
}
return &transportConn{
MuxedConn: smconn,
ConnMultiaddrs: maconn,
ConnSecurity: sconn,
transport: t,
}, nil
}
In the end, newSecureSession then runHandshake to negotiate security parameters:
func (s *secureSession) runHandshake(ctx context.Context) error {
defer log.EventBegin(ctx, "secureHandshake", s).Done()
result := make(chan error, 1)
go func() {
// do *not* close the channel (will look like a success).
result <- s.runHandshakeSync()
}()
var err error
select {
case <-ctx.Done():
err = ctx.Err()
// State unknown. We *have* to close this.
s.insecure.Close()
// Wait for the handshake to return.
<-result
case err = <-result:
}
return err
}
// SupportedExchanges is the list of supported ECDH curves
var SupportedExchanges = DefaultSupportedExchanges
const DefaultSupportedExchanges = "P-256,P-384,P-521"
// SupportedCiphers is the list of supported Ciphers
var SupportedCiphers = DefaultSupportedCiphers
const DefaultSupportedCiphers = "AES-256,AES-128"
// SupportedHashes is the list of supported Hashes
var SupportedHashes = DefaultSupportedHashes
const DefaultSupportedHashes = "SHA256,SHA512"
mux.Session.send -> secureSession.Write -> insecureConn.Write
func (w *etmWriter) WriteMsg(b []byte) error {
w.Lock()
defer w.Unlock()
// encrypt.
buf := pool.Get(4 + len(b) + w.mac.Size())
defer pool.Put(buf)
data := buf[4 : 4+len(b)]
w.str.XORKeyStream(data, b)
// log.Debugf("ENC plaintext (%d): %s %v", len(b), b, b)
// log.Debugf("ENC ciphertext (%d): %s %v", len(data), data, data)
// then, mac.
if _, err := w.mac.Write(data); err != nil {
return err
}
// Sum appends.
data = w.mac.Sum(data)
w.mac.Reset()
binary.BigEndian.PutUint32(buf[:4], uint32(len(data)))
_, err := w.w.Write(buf) // Write through insecure conn
return err
}
Callstack
github.com/libp2p/go-libp2p-secio.(*etmWriter).WriteMsg at rw.go:42
github.com/libp2p/go-libp2p-secio.(*etmWriter).Write at rw.go:34
<autogenerated>:2
<autogenerated>:2
github.com/libp2p/go-yamux.(*Session).sendLoop at session.go:472
github.com/libp2p/go-yamux.(*Session).send at session.go:384
runtime.goexit at asm_amd64.s:1357
- Async stack trace
github.com/libp2p/go-yamux.newSession at session.go:130
func (r *etmReader) ReadMsg() ([]byte, error) {
r.Lock()
defer r.Unlock()
msg, err := r.msg.ReadMsg()
if err != nil {
return nil, err
}
n, err := r.macCheckThenDecrypt(msg)
if err != nil {
r.msg.ReleaseMsg(msg)
return nil, err
}
return msg[:n], nil
}