1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-07-01 19:45:24 +00:00
v2fly/transport/internet/system_listener.go

161 lines
4.8 KiB
Go
Raw Normal View History

2018-09-10 11:23:27 +00:00
package internet
import (
"context"
"os"
2020-10-29 07:30:38 +00:00
"runtime"
"strconv"
"strings"
2018-09-15 19:35:32 +00:00
"syscall"
2021-11-13 21:31:49 +00:00
"time"
2018-09-10 11:23:27 +00:00
2020-10-29 07:30:38 +00:00
"github.com/pires/go-proxyproto"
2021-02-16 20:31:50 +00:00
"github.com/v2fly/v2ray-core/v5/common/net"
"github.com/v2fly/v2ray-core/v5/common/session"
2018-09-10 11:23:27 +00:00
)
2021-05-19 21:28:52 +00:00
var effectiveListener = DefaultListener{}
2018-09-10 11:23:27 +00:00
2018-12-03 16:41:24 +00:00
type controller func(network, address string, fd uintptr) error
2018-09-10 11:23:27 +00:00
2018-12-03 16:41:24 +00:00
type DefaultListener struct {
2020-06-24 04:57:03 +00:00
controllers []controller
2018-12-03 16:41:24 +00:00
}
2018-09-10 11:23:27 +00:00
type combinedListener struct {
net.Listener
locker *FileLocker // for unix domain socket
}
func (l *combinedListener) Close() error {
if l.locker != nil {
l.locker.Release()
l.locker = nil
}
return l.Listener.Close()
}
2020-06-24 04:57:03 +00:00
func getControlFunc(ctx context.Context, sockopt *SocketConfig, controllers []controller) func(network, address string, c syscall.RawConn) error {
2018-12-03 16:41:24 +00:00
return func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
if sockopt != nil {
2018-09-15 19:35:32 +00:00
if err := applyInboundSocketOptions(network, fd, sockopt); err != nil {
newError("failed to apply socket options to incoming connection").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
2018-12-03 16:41:24 +00:00
}
setReusePort(fd) // nolint: staticcheck
2020-06-24 04:57:03 +00:00
for _, controller := range controllers {
2018-12-03 16:41:24 +00:00
if err := controller(network, address, fd); err != nil {
newError("failed to apply external controller").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
}
})
}
}
func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *SocketConfig) (net.Listener, error) {
2018-12-03 16:41:24 +00:00
var lc net.ListenConfig
2020-10-29 07:30:38 +00:00
var network, address string
// callback is called after the Listen function returns
// this is used to wrap the listener and do some post processing
callback := func(l net.Listener, err error) (net.Listener, error) {
return l, err
}
2020-10-29 07:30:38 +00:00
switch addr := addr.(type) {
case *net.TCPAddr:
network = addr.Network()
address = addr.String()
lc.Control = getControlFunc(ctx, sockopt, dl.controllers)
if sockopt != nil && (sockopt.TcpKeepAliveInterval != 0 || sockopt.TcpKeepAliveIdle != 0) {
2021-11-13 21:31:49 +00:00
lc.KeepAlive = time.Duration(-1)
}
2020-10-29 07:30:38 +00:00
case *net.UnixAddr:
lc.Control = nil
network = addr.Network()
address = addr.Name
if (runtime.GOOS == "linux" || runtime.GOOS == "android") && address[0] == '@' {
2020-10-29 07:30:38 +00:00
// linux abstract unix domain socket is lockfree
if len(address) > 1 && address[1] == '@' {
// but may need padding to work with haproxy
fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path))
copy(fullAddr, address[1:])
address = string(fullAddr)
}
} else {
// normal unix domain socket
var fileMode *os.FileMode
// parse file mode from address
if s := strings.Split(address, ","); len(s) == 2 {
fMode, err := strconv.ParseUint(s[1], 8, 32)
if err != nil {
return nil, newError("failed to parse file mode").Base(err)
}
address = s[0]
fm := os.FileMode(fMode)
fileMode = &fm
}
2020-10-29 07:30:38 +00:00
// normal unix domain socket needs lock
locker := &FileLocker{
path: address + ".lock",
}
if err := locker.Acquire(); err != nil {
2020-10-29 07:30:38 +00:00
return nil, err
}
// set file mode for unix domain socket when it is created
callback = func(l net.Listener, err error) (net.Listener, error) {
if err != nil {
locker.Release()
return nil, err
}
l = &combinedListener{Listener: l, locker: locker}
if fileMode == nil {
return l, err
}
if cerr := os.Chmod(address, *fileMode); cerr != nil {
// failed to set file mode, close the listener
l.Close()
return nil, newError("failed to set file mode for file: ", address).Base(cerr)
}
return l, err
}
2020-10-29 07:30:38 +00:00
}
}
2018-12-03 16:41:24 +00:00
l, err := lc.Listen(ctx, network, address)
l, err = callback(l, err)
if err == nil && sockopt != nil && sockopt.AcceptProxyProtocol {
2020-10-29 07:30:38 +00:00
policyFunc := func(upstream net.Addr) (proxyproto.Policy, error) { return proxyproto.REQUIRE, nil }
l = &proxyproto.Listener{Listener: l, Policy: policyFunc}
}
return l, err
2018-09-15 19:35:32 +00:00
}
2018-12-03 16:41:24 +00:00
func (dl *DefaultListener) ListenPacket(ctx context.Context, addr net.Addr, sockopt *SocketConfig) (net.PacketConn, error) {
2018-09-15 19:35:32 +00:00
var lc net.ListenConfig
lc.Control = getControlFunc(ctx, sockopt, dl.controllers)
2018-09-10 11:23:27 +00:00
2018-09-15 19:35:32 +00:00
return lc.ListenPacket(ctx, addr.Network(), addr.String())
2018-09-10 11:23:27 +00:00
}
2018-12-03 16:41:24 +00:00
// RegisterListenerController adds a controller to the effective system listener.
// The controller can be used to operate on file descriptors before they are put into use.
2018-12-03 22:39:21 +00:00
//
// v2ray:api:beta
2018-12-03 16:41:24 +00:00
func RegisterListenerController(controller func(network, address string, fd uintptr) error) error {
if controller == nil {
return newError("nil listener controller")
}
2020-06-24 04:57:03 +00:00
effectiveListener.controllers = append(effectiveListener.controllers, controller)
2018-12-03 16:41:24 +00:00
return nil
}
2021-06-24 15:28:08 +00:00
type SystemListener interface {
Listen(ctx context.Context, addr net.Addr, sockopt *SocketConfig) (net.Listener, error)
ListenPacket(ctx context.Context, addr net.Addr, sockopt *SocketConfig) (net.PacketConn, error)
}