github.com/metacubex/sing-tun@v0.2.7-0.20240512075008-89e7c6208eec/internal/winipcfg/winipcfg.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package winipcfg
     7  
     8  import (
     9  	"runtime"
    10  	"unsafe"
    11  
    12  	"golang.org/x/sys/windows"
    13  )
    14  
    15  //
    16  // Common functions
    17  //
    18  
    19  //sys	freeMibTable(memory unsafe.Pointer) = iphlpapi.FreeMibTable
    20  
    21  //
    22  // Interface-related functions
    23  //
    24  
    25  //sys	initializeIPInterfaceEntry(row *MibIPInterfaceRow) = iphlpapi.InitializeIpInterfaceEntry
    26  //sys	getIPInterfaceTable(family AddressFamily, table **mibIPInterfaceTable) (ret error) = iphlpapi.GetIpInterfaceTable
    27  //sys	getIPInterfaceEntry(row *MibIPInterfaceRow) (ret error) = iphlpapi.GetIpInterfaceEntry
    28  //sys	setIPInterfaceEntry(row *MibIPInterfaceRow) (ret error) = iphlpapi.SetIpInterfaceEntry
    29  //sys	getIfEntry2(row *MibIfRow2) (ret error) = iphlpapi.GetIfEntry2
    30  //sys	getIfTable2Ex(level MibIfEntryLevel, table **mibIfTable2) (ret error) = iphlpapi.GetIfTable2Ex
    31  //sys	convertInterfaceLUIDToGUID(interfaceLUID *LUID, interfaceGUID *windows.GUID) (ret error) = iphlpapi.ConvertInterfaceLuidToGuid
    32  //sys	convertInterfaceGUIDToLUID(interfaceGUID *windows.GUID, interfaceLUID *LUID) (ret error) = iphlpapi.ConvertInterfaceGuidToLuid
    33  //sys	convertInterfaceIndexToLUID(interfaceIndex uint32, interfaceLUID *LUID) (ret error) = iphlpapi.ConvertInterfaceIndexToLuid
    34  
    35  // GetAdaptersAddresses function retrieves the addresses associated with the adapters on the local computer.
    36  // https://docs.microsoft.com/en-us/windows/desktop/api/iphlpapi/nf-iphlpapi-getadaptersaddresses
    37  func GetAdaptersAddresses(family AddressFamily, flags GAAFlags) ([]*IPAdapterAddresses, error) {
    38  	var b []byte
    39  	size := uint32(15000)
    40  
    41  	for {
    42  		b = make([]byte, size)
    43  		err := windows.GetAdaptersAddresses(uint32(family), uint32(flags), 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &size)
    44  		if err == nil {
    45  			break
    46  		}
    47  		if err != windows.ERROR_BUFFER_OVERFLOW || size <= uint32(len(b)) {
    48  			return nil, err
    49  		}
    50  	}
    51  
    52  	result := make([]*IPAdapterAddresses, 0, uintptr(size)/unsafe.Sizeof(IPAdapterAddresses{}))
    53  	for wtiaa := (*IPAdapterAddresses)(unsafe.Pointer(&b[0])); wtiaa != nil; wtiaa = wtiaa.Next {
    54  		result = append(result, wtiaa)
    55  	}
    56  
    57  	return result, nil
    58  }
    59  
    60  // GetIPInterfaceTable function retrieves the IP interface entries on the local computer.
    61  // https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getipinterfacetable
    62  func GetIPInterfaceTable(family AddressFamily) ([]MibIPInterfaceRow, error) {
    63  	var tab *mibIPInterfaceTable
    64  	err := getIPInterfaceTable(family, &tab)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	t := append(make([]MibIPInterfaceRow, 0, tab.numEntries), tab.get()...)
    69  	tab.free()
    70  	return t, nil
    71  }
    72  
    73  // GetIfTable2Ex function retrieves the MIB-II interface table.
    74  // https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getiftable2ex
    75  func GetIfTable2Ex(level MibIfEntryLevel) ([]MibIfRow2, error) {
    76  	var tab *mibIfTable2
    77  	err := getIfTable2Ex(level, &tab)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	t := append(make([]MibIfRow2, 0, tab.numEntries), tab.get()...)
    82  	tab.free()
    83  	return t, nil
    84  }
    85  
    86  //
    87  // Unicast IP address-related functions
    88  //
    89  
    90  //sys	getUnicastIPAddressTable(family AddressFamily, table **mibUnicastIPAddressTable) (ret error) = iphlpapi.GetUnicastIpAddressTable
    91  //sys	initializeUnicastIPAddressEntry(row *MibUnicastIPAddressRow) = iphlpapi.InitializeUnicastIpAddressEntry
    92  //sys	getUnicastIPAddressEntry(row *MibUnicastIPAddressRow) (ret error) = iphlpapi.GetUnicastIpAddressEntry
    93  //sys	setUnicastIPAddressEntry(row *MibUnicastIPAddressRow) (ret error) = iphlpapi.SetUnicastIpAddressEntry
    94  //sys	createUnicastIPAddressEntry(row *MibUnicastIPAddressRow) (ret error) = iphlpapi.CreateUnicastIpAddressEntry
    95  //sys	deleteUnicastIPAddressEntry(row *MibUnicastIPAddressRow) (ret error) = iphlpapi.DeleteUnicastIpAddressEntry
    96  
    97  // GetUnicastIPAddressTable function retrieves the unicast IP address table on the local computer.
    98  // https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getunicastipaddresstable
    99  func GetUnicastIPAddressTable(family AddressFamily) ([]MibUnicastIPAddressRow, error) {
   100  	var tab *mibUnicastIPAddressTable
   101  	err := getUnicastIPAddressTable(family, &tab)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	t := append(make([]MibUnicastIPAddressRow, 0, tab.numEntries), tab.get()...)
   106  	tab.free()
   107  	return t, nil
   108  }
   109  
   110  //
   111  // Anycast IP address-related functions
   112  //
   113  
   114  //sys	getAnycastIPAddressTable(family AddressFamily, table **mibAnycastIPAddressTable) (ret error) = iphlpapi.GetAnycastIpAddressTable
   115  //sys	getAnycastIPAddressEntry(row *MibAnycastIPAddressRow) (ret error) = iphlpapi.GetAnycastIpAddressEntry
   116  //sys	createAnycastIPAddressEntry(row *MibAnycastIPAddressRow) (ret error) = iphlpapi.CreateAnycastIpAddressEntry
   117  //sys	deleteAnycastIPAddressEntry(row *MibAnycastIPAddressRow) (ret error) = iphlpapi.DeleteAnycastIpAddressEntry
   118  
   119  // GetAnycastIPAddressTable function retrieves the anycast IP address table on the local computer.
   120  // https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getanycastipaddresstable
   121  func GetAnycastIPAddressTable(family AddressFamily) ([]MibAnycastIPAddressRow, error) {
   122  	var tab *mibAnycastIPAddressTable
   123  	err := getAnycastIPAddressTable(family, &tab)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	t := append(make([]MibAnycastIPAddressRow, 0, tab.numEntries), tab.get()...)
   128  	tab.free()
   129  	return t, nil
   130  }
   131  
   132  //
   133  // Routing-related functions
   134  //
   135  
   136  //sys	getIPForwardTable2(family AddressFamily, table **mibIPforwardTable2) (ret error) = iphlpapi.GetIpForwardTable2
   137  //sys	initializeIPForwardEntry(route *MibIPforwardRow2) = iphlpapi.InitializeIpForwardEntry
   138  //sys	getIPForwardEntry2(route *MibIPforwardRow2) (ret error) = iphlpapi.GetIpForwardEntry2
   139  //sys	setIPForwardEntry2(route *MibIPforwardRow2) (ret error) = iphlpapi.SetIpForwardEntry2
   140  //sys	createIPForwardEntry2(route *MibIPforwardRow2) (ret error) = iphlpapi.CreateIpForwardEntry2
   141  //sys	deleteIPForwardEntry2(route *MibIPforwardRow2) (ret error) = iphlpapi.DeleteIpForwardEntry2
   142  
   143  // GetIPForwardTable2 function retrieves the IP route entries on the local computer.
   144  // https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-getipforwardtable2
   145  func GetIPForwardTable2(family AddressFamily) ([]MibIPforwardRow2, error) {
   146  	var tab *mibIPforwardTable2
   147  	err := getIPForwardTable2(family, &tab)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	t := append(make([]MibIPforwardRow2, 0, tab.numEntries), tab.get()...)
   152  	tab.free()
   153  	return t, nil
   154  }
   155  
   156  //
   157  // Notifications-related functions
   158  //
   159  
   160  // https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-notifyipinterfacechange
   161  //sys	notifyIPInterfaceChange(family AddressFamily, callback uintptr, callerContext uintptr, initialNotification bool, notificationHandle *windows.Handle) (ret error) = iphlpapi.NotifyIpInterfaceChange
   162  
   163  // https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-notifyunicastipaddresschange
   164  //sys	notifyUnicastIPAddressChange(family AddressFamily, callback uintptr, callerContext uintptr, initialNotification bool, notificationHandle *windows.Handle) (ret error) = iphlpapi.NotifyUnicastIpAddressChange
   165  
   166  // https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-notifyroutechange2
   167  //sys	notifyRouteChange2(family AddressFamily, callback uintptr, callerContext uintptr, initialNotification bool, notificationHandle *windows.Handle) (ret error) = iphlpapi.NotifyRouteChange2
   168  
   169  // https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-cancelmibchangenotify2
   170  //sys	cancelMibChangeNotify2(notificationHandle windows.Handle) (ret error) = iphlpapi.CancelMibChangeNotify2
   171  
   172  //
   173  // DNS-related functions
   174  //
   175  
   176  //sys	setInterfaceDnsSettingsByPtr(guid *windows.GUID, settings *DnsInterfaceSettings) (ret error) = iphlpapi.SetInterfaceDnsSettings?
   177  //sys	setInterfaceDnsSettingsByQwords(guid1 uintptr, guid2 uintptr, settings *DnsInterfaceSettings) (ret error) = iphlpapi.SetInterfaceDnsSettings?
   178  //sys	setInterfaceDnsSettingsByDwords(guid1 uintptr, guid2 uintptr, guid3 uintptr, guid4 uintptr, settings *DnsInterfaceSettings) (ret error) = iphlpapi.SetInterfaceDnsSettings?
   179  
   180  // The GUID is passed by value, not by reference, which means different
   181  // things on different calling conventions.  On amd64, this means it's
   182  // passed by reference anyway, while on arm, arm64, and 386, it's split
   183  // into words.
   184  func SetInterfaceDnsSettings(guid windows.GUID, settings *DnsInterfaceSettings) error {
   185  	words := (*[4]uintptr)(unsafe.Pointer(&guid))
   186  	switch runtime.GOARCH {
   187  	case "amd64":
   188  		return setInterfaceDnsSettingsByPtr(&guid, settings)
   189  	case "arm64":
   190  		return setInterfaceDnsSettingsByQwords(words[0], words[1], settings)
   191  	case "arm", "386":
   192  		return setInterfaceDnsSettingsByDwords(words[0], words[1], words[2], words[3], settings)
   193  	default:
   194  		panic("unknown calling convention")
   195  	}
   196  }