mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-19 20:32:35 +02:00
94 lines
2.3 KiB
Go
94 lines
2.3 KiB
Go
package route
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
|
|
T "github.com/yusing/go-proxy/internal/proxy/fields"
|
|
U "github.com/yusing/go-proxy/internal/utils"
|
|
)
|
|
|
|
type (
|
|
RawStream struct {
|
|
*StreamRoute
|
|
|
|
listener net.Listener
|
|
targetAddr net.Addr
|
|
}
|
|
)
|
|
|
|
const (
|
|
streamBufferSize = 8192
|
|
streamDialTimeout = 5 * time.Second
|
|
)
|
|
|
|
func NewRawStreamRoute(base *StreamRoute) *RawStream {
|
|
return &RawStream{
|
|
StreamRoute: base,
|
|
}
|
|
}
|
|
|
|
func (route *RawStream) Setup() error {
|
|
var lcfg net.ListenConfig
|
|
var err error
|
|
|
|
switch route.Scheme.ListeningScheme {
|
|
case "tcp":
|
|
route.targetAddr, err = net.ResolveTCPAddr(string(route.Scheme.ProxyScheme), fmt.Sprintf("%s:%v", route.Host, route.Port.ProxyPort))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
tcpListener, err := lcfg.Listen(route.task.Context(), "tcp", fmt.Sprintf(":%v", route.Port.ListeningPort))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
route.Port.ListeningPort = T.Port(tcpListener.Addr().(*net.TCPAddr).Port)
|
|
route.listener = tcpListener
|
|
case "udp":
|
|
route.targetAddr, err = net.ResolveUDPAddr(string(route.Scheme.ProxyScheme), fmt.Sprintf("%s:%v", route.Host, route.Port.ProxyPort))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
udpListener, err := lcfg.ListenPacket(route.task.Context(), "udp", fmt.Sprintf(":%v", route.Port.ListeningPort))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
route.Port.ListeningPort = T.Port(udpListener.LocalAddr().(*net.UDPAddr).Port)
|
|
route.listener = newUDPListenerAdaptor(route.task.Context(), udpListener)
|
|
default:
|
|
return errors.New("invalid listening scheme: " + string(route.Scheme.ListeningScheme))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (route *RawStream) Accept() (net.Conn, error) {
|
|
if route.listener == nil {
|
|
return nil, errors.New("listener not yet set up")
|
|
}
|
|
return route.listener.Accept()
|
|
}
|
|
|
|
func (route *RawStream) Handle(c net.Conn) error {
|
|
clientConn := c.(net.Conn)
|
|
|
|
defer clientConn.Close()
|
|
route.task.OnCancel("close conn", func() { clientConn.Close() })
|
|
|
|
dialer := &net.Dialer{Timeout: streamDialTimeout}
|
|
|
|
serverAddr := fmt.Sprintf("%s:%v", route.Host, route.Port.ProxyPort)
|
|
serverConn, err := dialer.DialContext(route.task.Context(), string(route.Scheme.ProxyScheme), serverAddr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pipe := U.NewBidirectionalPipe(route.task.Context(), clientConn, serverConn)
|
|
return pipe.Start()
|
|
}
|
|
|
|
func (route *RawStream) Close() error {
|
|
return route.listener.Close()
|
|
}
|