winnet.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. //go:build windows
  4. package winnet
  5. import (
  6. "fmt"
  7. "syscall"
  8. "unsafe"
  9. "github.com/go-ole/go-ole"
  10. "github.com/go-ole/go-ole/oleutil"
  11. )
  12. const CLSID_NetworkListManager = "{DCB00C01-570F-4A9B-8D69-199FDBA5723B}"
  13. var IID_INetwork = ole.NewGUID("{8A40A45D-055C-4B62-ABD7-6D613E2CEAEC}")
  14. var IID_INetworkConnection = ole.NewGUID("{DCB00005-570F-4A9B-8D69-199FDBA5723B}")
  15. type NetworkListManager struct {
  16. d *ole.Dispatch
  17. }
  18. type INetworkConnection struct {
  19. ole.IDispatch
  20. }
  21. type ConnectionList []*INetworkConnection
  22. type INetworkConnectionVtbl struct {
  23. ole.IDispatchVtbl
  24. GetNetwork uintptr
  25. Get_IsConnectedToInternet uintptr
  26. Get_IsConnected uintptr
  27. GetConnectivity uintptr
  28. GetConnectionId uintptr
  29. GetAdapterId uintptr
  30. GetDomainType uintptr
  31. }
  32. type INetwork struct {
  33. ole.IDispatch
  34. }
  35. type INetworkVtbl struct {
  36. ole.IDispatchVtbl
  37. GetName uintptr
  38. SetName uintptr
  39. GetDescription uintptr
  40. SetDescription uintptr
  41. GetNetworkId uintptr
  42. GetDomainType uintptr
  43. GetNetworkConnections uintptr
  44. GetTimeCreatedAndConnected uintptr
  45. Get_IsConnectedToInternet uintptr
  46. Get_IsConnected uintptr
  47. GetConnectivity uintptr
  48. GetCategory uintptr
  49. SetCategory uintptr
  50. }
  51. func NewNetworkListManager(c *ole.Connection) (*NetworkListManager, error) {
  52. err := c.Create(CLSID_NetworkListManager)
  53. if err != nil {
  54. return nil, err
  55. }
  56. defer c.Release()
  57. d, err := c.Dispatch()
  58. if err != nil {
  59. return nil, err
  60. }
  61. return &NetworkListManager{
  62. d: d,
  63. }, nil
  64. }
  65. func (m *NetworkListManager) Release() {
  66. m.d.Release()
  67. }
  68. func (cl ConnectionList) Release() {
  69. for _, v := range cl {
  70. v.Release()
  71. }
  72. }
  73. func asIID(u ole.UnknownLike, iid *ole.GUID) (*ole.IDispatch, error) {
  74. if u == nil {
  75. return nil, fmt.Errorf("asIID: nil UnknownLike")
  76. }
  77. d, err := u.QueryInterface(iid)
  78. u.Release()
  79. if err != nil {
  80. return nil, err
  81. }
  82. return d, nil
  83. }
  84. func (m *NetworkListManager) GetNetworkConnections() (ConnectionList, error) {
  85. ncraw, err := m.d.Call("GetNetworkConnections")
  86. if err != nil {
  87. return nil, err
  88. }
  89. nli := ncraw.ToIDispatch()
  90. if nli == nil {
  91. return nil, fmt.Errorf("GetNetworkConnections: not IDispatch")
  92. }
  93. cl := ConnectionList{}
  94. err = oleutil.ForEach(nli, func(v *ole.VARIANT) error {
  95. nc, err := asIID(v.ToIUnknown(), IID_INetworkConnection)
  96. if err != nil {
  97. return err
  98. }
  99. nco := (*INetworkConnection)(unsafe.Pointer(nc))
  100. cl = append(cl, nco)
  101. return nil
  102. })
  103. if err != nil {
  104. cl.Release()
  105. return nil, err
  106. }
  107. return cl, nil
  108. }
  109. func (n *INetwork) GetName() (string, error) {
  110. v, err := n.CallMethod("GetName")
  111. if err != nil {
  112. return "", err
  113. }
  114. return v.ToString(), err
  115. }
  116. func (n *INetwork) GetCategory() (int32, error) {
  117. var result int32
  118. r, _, _ := syscall.SyscallN(
  119. n.VTable().GetCategory,
  120. uintptr(unsafe.Pointer(n)),
  121. uintptr(unsafe.Pointer(&result)),
  122. )
  123. if int32(r) < 0 {
  124. return 0, ole.NewError(r)
  125. }
  126. return result, nil
  127. }
  128. func (n *INetwork) SetCategory(v int32) error {
  129. r, _, _ := syscall.SyscallN(
  130. n.VTable().SetCategory,
  131. uintptr(unsafe.Pointer(n)),
  132. uintptr(v),
  133. )
  134. if int32(r) < 0 {
  135. return ole.NewError(r)
  136. }
  137. return nil
  138. }
  139. func (n *INetwork) VTable() *INetworkVtbl {
  140. return (*INetworkVtbl)(unsafe.Pointer(n.RawVTable))
  141. }
  142. func (v *INetworkConnection) VTable() *INetworkConnectionVtbl {
  143. return (*INetworkConnectionVtbl)(unsafe.Pointer(v.RawVTable))
  144. }
  145. func (v *INetworkConnection) GetNetwork() (*INetwork, error) {
  146. var result *INetwork
  147. r, _, _ := syscall.SyscallN(
  148. v.VTable().GetNetwork,
  149. uintptr(unsafe.Pointer(v)),
  150. uintptr(unsafe.Pointer(&result)),
  151. )
  152. if int32(r) < 0 {
  153. return nil, ole.NewError(r)
  154. }
  155. return result, nil
  156. }