After reading this post
about ifconfig output parsing by Kris, I remembered I once needed a
cross-platform way to get the IP address of an interface in Python.
Of course I could just parse the output of `ifconfig`, but I really don’t like
such ugly hacks. I guess I’ve got too many (bad) experiences with libwww-perl scripts I wrote
for web harvesting various stuff. Basically, this is output parsing too, as
HTML is generally the result of some server side script. Each time the webpage
changed the way it looked (non-CSS changes) or worked, my scripts started to
fail.
That’s when I decided I’ll always try to avoid such clumsy dependencies on
third party software.
So, back to the Python question. I set out for a
short adventure on comp.lang.python and came up with a solution
after some fiddling: pyfconfig, a cross platform Python module to query for the
IP address of an interface. Tested on FreeBSD x86, GNU/Linux x86 and GNU/Linux
x86_64, with Python 2.4 and Python 2.5. Works just fine.
#include "Python.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
// parameters: string (interface name)
// output: string (ip address of interface in decimal notation)
PyObject * ipaddr(PyObject *self, PyObject *args) {
char ip[ 200 ];
char *itf;
if (! PyArg_ParseTuple(args, "s", &itf)) {
PyErr_SetString(PyExc_Exception, "no interface given!");
return NULL;
}
struct ifaddrs *ifa = NULL, *ifp = NULL;
if (getifaddrs (&ifp) < 0) {
perror ("getifaddrs");
return NULL;
}
for (ifa = ifp; ifa; ifa = ifa->ifa_next) {
socklen_t salen;
if (ifa->ifa_addr->sa_family == AF_INET)
salen = sizeof (struct sockaddr_in);
else if (ifa->ifa_addr->sa_family == AF_INET6)
salen = sizeof (struct sockaddr_in6);
else
continue;
if (strncmp(ifa->ifa_name, itf, sizeof(itf))) {
continue;
}
if (getnameinfo (ifa->ifa_addr, salen, ip, sizeof (ip), NULL, 0, NI_NUMERICHOST) < 0) {
perror ("getnameinfo");
continue;
}
break;
}
freeifaddrs (ifp);
return Py_BuildValue("s", ip);
}
static PyMethodDef pyfconfig_methods[] = {
{"ipaddr", (PyCFunction)ipaddr, METH_VARARGS, "ipaddr(string)\n"},
{NULL, NULL, 0, NULL}
};
DL_EXPORT(void) initpyfconfig(void) {
Py_InitModule3("pyfconfig", pyfconfig_methods, "Provides a function to get an ip address of a certain interface.\n");
}
Compile with gcc -fPIC -shared -Wl -soname pyfconfig.so -o pyfconfig.so -I/usr/include/python2.5/ pyfconfig.c (for Python 2.5) and after an
import pyfconfig, pyfconfig.ipaddr('lo') should return '127.0.0.1' (YMMV).
No dependency on the output formatting of ifconfig. Less bugs.