linkchecker/linkcheck/network/__init__.py

145 lines
5 KiB
Python

# -*- coding: iso-8859-1 -*-
"""from http://twistedmatrix.com/wiki/python/IfConfig
"""
import socket
import errno
import array
import struct
from _network import ifreq_size
from .. import log, LOG_DNS
class IfConfig (object):
"""Access to socket interfaces"""
SIOCGIFNAME = 0x8910
SIOCGIFCONF = 0x8912
SIOCGIFFLAGS = 0x8913
SIOCGIFADDR = 0x8915
SIOCGIFBRDADDR = 0x8919
SIOCGIFNETMASK = 0x891b
SIOCGIFCOUNT = 0x8938
IFF_UP = 0x1 # Interface is up.
IFF_BROADCAST = 0x2 # Broadcast address valid.
IFF_DEBUG = 0x4 # Turn on debugging.
IFF_LOOPBACK = 0x8 # Is a loopback net.
IFF_POINTOPOINT = 0x10 # Interface is point-to-point link.
IFF_NOTRAILERS = 0x20 # Avoid use of trailers.
IFF_RUNNING = 0x40 # Resources allocated.
IFF_NOARP = 0x80 # No address resolution protocol.
IFF_PROMISC = 0x100 # Receive all packets.
IFF_ALLMULTI = 0x200 # Receive all multicast packets.
IFF_MASTER = 0x400 # Master of a load balancer.
IFF_SLAVE = 0x800 # Slave of a load balancer.
IFF_MULTICAST = 0x1000 # Supports multicast.
IFF_PORTSEL = 0x2000 # Can set media type.
IFF_AUTOMEDIA = 0x4000 # Auto media select active.
def __init__ (self):
# create a socket so we have a handle to query
self.sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Note that sizeof(struct ifreq) is not always 32
# (eg. on *BSD, x86_64 Linux) Thus the function call.
self.ifr_size = ifreq_size()
def _ioctl (self, func, args):
import fcntl
return fcntl.ioctl(self.sockfd.fileno(), func, args)
def _getifreq (self, ifname):
"""Return ifreq buffer for given interface name."""
return struct.pack("%ds" % self.ifr_size, ifname)
def _getaddr (self, ifname, func):
try:
result = self._ioctl(func, self._getifreq(ifname))
except IOError, msg:
log.warn(LOG_DNS,
"error getting addr for interface %r: %s", ifname, msg)
return None
return socket.inet_ntoa(result[20:24])
def getInterfaceList (self):
"""Get all interface names in a list."""
# initial 8kB buffer to hold interface data
bufsize = 8192
# 80kB buffer should be enough for most boxen
max_bufsize = bufsize * 10
while True:
buf = array.array('c', '\0' * bufsize)
ifreq = struct.pack("iP", buf.buffer_info()[1], buf.buffer_info()[0])
try:
result = self._ioctl(self.SIOCGIFCONF, ifreq)
break
except IOError, msg:
# in case of EINVAL the buffer size was too small
if msg[0] != errno.EINVAL or bufsize == max_bufsize:
raise
# increase buffer
bufsize += 8192
# loop over interface names
data = buf.tostring()
iflist = []
size, ptr = struct.unpack("iP", result)
i = 0
while i < size:
ifconf = data[i:i+self.ifr_size]
name = struct.unpack("16s%ds" % (self.ifr_size-16), ifconf)[0]
name = name.split('\0', 1)[0]
if name:
iflist.append(name)
i += self.ifr_size
return iflist
def getFlags (self, ifname):
"""Get the flags for an interface"""
try:
result = self._ioctl(self.SIOCGIFFLAGS, self._getifreq(ifname))
except IOError, msg:
log.warn(LOG_DNS,
"error getting flags for interface %r: %s", ifname, msg)
return 0
# extract the interface's flags from the return value
flags, = struct.unpack('H', result[16:18])
# return "UP" bit
return flags
def getAddr (self, ifname):
"""Get the inet addr for an interface.
@param ifname: interface name
@type ifname: string
"""
return self._getaddr(ifname, self.SIOCGIFADDR)
def getMask (self, ifname):
"""Get the netmask for an interface.
@param ifname: interface name
@type ifname: string
"""
return self._getaddr(ifname, self.SIOCGIFNETMASK)
def getBroadcast (self, ifname):
"""Get the broadcast addr for an interface.
@param ifname: interface name
@type ifname: string
"""
return self._getaddr(ifname, self.SIOCGIFBRDADDR)
def isUp (self, ifname):
"""Check whether interface is UP.
@param ifname: interface name
@type ifname: string
"""
return (self.getFlags(ifname) & self.IFF_UP) != 0
def isLoopback (self, ifname):
"""Check whether interface is a loopback device.
@param ifname: interface name
@type ifname: string
"""
# since not all systems have IFF_LOOPBACK as a flag defined,
# the ifname is tested first
if ifname == 'lo':
return True
return (self.getFlags(ifname) & self.IFF_LOOPBACK) != 0