87 lines
2.1 KiB
Go
87 lines
2.1 KiB
Go
package sbproxy
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/cipher"
|
|
"io"
|
|
"net"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/sagernet/sing-box/adapter"
|
|
M "github.com/sagernet/sing/common/metadata"
|
|
)
|
|
|
|
type javaTunnelConn struct {
|
|
h *Inbound
|
|
conn net.Conn
|
|
encrypter cipher.Stream
|
|
readBuf bytes.Buffer
|
|
readMutex sync.Mutex
|
|
readCond *sync.Cond
|
|
closed bool
|
|
}
|
|
|
|
func (c *javaTunnelConn) Read(b []byte) (int, error) {
|
|
c.readMutex.Lock()
|
|
defer c.readMutex.Unlock()
|
|
for c.readBuf.Len() == 0 && !c.closed {
|
|
c.readCond.Wait()
|
|
}
|
|
if c.closed && c.readBuf.Len() == 0 {
|
|
return 0, io.EOF
|
|
}
|
|
return c.readBuf.Read(b)
|
|
}
|
|
|
|
func (c *javaTunnelConn) Write(b []byte) (int, error) {
|
|
encrypted := make([]byte, len(b))
|
|
c.encrypter.XORKeyStream(encrypted, b)
|
|
err := c.h.sendJavaPluginMessage(c.conn, JavaChannelData, encrypted)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return len(b), nil
|
|
}
|
|
|
|
func (c *javaTunnelConn) Feed(data []byte) {
|
|
c.readMutex.Lock()
|
|
c.readBuf.Write(data)
|
|
c.readCond.Broadcast()
|
|
c.readMutex.Unlock()
|
|
}
|
|
|
|
func (c *javaTunnelConn) Close() error {
|
|
c.readMutex.Lock()
|
|
if !c.closed {
|
|
c.closed = true
|
|
c.readCond.Broadcast()
|
|
}
|
|
c.readMutex.Unlock()
|
|
return nil
|
|
}
|
|
|
|
func (c *javaTunnelConn) LocalAddr() net.Addr { return c.conn.LocalAddr() }
|
|
func (c *javaTunnelConn) RemoteAddr() net.Addr { return c.conn.RemoteAddr() }
|
|
func (c *javaTunnelConn) SetDeadline(t time.Time) error { return nil }
|
|
func (c *javaTunnelConn) SetReadDeadline(t time.Time) error { return nil }
|
|
func (c *javaTunnelConn) SetWriteDeadline(t time.Time) error { return nil }
|
|
|
|
func (h *Inbound) startJavaTunnel(ctx context.Context, conn net.Conn, username string, encrypter, decrypter cipher.Stream, inboundMetadata adapter.InboundContext) *javaTunnelConn {
|
|
tunnel := &javaTunnelConn{
|
|
h: h,
|
|
conn: conn,
|
|
encrypter: encrypter,
|
|
}
|
|
tunnel.readCond = sync.NewCond(&tunnel.readMutex)
|
|
|
|
metadata := M.Metadata{}
|
|
if h.options.Dest != "" {
|
|
metadata.Destination = M.ParseAddress(h.options.Dest)
|
|
}
|
|
|
|
go h.router.RouteConnectionEx(ctx, tunnel, inboundMetadata, metadata, nil)
|
|
return tunnel
|
|
}
|