listener.go 2.03 KB
Newer Older
Marten Seemann's avatar
Marten Seemann committed
1
2
3
package libp2pquic

import (
4
5
6
7
8
9
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"encoding/pem"
	"math/big"
Marten Seemann's avatar
Marten Seemann committed
10
11
12
	"net"

	tpt "github.com/libp2p/go-libp2p-transport"
13
	quic "github.com/lucas-clemente/quic-go"
Marten Seemann's avatar
Marten Seemann committed
14
	ma "github.com/multiformats/go-multiaddr"
Marten Seemann's avatar
Marten Seemann committed
15
	manet "github.com/multiformats/go-multiaddr-net"
Marten Seemann's avatar
Marten Seemann committed
16
17
)

Marten Seemann's avatar
Marten Seemann committed
18
19
type listener struct {
	laddr        ma.Multiaddr
20
	quicListener quic.Listener
Marten Seemann's avatar
Marten Seemann committed
21
22
23
24

	transport tpt.Transport
}

25
26
27
28
var _ tpt.Listener = &listener{}

func newListener(laddr ma.Multiaddr, t tpt.Transport) (*listener, error) {
	_, host, err := manet.DialArgs(laddr)
Marten Seemann's avatar
Marten Seemann committed
29
30
31
	if err != nil {
		return nil, err
	}
32
33
34
35
36
	tlsConf, err := generateTLSConfig()
	if err != nil {
		return nil, err
	}
	qln, err := quic.ListenAddr(host, tlsConf, nil)
Marten Seemann's avatar
Marten Seemann committed
37
38
39
	if err != nil {
		return nil, err
	}
40
41
42
43
	addr, err := quicMultiAddress(qln.Addr())
	if err != nil {
		return nil, err
	}
44

Marten Seemann's avatar
Marten Seemann committed
45
	return &listener{
46
		laddr:        addr,
Marten Seemann's avatar
Marten Seemann committed
47
		quicListener: qln,
48
		transport:    t,
Marten Seemann's avatar
Marten Seemann committed
49
50
	}, nil
}
Marten Seemann's avatar
Marten Seemann committed
51
52

func (l *listener) Accept() (tpt.Conn, error) {
53
	sess, err := l.quicListener.Accept()
Marten Seemann's avatar
Marten Seemann committed
54
55
56
	if err != nil {
		return nil, err
	}
57
	return newQuicConn(sess, l.transport)
Marten Seemann's avatar
Marten Seemann committed
58
59
60
}

func (l *listener) Close() error {
Marten Seemann's avatar
Marten Seemann committed
61
	return l.quicListener.Close()
Marten Seemann's avatar
Marten Seemann committed
62
63
64
}

func (l *listener) Addr() net.Addr {
Marten Seemann's avatar
Marten Seemann committed
65
	return l.quicListener.Addr()
Marten Seemann's avatar
Marten Seemann committed
66
67
68
}

func (l *listener) Multiaddr() ma.Multiaddr {
Marten Seemann's avatar
Marten Seemann committed
69
	return l.laddr
Marten Seemann's avatar
Marten Seemann committed
70
}
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

// Generate a bare-bones TLS config for the server.
// The client doesn't verify the certificate yet.
func generateTLSConfig() (*tls.Config, error) {
	key, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return nil, err
	}
	template := x509.Certificate{SerialNumber: big.NewInt(1)}
	certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
	if err != nil {
		return nil, err
	}
	keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
	certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
	tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
	if err != nil {
		return nil, err
	}
	return &tls.Config{Certificates: []tls.Certificate{tlsCert}}, nil
}