Skip to content

نظام المستمع

يوفر نظام المستمع تنفيذات مشتركة لمستمعات TCP وUDP تستخدمها جميع بروتوكولات الوارد.

المصدر: common/listener/

مستمع TCP

go
type Listener struct {
    ctx          context.Context
    logger       logger.ContextLogger
    network      []string
    listenAddr   netip.AddrPort
    tcpListener  *net.TCPListener
    handler      adapter.ConnectionHandlerEx
    threadUnsafe bool
    // TLS، بروتوكول البروكسي، إلخ.
}

الميزات

  • عنوان الاستماع: الربط بعنوان IPv4/IPv6 ومنفذ محدد
  • خيارات TCP: SO_REUSEADDR، TCP_FASTOPEN، TCP_DEFER_ACCEPT
  • بروتوكول البروكسي: دعم بروتوكول بروكسي HAProxy الإصدار 1/2
  • آمن/غير آمن للخيوط: وضع goroutine واحد اختياري للبروتوكولات التي تحتاجه

حلقة القبول

go
func (l *Listener) loopTCPIn() {
    for {
        conn, err := l.tcpListener.AcceptTCP()
        if err != nil {
            return
        }
        // تطبيق بروتوكول البروكسي إذا كان معداً
        // التغليف بـ TLS إذا كان معداً
        go l.handler.NewConnectionEx(ctx, conn, metadata, onClose)
    }
}

مستمع UDP

go
type UDPListener struct {
    ctx        context.Context
    logger     logger.ContextLogger
    listenAddr netip.AddrPort
    udpConn    *net.UDPConn
    handler    adapter.PacketHandlerEx
    // معالج OOB لـ TProxy
}

الميزات

  • بيانات OOB: لـ TProxy، تحمل البيانات خارج النطاق الوجهة الأصلية
  • معالج الحزم: يمرر الحزم الفردية مع عنوان المصدر

حلقة القراءة

go
func (l *UDPListener) loopUDPIn() {
    buffer := buf.NewPacket()
    for {
        n, addr, err := l.udpConn.ReadFromUDPAddrPort(buffer.FreeBytes())
        if err != nil {
            return
        }
        buffer.Truncate(n)
        l.handler.NewPacketEx(buffer, M.SocksaddrFromNetIP(addr))
        buffer = buf.NewPacket()
    }
}

خيارات الاستماع المشتركة

go
type ListenOptions struct {
    Listen         ListenAddress
    ListenPort     uint16
    ListenFields   ListenFields
    TCPFastOpen    bool
    TCPMultiPath   bool
    UDPFragment    *bool
    UDPTimeout     Duration
    ProxyProtocol  bool
    ProxyProtocolAcceptNoHeader bool
    Detour         string
    InboundOptions
}

type InboundOptions struct {
    SniffEnabled              bool
    SniffOverrideDestination  bool
    SniffTimeout              Duration
    DomainStrategy            DomainStrategy
}

دعم بروتوكول البروكسي

عند تعيين proxy_protocol: true، يغلّف المستمع الاتصالات بتحليل بروتوكول البروكسي:

go
import proxyproto "github.com/pires/go-proxyproto"

listener = &proxyproto.Listener{
    Listener: tcpListener,
    Policy: func(upstream net.Addr) (proxyproto.Policy, error) {
        if acceptNoHeader {
            return proxyproto.USE, nil
        }
        return proxyproto.REQUIRE, nil
    },
}

يستخرج هذا عنوان العميل الأصلي من خلف موازنات التحميل/البروكسيات العكسية.