github.com/sagernet/sing@v0.4.0-beta.19.0.20240518125136-f67a0988a636/common/control/protect_unix.go (about)

     1  //go:build (go1.19 && unix) || (!go1.19 && (linux || darwin))
     2  
     3  package control
     4  
     5  import (
     6  	"syscall"
     7  
     8  	E "github.com/sagernet/sing/common/exceptions"
     9  )
    10  
    11  func sendAncillaryFileDescriptors(protectPath string, fileDescriptors []int) error {
    12  	socket, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
    13  	if err != nil {
    14  		return E.Cause(err, "open protect socket")
    15  	}
    16  	defer syscall.Close(socket)
    17  	err = syscall.Connect(socket, &syscall.SockaddrUnix{Name: protectPath})
    18  	if err != nil {
    19  		return E.Cause(err, "connect protect path")
    20  	}
    21  	oob := syscall.UnixRights(fileDescriptors...)
    22  	dummy := []byte{1}
    23  	err = syscall.Sendmsg(socket, dummy, oob, nil, 0)
    24  	if err != nil {
    25  		return err
    26  	}
    27  	n, err := syscall.Read(socket, dummy)
    28  	if err != nil {
    29  		return err
    30  	}
    31  	if n != 1 {
    32  		return E.New("failed to protect fd")
    33  	}
    34  	return nil
    35  }
    36  
    37  func ProtectPath(protectPath string) Func {
    38  	return func(network, address string, conn syscall.RawConn) error {
    39  		return Raw(conn, func(fd uintptr) error {
    40  			return sendAncillaryFileDescriptors(protectPath, []int{int(fd)})
    41  		})
    42  	}
    43  }