Add systemd socket activation support

This commit is contained in:
z5ljl 2023-07-30 06:31:34 +00:00
parent 018ee8921e
commit 15ffe148d4
4 changed files with 74 additions and 9 deletions

View File

@ -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)
}

View File

@ -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())

View File

@ -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
}

View File

@ -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:"-"`