tailscale/wgengine/winnet/winnet.go

158 lines
3.1 KiB
Go

// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build windows
// +build windows
package winnet
import (
"fmt"
"unsafe"
"github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil"
)
const CLSID_NetworkListManager = "{DCB00C01-570F-4A9B-8D69-199FDBA5723B}"
var IID_INetwork = ole.NewGUID("{8A40A45D-055C-4B62-ABD7-6D613E2CEAEC}")
var IID_INetworkConnection = ole.NewGUID("{DCB00005-570F-4A9B-8D69-199FDBA5723B}")
type NetworkListManager struct {
d *ole.Dispatch
}
type INetworkConnection struct {
ole.IDispatch
}
type ConnectionList []*INetworkConnection
type INetworkConnectionVtbl struct {
ole.IDispatchVtbl
GetNetwork uintptr
Get_IsConnectedToInternet uintptr
Get_IsConnected uintptr
GetConnectivity uintptr
GetConnectionId uintptr
GetAdapterId uintptr
GetDomainType uintptr
}
type INetwork struct {
ole.IDispatch
}
func NewNetworkListManager(c *ole.Connection) (*NetworkListManager, error) {
err := c.Create(CLSID_NetworkListManager)
if err != nil {
return nil, err
}
defer c.Release()
d, err := c.Dispatch()
if err != nil {
return nil, err
}
return &NetworkListManager{
d: d,
}, nil
}
func (m *NetworkListManager) Release() {
m.d.Release()
}
func (cl ConnectionList) Release() {
for _, v := range cl {
v.Release()
}
}
func asIID(u ole.UnknownLike, iid *ole.GUID) (*ole.IDispatch, error) {
if u == nil {
return nil, fmt.Errorf("asIID: nil UnknownLike")
}
d, err := u.QueryInterface(iid)
u.Release()
if err != nil {
return nil, err
}
return d, nil
}
func (m *NetworkListManager) GetNetworkConnections() (ConnectionList, error) {
ncraw, err := m.d.Call("GetNetworkConnections")
if err != nil {
return nil, err
}
nli := ncraw.ToIDispatch()
if nli == nil {
return nil, fmt.Errorf("GetNetworkConnections: not IDispatch")
}
cl := ConnectionList{}
err = oleutil.ForEach(nli, func(v *ole.VARIANT) error {
nc, err := asIID(v.ToIUnknown(), IID_INetworkConnection)
if err != nil {
return err
}
nco := (*INetworkConnection)(unsafe.Pointer(nc))
cl = append(cl, nco)
return nil
})
if err != nil {
cl.Release()
return nil, err
}
return cl, nil
}
func (n *INetwork) GetName() (string, error) {
v, err := n.CallMethod("GetName")
if err != nil {
return "", err
}
return v.ToString(), err
}
func (n *INetwork) GetCategory() (int32, error) {
v, err := n.CallMethod("GetCategory")
if err != nil {
return 0, err
}
return v.Value().(int32), err
}
func (n *INetwork) SetCategory(v uint32) error {
_, err := n.CallMethod("SetCategory", v)
return err
}
func (v *INetworkConnection) VTable() *INetworkConnectionVtbl {
return (*INetworkConnectionVtbl)(unsafe.Pointer(v.RawVTable))
}
func (v *INetworkConnection) GetNetwork() (*INetwork, error) {
nraw, err := v.CallMethod("GetNetwork")
if err != nil {
return nil, err
}
n := nraw.ToIDispatch()
if n == nil {
return nil, fmt.Errorf("GetNetwork: nil IDispatch")
}
if err != nil {
return nil, err
}
return (*INetwork)(unsafe.Pointer(n)), nil
}