Update On Sat Apr 6 20:26:16 CEST 2024

This commit is contained in:
github-action[bot]
2024-04-06 20:26:16 +02:00
parent e3388d2bef
commit e2eecadc74
113 changed files with 2052 additions and 1463 deletions

View File

@@ -9,7 +9,6 @@ require (
github.com/getsentry/sentry-go v0.27.0
github.com/go-ping/ping v1.1.0
github.com/gobwas/ws v1.3.2
github.com/gorilla/mux v1.8.1
github.com/labstack/echo/v4 v4.11.4
github.com/prometheus/client_golang v1.19.0
github.com/prometheus/common v0.48.0

View File

@@ -110,8 +110,6 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=

View File

@@ -57,6 +57,10 @@ func (r *Config) Validate() error {
if len(r.TCPRemotes) == 0 && len(r.UDPRemotes) == 0 {
return errors.New("both tcp and udp remotes are empty")
}
if len(r.UDPRemotes) > 0 {
zap.S().Warn("UDP RELAY WAS DISABLED FOR NOW, THIS FEATURE WILL BE AVAILABLE IN THE FUTURE")
}
return nil
}
@@ -111,7 +115,7 @@ func (r *Config) defaultLabel() string {
func (r *Config) Adjust() error {
if r.Label == "" {
r.Label = r.defaultLabel()
zap.S().Warnf("label is empty, set default label:%s", r.Label)
zap.S().Debugf("label is empty, set default label:%s", r.Label)
}
return nil
}

View File

@@ -7,22 +7,19 @@ import (
"github.com/Ehco1996/ehco/internal/cmgr"
"github.com/Ehco1996/ehco/internal/constant"
"github.com/Ehco1996/ehco/internal/metrics"
"github.com/Ehco1996/ehco/internal/relay/conf"
"github.com/Ehco1996/ehco/internal/transporter"
)
type Relay struct {
Name string // unique name for all relay\
Name string // unique name for all relay
TransportType string
ListenType string
TP transporter.RelayTransporter
TP transporter.RelayTransporter
LocalTCPAddr *net.TCPAddr
LocalUDPAddr *net.UDPAddr
closeTcpF func() error
closeUdpF func() error
closeTcpF func() error
cfg *conf.Config
l *zap.SugaredLogger
@@ -33,10 +30,6 @@ func NewRelay(cfg *conf.Config, connMgr cmgr.Cmgr) (*Relay, error) {
if err != nil {
return nil, err
}
localUDPAddr, err := net.ResolveUDPAddr("udp", cfg.Listen)
if err != nil {
return nil, err
}
r := &Relay{
cfg: cfg,
@@ -44,7 +37,6 @@ func NewRelay(cfg *conf.Config, connMgr cmgr.Cmgr) (*Relay, error) {
Name: cfg.Label,
LocalTCPAddr: localTCPAddr,
LocalUDPAddr: localUDPAddr,
ListenType: cfg.ListenType,
TransportType: cfg.TransportType,
TP: transporter.NewRelayTransporter(cfg, connMgr),
@@ -80,23 +72,11 @@ func (r *Relay) ListenAndServe() error {
}()
}
}
if len(r.cfg.UDPRemotes) > 0 {
go func() {
errCh <- r.RunLocalUDPServer()
}()
}
return <-errCh
}
func (r *Relay) Close() {
r.l.Infof("Close relay label: %s", r.Name)
if r.closeUdpF != nil {
err := r.closeUdpF()
if err != nil {
r.l.Errorf(err.Error())
}
}
if r.closeTcpF != nil {
err := r.closeTcpF()
if err != nil {
@@ -106,63 +86,19 @@ func (r *Relay) Close() {
}
func (r *Relay) RunLocalTCPServer() error {
lis, err := net.ListenTCP("tcp", r.LocalTCPAddr)
rawServer, err := transporter.NewRawServer(r.LocalTCPAddr.String(), r.TP)
if err != nil {
return err
}
defer lis.Close() //nolint: errcheck
r.closeTcpF = func() error {
return lis.Close()
return rawServer.Close()
}
r.l.Infof("Start TCP relay Server: %s", r.Name)
for {
c, err := lis.AcceptTCP()
if err != nil {
return err
}
go func(c net.Conn) {
remote := r.TP.GetRemote()
metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Inc()
defer metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Dec()
if err := r.TP.HandleTCPConn(c, remote); err != nil {
r.l.Errorf("HandleTCPConn meet error tp:%s from:%s to:%s err:%s",
r.TransportType,
c.RemoteAddr(), remote.Address, err)
}
}(c)
}
}
func (r *Relay) RunLocalUDPServer() error {
lis, err := net.ListenUDP("udp", r.LocalUDPAddr)
if err != nil {
return err
}
defer lis.Close() //nolint: errcheck
r.closeUdpF = func() error {
return lis.Close()
}
r.l.Infof("Start UDP relay Server: %s", r.Name)
buf := transporter.BufferPool.Get()
defer transporter.BufferPool.Put(buf)
for {
n, addr, err := lis.ReadFromUDP(buf)
if err != nil {
return err
}
bc := r.TP.GetOrCreateBufferCh(addr)
bc.Ch <- buf[0:n]
if !bc.Handled.Load() {
bc.Handled.Store(true)
go r.TP.HandleUDPConn(bc.UDPAddr, lis)
}
}
return rawServer.ListenAndServe()
}
func (r *Relay) RunLocalMTCPServer() error {
tp := r.TP.(*transporter.Raw)
tp := r.TP.(*transporter.RawClient)
mTCPServer := transporter.NewMTCPServer(r.LocalTCPAddr.String(), tp, r.l.Named("MTCPServer"))
r.closeTcpF = func() error {
return mTCPServer.Close()
@@ -172,7 +108,7 @@ func (r *Relay) RunLocalMTCPServer() error {
}
func (r *Relay) RunLocalWSServer() error {
tp := r.TP.(*transporter.Raw)
tp := r.TP.(*transporter.RawClient)
wsServer := transporter.NewWSServer(r.LocalTCPAddr.String(), tp, r.l.Named("WSServer"))
r.closeTcpF = func() error {
return wsServer.Close()
@@ -182,8 +118,8 @@ func (r *Relay) RunLocalWSServer() error {
}
func (r *Relay) RunLocalWSSServer() error {
tp := r.TP.(*transporter.Raw)
wssServer := transporter.NewWSSServer(r.LocalTCPAddr.String(), tp, r.l.Named("NewWSSServer"))
tp := r.TP.(*transporter.RawClient)
wssServer := transporter.NewWSSServer(r.LocalTCPAddr.String(), tp, r.l.Named("WSSServer"))
r.closeTcpF = func() error {
return wssServer.Close()
}
@@ -192,7 +128,7 @@ func (r *Relay) RunLocalWSSServer() error {
}
func (r *Relay) RunLocalMWSSServer() error {
tp := r.TP.(*transporter.Raw)
tp := r.TP.(*transporter.RawClient)
mwssServer := transporter.NewMWSSServer(r.LocalTCPAddr.String(), tp, r.l.Named("MWSSServer"))
r.closeTcpF = func() error {
return mwssServer.Close()

View File

@@ -1,10 +1,6 @@
package transporter
import (
"net"
"go.uber.org/atomic"
"github.com/Ehco1996/ehco/internal/constant"
)
@@ -51,17 +47,3 @@ func (bp *BytePool) Put(b []byte) {
// buffer didn't go back into pool, just discard
}
}
type BufferCh struct {
Ch chan []byte
Handled atomic.Bool
UDPAddr *net.UDPAddr
}
func newudpBufferCh(clientUDPAddr *net.UDPAddr) *BufferCh {
return &BufferCh{
Ch: make(chan []byte, 100),
Handled: atomic.Bool{},
UDPAddr: clientUDPAddr,
}
}

View File

@@ -12,11 +12,6 @@ import (
// RelayTransporter
type RelayTransporter interface {
// UDP相关
GetOrCreateBufferCh(uaddr *net.UDPAddr) *BufferCh
HandleUDPConn(uaddr *net.UDPAddr, local *net.UDPConn)
// TCP相关
dialRemote(remote *lb.Node) (net.Conn, error)
HandleTCPConn(c net.Conn, remote *lb.Node) error
GetRemote() *lb.Node
@@ -30,34 +25,18 @@ func NewRelayTransporter(cfg *conf.Config, connMgr cmgr.Cmgr) RelayTransporter {
Label: fmt.Sprintf("%s-%s", cfg.Label, addr),
}
}
udpNodeList := make([]*lb.Node, len(cfg.UDPRemotes))
for idx, addr := range cfg.UDPRemotes {
udpNodeList[idx] = &lb.Node{
Address: addr,
Label: fmt.Sprintf("%s-%s", cfg.Label, addr),
}
}
raw := newRaw(cfg.Label, lb.NewRoundRobin(tcpNodeList), lb.NewRoundRobin(udpNodeList), connMgr)
raw := newRawClient(cfg.Label, lb.NewRoundRobin(tcpNodeList), connMgr)
switch cfg.TransportType {
case constant.Transport_RAW:
return raw
case constant.Transport_WS:
return &Ws{Raw: raw}
return newWsClient(raw)
case constant.Transport_WSS:
return &Wss{Raw: raw}
return newWSSClient(raw)
case constant.Transport_MWSS:
logger := raw.l.Named("MWSSClient")
mWSSClient := NewMWSSClient(logger)
mwss := &Mwss{mtp: NewSmuxTransporter(logger, mWSSClient.InitNewSession)}
mwss.Raw = raw
return mwss
return newMWSSClient(raw)
case constant.Transport_MTCP:
logger := raw.l.Named("MTCPClient")
mTCPClient := NewMTCPClient(logger)
mtcp := &MTCP{mtp: NewSmuxTransporter(logger, mTCPClient.InitNewSession)}
mtcp.Raw = raw
return mtcp
return newMTCPClient(raw)
}
return nil
}

View File

@@ -56,7 +56,8 @@ func (sm *SessionWithMetrics) canCloseSession(remoteAddr string, l *zap.SugaredL
return true
}
func NewSmuxTransporter(l *zap.SugaredLogger,
func NewSmuxTransporter(
l *zap.SugaredLogger,
initSessionF func(ctx context.Context, addr string) (*smux.Session, error),
) *smuxTransporter {
tr := &smuxTransporter{

View File

@@ -2,9 +2,7 @@
package transporter
import (
"context"
"net"
"sync"
"time"
"go.uber.org/zap"
@@ -16,134 +14,28 @@ import (
"github.com/Ehco1996/ehco/pkg/lb"
)
type Raw struct {
type RawClient struct {
relayLabel string
// TCP
cmgr cmgr.Cmgr
tCPRemotes lb.RoundRobin
// UDP todo refactor udp relay
udpmu sync.Mutex
uDPRemotes lb.RoundRobin
uDPBufferChMap map[string]*BufferCh
l *zap.SugaredLogger
l *zap.SugaredLogger
}
func newRaw(
relayLabel string,
tcpRemotes, udpRemotes lb.RoundRobin,
cmgr cmgr.Cmgr,
) *Raw {
r := &Raw{
cmgr: cmgr,
relayLabel: relayLabel,
tCPRemotes: tcpRemotes,
uDPRemotes: udpRemotes,
uDPBufferChMap: make(map[string]*BufferCh),
l: zap.S().Named(relayLabel),
func newRawClient(relayLabel string, tcpRemotes lb.RoundRobin, cmgr cmgr.Cmgr) *RawClient {
r := &RawClient{
cmgr: cmgr,
relayLabel: relayLabel,
tCPRemotes: tcpRemotes,
l: zap.S().Named(relayLabel),
}
return r
}
func (raw *Raw) GetOrCreateBufferCh(uaddr *net.UDPAddr) *BufferCh {
raw.udpmu.Lock()
defer raw.udpmu.Unlock()
bc, found := raw.uDPBufferChMap[uaddr.String()]
if !found {
bc := newudpBufferCh(uaddr)
raw.uDPBufferChMap[uaddr.String()] = bc
return bc
}
return bc
}
func (raw *Raw) HandleUDPConn(uaddr *net.UDPAddr, local *net.UDPConn) {
remote := raw.uDPRemotes.Next()
metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_UDP).Inc()
defer metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_UDP).Dec()
bc := raw.GetOrCreateBufferCh(uaddr)
remoteUdp, _ := net.ResolveUDPAddr("udp", remote.Address)
rc, err := net.DialUDP("udp", nil, remoteUdp)
if err != nil {
raw.l.Error(err)
return
}
defer func() {
rc.Close()
raw.udpmu.Lock()
delete(raw.uDPBufferChMap, uaddr.String())
raw.udpmu.Unlock()
}()
raw.l.Infof("HandleUDPConn from %s to %s", local.LocalAddr().String(), remote.Label)
buf := BufferPool.Get()
defer BufferPool.Put(buf)
var wg sync.WaitGroup
wg.Add(1)
ctx, cancel := context.WithCancel(context.Background())
go func() {
defer wg.Done()
defer cancel()
for {
_ = rc.SetDeadline(time.Now().Add(constant.IdleTimeOut))
i, err := rc.Read(buf)
if err != nil {
raw.l.Error(err)
break
}
metrics.NetWorkTransmitBytes.WithLabelValues(
remote.Label, metrics.METRIC_CONN_TYPE_UDP, metrics.METRIC_CONN_FLOW_READ,
).Add(float64(i))
if _, err := local.WriteToUDP(buf[0:i], uaddr); err != nil {
raw.l.Error(err)
break
}
metrics.NetWorkTransmitBytes.WithLabelValues(
remote.Label, metrics.METRIC_CONN_TYPE_UDP, metrics.METRIC_CONN_FLOW_WRITE,
).Add(float64(i))
}
}()
wg.Add(1)
go func() {
defer wg.Done()
select {
case <-ctx.Done():
return
case b := <-bc.Ch:
// read from local udp listener ch
metrics.NetWorkTransmitBytes.WithLabelValues(
remote.Label, metrics.METRIC_CONN_TYPE_UDP, metrics.METRIC_CONN_FLOW_READ,
).Add(float64(len(b)))
_ = rc.SetDeadline(time.Now().Add(constant.IdleTimeOut))
if _, err := rc.Write(b); err != nil {
raw.l.Error(err)
return
}
metrics.NetWorkTransmitBytes.WithLabelValues(
remote.Label, metrics.METRIC_CONN_TYPE_UDP, metrics.METRIC_CONN_FLOW_WRITE,
).Add(float64(len(b)))
}
}()
wg.Wait()
}
func (raw *Raw) GetRemote() *lb.Node {
func (raw *RawClient) GetRemote() *lb.Node {
return raw.tCPRemotes.Next()
}
func (raw *Raw) dialRemote(remote *lb.Node) (net.Conn, error) {
func (raw *RawClient) dialRemote(remote *lb.Node) (net.Conn, error) {
t1 := time.Now()
d := net.Dialer{Timeout: constant.DialTimeOut}
rc, err := d.Dial("tcp", remote.Address)
@@ -156,8 +48,7 @@ func (raw *Raw) dialRemote(remote *lb.Node) (net.Conn, error) {
return rc, nil
}
func (raw *Raw) HandleTCPConn(c net.Conn, remote *lb.Node) error {
// todo refactor metrics to server
func (raw *RawClient) HandleTCPConn(c net.Conn, remote *lb.Node) error {
metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Inc()
defer metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Dec()
@@ -172,3 +63,44 @@ func (raw *Raw) HandleTCPConn(c net.Conn, remote *lb.Node) error {
defer raw.cmgr.RemoveConnection(relayConn)
return relayConn.Transport(remote.Label)
}
type RawServer struct {
rtp RelayTransporter
lis *net.TCPListener
l *zap.SugaredLogger
}
func NewRawServer(addr string, rtp RelayTransporter) (*RawServer, error) {
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
if err != nil {
return nil, err
}
lis, err := net.ListenTCP("tcp", tcpAddr)
if err != nil {
return nil, err
}
return &RawServer{lis: lis, rtp: rtp}, nil
}
func (s *RawServer) Close() error {
return s.lis.Close()
}
func (s *RawServer) ListenAndServe() error {
for {
c, err := s.lis.AcceptTCP()
if err != nil {
return err
}
go func(c net.Conn) {
remote := s.rtp.GetRemote()
metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Inc()
defer metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Dec()
if err := s.rtp.HandleTCPConn(c, remote); err != nil {
s.l.Errorf("HandleTCPConn meet error tp:%s from:%s to:%s err:%s",
s.rtp,
c.RemoteAddr(), remote.Address, err)
}
}(c)
}
}

View File

@@ -15,12 +15,37 @@ import (
"github.com/Ehco1996/ehco/pkg/lb"
)
type MTCP struct {
*Raw
mtp *smuxTransporter
type MTCPClient struct {
*RawClient
dialer *net.Dialer
mtp *smuxTransporter
}
func (s *MTCP) dialRemote(remote *lb.Node) (net.Conn, error) {
func newMTCPClient(raw *RawClient) *MTCPClient {
dialer := &net.Dialer{Timeout: constant.DialTimeOut}
c := &MTCPClient{dialer: dialer, RawClient: raw}
mtp := NewSmuxTransporter(raw.l.Named("mtcp"), c.initNewSession)
c.mtp = mtp
return c
}
func (c *MTCPClient) initNewSession(ctx context.Context, addr string) (*smux.Session, error) {
rc, err := c.dialer.Dial("tcp", addr)
if err != nil {
return nil, err
}
// stream multiplex
cfg := smux.DefaultConfig()
cfg.KeepAliveDisabled = true
session, err := smux.Client(rc, cfg)
if err != nil {
return nil, err
}
c.l.Infof("init new session to: %s", rc.RemoteAddr())
return session, nil
}
func (s *MTCPClient) dialRemote(remote *lb.Node) (net.Conn, error) {
t1 := time.Now()
mtcpc, err := s.mtp.Dial(context.TODO(), remote.Address)
if err != nil {
@@ -32,7 +57,7 @@ func (s *MTCP) dialRemote(remote *lb.Node) (net.Conn, error) {
return mtcpc, nil
}
func (s *MTCP) HandleTCPConn(c net.Conn, remote *lb.Node) error {
func (s *MTCPClient) HandleTCPConn(c net.Conn, remote *lb.Node) error {
clonedRemote := remote.Clone()
mtcpc, err := s.dialRemote(clonedRemote)
if err != nil {
@@ -46,7 +71,7 @@ func (s *MTCP) HandleTCPConn(c net.Conn, remote *lb.Node) error {
}
type MTCPServer struct {
raw *Raw
raw *RawClient
listenAddr string
listener net.Listener
l *zap.SugaredLogger
@@ -55,7 +80,7 @@ type MTCPServer struct {
connChan chan net.Conn
}
func NewMTCPServer(listenAddr string, raw *Raw, l *zap.SugaredLogger) *MTCPServer {
func NewMTCPServer(listenAddr string, raw *RawClient, l *zap.SugaredLogger) *MTCPServer {
return &MTCPServer{
l: l,
raw: raw,
@@ -138,28 +163,3 @@ func (s *MTCPServer) ListenAndServe() error {
func (s *MTCPServer) Close() error {
return s.listener.Close()
}
type MTCPClient struct {
l *zap.SugaredLogger
dialer *net.Dialer
}
func NewMTCPClient(l *zap.SugaredLogger) *MTCPClient {
return &MTCPClient{l: l, dialer: &net.Dialer{Timeout: constant.DialTimeOut}}
}
func (c *MTCPClient) InitNewSession(ctx context.Context, addr string) (*smux.Session, error) {
rc, err := c.dialer.Dial("tcp", addr)
if err != nil {
return nil, err
}
// stream multiplex
cfg := smux.DefaultConfig()
cfg.KeepAliveDisabled = true
session, err := smux.Client(rc, cfg)
if err != nil {
return nil, err
}
c.l.Infof("init new session to: %s", rc.RemoteAddr())
return session, nil
}

View File

@@ -7,7 +7,7 @@ import (
"time"
"github.com/gobwas/ws"
"github.com/gorilla/mux"
"github.com/labstack/echo/v4"
"go.uber.org/zap"
"github.com/Ehco1996/ehco/internal/conn"
@@ -17,14 +17,18 @@ import (
"github.com/Ehco1996/ehco/pkg/lb"
)
type Ws struct {
*Raw
type WsClient struct {
*RawClient
}
func (s *Ws) dialRemote(remote *lb.Node) (net.Conn, error) {
func newWsClient(raw *RawClient) *WsClient {
return &WsClient{RawClient: raw}
}
func (s *WsClient) dialRemote(remote *lb.Node) (net.Conn, error) {
t1 := time.Now()
d := ws.Dialer{Timeout: constant.DialTimeOut}
wsc, _, _, err := d.Dial(context.TODO(), remote.Address+"/ws/")
wsc, _, _, err := d.Dial(context.TODO(), remote.Address+"/handshake/")
if err != nil {
return nil, err
}
@@ -34,7 +38,7 @@ func (s *Ws) dialRemote(remote *lb.Node) (net.Conn, error) {
return wsc, nil
}
func (s *Ws) HandleTCPConn(c net.Conn, remote *lb.Node) error {
func (s *WsClient) HandleTCPConn(c net.Conn, remote *lb.Node) error {
clonedRemote := remote.Clone()
wsc, err := s.dialRemote(clonedRemote)
if err != nil {
@@ -50,30 +54,32 @@ func (s *Ws) HandleTCPConn(c net.Conn, remote *lb.Node) error {
}
type WSServer struct {
raw *Raw
l *zap.SugaredLogger
raw *RawClient
e *echo.Echo
httpServer *http.Server
l *zap.SugaredLogger
}
func NewWSServer(listenAddr string, raw *Raw, l *zap.SugaredLogger) *WSServer {
s := &WSServer{raw: raw, l: l}
mux := mux.NewRouter()
mux.HandleFunc("/", web.MakeIndexF())
mux.HandleFunc("/ws/", s.HandleRequest)
s.httpServer = &http.Server{
Addr: listenAddr,
ReadHeaderTimeout: 30 * time.Second,
Handler: mux,
func NewWSServer(listenAddr string, raw *RawClient, l *zap.SugaredLogger) *WSServer {
s := &WSServer{
l: l,
raw: raw,
httpServer: &http.Server{Addr: listenAddr, ReadHeaderTimeout: 30 * time.Second},
}
e := web.NewEchoServer()
e.GET("/", echo.WrapHandler(web.MakeIndexF()))
e.GET("/handshake/", echo.WrapHandler(http.HandlerFunc(s.HandleRequest)))
s.e = e
s.httpServer.Handler = e
return s
}
func (s *WSServer) ListenAndServe() error {
return s.httpServer.ListenAndServe()
return s.e.StartServer(s.httpServer)
}
func (s *WSServer) Close() error {
return s.httpServer.Close()
return s.e.Close()
}
func (s *WSServer) HandleRequest(w http.ResponseWriter, req *http.Request) {
@@ -81,7 +87,6 @@ func (s *WSServer) HandleRequest(w http.ResponseWriter, req *http.Request) {
if err != nil {
return
}
remote := s.raw.GetRemote()
if err := s.raw.HandleTCPConn(wsc, remote); err != nil {
s.l.Errorf("HandleTCPConn meet error from:%s to:%s err:%s", wsc.RemoteAddr(), remote.Address, err)

View File

@@ -3,31 +3,32 @@ package transporter
import (
"context"
"crypto/tls"
"net"
"net/http"
"time"
"github.com/gobwas/ws"
"github.com/gorilla/mux"
"go.uber.org/zap"
"github.com/Ehco1996/ehco/internal/conn"
"github.com/Ehco1996/ehco/internal/metrics"
mytls "github.com/Ehco1996/ehco/internal/tls"
"github.com/Ehco1996/ehco/internal/web"
"github.com/Ehco1996/ehco/pkg/lb"
)
type Wss struct {
*Raw
type WSSClient struct {
WsClient
}
func (s *Wss) dialRemote(remote *lb.Node) (net.Conn, error) {
func newWSSClient(raw *RawClient) *WSSClient {
return &WSSClient{*newWsClient(raw)}
}
func (s *WSSClient) dialRemote(remote *lb.Node) (net.Conn, error) {
t1 := time.Now()
d := ws.Dialer{TLSConfig: mytls.DefaultTLSConfig}
wssc, _, _, err := d.Dial(context.TODO(), remote.Address+"/wss/")
wssc, _, _, err := d.Dial(context.TODO(), remote.Address+"/handshake/")
if err != nil {
println("wss called", err.Error())
return nil, err
}
latency := time.Since(t1)
@@ -36,7 +37,7 @@ func (s *Wss) dialRemote(remote *lb.Node) (net.Conn, error) {
return wssc, nil
}
func (s *Wss) HandleTCPConn(c net.Conn, remote *lb.Node) error {
func (s *WSSClient) HandleTCPConn(c net.Conn, remote *lb.Node) error {
clonedRemote := remote.Clone()
wssc, err := s.dialRemote(clonedRemote)
if err != nil {
@@ -50,48 +51,14 @@ func (s *Wss) HandleTCPConn(c net.Conn, remote *lb.Node) error {
return relayConn.Transport(remote.Label)
}
type WSSServer struct {
raw *Raw
l *zap.SugaredLogger
httpServer *http.Server
}
type WSSServer struct{ WSServer }
func NewWSSServer(listenAddr string, raw *Raw, l *zap.SugaredLogger) *WSSServer {
s := &WSSServer{raw: raw, l: l}
mux := mux.NewRouter()
mux.HandleFunc("/", web.MakeIndexF())
mux.HandleFunc("/wss/", s.HandleRequest)
s.httpServer = &http.Server{
Handler: mux,
Addr: listenAddr,
ReadHeaderTimeout: 30 * time.Second,
TLSConfig: mytls.DefaultTLSConfig,
}
return s
func NewWSSServer(listenAddr string, raw *RawClient, l *zap.SugaredLogger) *WSSServer {
wsServer := NewWSServer(listenAddr, raw, l)
return &WSSServer{WSServer: *wsServer}
}
func (s *WSSServer) ListenAndServe() error {
lis, err := net.Listen("tcp", s.httpServer.Addr)
if err != nil {
return err
}
defer lis.Close()
return s.httpServer.Serve(tls.NewListener(lis, s.httpServer.TLSConfig))
}
func (s *WSSServer) Close() error {
return s.httpServer.Close()
}
func (s *WSSServer) HandleRequest(w http.ResponseWriter, req *http.Request) {
wsc, _, _, err := ws.UpgradeHTTP(req, w)
if err != nil {
return
}
remote := s.raw.GetRemote()
if err := s.raw.HandleTCPConn(wsc, remote); err != nil {
s.l.Errorf("HandleTCPConn meet error from:%s to:%s err:%s", wsc.RemoteAddr(), remote.Address, err)
}
s.httpServer.TLSConfig = mytls.DefaultTLSConfig
return s.WSServer.ListenAndServe()
}

View File

@@ -9,7 +9,7 @@ import (
"time"
"github.com/gobwas/ws"
"github.com/gorilla/mux"
"github.com/labstack/echo/v4"
"github.com/xtaci/smux"
"go.uber.org/zap"
@@ -21,14 +21,39 @@ import (
"github.com/Ehco1996/ehco/pkg/lb"
)
type Mwss struct {
*Raw
mtp *smuxTransporter
type MWSSClient struct {
*RawClient
dialer *ws.Dialer
mtp *smuxTransporter
}
func (s *Mwss) dialRemote(remote *lb.Node) (net.Conn, error) {
func newMWSSClient(raw *RawClient) *MWSSClient {
dialer := &ws.Dialer{TLSConfig: mytls.DefaultTLSConfig, Timeout: constant.DialTimeOut}
c := &MWSSClient{dialer: dialer, RawClient: raw}
mtp := NewSmuxTransporter(raw.l.Named("mwss"), c.initNewSession)
c.mtp = mtp
return c
}
func (c *MWSSClient) initNewSession(ctx context.Context, addr string) (*smux.Session, error) {
rc, _, _, err := c.dialer.Dial(ctx, addr)
if err != nil {
return nil, err
}
// stream multiplex
cfg := smux.DefaultConfig()
cfg.KeepAliveDisabled = true
session, err := smux.Client(rc, cfg)
if err != nil {
return nil, err
}
c.l.Infof("init new session to: %s", rc.RemoteAddr())
return session, nil
}
func (s *MWSSClient) dialRemote(remote *lb.Node) (net.Conn, error) {
t1 := time.Now()
mwssc, err := s.mtp.Dial(context.TODO(), remote.Address+"/mwss/")
mwssc, err := s.mtp.Dial(context.TODO(), remote.Address+"/handshake/")
if err != nil {
return nil, err
}
@@ -39,7 +64,7 @@ func (s *Mwss) dialRemote(remote *lb.Node) (net.Conn, error) {
return mwssc, nil
}
func (s *Mwss) HandleTCPConn(c net.Conn, remote *lb.Node) error {
func (s *MWSSClient) HandleTCPConn(c net.Conn, remote *lb.Node) error {
clonedRemote := remote.Clone()
mwsc, err := s.dialRemote(clonedRemote)
if err != nil {
@@ -53,7 +78,7 @@ func (s *Mwss) HandleTCPConn(c net.Conn, remote *lb.Node) error {
}
type MWSSServer struct {
raw *Raw
raw *RawClient
httpServer *http.Server
l *zap.SugaredLogger
@@ -61,7 +86,7 @@ type MWSSServer struct {
errChan chan error
}
func NewMWSSServer(listenAddr string, raw *Raw, l *zap.SugaredLogger) *MWSSServer {
func NewMWSSServer(listenAddr string, raw *RawClient, l *zap.SugaredLogger) *MWSSServer {
s := &MWSSServer{
raw: raw,
l: l,
@@ -69,12 +94,12 @@ func NewMWSSServer(listenAddr string, raw *Raw, l *zap.SugaredLogger) *MWSSServe
connChan: make(chan net.Conn, 1024),
}
mux := mux.NewRouter()
mux.Handle("/", web.MakeIndexF())
mux.Handle("/mwss/", http.HandlerFunc(s.HandleRequest))
e := web.NewEchoServer()
e.GET("/", echo.WrapHandler(web.MakeIndexF()))
e.GET("/handshake/", echo.WrapHandler(http.HandlerFunc(s.HandleRequest)))
s.httpServer = &http.Server{
Addr: listenAddr,
Handler: mux,
Handler: e,
TLSConfig: mytls.DefaultTLSConfig,
ReadHeaderTimeout: 30 * time.Second,
}
@@ -154,32 +179,3 @@ func (s *MWSSServer) Accept() (conn net.Conn, err error) {
func (s *MWSSServer) Close() error {
return s.httpServer.Close()
}
type MWSSClient struct {
dialer *ws.Dialer
l *zap.SugaredLogger
}
func NewMWSSClient(l *zap.SugaredLogger) *MWSSClient {
dialer := &ws.Dialer{TLSConfig: mytls.DefaultTLSConfig, Timeout: constant.DialTimeOut}
return &MWSSClient{
dialer: dialer,
l: l,
}
}
func (c *MWSSClient) InitNewSession(ctx context.Context, addr string) (*smux.Session, error) {
rc, _, _, err := c.dialer.Dial(ctx, addr)
if err != nil {
return nil, err
}
// stream multiplex
cfg := smux.DefaultConfig()
cfg.KeepAliveDisabled = true
session, err := smux.Client(rc, cfg)
if err != nil {
return nil, err
}
c.l.Infof("init new session to: %s", rc.RemoteAddr())
return session, nil
}

View File

@@ -49,10 +49,7 @@ func NewServer(cfg *config.Config, relayReloader reloader.Reloader, connMgr cmgr
for _, temp := range templates.Templates() {
l.Debug("template name: ", temp.Name())
}
e := echo.New()
e.Debug = true
e.HidePort = true
e.HideBanner = true
e := NewEchoServer()
e.Use(NginxLogMiddleware(l))
e.Renderer = &echoTemplate{templates: templates}
if cfg.WebToken != "" {

View File

@@ -0,0 +1,11 @@
package web
import "github.com/labstack/echo/v4"
func NewEchoServer() *echo.Echo {
e := echo.New()
e.Debug = true
e.HidePort = true
e.HideBanner = true
return e
}

View File

@@ -148,11 +148,11 @@ func TestRelayOverRaw(t *testing.T) {
t.Log("test tcp done!")
// test udp
res = echo.SendUdpMsg(msg, RAW_LISTEN)
if string(res) != string(msg) {
t.Fatal(res)
}
t.Log("test udp done!")
// res = echo.SendUdpMsg(msg, RAW_LISTEN)
// if string(res) != string(msg) {
// t.Fatal(res)
// }
// t.Log("test udp done!")
}
func TestRelayWithDeadline(t *testing.T) {