searcher_windows.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. package process
  2. import (
  3. "context"
  4. "net/netip"
  5. "syscall"
  6. "github.com/sagernet/sing-box/adapter"
  7. E "github.com/sagernet/sing/common/exceptions"
  8. "github.com/sagernet/sing/common/winiphlpapi"
  9. "golang.org/x/sys/windows"
  10. )
  11. var _ Searcher = (*windowsSearcher)(nil)
  12. type windowsSearcher struct{}
  13. func NewSearcher(_ Config) (Searcher, error) {
  14. err := initWin32API()
  15. if err != nil {
  16. return nil, E.Cause(err, "init win32 api")
  17. }
  18. return &windowsSearcher{}, nil
  19. }
  20. func initWin32API() error {
  21. return winiphlpapi.LoadExtendedTable()
  22. }
  23. func (s *windowsSearcher) Close() error {
  24. return nil
  25. }
  26. func (s *windowsSearcher) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*adapter.ConnectionOwner, error) {
  27. pid, err := winiphlpapi.FindPid(network, source)
  28. if err != nil {
  29. return nil, err
  30. }
  31. path, err := getProcessPath(pid)
  32. if err != nil {
  33. return &adapter.ConnectionOwner{ProcessID: pid, UserId: -1}, err
  34. }
  35. return &adapter.ConnectionOwner{ProcessID: pid, ProcessPath: path, UserId: -1}, nil
  36. }
  37. func getProcessPath(pid uint32) (string, error) {
  38. switch pid {
  39. case 0:
  40. return ":System Idle Process", nil
  41. case 4:
  42. return ":System", nil
  43. }
  44. handle, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, pid)
  45. if err != nil {
  46. return "", err
  47. }
  48. defer windows.CloseHandle(handle)
  49. size := uint32(syscall.MAX_LONG_PATH)
  50. buf := make([]uint16, syscall.MAX_LONG_PATH)
  51. err = windows.QueryFullProcessImageName(handle, 0, &buf[0], &size)
  52. if err != nil {
  53. return "", err
  54. }
  55. return windows.UTF16ToString(buf[:size]), nil
  56. }