sing-tun/redirect_server.go

89 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"
)
const ProtocolRedirect = "redirect"
type redirectServer struct {
ctx context.Context
handler Handler
logger logger.Logger
listenAddr netip.Addr
listener *net.TCPListener
inShutdown atomic.Bool
}
func newRedirectServer(ctx context.Context, handler Handler, 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
//goland:noinspection GoDeprecation
//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
}
var metadata M.Metadata
metadata.Protocol = ProtocolRedirect
metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr()).Unwrap()
destination, err := control.GetOriginalDestination(conn)
if err != nil {
_ = conn.SetLinger(0)
_ = conn.Close()
s.logger.Error("process connection from ", metadata.Source, ": invalid connection: ", err)
continue
}
metadata.Destination = M.SocksaddrFromNetIP(destination).Unwrap()
go s.handler.NewConnection(s.ctx, conn, metadata)
}
}