Skip to content

Instantly share code, notes, and snippets.

@blink1073
Last active May 2, 2025 11:53
Show Gist options
  • Save blink1073/349f83fdccabd23aeeabcfd3583f8017 to your computer and use it in GitHub Desktop.
Save blink1073/349f83fdccabd23aeeabcfd3583f8017 to your computer and use it in GitHub Desktop.
import ctypes
import ctypes.wintypes as wintypes
# Load the IP Helper library
IPHLPAPI = ctypes.WinDLL('Iphlpapi.dll')
# Based on the following documentation:
# https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses
# https://learn.microsoft.com/en-us/windows/win32/api/iptypes/ns-iptypes-ip_adapter_addresses_lh
# https://learn.microsoft.com/en-us/windows/win32/api/iptypes/ns-iptypes-ip_adapter_dns_server_address_xp
# https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
# Constants
AF_UNSPEC = 0
ERROR_SUCCESS = 0
GAA_FLAG_INCLUDE_PREFIX = 0x00000010
AF_INET = 2
AF_INET6 = 23
IF_TYPE_SOFTWARE_LOOPBACK = 24
# Define necessary structures
class SOCKADDR(ctypes.Structure):
_fields_ = [
("sa_family", wintypes.USHORT),
("sa_data", ctypes.c_ubyte * 14)
]
class SOCKET_ADDRESS(ctypes.Structure):
_fields_ = [
("lpSockaddr", ctypes.POINTER(SOCKADDR)),
("iSockaddrLength", wintypes.INT)
]
class IP_ADAPTER_DNS_SERVER_ADDRESS(ctypes.Structure):
pass # Forward declaration
IP_ADAPTER_DNS_SERVER_ADDRESS._fields_ = [
("Length", wintypes.ULONG),
("Reserved", wintypes.DWORD),
("Next", ctypes.POINTER(IP_ADAPTER_DNS_SERVER_ADDRESS)),
("Address", SOCKET_ADDRESS)
]
class IP_ADAPTER_ADDRESSES(ctypes.Structure):
pass # Forward declaration
IP_ADAPTER_ADDRESSES._fields_ = [
("Length", wintypes.ULONG),
("IfIndex", wintypes.DWORD),
("Next", ctypes.POINTER(IP_ADAPTER_ADDRESSES)),
("AdapterName", ctypes.c_char_p),
("FirstUnicastAddress", ctypes.POINTER(SOCKET_ADDRESS)),
("FirstAnycastAddress", ctypes.POINTER(SOCKET_ADDRESS)),
("FirstMulticastAddress", ctypes.POINTER(SOCKET_ADDRESS)),
("FirstDnsServerAddress", ctypes.POINTER(IP_ADAPTER_DNS_SERVER_ADDRESS)),
("DnsSuffix", wintypes.LPWSTR),
("Description", wintypes.LPWSTR),
("FriendlyName", wintypes.LPWSTR),
("PhysicalAddress", ctypes.c_ubyte * 8),
("PhysicalAddressLength", wintypes.ULONG),
("Flags", wintypes.ULONG),
("Mtu", wintypes.ULONG),
("IfType", wintypes.ULONG),
("OperStatus", ctypes.c_uint),
# Remaining types removed for brevity.
]
def format_ipv4(sockaddr_in):
return ".".join(map(str, sockaddr_in.sa_data[2:6]))
def format_ipv6(sockaddr_in6):
parts = [sockaddr_in6.sa_data[i] << 8 | sockaddr_in6.sa_data[i+1] for i in range(0, 14, 2)]
return ":".join(f"{part:04x}" for part in parts)
def get_dns_servers():
buffer_size = ctypes.c_ulong(15000)
while True:
buffer = ctypes.create_string_buffer(buffer_size.value)
ret_val = IPHLPAPI.GetAdaptersAddresses(
AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, None, buffer, ctypes.byref(buffer_size)
)
if ret_val == ERROR_SUCCESS:
break
elif ret_val != 0x6F: # ERROR_BUFFER_OVERFLOW
print(f"Error retrieving adapter information: {ret_val}")
return
adapter_addresses = ctypes.cast(buffer, ctypes.POINTER(IP_ADAPTER_ADDRESSES))
current_adapter = adapter_addresses
while current_adapter:
friendly_name = ctypes.wstring_at(current_adapter.contents.FriendlyName)
oper_status = current_adapter.contents.OperStatus
oper_status_str = "Operational" if oper_status == 1 else "Non-Operational"
print(f"Adapter: {friendly_name}, Status: {oper_status_str}")
# Exclude loopback adapters.
if current_adapter.contents.IfType == IF_TYPE_SOFTWARE_LOOPBACK:
current_adapter = current_adapter.contents.Next
print("Skipping loopback adapter")
continue
current_dns_server = current_adapter.contents.FirstDnsServerAddress
while current_dns_server:
sockaddr = current_dns_server.contents.Address.lpSockaddr
sockaddr_family = sockaddr.contents.sa_family
ip = None
if sockaddr_family == AF_INET: # IPv4
ip = format_ipv4(sockaddr.contents)
elif sockaddr_family == AF_INET6: # IPv6
ip = format_ipv6(sockaddr.contents)
if ip:
print(f"DNS Server: {ip}")
current_dns_server = current_dns_server.contents.Next
current_adapter = current_adapter.contents.Next
get_dns_servers()
"""
Output:
Adapter: Ethernet 4, Status: Operational
DNS Server: 10.122.0.2
Adapter: Loopback Pseudo-Interface 1, Status: Operational
Skipping loopback adapter
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment