searcher_linux.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. //go:build linux && !android
  2. package process
  3. import (
  4. "context"
  5. "errors"
  6. "net/netip"
  7. "syscall"
  8. "time"
  9. "github.com/sagernet/sing-box/adapter"
  10. "github.com/sagernet/sing-box/log"
  11. E "github.com/sagernet/sing/common/exceptions"
  12. )
  13. var _ Searcher = (*linuxSearcher)(nil)
  14. type linuxSearcher struct {
  15. logger log.ContextLogger
  16. diagConns [4]*socketDiagConn
  17. processPathCache *uidProcessPathCache
  18. }
  19. func NewSearcher(config Config) (Searcher, error) {
  20. searcher := &linuxSearcher{
  21. logger: config.Logger,
  22. processPathCache: newUIDProcessPathCache(time.Second),
  23. }
  24. for _, family := range []uint8{syscall.AF_INET, syscall.AF_INET6} {
  25. for _, protocol := range []uint8{syscall.IPPROTO_TCP, syscall.IPPROTO_UDP} {
  26. searcher.diagConns[socketDiagConnIndex(family, protocol)] = newSocketDiagConn(family, protocol)
  27. }
  28. }
  29. return searcher, nil
  30. }
  31. func (s *linuxSearcher) Close() error {
  32. var errs []error
  33. for _, conn := range s.diagConns {
  34. if conn == nil {
  35. continue
  36. }
  37. errs = append(errs, conn.Close())
  38. }
  39. return E.Errors(errs...)
  40. }
  41. func (s *linuxSearcher) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*adapter.ConnectionOwner, error) {
  42. inode, uid, err := s.resolveSocketByNetlink(network, source, destination)
  43. if err != nil {
  44. return nil, err
  45. }
  46. processInfo := &adapter.ConnectionOwner{
  47. UserId: int32(uid),
  48. }
  49. processPath, err := s.processPathCache.findProcessPath(inode, uid)
  50. if err != nil {
  51. s.logger.DebugContext(ctx, "find process path: ", err)
  52. } else {
  53. processInfo.ProcessPath = processPath
  54. }
  55. return processInfo, nil
  56. }
  57. func (s *linuxSearcher) resolveSocketByNetlink(network string, source netip.AddrPort, destination netip.AddrPort) (inode, uid uint32, err error) {
  58. family, protocol, err := socketDiagSettings(network, source)
  59. if err != nil {
  60. return 0, 0, err
  61. }
  62. conn := s.diagConns[socketDiagConnIndex(family, protocol)]
  63. if conn == nil {
  64. return 0, 0, E.New("missing socket diag connection for family=", family, " protocol=", protocol)
  65. }
  66. if destination.IsValid() && source.Addr().BitLen() == destination.Addr().BitLen() {
  67. inode, uid, err = conn.query(source, destination)
  68. if err == nil {
  69. return inode, uid, nil
  70. }
  71. if !errors.Is(err, ErrNotFound) {
  72. return 0, 0, err
  73. }
  74. }
  75. return querySocketDiagOnce(family, protocol, source)
  76. }