From 15ffe148d493226ade721514ce8dfb4111cf2b9b Mon Sep 17 00:00:00 2001 From: z5ljl <110731994+z5ljl@users.noreply.github.com> Date: Sun, 30 Jul 2023 06:31:34 +0000 Subject: [PATCH] Add systemd socket activation support --- inbound/default.go | 22 ++++++++++++++++++++++ inbound/default_tcp.go | 22 ++++++++++++++++++---- inbound/default_udp.go | 38 +++++++++++++++++++++++++++++++++----- option/inbound.go | 1 + 4 files changed, 74 insertions(+), 9 deletions(-) diff --git a/inbound/default.go b/inbound/default.go index 28f8cee2..bfde00ce 100644 --- a/inbound/default.go +++ b/inbound/default.go @@ -14,6 +14,8 @@ import ( E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" + + "golang.org/x/sys/unix" ) var _ adapter.Inbound = (*myInboundAdapter)(nil) @@ -38,6 +40,8 @@ type myInboundAdapter struct { // internal + tcpFd int + udpFd int tcpListener net.Listener udpConn *net.UDPConn udpAddr M.Socksaddr @@ -111,6 +115,24 @@ func (a *myInboundAdapter) Close() error { )) } +func (a *myInboundAdapter) initFds() { + if len(a.listenOptions.Fds) != 0 && a.tcpFd == 0 && a.udpFd == 0 { + for _, fd := range a.listenOptions.Fds { + sotype, err := unix.GetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_TYPE) + if err != nil { + a.logger.Error("fd:", fd, " get type error: ", err) + continue + } + switch sotype { + case unix.SOCK_STREAM: + a.tcpFd = fd + case unix.SOCK_DGRAM: + a.udpFd = fd + } + } + } +} + func (a *myInboundAdapter) upstreamHandler(metadata adapter.InboundContext) adapter.UpstreamHandlerAdapter { return adapter.NewUpstreamHandler(metadata, a.newConnection, a.streamPacketConnection, a) } diff --git a/inbound/default_tcp.go b/inbound/default_tcp.go index 238762dc..42f70600 100644 --- a/inbound/default_tcp.go +++ b/inbound/default_tcp.go @@ -3,6 +3,7 @@ package inbound import ( "context" "net" + "os" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/proxyproto" @@ -15,12 +16,25 @@ import ( func (a *myInboundAdapter) ListenTCP() (net.Listener, error) { var err error - bindAddr := M.SocksaddrFrom(a.listenOptions.Listen.Build(), a.listenOptions.ListenPort) var tcpListener net.Listener - if !a.listenOptions.TCPFastOpen { - tcpListener, err = net.ListenTCP(M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.TCPAddr()) + a.initFds() + if a.tcpFd != 0 { + if a.listenOptions.TCPFastOpen { + err = tfo.SetTFOListener(uintptr(a.tcpFd)) + if err != nil { + a.logger.Warn("fd:", a.tcpFd, " set tfo error: ", err) + } + } + f := os.NewFile(uintptr(a.tcpFd), "") + tcpListener, err = net.FileListener(f) + f.Close() } else { - tcpListener, err = tfo.ListenTCP(M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.TCPAddr()) + bindAddr := M.SocksaddrFrom(a.listenOptions.Listen.Build(), a.listenOptions.ListenPort) + if !a.listenOptions.TCPFastOpen { + tcpListener, err = net.ListenTCP(M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.TCPAddr()) + } else { + tcpListener, err = tfo.ListenTCP(M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.TCPAddr()) + } } if err == nil { a.logger.Info("tcp server started at ", tcpListener.Addr()) diff --git a/inbound/default_udp.go b/inbound/default_udp.go index 8e39471a..c7ab7d5f 100644 --- a/inbound/default_udp.go +++ b/inbound/default_udp.go @@ -12,21 +12,49 @@ import ( E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" + + "golang.org/x/sys/unix" ) func (a *myInboundAdapter) ListenUDP() (net.PacketConn, error) { - bindAddr := M.SocksaddrFrom(a.listenOptions.Listen.Build(), a.listenOptions.ListenPort) - var lc net.ListenConfig + var bindAddr M.Socksaddr var udpFragment bool if a.listenOptions.UDPFragment != nil { udpFragment = *a.listenOptions.UDPFragment } else { udpFragment = a.listenOptions.UDPFragmentDefault } - if !udpFragment { - lc.Control = control.Append(lc.Control, control.DisableUDPFragment()) + var udpConn net.PacketConn + var err error + a.initFds() + if a.udpFd != 0 { + if !udpFragment { + if err := unix.SetsockoptInt(a.udpFd, unix.IPPROTO_IP, unix.IP_MTU_DISCOVER, unix.IP_PMTUDISC_DO); err != nil { + a.logger.Warn("SETSOCKOPT IP_MTU_DISCOVER IP_PMTUDISC_DO: ", err) + } + sa, err := unix.Getsockname(a.udpFd) + if err == nil { + if _, isIpv6 := sa.(*unix.SockaddrInet6); isIpv6 { + if err := unix.SetsockoptInt(a.udpFd, unix.IPPROTO_IPV6, unix.IPV6_MTU_DISCOVER, unix.IP_PMTUDISC_DO); err != nil { + a.logger.Warn("SETSOCKOPT IPV6_MTU_DISCOVER IP_PMTUDISC_DO", err) + } + } + } else { + a.logger.Error("fd:", a.udpFd, " get addr error: ", err) + } + } + f := os.NewFile(uintptr(a.udpFd), "") + udpConn, err = net.FilePacketConn(f) + f.Close() + bindAddr = M.SocksaddrFromNet(udpConn.LocalAddr()) + } else { + var lc net.ListenConfig + bindAddr = M.SocksaddrFrom(a.listenOptions.Listen.Build(), a.listenOptions.ListenPort) + if !udpFragment { + lc.Control = control.Append(lc.Control, control.DisableUDPFragment()) + } + udpConn, err = lc.ListenPacket(a.ctx, M.NetworkFromNetAddr(N.NetworkUDP, bindAddr.Addr), bindAddr.String()) } - udpConn, err := lc.ListenPacket(a.ctx, M.NetworkFromNetAddr(N.NetworkUDP, bindAddr.Addr), bindAddr.String()) if err != nil { return nil, err } diff --git a/option/inbound.go b/option/inbound.go index 9533532b..9aec9496 100644 --- a/option/inbound.go +++ b/option/inbound.go @@ -119,6 +119,7 @@ type InboundOptions struct { type ListenOptions struct { Listen *ListenAddress `json:"listen,omitempty"` ListenPort uint16 `json:"listen_port,omitempty"` + Fds []int `json:"fds,omitempty"` TCPFastOpen bool `json:"tcp_fast_open,omitempty"` UDPFragment *bool `json:"udp_fragment,omitempty"` UDPFragmentDefault bool `json:"-"`