mirror of
https://github.com/SagerNet/sing-tun.git
synced 2025-03-31 10:27:39 +03:00
83 lines
2.1 KiB
Go
83 lines
2.1 KiB
Go
//go:build linux
|
|
|
|
package tun
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net"
|
|
"net/netip"
|
|
"time"
|
|
|
|
"github.com/sagernet/sing/common/atomic"
|
|
"github.com/sagernet/sing/common/control"
|
|
E "github.com/sagernet/sing/common/exceptions"
|
|
"github.com/sagernet/sing/common/logger"
|
|
M "github.com/sagernet/sing/common/metadata"
|
|
N "github.com/sagernet/sing/common/network"
|
|
)
|
|
|
|
type redirectServer struct {
|
|
ctx context.Context
|
|
handler N.TCPConnectionHandlerEx
|
|
logger logger.Logger
|
|
listenAddr netip.Addr
|
|
listener *net.TCPListener
|
|
inShutdown atomic.Bool
|
|
}
|
|
|
|
func newRedirectServer(ctx context.Context, handler N.TCPConnectionHandlerEx, logger logger.Logger, listenAddr netip.Addr) *redirectServer {
|
|
return &redirectServer{
|
|
ctx: ctx,
|
|
handler: handler,
|
|
logger: logger,
|
|
listenAddr: listenAddr,
|
|
}
|
|
}
|
|
|
|
func (s *redirectServer) Start() error {
|
|
var listenConfig net.ListenConfig
|
|
// listenConfig.KeepAlive = C.TCPKeepAliveInitial
|
|
listenConfig.KeepAlive = 10 * time.Minute
|
|
listener, err := listenConfig.Listen(s.ctx, M.NetworkFromNetAddr("tcp", s.listenAddr), M.SocksaddrFrom(s.listenAddr, 0).String())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.listener = listener.(*net.TCPListener)
|
|
go s.loopIn()
|
|
return nil
|
|
}
|
|
|
|
func (s *redirectServer) Close() error {
|
|
s.inShutdown.Store(true)
|
|
return s.listener.Close()
|
|
}
|
|
|
|
func (s *redirectServer) loopIn() {
|
|
for {
|
|
conn, err := s.listener.AcceptTCP()
|
|
if err != nil {
|
|
var netError net.Error
|
|
//nolint:staticcheck
|
|
if errors.As(err, &netError) && netError.Temporary() {
|
|
s.logger.Error(err)
|
|
continue
|
|
}
|
|
if s.inShutdown.Load() && E.IsClosed(err) {
|
|
return
|
|
}
|
|
s.listener.Close()
|
|
s.logger.Error("serve error: ", err)
|
|
continue
|
|
}
|
|
source := M.SocksaddrFromNet(conn.RemoteAddr()).Unwrap()
|
|
destination, err := control.GetOriginalDestination(conn)
|
|
if err != nil {
|
|
_ = conn.SetLinger(0)
|
|
_ = conn.Close()
|
|
s.logger.Error("process redirect connection from ", source, ": invalid connection: ", err)
|
|
continue
|
|
}
|
|
go s.handler.NewConnectionEx(s.ctx, conn, source, M.SocksaddrFromNetIP(destination).Unwrap(), nil)
|
|
}
|
|
}
|