pkg/peernet/network.go (82 lines of code) (raw):

// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. package peernet import ( "crypto/tls" "net/http" "time" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls" ) const ( // defaultTimeout is the total HTTP timeout that should work with most peers to download 1 Mb of data. defaultTimeout = 90 * time.Second ) var ( // defaultHttpClient is the default HTTP client that does not authenticate peers. defaultHttpClient = &http.Client{ Timeout: defaultTimeout, } ) // Network provides the transport and HTTP clients for communicating with peers. type Network interface { // DefaultTLSConfig creates a default TLS config. // This config should not require client certificate verification. DefaultTLSConfig() *tls.Config // RoundTripperFor returns an HTTP round tripper which authenticates the given peer. // If pid is empty, the round tripper should work for any peer. RoundTripperFor(pid peer.ID) http.RoundTripper // HTTPClientFor returns an HTTP client which authenticates the given peer. // If pid is empty, the client should work for any peer. HTTPClientFor(pid peer.ID) *http.Client } type network struct { id *libp2ptls.Identity defaultTLSConfig *tls.Config defaultTransport *http.Transport } var _ Network = &network{} // DefaultTLSConfig creates a TLS config to use for this server. // This config does not require client certificate verification and is reusable. func (n *network) DefaultTLSConfig() *tls.Config { return n.defaultTLSConfig } // HTTPClientFor returns a single use HTTP client for the given peer. // The client does not verify the peer's certificate. func (n *network) HTTPClientFor(pid peer.ID) *http.Client { if pid == "" { return defaultHttpClient } return &http.Client{ Transport: n.transportFor(pid), Timeout: defaultTimeout, } } // RoundTripperFor returns a single use round tripper for the given peer. // The peer is expected to provide a valid certificate. // If pid is empty, the round tripper will work for any peer. func (n *network) RoundTripperFor(pid peer.ID) http.RoundTripper { if pid == "" { return n.defaultTransport } return n.transportFor(pid) } // transportFor returns a single use transport for outbound connection to the given peer. // The peer is expected to provide a valid certificate. // If pid is empty, the transport will work for any peer. func (n *network) transportFor(pid peer.ID) *http.Transport { if pid == "" { return n.defaultTransport } p2pTlsConfigForPeer, _ := n.id.ConfigForPeer(pid) transport := &http.Transport{ TLSClientConfig: &tls.Config{ Certificates: p2pTlsConfigForPeer.Certificates, ClientAuth: tls.RequireAndVerifyClientCert, VerifyPeerCertificate: p2pTlsConfigForPeer.VerifyPeerCertificate, InsecureSkipVerify: true, }, MaxConnsPerHost: 100, } return transport } // New creates a new network interface for communicating with peers. func New(h host.Host) (Network, error) { privKey := h.Peerstore().PrivKey(h.ID()) id, err := libp2ptls.NewIdentity(privKey) if err != nil { return nil, err } tlsConfig, _ := id.ConfigForPeer(peer.ID("")) defaultTLSConfig := &tls.Config{ Certificates: tlsConfig.Certificates, } defaultTransport := &http.Transport{ TLSClientConfig: defaultTLSConfig, MaxConnsPerHost: 100, } return &network{ id: id, defaultTLSConfig: defaultTLSConfig, defaultTransport: defaultTransport, }, nil }