protect.go 1.1 KB

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