[python-win32] detecting windows type

David Fraser davidf at sjsoft.com
Wed Sep 14 13:28:06 CEST 2005


I wrote a module that has a variety of ways to get a MAC address on 
different platorms, it may be useful:

import sys
import os

def rawtohex(raw):
    """converts a raw mac address to hex"""
    return ":".join(["%02X" % (ord(ch),) for ch in raw])

def getmacs_netbios():
    """uses netbios to find mac addresses"""
    # code ported from "HOWTO: Get the MAC Address for an Ethernet Adapter"
    # MS KB ID: Q118623
    import netbios
    ncb = netbios.NCB()
    ncb.Command = netbios.NCBENUM
    la_enum = netbios.LANA_ENUM()
    ncb.Buffer = la_enum
    rc = netbios.Netbios(ncb)
    if rc != 0: raise RuntimeError, "Unexpected result %d" % (rc,)
    for i in range(la_enum.length):
        ncb.Reset()
        ncb.Command = netbios.NCBRESET
        ncb.Lana_num = ord(la_enum.lana[i])
        rc = netbios.Netbios(ncb)
        if rc != 0: raise RuntimeError, "Unexpected result %d" % (rc,)
        ncb.Reset()
        ncb.Command = netbios.NCBASTAT
        ncb.Lana_num = ord(la_enum.lana[i])
        ncb.Callname = "*               "
        adapter = netbios.ADAPTER_STATUS()
        ncb.Buffer = adapter
        netbios.Netbios(ncb)
        address = rawtohex(adapter.adapter_address)
        yield address

def getmacs_wmi():
    """uses wmi interface to find mac addresses"""
    # this uses wmi from http://tgolden.sc.sabren.com/python/wmi.html
    # its from the example at 
http://tgolden.sc.sabren.com/python/wmi_cookbook.html#ip_addresses
    import wmi
    c = wmi.WMI ()
    for interface in c.Win32_NetworkAdapterConfiguration (IPEnabled=1):
        hasip = False
        for ipaddress in interface.IPAddress:
            if ipaddress: hasip = True
        if hasip:
            yield interface.MACAddress

def getmacs_ifconfig():
    """parses the output of unix ifconfig to find mac addresses"""
    lines = os.popen("ifconfig", "r").readlines()
    headerlines = [line for line in lines if line and not 
line[:1].isspace()]
    for line in headerlines:
        parts = line.split()
        ifname = parts[0]
        if 'HWaddr' in parts:
            hwpart = parts.index('HWaddr')
            if hwpart+1 < len(parts):
                mac = parts[hwpart+1]
                yield mac

def getmacs_ipconfig():
    """parses the output of windows ipconfig to find MAC addresses"""
    lines = os.popen("ipconfig /all", "r").readlines()
    for line in lines:
        if line and not line[:1].isspace():
            header = line
            ipaddress, mac = None, None
        elif line.strip():
            if line.strip().startswith("IP Address") and ":" in line:
                ipaddress = line.split(":", 1)[1].strip()
                if mac:
                    yield mac
                    ipaddress, mac = None, None
            if line.strip().startswith("Physical Address") and ":" in line:
                mac = line.split(":", 1)[1].strip()
                if ipaddress:
                    yield mac
                    ipaddress, mac = None, None

def getmacs_winarp():
    """parses the output of windows arp to find MAC addresses"""
    lines = os.popen("arp -a", "r").readlines()
    for line in lines:
        if line.startswith("Interface"):
            header = line
            ipaddress, mac = None, None
        elif line.strip().startswith("Internet Address"):
            pass
        elif line.strip():
            ipaddress, mac = line.strip().split()[:2]
            yield mac

def ipaddr2mac_winarp(ipaddr):
    """uses SendARP and ctypes to convert an IP Address to an ethernet 
address"""
    # see http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/347812
    import ctypes
    try:
        SendARP = ctypes.windll.Iphlpapi.SendARP
    except:
        raise NotImplementedError('Usage only on Windows 2000 and above')
    import struct
    ip = ipaddr
    if isinstance(ip, (str, unicode)):
        ip = [int(i) for i in ip.split(".")]
    ip = struct.pack("BBBB", *ip)
    ip = struct.unpack("l", ip)[0]
    buffer = ctypes.c_buffer(6)
    addlen = ctypes.c_ulong(ctypes.sizeof(buffer))
    if SendARP(ip, 0, ctypes.byref(buffer), ctypes.byref(addlen)) != 0:
        raise WindowsError('Retrieval of mac address(%s) - failed' % ipaddr)
    macaddr = rawtohex(struct.unpack('6s', buffer)[0])
    return macaddr

def getethdevs_ifconfig():
    """parses the output of ifconfig to get a list of ethernet devices"""
    lines = os.popen("ifconfig", "r").readlines()
    headerlines = [line for line in lines if line and not 
line[:1].isspace()]
    for line in headerlines:
        parts = line.split()
        ifname = parts[0]
        yield ifname

def getethdevs_proc():
    """looks at /proc/net/dev to get a list of ethernet devices"""
    lines = open("/proc/net/dev").readlines()
    for line in lines:
        if ":" in line:
           ethdev = line.split(":", 1)[0].strip()
           yield ethdev

getethdevs = getethdevs_proc

def getmac_socket(ethdev):
    """returns the mac address by opening a socket on the given device. 
requires right permissions"""
    import socket
    s = socket.socket(socket.AF_PACKET,socket.SOCK_RAW)
    s.bind((ethdev,9999))
    rawmac = s.getsockname()[-1]
    return rawtohex(rawmac)

def getmacs_socket():
    """returns the mac address by opening a socket on the  devices found 
by getethdevs. requires right permissions"""
    for ethdev in getethdevs():
        mac = getmac_socket(ethdev)
        if mac:
            yield mac

def getmac_ioctl(ethdev):
    """returns the mac address by using ioctl calls on a socket"""
    # 
http://groups-beta.google.com/group/comp.lang.python/search?q=fcntl+socket+ifconfig
    # look at http://www.webservertalk.com/message891078.html for some C 
code
    import fcntl
    import struct
    import socket
    ifrn_name = ethdev
    ifru_addr_family = socket.AF_INET
    ifru_addr_data = ""
    ifr = struct.pack("16sH14s", ifrn_name, ifru_addr_family, "")
    SIOCGIFADDR = 0x8915
    SIOCGIFHWADDR = 0x8927
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sfd = s.fileno()
    # get the IP address
    try:
        ifr_result = fcntl.ioctl(sfd, SIOCGIFADDR, ifr)
        ipaddr = struct.unpack("16sHH4B8s", ifr_result)[3:7]
        ipaddr = ".".join([str(d) for d in ipaddr])
    except IOError:
        ipaddr = None
    # get the ethernet address
    try:
        ifr_result = fcntl.ioctl(sfd, SIOCGIFHWADDR, ifr)
        ethaddr = struct.unpack("16sH6s8s", ifr_result)[2]
        if sum([ord(c) for c in ethaddr]) == 0:
            return None
        ethaddr = rawtohex(ethaddr)
    except IOError:
        ethaddr = None
    return ethaddr

def getmacs_ioctl():
    """returns the mac address by opening a socket on the  devices found 
by getethdevs. requires right permissions"""
    for ethdev in getethdevs():
        mac = getmac_ioctl(ethdev)
        if mac:
            yield mac

def getmacs():
    if sys.platform == 'linux2':
        return getmacs_ioctl()
    elif sys.platform == 'win32':
        return getmacs_winarp()

if __name__ == "__main__":
  for address in getmacs():
    print address

le dahut wrote:

>Thanks for your advice. A colleague told me how to get those
>informations. First install WMI on the 95/98 station, then write the
>program and compile it with py2exe, then it should work on every 95/98
>station (also where WMI is NOT installed !).
>
>Note that 'ipconfig' is available on win98 so a
>os.popen('ipconfig /all') can be parsed to get infos.
>
>
>K.
>
>Le vendredi 09 septembre 2005 à 10:44 -0700, Tim Roberts a écrit :
>  
>
>>On Fri, 09 Sep 2005 09:42:18 +0200, le dahut <le.dahut at laposte.net> wrote:
>>
>>    
>>
>>>Maybe I can parse the output of a 'ipfonfig' command, 
>>>
>>>      
>>>
>>Nope, that won't work.  Ipconfig is NT-only.  95 and 98 have winipcfg, 
>>but it is a GUI tool, not a command-line tool.
>>
>>    
>>
>>>but commands.getoutput only work with unix, not with windows. Is there
>>>another way to get the output of a command line program under windows ?
>>>
>>>      
>>>
>>The usual way is to use os.popen, which works everywhere.  However, as I 
>>said, that won't help you with this information.
>>
>>In fact, it is surprisingly difficult to get information about the 
>>network interfaces on a 95/98 machine.  Have you tried the downloadable 
>>WMI support mentioned earlier?
>>



More information about the Python-win32 mailing list