GoDoxy/internal/route/raw.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()
}