mirror of
https://github.com/neilalexander/yggmail.git
synced 2026-05-05 19:46:27 +03:00
Use yggquic
This commit is contained in:
@@ -207,7 +207,7 @@ func main() {
|
||||
overlayServer.MaxRecipients = 50
|
||||
overlayServer.AuthDisabled = true
|
||||
|
||||
if err := overlayServer.Serve(transport.Listener()); err != nil {
|
||||
if err := overlayServer.Serve(transport); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
7
go.mod
7
go.mod
@@ -1,9 +1,8 @@
|
||||
module github.com/neilalexander/yggmail
|
||||
|
||||
go 1.20
|
||||
go 1.21.0
|
||||
|
||||
require (
|
||||
github.com/Arceliar/ironwood v0.0.0-20231104025256-ec84c695fc44
|
||||
github.com/emersion/go-imap v1.2.1
|
||||
github.com/emersion/go-imap-idle v0.0.0-20210907174914-db2568431445
|
||||
github.com/emersion/go-message v0.17.0
|
||||
@@ -12,14 +11,15 @@ require (
|
||||
github.com/fatih/color v1.15.0
|
||||
github.com/gologme/log v1.3.0
|
||||
github.com/mattn/go-sqlite3 v1.14.17
|
||||
github.com/quic-go/quic-go v0.40.0
|
||||
github.com/yggdrasil-network/yggdrasil-go v0.5.2
|
||||
github.com/yggdrasil-network/yggquic v0.0.0-20231126155506-966e783e183d
|
||||
go.uber.org/atomic v1.11.0
|
||||
golang.org/x/crypto v0.14.0
|
||||
golang.org/x/term v0.13.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Arceliar/ironwood v0.0.0-20231104025256-ec84c695fc44 // indirect
|
||||
github.com/Arceliar/phony v0.0.0-20220903101357-530938a4b13d // indirect
|
||||
github.com/bits-and-blooms/bitset v1.10.0 // indirect
|
||||
github.com/bits-and-blooms/bloom/v3 v3.6.0 // indirect
|
||||
@@ -31,6 +31,7 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.13.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
||||
github.com/quic-go/quic-go v0.40.0 // indirect
|
||||
github.com/stretchr/testify v1.7.0 // indirect
|
||||
go.uber.org/mock v0.3.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
|
||||
|
||||
8
go.sum
8
go.sum
@@ -33,12 +33,15 @@ github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/gologme/log v1.3.0 h1:l781G4dE+pbigClDSDzSaaYKtiueHCILUa/qSDsmHAo=
|
||||
github.com/gologme/log v1.3.0/go.mod h1:yKT+DvIPdDdDoPtqFrFxheooyVmoqi0BAsw+erN3wA4=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk=
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/hjson/hjson-go/v4 v4.3.1 h1:wfmDwHGxjzmYKXRFL0Qr9nonY/Xxe5y7IalwjlY7ekA=
|
||||
@@ -54,6 +57,7 @@ github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S
|
||||
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
|
||||
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
|
||||
@@ -69,6 +73,8 @@ github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg=
|
||||
github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
||||
github.com/yggdrasil-network/yggdrasil-go v0.5.2 h1:OEt5xi5iQDhK4yGjp0Bq9B0uZyQz741WIlorE8oVW1c=
|
||||
github.com/yggdrasil-network/yggdrasil-go v0.5.2/go.mod h1:oATGHx91oFqq3h3RKFU9qADFcO27TCf3CbQqrG2wzvU=
|
||||
github.com/yggdrasil-network/yggquic v0.0.0-20231126155506-966e783e183d h1:4sK8R6zUDo8jD7Rph5lMV3mhbIfAh60ihpfpB4kASJU=
|
||||
github.com/yggdrasil-network/yggquic v0.0.0-20231126155506-966e783e183d/go.mod h1:gv+bkfk5XSTignK4PJNOKCiwbQX5QA+TCxxYYOVkEpw=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
@@ -130,6 +136,8 @@ golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -123,7 +123,7 @@ func (q *Queue) run() {
|
||||
q.queues.Log.Println("Sending mail from", ref.From, "to", q.destination)
|
||||
|
||||
if err := func() error {
|
||||
conn, err := q.queues.Transport.Dial(q.destination)
|
||||
conn, err := q.queues.Transport.Dial("yggdrasil", q.destination)
|
||||
if err != nil {
|
||||
return fmt.Errorf("q.queues.Transport.Dial: %w", err)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,6 @@ import (
|
||||
)
|
||||
|
||||
type Transport interface {
|
||||
Dial(host string) (net.Conn, error)
|
||||
Listener() net.Listener
|
||||
Dial(network, host string) (net.Conn, error)
|
||||
net.Listener
|
||||
}
|
||||
|
||||
@@ -9,48 +9,21 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"regexp"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
iwt "github.com/Arceliar/ironwood/types"
|
||||
"github.com/fatih/color"
|
||||
gologme "github.com/gologme/log"
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/core"
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
|
||||
"github.com/yggdrasil-network/yggquic"
|
||||
)
|
||||
|
||||
type YggdrasilTransport struct {
|
||||
listener *quic.Listener
|
||||
yggdrasil net.PacketConn
|
||||
transport *quic.Transport
|
||||
tlsConfig *tls.Config
|
||||
quicConfig *quic.Config
|
||||
incoming chan *yggdrasilSession
|
||||
sessions sync.Map // string -> quic.Connection
|
||||
dials sync.Map // string -> *yggdrasilDial
|
||||
}
|
||||
|
||||
type yggdrasilSession struct {
|
||||
quic.Connection
|
||||
quic.Stream
|
||||
}
|
||||
|
||||
type yggdrasilDial struct {
|
||||
context.Context
|
||||
context.CancelFunc
|
||||
}
|
||||
|
||||
func NewYggdrasilTransport(log *log.Logger, sk ed25519.PrivateKey, pk ed25519.PublicKey, peers []string, mcast bool) (*YggdrasilTransport, error) {
|
||||
func NewYggdrasilTransport(log *log.Logger, sk ed25519.PrivateKey, pk ed25519.PublicKey, peers []string, mcast bool) (*yggquic.YggdrasilTransport, error) {
|
||||
yellow := color.New(color.FgYellow).SprintfFunc()
|
||||
glog := gologme.New(log.Writer(), fmt.Sprintf("[ %s ] ", yellow("Yggdrasil")), gologme.LstdFlags|gologme.Lmsgprefix)
|
||||
glog.EnableLevel("warn")
|
||||
@@ -96,140 +69,5 @@ func NewYggdrasilTransport(log *log.Logger, sk ed25519.PrivateKey, pk ed25519.Pu
|
||||
}
|
||||
}
|
||||
|
||||
tr := &YggdrasilTransport{
|
||||
tlsConfig: &tls.Config{
|
||||
ServerName: hex.EncodeToString(ygg.PublicKey()),
|
||||
Certificates: []tls.Certificate{
|
||||
*cfg.Certificate,
|
||||
},
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
quicConfig: &quic.Config{
|
||||
HandshakeIdleTimeout: time.Second * 5,
|
||||
MaxIdleTimeout: time.Second * 60,
|
||||
},
|
||||
transport: &quic.Transport{
|
||||
Conn: ygg,
|
||||
},
|
||||
yggdrasil: ygg,
|
||||
incoming: make(chan *yggdrasilSession, 1),
|
||||
}
|
||||
|
||||
if tr.listener, err = tr.transport.Listen(tr.tlsConfig, tr.quicConfig); err != nil {
|
||||
return nil, fmt.Errorf("quic.Listen: %w", err)
|
||||
}
|
||||
|
||||
go tr.connectionAcceptLoop()
|
||||
return tr, nil
|
||||
}
|
||||
|
||||
func (t *YggdrasilTransport) connectionAcceptLoop() {
|
||||
for {
|
||||
qc, err := t.listener.Accept(context.TODO())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
host := qc.RemoteAddr().String()
|
||||
if eqc, ok := t.sessions.LoadAndDelete(host); ok {
|
||||
eqc := eqc.(quic.Connection)
|
||||
_ = eqc.CloseWithError(0, "Connection replaced")
|
||||
}
|
||||
t.sessions.Store(host, qc)
|
||||
if dial, ok := t.dials.LoadAndDelete(host); ok {
|
||||
dial := dial.(*yggdrasilDial)
|
||||
dial.CancelFunc()
|
||||
}
|
||||
|
||||
go t.streamAcceptLoop(qc)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *YggdrasilTransport) streamAcceptLoop(qc quic.Connection) {
|
||||
host := qc.RemoteAddr().String()
|
||||
|
||||
defer qc.CloseWithError(0, "Timed out") // nolint:errcheck
|
||||
defer t.sessions.Delete(host)
|
||||
|
||||
for {
|
||||
qs, err := qc.AcceptStream(context.Background())
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
t.incoming <- &yggdrasilSession{qc, qs}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *YggdrasilTransport) Dial(host string) (net.Conn, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
defer cancel()
|
||||
var retry bool
|
||||
retry:
|
||||
qc, ok := t.sessions.Load(host)
|
||||
if !ok {
|
||||
if dial, ok := t.dials.Load(host); ok {
|
||||
<-dial.(*yggdrasilDial).Done()
|
||||
}
|
||||
if qc, ok = t.sessions.Load(host); !ok {
|
||||
dialctx, dialcancel := context.WithCancel(ctx)
|
||||
defer dialcancel()
|
||||
|
||||
t.dials.Store(host, &yggdrasilDial{dialctx, dialcancel})
|
||||
defer t.dials.Delete(host)
|
||||
|
||||
addr := make(iwt.Addr, ed25519.PublicKeySize)
|
||||
k, err := hex.DecodeString(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(addr, k)
|
||||
|
||||
if qc, err = t.transport.Dial(dialctx, addr, t.tlsConfig, t.quicConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
qc := qc.(quic.Connection)
|
||||
t.sessions.Store(host, qc)
|
||||
go t.streamAcceptLoop(qc)
|
||||
}
|
||||
}
|
||||
if qc == nil {
|
||||
return nil, net.ErrClosed
|
||||
} else {
|
||||
qc := qc.(quic.Connection)
|
||||
qs, err := qc.OpenStreamSync(ctx)
|
||||
if err != nil {
|
||||
if !retry {
|
||||
retry = true
|
||||
goto retry
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
// For some reason this is needed to kick the stream
|
||||
_, err = qs.Write([]byte(" "))
|
||||
return &yggdrasilSession{qc, qs}, err
|
||||
}
|
||||
}
|
||||
|
||||
func (t *YggdrasilTransport) Listener() net.Listener {
|
||||
return &yggdrasilListener{t}
|
||||
}
|
||||
|
||||
type yggdrasilListener struct {
|
||||
*YggdrasilTransport
|
||||
}
|
||||
|
||||
func (t *yggdrasilListener) Accept() (net.Conn, error) {
|
||||
return <-t.incoming, nil
|
||||
}
|
||||
|
||||
func (t *yggdrasilListener) Addr() net.Addr {
|
||||
return t.listener.Addr()
|
||||
}
|
||||
|
||||
func (t *yggdrasilListener) Close() error {
|
||||
if err := t.listener.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return t.yggdrasil.Close()
|
||||
return yggquic.New(ygg, *cfg.Certificate)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user