From 46f28a9de971f41b3afc3ae49701d0715a17b2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 6 Jul 2022 14:45:56 +0800 Subject: [PATCH] Add protect path dialer option --- option/outbound.go | 1 + outbound/dialer/default.go | 4 +++ outbound/dialer/protect.go | 47 +++++++++++++++++++++++++++++++++ outbound/dialer/protect_stub.go | 9 +++++++ 4 files changed, 61 insertions(+) create mode 100644 outbound/dialer/protect.go create mode 100644 outbound/dialer/protect_stub.go diff --git a/option/outbound.go b/option/outbound.go index 91ccaf7d..8f8b1945 100644 --- a/option/outbound.go +++ b/option/outbound.go @@ -67,6 +67,7 @@ func (h *Outbound) UnmarshalJSON(bytes []byte) error { type DialerOptions struct { Detour string `json:"detour,omitempty"` BindInterface string `json:"bind_interface,omitempty"` + ProtectPath string `json:"protect_path,omitempty"` RoutingMark int `json:"routing_mark,omitempty"` ReuseAddr bool `json:"reuse_addr,omitempty"` ConnectTimeout int `json:"connect_timeout,omitempty"` diff --git a/outbound/dialer/default.go b/outbound/dialer/default.go index 8e11ca1e..75752a7a 100644 --- a/outbound/dialer/default.go +++ b/outbound/dialer/default.go @@ -32,6 +32,10 @@ func newDefault(options option.DialerOptions) N.Dialer { if options.ReuseAddr { listener.Control = control.Append(listener.Control, control.ReuseAddr()) } + if options.ProtectPath != "" { + dialer.Control = control.Append(dialer.Control, ProtectPath(options.ProtectPath)) + listener.Control = control.Append(listener.Control, ProtectPath(options.ProtectPath)) + } if options.ConnectTimeout != 0 { dialer.Timeout = time.Duration(options.ConnectTimeout) * time.Second } diff --git a/outbound/dialer/protect.go b/outbound/dialer/protect.go new file mode 100644 index 00000000..de789b55 --- /dev/null +++ b/outbound/dialer/protect.go @@ -0,0 +1,47 @@ +//go:build android || with_protect + +package dialer + +import ( + "syscall" + + "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/control" + E "github.com/sagernet/sing/common/exceptions" +) + +func sendAncillaryFileDescriptors(protectPath string, fileDescriptors []int) error { + socket, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_STREAM, 0) + if err != nil { + return E.Cause(err, "open protect socket") + } + defer syscall.Close(socket) + err = syscall.Connect(socket, &syscall.SockaddrUnix{Name: protectPath}) + if err != nil { + return E.Cause(err, "connect protect path") + } + oob := syscall.UnixRights(fileDescriptors...) + dummy := []byte{1} + err = syscall.Sendmsg(socket, dummy, oob, nil, 0) + if err != nil { + return err + } + n, err := syscall.Read(socket, dummy) + if err != nil { + return err + } + if n != 1 { + return E.New("failed to protect fd") + } + return nil +} + +func ProtectPath(protectPath string) control.Func { + return func(network, address string, conn syscall.RawConn) error { + var innerErr error + err := conn.Control(func(fd uintptr) { + innerErr = sendAncillaryFileDescriptors(protectPath, []int{int(fd)}) + }) + return common.AnyError(innerErr, err) + } +} diff --git a/outbound/dialer/protect_stub.go b/outbound/dialer/protect_stub.go new file mode 100644 index 00000000..b484654a --- /dev/null +++ b/outbound/dialer/protect_stub.go @@ -0,0 +1,9 @@ +//go:build !android && !with_protect + +package dialer + +import "github.com/sagernet/sing/common/control" + +func ProtectPath(protectPath string) control.Func { + return nil +}