Improved network interface detection on POSIX systems

git-svn-id: https://linkchecker.svn.sourceforge.net/svnroot/linkchecker/trunk/linkchecker@3792 e7d03fd6-7b0d-0410-9947-9c21f3af8025
This commit is contained in:
calvin 2008-06-07 13:08:36 +00:00
parent 7cb6900a9c
commit 83bd7ce4ac
8 changed files with 129 additions and 34 deletions

View file

@ -26,6 +26,10 @@
Changed: linkchecker, linkcheck/checker/urlbase.py
Added: linkcheck/clamav.py
* Improved network interface detection on POSIX systems.
Type: bugfix
Added: linkcheck/network/*
4.9 "Michael Clayton" (released 25.4.2008)
* Parse Shockwave Flash (SWF) for URLs to check

View file

@ -59,6 +59,7 @@ localbuild: MANIFEST
$(PYTHON) setup.py build
cp -f build/lib.linux-$(MACHINE)-$(PYVER)/linkcheck/HtmlParser/htmlsax.so linkcheck/HtmlParser
cp -f build/lib.linux-$(MACHINE)-$(PYVER)/linkcheck/ftpparse/_ftpparse.so linkcheck/ftpparse
cp -f build/lib.linux-$(MACHINE)-$(PYVER)/linkcheck/network/_network.so linkcheck/network
.PHONY: deb_orig
deb_orig:

View file

@ -20,7 +20,6 @@ __all__ = [
'dnssec',
'exception',
'flags',
'ifconfig',
'inet',
'ipv4',
'ipv6',

View file

@ -22,6 +22,7 @@
import socket
import sets
import sys
import os
import time
import encodings.idna
@ -377,11 +378,11 @@ class Resolver(object):
@return: list of IP addresses
@rtype: list of strings
"""
if not sys.platform.startswith('linux'):
# only Linux is supported right now
if os.name != 'posix':
# only POSIX is supported right now
return []
import linkcheck.dns.ifconfig
ifc = linkcheck.dns.ifconfig.IfConfig()
from linkcheck.network import IfConfig
ifc = IfConfig()
return [ifc.getAddr(iface) for iface in ifc.getInterfaceList() \
if ifc.isUp(iface)]

View file

@ -1,12 +1,12 @@
# -*- coding: iso-8859-1 -*-
"""from http://twistedmatrix.com/wiki/python/IfConfig
"""
import socket
import errno
import array
import fcntl
import struct
from _network import ifreq_size
from .. import log, LOG_DNS
@ -40,14 +40,20 @@ class IfConfig (object):
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):
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):
ifreq = struct.pack("32s", ifname)
try:
result = self._ioctl(func, ifreq)
result = self._ioctl(func, self._getifreq(ifname))
except IOError, msg:
log.warn(LOG_DNS,
"error getting addr for interface %r: %s", ifname, msg)
@ -55,9 +61,7 @@ class IfConfig (object):
return socket.inet_ntoa(result[20:24])
def getInterfaceList (self):
"""
Get all interface names in a list.
"""
"""Get all interface names in a list."""
# initial 8kB buffer to hold interface data
bufsize = 8192
# 80kB buffer should be enough for most boxen
@ -80,22 +84,18 @@ class IfConfig (object):
size, ptr = struct.unpack("iP", result)
i = 0
while i < size:
# XXX on *BSD, struct ifreq is not hardcoded 32, but dynamic.
ifreq_size = 32
ifconf = data[i:i+ifreq_size]
name, dummy = struct.unpack("16s16s", ifconf)
name, dummy = name.split('\0', 1)
iflist.append(name)
i += ifreq_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
"""
ifreq = struct.pack("32s", ifname)
"""Get the flags for an interface"""
try:
result = self._ioctl(self.SIOCGIFFLAGS, ifreq)
result = self._ioctl(self.SIOCGIFFLAGS, self._getifreq(ifname))
except IOError, msg:
log.warn(LOG_DNS,
"error getting flags for interface %r: %s", ifname, msg)
@ -106,40 +106,35 @@ class IfConfig (object):
return flags
def getAddr (self, ifname):
"""
Get the inet addr for an interface.
"""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.
"""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.
"""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.
"""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.
"""Check whether interface is a loopback device.
@param ifname: interface name
@type ifname: string
"""

View file

@ -0,0 +1,44 @@
/* Copyright (C) 2000-2008 Bastian Kleineidam
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Python.h"
#include <sys/ioctl.h>
#include <net/if.h>
/* The struct ifreq size varies on different platforms, so we need
this helper function to determine the size of it.
*/
static PyObject* network_ifreq_size (PyObject* self, PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
return Py_BuildValue("i", sizeof(struct ifreq));
}
static PyMethodDef _functions[] = {
{"ifreq_size", network_ifreq_size, METH_VARARGS,
"Return sizeof(struct ifreq)."},
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyMODINIT_FUNC init_network(void)
{
(void) Py_InitModule("_network", _functions);
}

View file

@ -507,7 +507,8 @@ o a (Fast)CGI web interface (requires HTTP server)
'linkcheck.cache', 'linkcheck.htmlutil',
'linkcheck.dns', 'linkcheck.dns.rdtypes',
'linkcheck.dns.rdtypes.ANY', 'linkcheck.dns.rdtypes.IN',
'linkcheck.HtmlParser', 'linkcheck.ftpparse', ],
'linkcheck.HtmlParser', 'linkcheck.ftpparse',
'linkcheck.network', ],
ext_modules = [Extension('linkcheck.HtmlParser.htmlsax',
sources = ['linkcheck/HtmlParser/htmllex.c',
'linkcheck/HtmlParser/htmlparse.c',
@ -520,6 +521,14 @@ o a (Fast)CGI web interface (requires HTTP server)
include_dirs = include_dirs + \
[normpath("linkcheck/HtmlParser")],
),
Extension("linkcheck.network._network",
["linkcheck/network/_network.c",],
extra_compile_args = extra_compile_args,
library_dirs = library_dirs,
libraries = libraries,
define_macros = define_macros,
include_dirs = include_dirs,
),
Extension("linkcheck.ftpparse._ftpparse",
["linkcheck/ftpparse/_ftpparse.c",
"linkcheck/ftpparse/ftpparse.c"],

42
tests/test_network.py Normal file
View file

@ -0,0 +1,42 @@
# -*- coding: iso-8859-1 -*-
# Copyright (C) 2008 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
"""
Test network functions.
"""
import unittest
import linkcheck.network
class TestNetwork (unittest.TestCase):
"""Test network functions."""
def test_ifreq_size (self):
self.assertTrue(linkcheck.network.ifreq_size() > 0)
def test_interfaces (self):
ifc = linkcheck.network.IfConfig()
ifc.getInterfaceList()
def test_suite ():
"""Build and return a TestSuite."""
return unittest.makeSuite(TestNetwork)
if __name__ == '__main__':
unittest.main()