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