7

How would one go about retrieving a network device's netmask (In Linux preferably, but if it's cross-platform then cool)? I know how in C on Linux but I can't find a way in Python -- minus ctypes perhaps. That or parsing ifconfig. Any other way?

ioctl(socknr, SIOCGIFNETMASK, &ifreq) // C version

9 Answers 9

10

This works for me in Python 2.2 on Linux:

iface = "eth0"
socket.inet_ntoa(fcntl.ioctl(socket.socket(socket.AF_INET, socket.SOCK_DGRAM), 35099, struct.pack('256s', iface))[20:24])
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. I was hunting down the op value.
Does this work with an IPv6-only network?
9

The netifaces module deserves a mention here. Straight from the docs:

>>> netifaces.interfaces()
['lo0', 'gif0', 'stf0', 'en0', 'en1', 'fw0']

>>> addrs = netifaces.ifaddresses('en0')
>>> addrs[netifaces.AF_INET]
[{'broadcast': '10.15.255.255', 'netmask': '255.240.0.0', 'addr': '10.0.1.4'}, {'broadcast': '192.168.0.255', 'addr': '192.168.0.47'}]

Works on Windows, Linux, OS X, and probably other UNIXes.

1 Comment

Thanks for that. Works great and easier that starting a subprocess like I was doing.
4

Did you look here?

http://docs.python.org/library/fcntl.html

This works for me in python 2.5.2 on Linux. Was finishing it when Ben got ahead, but still here it goes (sad to waste the effort :-) ):

vinko@parrot:~$ more get_netmask.py
# get_netmask.py by Vinko Vrsalovic 2009
# Inspired by http://code.activestate.com/recipes/439093/
# and http://code.activestate.com/recipes/439094/
# Code: 0x891b SIOCGIFNETMASK

import socket
import fcntl
import struct
import sys

def get_netmask(ifname):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x891b, struct.pack('256
s',ifname))[20:24])

if len(sys.argv) == 2:
        print get_netmask(sys.argv[1])
vinko@parrot:~$ python get_netmask.py lo
255.0.0.0
vinko@parrot:~$ python get_netmask.py eth0
255.255.255.0

1 Comment

Nope didn't see that one. Sweet. Thanks.
3

I had the idea to rely on subprocess to use a simple ifconfig (Linux) or ipconfig (windows) request to retrieve the info (if the ip is known). Comments welcome :

WINDOWS

ip = '192.168.1.10' #Example
proc = subprocess.Popen('ipconfig',stdout=subprocess.PIPE)
while True:
    line = proc.stdout.readline()
    if ip.encode() in line:
        break
mask = proc.stdout.readline().rstrip().split(b':')[-1].replace(b' ',b'').decode()

UNIX-Like

ip = '192.168.1.10' #Example
proc = subprocess.Popen('ifconfig',stdout=subprocess.PIPE)
while True:
    line = proc.stdout.readline()
    if ip.encode() in line:
        break
mask = line.rstrip().split(b':')[-1].replace(b' ',b'').decode()

IP is retrieved using a socket connection to the web and using getsockname()[0]

2 Comments

ifconfig is not always pre-installed on linux anymore, the new command is ip addr
@Typewar, is ip addr pre-installed on old linux versions ?
2

You can use this library: http://github.com/rlisagor/pynetlinux. Note: I'm the author of the library.

Comments

2

Answer using psutil:

import psutil
import socket

def get_ipv4_netmask_from_nic(interface):
    interface_addrs = psutil.net_if_addrs().get(interface) or []
    for snicaddr in interface_addrs:
        if snicaddr.family == socket.AF_INET:
            return snicaddr.netmask

Example:

>>> get_ipv4_netmask_from_nic("eth0")
'255.255.255.0'

Comments

1

In Windows this piece of code may be useful:

import os
import sys
import _winreg


def main():
    adapter_list_key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
        r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards')

    adapter_count = _winreg.QueryInfoKey(adapter_list_key)[0]

    for i in xrange(adapter_count):
        sub_key_name = _winreg.EnumKey(adapter_list_key, i)
        adapter_key = _winreg.OpenKey(adapter_list_key, sub_key_name)
        (adapter_service_name, _) = _winreg.QueryValueEx(adapter_key, "ServiceName")
        (description, _) = _winreg.QueryValueEx(adapter_key, "Description")

        adapter_registry_path = os.path.join(r'SYSTEM\ControlSet001\Services',
            adapter_service_name, "Parameters", "Tcpip")
        adapter_service_key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
            adapter_registry_path)
        (subnet_mask, _) = _winreg.QueryValueEx(adapter_service_key, "SubnetMask")
        (ip_address, _) = _winreg.QueryValueEx(adapter_service_key, "IpAddress")

        sys.stdout.write("Name: %s\n" % adapter_service_name)
        sys.stdout.write("Description: %s\n" % description)
        sys.stdout.write("SubnetMask: %s\n" % subnet_mask)
        sys.stdout.write("IpAdress: %s\n" % ip_address)


if __name__ == "__main__":
    main()

Get network adapters list from HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards registry key and than extract more info about each adapter from HKLM\SYSTEM\ControlSet001\Services\{adapter_guid}\Parameters\Tcpip key.

I test it on Windows XP with 2 virtual adapters, it works fine. Should work in 2000, 2003, and Vista too.

1 Comment

I added Py3 compat (no big deal) and DHCP (big deal for me). Also uses CurrentControlSet. I put a copy here because it's too long for a comment.
0

Using the python pyroute2 library you can get all network element attributes:

from pyroute2 import IPRoute
ip = IPRoute()
info = [{'iface': x['index'], 'addr': x.get_attr('IFA_ADDRESS'), 'mask':  x['prefixlen']} for x in ip.get_addr()]

More information available here:http://pyroute2.org/pyroute2-0.3.14p4/iproute.html

Comments

0

I have an update on the original answer as the original code:

struct.pack('256s', iface)

Throws an error in Python 3.9, so here is a revisited version:


    SIOCGIFADDR = 0x8915

    def get_iface_ip(iface: str):
        """
        Get network interface IP using the network interface name
        :param iface: Interface name (like eth0, enp2s0, etc.)
        :return IP address in the form XX.XX.XX.XX
        """
        with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
            iface_bin = struct.pack('256s', bytes(iface, 'utf-8'))
            packet_ip = fcntl.ioctl(s.fileno(), SIOCGIFADDR, iface_bin)[20:24]
        return socket.inet_ntoa(packet_ip)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.