searcher_windows.go 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  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) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*adapter.ConnectionOwner, error) {
  24. pid, err := winiphlpapi.FindPid(network, source)
  25. if err != nil {
  26. return nil, err
  27. }
  28. path, err := getProcessPath(pid)
  29. if err != nil {
  30. return &adapter.ConnectionOwner{ProcessID: pid, UserId: -1}, err
  31. }
  32. return &adapter.ConnectionOwner{ProcessID: pid, ProcessPath: path, UserId: -1}, nil
  33. }
  34. func getProcessPath(pid uint32) (string, error) {
  35. switch pid {
  36. case 0:
  37. return ":System Idle Process", nil
  38. case 4:
  39. return ":System", nil
  40. }
  41. handle, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, pid)
  42. if err != nil {
  43. return "", err
  44. }
  45. defer windows.CloseHandle(handle)
  46. size := uint32(syscall.MAX_LONG_PATH)
  47. buf := make([]uint16, syscall.MAX_LONG_PATH)
  48. err = windows.QueryFullProcessImageName(handle, 0, &buf[0], &size)
  49. if err != nil {
  50. return "", err
  51. }
  52. return windows.UTF16ToString(buf[:size]), nil
  53. }