08e9d996b6
Squashed commit of the following:
commit 6c2c48f862c1b6f8e741c57804282eceffe02487
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Fri Jul 10 16:28:09 2020 +0100
Add README.md
commit 5eeefdadf8e3881dd7a32559a92be49bd7ddaf47
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Fri Jul 10 10:18:50 2020 +0100
Fix wedge in federation sender
commit e2ebffbfba25cf82378393940a613ec32bfb909f
Merge: 0883ef88 abf26c12
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Fri Jul 10 09:51:23 2020 +0100
Merge branch 'master' into neilalexander/yggdrasil
commit 0883ef8870e340f2ae9a0c37ed939dc2ab9911f6
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Fri Jul 10 09:51:06 2020 +0100
Adjust timeouts
commit ba2d53199910f13b60cc892debe96a962e8c9acb
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Thu Jul 9 16:34:40 2020 +0100
Try to wake up from peers/sessions properly
commit 73f42eb494741ba5b0e0cef43654708e3c8eb399
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Thu Jul 9 15:43:38 2020 +0100
Use TransactionWriter to reduce database lock issues on SQLite
commit 08bfe63241a18c58c539c91b9f52edccda63a611
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Thu Jul 9 12:38:02 2020 +0100
Un-wedge federation
Squashed commit of the following:
commit aee933f8785e7a7998105f6090f514d18051a1bd
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Thu Jul 9 12:22:41 2020 +0100
Un-goroutine the goroutines
commit 478374e5d18a3056cac6682ef9095d41352d1295
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Thu Jul 9 12:09:31 2020 +0100
Reduce federation sender wedges
commit 40cc62c54d9e3a863868214c48b7c18e522a4772
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Thu Jul 9 10:02:52 2020 +0100
Handle switching in/out background more reliably
162 lines
4.2 KiB
Go
162 lines
4.2 KiB
Go
// Copyright 2020 The Matrix.org Foundation C.I.C.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package yggconn
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/hex"
|
|
"encoding/pem"
|
|
"errors"
|
|
"math/big"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/lucas-clemente/quic-go"
|
|
"github.com/matrix-org/gomatrixserverlib"
|
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
|
)
|
|
|
|
func (n *Node) listenFromYgg() {
|
|
var err error
|
|
n.listener, err = quic.Listen(
|
|
n.packetConn, // yggdrasil.PacketConn
|
|
n.tlsConfig, // TLS config
|
|
n.quicConfig, // QUIC config
|
|
)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
for {
|
|
session, err := n.listener.Accept(context.TODO())
|
|
if err != nil {
|
|
n.log.Println("n.listener.Accept:", err)
|
|
return
|
|
}
|
|
go n.listenFromQUIC(session)
|
|
}
|
|
}
|
|
|
|
func (n *Node) listenFromQUIC(session quic.Session) {
|
|
n.sessions.Store(session.RemoteAddr().String(), session)
|
|
defer n.sessions.Delete(session.RemoteAddr())
|
|
if n.NewSession != nil {
|
|
if len(session.ConnectionState().PeerCertificates) == 1 {
|
|
subjectName := session.ConnectionState().PeerCertificates[0].Subject.CommonName
|
|
go n.NewSession(gomatrixserverlib.ServerName(subjectName))
|
|
}
|
|
}
|
|
for {
|
|
st, err := session.AcceptStream(context.TODO())
|
|
if err != nil {
|
|
n.log.Println("session.AcceptStream:", err)
|
|
return
|
|
}
|
|
n.incoming <- QUICStream{st, session}
|
|
}
|
|
}
|
|
|
|
// Implements net.Listener
|
|
func (n *Node) Accept() (net.Conn, error) {
|
|
return <-n.incoming, nil
|
|
}
|
|
|
|
// Implements net.Listener
|
|
func (n *Node) Close() error {
|
|
return n.listener.Close()
|
|
}
|
|
|
|
// Implements net.Listener
|
|
func (n *Node) Addr() net.Addr {
|
|
return n.listener.Addr()
|
|
}
|
|
|
|
// Implements http.Transport.Dial
|
|
func (n *Node) Dial(network, address string) (net.Conn, error) {
|
|
return n.DialContext(context.TODO(), network, address)
|
|
}
|
|
|
|
// Implements http.Transport.DialContext
|
|
func (n *Node) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
|
s, ok1 := n.sessions.Load(address)
|
|
session, ok2 := s.(quic.Session)
|
|
if !ok1 || !ok2 || (ok1 && ok2 && session.ConnectionState().HandshakeComplete) {
|
|
dest, err := hex.DecodeString(address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(dest) != crypto.BoxPubKeyLen {
|
|
return nil, errors.New("invalid key length supplied")
|
|
}
|
|
var pubKey crypto.BoxPubKey
|
|
copy(pubKey[:], dest)
|
|
|
|
session, err = quic.Dial(
|
|
n.packetConn, // yggdrasil.PacketConn
|
|
&pubKey, // dial address
|
|
address, // dial SNI
|
|
n.tlsConfig, // TLS config
|
|
n.quicConfig, // QUIC config
|
|
)
|
|
if err != nil {
|
|
n.log.Println("n.dialer.DialContext:", err)
|
|
return nil, err
|
|
}
|
|
go n.listenFromQUIC(session)
|
|
}
|
|
st, err := session.OpenStream()
|
|
if err != nil {
|
|
n.log.Println("session.OpenStream:", err)
|
|
return nil, err
|
|
}
|
|
return QUICStream{st, session}, nil
|
|
}
|
|
|
|
func (n *Node) generateTLSConfig() *tls.Config {
|
|
key, err := rsa.GenerateKey(rand.Reader, 1024)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
template := x509.Certificate{
|
|
Subject: pkix.Name{
|
|
CommonName: n.DerivedServerName(),
|
|
},
|
|
SerialNumber: big.NewInt(1),
|
|
NotAfter: time.Now().Add(time.Hour * 24 * 365),
|
|
DNSNames: []string{n.DerivedSessionName()},
|
|
}
|
|
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
|
|
if err != nil {
|
|
panic(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 {
|
|
panic(err)
|
|
}
|
|
return &tls.Config{
|
|
Certificates: []tls.Certificate{tlsCert},
|
|
NextProtos: []string{"quic-matrix-ygg"},
|
|
InsecureSkipVerify: true,
|
|
}
|
|
}
|