summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgignore8
-rw-r--r--CHANGELOG61
-rw-r--r--PKG-INFO25
-rw-r--r--README.rst194
-rw-r--r--netifaces.c2619
-rw-r--r--pypi_windows_packages.bat4
-rw-r--r--setup.cfg5
-rw-r--r--setup.py539
-rw-r--r--test.py50
9 files changed, 3505 insertions, 0 deletions
diff --git a/.hgignore b/.hgignore
new file mode 100644
index 0000000..c353c18
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,8 @@
+syntax: glob
+build
+dist
+*.pyc
+*.pyd
+*.so
+*~
+*.egg-info
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 0000000..c74ffc9
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,61 @@
+2014-05-19 Version 0.10.4
+
+ * Fixed a problem with multi-part Netlink messages on Linux.
+
+2014-05-06 Version 0.10.3
+
+ * When using Netlink (i.e. Linux), check for the constant
+ NLM_F_DUMP_INTR, since it only appeared in kernel version 3.1
+
+2014-05-03 Version 0.10.2
+
+ * Added a workaround for broken netlink headers on certain Linux
+ distributions (the problem being that the netlink headers fail to
+ include <bits/sockaddr.h>, which causes a build failure).
+
+2014-05-02 Version 0.10.1
+
+ * Fixed a problem with the gateways() function that caused it a
+ crash on PyPy.
+ * The CI system is now set up to build for PyPy as well, so
+ problems will be found sooner.
+
+2014-05-01 Version 0.10.0
+
+ * Python 3 compatibility.
+ * Improved Windows source code compatibility.
+ * Added gateway detection via gateways() function.
+ * New version number format (skipped 0.9.0 due to its use by
+ the netifaces-merged fork).
+
+2012-01-31 Version 0.8
+
+ All changes in this version relate to the ioctl( ) code path,
+ which is not used on Windows or on any modern UNIX or UNIX-like
+ system that implements getaddrinfo().
+
+ * Fixed bit-rot in the ioctl() code path.
+ * Fixed a problem with setup.py that might manifest itself if the
+ config.cache file was manually edited.
+ * Fixed the ioctl() code path to cope with systems that have
+ sa_len and return longer than normal struct ifreq requests from
+ SIOCG[L]IFCONF (for instance, Mac OS X).
+
+2012-01-30 Version 0.7
+
+ * Dropped support for Win2K and earlier
+ * Added support for addresses other than IPv4 on Windows
+ * Removed empty 'addr' entries for interfaces that don't provide
+ any addresses.
+ * Fixed problems with setup script that prevented it running on
+ Windows, and improved the chances of it working with
+ cross-compilers somewhat.
+ * Added a verion property to the module that you can test at
+ runtime.
+
+2011-11-04 Version 0.6
+
+ * Added a workaround for a FreeBSD kernel bug (kern/152036).
+ * Added address_families dictionary to allow code to look up the
+ symbolic name corresponding to a given numberic address family
+ code.
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..8fe1dcf
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,25 @@
+Metadata-Version: 1.0
+Name: netifaces
+Version: 0.5
+Summary: Portable network interface information.
+Home-page: http://alastairs-place.net/netifaces
+Author: Alastair Houghton
+Author-email: alastair@alastairs-place.net
+License: MIT License
+Description: netifaces provides a (hopefully portable-ish) way for Python programmers to
+ get access to a list of the network interfaces on the local machine, and to
+ obtain the addresses of those network interfaces.
+
+ The package has been tested on Mac OS X, Windows XP, Windows Vista, Linux
+ and Solaris. On Windows, it is currently not able to retrieve IPv6
+ addresses, owing to shortcomings of the Windows API.
+
+ It should work on other UNIX-like systems provided they implement
+ either getifaddrs() or support the SIOCGIFxxx socket options, although the
+ data provided by the socket options is normally less complete.
+
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Topic :: System :: Networking
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..67889c8
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,194 @@
+netifaces 0.10.4
+================
+
+.. image:: https://drone.io/bitbucket.org/al45tair/netifaces/status.png
+ :target: https://drone.io/bitbucket.org/al45tair/netifaces/latest
+ :alt: Build Status
+
+1. What is this?
+----------------
+
+It's been annoying me for some time that there's no easy way to get the
+address(es) of the machine's network interfaces from Python. There is
+a good reason for this difficulty, which is that it is virtually impossible
+to do so in a portable manner. However, it seems to me that there should
+be a package you can easy_install that will take care of working out the
+details of doing so on the machine you're using, then you can get on with
+writing Python code without concerning yourself with the nitty gritty of
+system-dependent low-level networking APIs.
+
+This package attempts to solve that problem.
+
+2. How do I use it?
+-------------------
+
+First you need to install it, which you can do by typing::
+
+ tar xvzf netifaces-0.10.4.tar.gz
+ cd netifaces-0.10.4
+ python setup.py install
+
+Once that's done, you'll need to start Python and do something like the
+following::
+
+>>> import netifaces
+
+Then if you enter
+
+>>> netifaces.interfaces()
+['lo0', 'gif0', 'stf0', 'en0', 'en1', 'fw0']
+
+you'll see the list of interface identifiers for your machine.
+
+You can ask for the addresses of a particular interface by doing
+
+>>> netifaces.ifaddresses('lo0')
+{18: [{'addr': ''}], 2: [{'peer': '127.0.0.1', 'netmask': '255.0.0.0', 'addr': '127.0.0.1'}], 30: [{'peer': '::1', 'netmask': 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', 'addr': '::1'}, {'peer': '', 'netmask': 'ffff:ffff:ffff:ffff::', 'addr': 'fe80::1%lo0'}]}
+
+Hmmmm. That result looks a bit cryptic; let's break it apart and explain
+what each piece means. It returned a dictionary, so let's look there first::
+
+ { 18: [...], 2: [...], 30: [...] }
+
+Each of the numbers refers to a particular address family. In this case, we
+have three address families listed; on my system, 18 is ``AF_LINK`` (which means
+the link layer interface, e.g. Ethernet), 2 is ``AF_INET`` (normal Internet
+addresses), and 30 is ``AF_INET6`` (IPv6).
+
+But wait! Don't use these numbers in your code. The numeric values here are
+system dependent; fortunately, I thought of that when writing netifaces, so
+the module declares a range of values that you might need. e.g.
+
+>>> netifaces.AF_LINK
+18
+
+Again, on your system, the number may be different.
+
+So, what we've established is that the dictionary that's returned has one
+entry for each address family for which this interface has an address. Let's
+take a look at the ``AF_INET`` addresses now:
+
+>>> addrs = netifaces.ifaddresses('lo0')
+>>> addrs[netifaces.AF_INET]
+[{'peer': '127.0.0.1', 'netmask': '255.0.0.0', 'addr': '127.0.0.1'}]
+
+You might be wondering why this value is a list. The reason is that it's
+possible for an interface to have more than one address, even within the
+same family. I'll say that again: *you can have more than one address of
+the same type associated with each interface*.
+
+*Asking for "the" address of a particular interface doesn't make sense.*
+
+Right, so, we can see that this particular interface only has one address,
+and, because it's a loopback interface, it's point-to-point and therefore
+has a *peer* address rather than a broadcast address.
+
+Let's look at a more interesting interface.
+
+>>> 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'}]
+
+This interface has two addresses (see, I told you...) Both of them are
+regular IPv4 addresses, although in one case the netmask has been changed
+from its default. The netmask *may not* appear on your system if it's set
+to the default for the address range.
+
+Because this interface isn't point-to-point, it also has broadcast addresses.
+
+Now, say we want, instead of the IP addresses, to get the MAC address; that
+is, the hardware address of the Ethernet adapter running this interface. We
+can do
+
+>>> addrs[netifaces.AF_LINK]
+[{'addr': '00:12:34:56:78:9a'}]
+
+Note that this may not be available on platforms without getifaddrs(), unless
+they happen to implement ``SIOCGIFHWADDR``. Note also that you just get the
+address; it's unlikely that you'll see anything else with an ``AF_LINK`` address.
+Oh, and don't assume that all ``AF_LINK`` addresses are Ethernet; you might, for
+instance, be on a Mac, in which case:
+
+>>> addrs = netifaces.ifaddresses('fw0')
+>>> addrs[netifaces.AF_LINK]
+[{'addr': '00:12:34:56:78:9a:bc:de'}]
+
+No, that isn't an exceptionally long Ethernet MAC address---it's a FireWire
+address.
+
+As of version 0.10.0, you can also obtain a list of gateways on your
+machine:
+
+>>> netifaces.gateways()
+{2: [('10.0.1.1', 'en0', True), ('10.2.1.1', 'en1', False)], 30: [('fe80::1', 'en0', True)], 'default': { 2: ('10.0.1.1', 'en0'), 30: ('fe80::1', 'en0') }}
+
+This dictionary is keyed on address family---in this case, ``AF_INET``---and
+each entry is a list of gateways as ``(address, interface, is_default)`` tuples.
+Notice that here we have two separate gateways for IPv4 (``AF_INET``); some
+operating systems support configurations like this and can either route packets
+based on their source, or based on administratively configured routing tables.
+
+For convenience, we also allow you to index the dictionary with the special
+value ``'default'``, which returns a dictionary mapping address families to the
+default gateway in each case. Thus you can get the default IPv4 gateway with
+
+>>> gws = netifaces.gateways()
+>>> gws['default'][netifaces.AF_INET]
+('10.0.1.1', 'en0')
+
+Do note that there may be no default gateway for any given address family;
+this is currently very common for IPv6 and much less common for IPv4 but it
+can happen even for ``AF_INET``.
+
+BTW, if you're trying to configure your machine to have multiple gateways for
+the same address family, it's a very good idea to check the documentation for
+your operating system *very* carefully, as some systems become extremely
+confused or route packets in a non-obvious manner.
+
+I'm very interested in hearing from anyone (on any platform) for whom the
+``gateways()`` method doesn't produce the expected results. It's quite
+complicated extracting this information from the operating system (whichever
+operating system we're talking about), and so I expect there's at least one
+system out there where this just won't work.
+
+3. This is great! What platforms does it work on?
+--------------------------------------------------
+
+It gets regular testing on OS X, Linux and Windows. It has also been used
+successfully on Solaris, and it's expected to work properly on other UNIX-like
+systems as well. If you are running something that is not supported, and
+wish to contribute a patch, please use BitBucket to send a pull request.
+
+4. What license is this under?
+------------------------------
+
+It's an MIT-style license. Here goes:
+
+Copyright (c) 2007-2014 Alastair Houghton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+5. Why the jump to 0.10.0?
+--------------------------
+
+Because someone released a fork of netifaces with the version 0.9.0.
+Hopefully skipping the version number should remove any confusion. In
+addition starting with 0.10.0 Python 3 is now supported and other
+features/bugfixes have been included as well. See the CHANGELOG for a
+more complete list of changes.
diff --git a/netifaces.c b/netifaces.c
new file mode 100644
index 0000000..8b82819
--- /dev/null
+++ b/netifaces.c
@@ -0,0 +1,2619 @@
+#include <Python.h>
+
+/* Python 3 compatibility */
+#if PY_MAJOR_VERSION >= 3
+#define PyInt_FromLong PyLong_FromLong
+#define PyString_FromString PyUnicode_FromString
+
+#define MODULE_ERROR NULL
+#define MODULE_RETURN(v) return (v)
+#define MODULE_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
+#define MODULE_DEF(name,doc,methods) \
+ static struct PyModuleDef moduledef = { \
+ PyModuleDef_HEAD_INIT, (name), (doc), -1, (methods), };
+#define MODULE_CREATE(obj,name,doc,methods) \
+ obj = PyModule_Create(&moduledef);
+#else /* PY_MAJOR_VERSION < 3 */
+#define MODULE_ERROR
+#define MODULE_RETURN(v)
+#define MODULE_INIT(name) void init##name(void)
+#define MODULE_DEF(name,doc,methods)
+#define MODULE_CREATE(obj,name,doc,methods) \
+ obj = Py_InitModule3((name), (methods), (doc));
+#endif
+
+#ifndef WIN32
+
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <net/if.h>
+# include <netdb.h>
+
+# if HAVE_PF_ROUTE
+# include <net/route.h>
+# endif
+
+# if HAVE_SYSCTL_CTL_NET
+# include <sys/sysctl.h>
+# include <net/route.h>
+# endif
+
+# if HAVE_PF_NETLINK
+# include <asm/types.h>
+# include <linux/netlink.h>
+# include <linux/rtnetlink.h>
+# include <arpa/inet.h>
+# endif
+
+# if HAVE_SOCKET_IOCTLS
+# include <sys/ioctl.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# if defined(__sun)
+# include <unistd.h>
+# include <stropts.h>
+# include <sys/sockio.h>
+# endif
+# endif /* HAVE_SOCKET_IOCTLS */
+
+/* For logical interfaces support we convert all names to same name prefixed
+ with l */
+#if HAVE_SIOCGLIFNUM
+#define CNAME(x) l##x
+#else
+#define CNAME(x) x
+#endif
+
+#if HAVE_NET_IF_DL_H
+# include <net/if_dl.h>
+#endif
+
+/* For the benefit of stupid platforms (Linux), include all the sockaddr
+ definitions we can lay our hands on. It can also be useful for the benefit
+ of another stupid platform (FreeBSD, see PR 152036). */
+#include <netinet/in.h>
+# if HAVE_NETASH_ASH_H
+# include <netash/ash.h>
+# endif
+# if HAVE_NETATALK_AT_H
+# include <netatalk/at.h>
+# endif
+# if HAVE_NETAX25_AX25_H
+# include <netax25/ax25.h>
+# endif
+# if HAVE_NETECONET_EC_H
+# include <neteconet/ec.h>
+# endif
+# if HAVE_NETIPX_IPX_H
+# include <netipx/ipx.h>
+# endif
+# if HAVE_NETPACKET_PACKET_H
+# include <netpacket/packet.h>
+# endif
+# if HAVE_NETROSE_ROSE_H
+# include <netrose/rose.h>
+# endif
+# if HAVE_LINUX_IRDA_H
+# include <linux/irda.h>
+# endif
+# if HAVE_LINUX_ATM_H
+# include <linux/atm.h>
+# endif
+# if HAVE_LINUX_LLC_H
+# include <linux/llc.h>
+# endif
+# if HAVE_LINUX_TIPC_H
+# include <linux/tipc.h>
+# endif
+# if HAVE_LINUX_DN_H
+# include <linux/dn.h>
+# endif
+
+/* Map address families to sizes of sockaddr structs */
+static int af_to_len(int af)
+{
+ switch (af) {
+ case AF_INET: return sizeof (struct sockaddr_in);
+#if defined(AF_INET6) && HAVE_SOCKADDR_IN6
+ case AF_INET6: return sizeof (struct sockaddr_in6);
+#endif
+#if defined(AF_AX25) && HAVE_SOCKADDR_AX25
+# if defined(AF_NETROM)
+ case AF_NETROM: /* I'm assuming this is carried over x25 */
+# endif
+ case AF_AX25: return sizeof (struct sockaddr_ax25);
+#endif
+#if defined(AF_IPX) && HAVE_SOCKADDR_IPX
+ case AF_IPX: return sizeof (struct sockaddr_ipx);
+#endif
+#if defined(AF_APPLETALK) && HAVE_SOCKADDR_AT
+ case AF_APPLETALK: return sizeof (struct sockaddr_at);
+#endif
+#if defined(AF_ATMPVC) && HAVE_SOCKADDR_ATMPVC
+ case AF_ATMPVC: return sizeof (struct sockaddr_atmpvc);
+#endif
+#if defined(AF_ATMSVC) && HAVE_SOCKADDR_ATMSVC
+ case AF_ATMSVC: return sizeof (struct sockaddr_atmsvc);
+#endif
+#if defined(AF_X25) && HAVE_SOCKADDR_X25
+ case AF_X25: return sizeof (struct sockaddr_x25);
+#endif
+#if defined(AF_ROSE) && HAVE_SOCKADDR_ROSE
+ case AF_ROSE: return sizeof (struct sockaddr_rose);
+#endif
+#if defined(AF_DECnet) && HAVE_SOCKADDR_DN
+ case AF_DECnet: return sizeof (struct sockaddr_dn);
+#endif
+#if defined(AF_PACKET) && HAVE_SOCKADDR_LL
+ case AF_PACKET: return sizeof (struct sockaddr_ll);
+#endif
+#if defined(AF_ASH) && HAVE_SOCKADDR_ASH
+ case AF_ASH: return sizeof (struct sockaddr_ash);
+#endif
+#if defined(AF_ECONET) && HAVE_SOCKADDR_EC
+ case AF_ECONET: return sizeof (struct sockaddr_ec);
+#endif
+#if defined(AF_IRDA) && HAVE_SOCKADDR_IRDA
+ case AF_IRDA: return sizeof (struct sockaddr_irda);
+#endif
+#if defined(AF_LINK) && HAVE_SOCKADDR_DL
+ case AF_LINK: return sizeof (struct sockaddr_dl);
+#endif
+ }
+ return sizeof (struct sockaddr);
+}
+
+#if !HAVE_SOCKADDR_SA_LEN
+#define SA_LEN(sa) af_to_len(sa->sa_family)
+#if HAVE_SIOCGLIFNUM
+#define SS_LEN(sa) af_to_len(sa->ss_family)
+#else
+#define SS_LEN(sa) SA_LEN(sa)
+#endif
+#else
+#define SA_LEN(sa) sa->sa_len
+#endif /* !HAVE_SOCKADDR_SA_LEN */
+
+# if HAVE_GETIFADDRS
+# include <ifaddrs.h>
+# endif /* HAVE_GETIFADDRS */
+
+# if !HAVE_GETIFADDRS && (!HAVE_SOCKET_IOCTLS || !HAVE_SIOCGIFCONF)
+/* If the platform doesn't define, what we need, barf. If you're seeing this,
+ it means you need to write suitable code to retrieve interface information
+ on your system. */
+# error You need to add code for your platform.
+# endif
+
+#else /* defined(WIN32) */
+
+#define _WIN32_WINNT 0x0501
+
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <iphlpapi.h>
+# include <netioapi.h>
+
+#endif /* defined(WIN32) */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* On systems without AF_LINK (Windows, for instance), define it anyway, but
+ give it a crazy value. On Linux, which has AF_PACKET but not AF_LINK,
+ define AF_LINK as the latter instead. */
+#ifndef AF_LINK
+# ifdef AF_PACKET
+# define AF_LINK AF_PACKET
+# else
+# define AF_LINK -1000
+# endif
+# define HAVE_AF_LINK 0
+#else
+# define HAVE_AF_LINK 1
+#endif
+
+/* -- Utility Functions ----------------------------------------------------- */
+
+#if !defined(WIN32)
+#if !HAVE_GETNAMEINFO
+#undef getnameinfo
+#undef NI_NUMERICHOST
+
+#define getnameinfo our_getnameinfo
+#define NI_NUMERICHOST 1
+
+/* A very simple getnameinfo() for platforms without */
+static int
+getnameinfo (const struct sockaddr *addr, int addr_len,
+ char *buffer, int buflen,
+ char *buf2, int buf2len,
+ int flags)
+{
+ switch (addr->sa_family) {
+ case AF_INET:
+ {
+ const struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+ const unsigned char *bytes = (unsigned char *)&sin->sin_addr.s_addr;
+ char tmpbuf[20];
+
+ sprintf (tmpbuf, "%d.%d.%d.%d",
+ bytes[0], bytes[1], bytes[2], bytes[3]);
+
+ strncpy (buffer, tmpbuf, buflen);
+ }
+ break;
+#ifdef AF_INET6
+ case AF_INET6:
+ {
+ const struct sockaddr_in6 *sin = (const struct sockaddr_in6 *)addr;
+ const unsigned char *bytes = sin->sin6_addr.s6_addr;
+ int n;
+ char tmpbuf[80], *ptr = tmpbuf;
+ int done_double_colon = FALSE;
+ int colon_mode = FALSE;
+
+ for (n = 0; n < 8; ++n) {
+ unsigned char b1 = bytes[2 * n];
+ unsigned char b2 = bytes[2 * n + 1];
+
+ if (b1) {
+ if (colon_mode) {
+ colon_mode = FALSE;
+ *ptr++ = ':';
+ }
+ sprintf (ptr, "%x%02x", b1, b2);
+ ptr += strlen (ptr);
+ *ptr++ = ':';
+ } else if (b2) {
+ if (colon_mode) {
+ colon_mode = FALSE;
+ *ptr++ = ':';
+ }
+ sprintf (ptr, "%x", b2);
+ ptr += strlen (ptr);
+ *ptr++ = ':';
+ } else {
+ if (!colon_mode) {
+ if (done_double_colon) {
+ *ptr++ = '0';
+ *ptr++ = ':';
+ } else {
+ if (n == 0)
+ *ptr++ = ':';
+ colon_mode = TRUE;
+ done_double_colon = TRUE;
+ }
+ }
+ }
+ }
+ if (colon_mode) {
+ colon_mode = FALSE;
+ *ptr++ = ':';
+ *ptr++ = '\0';
+ } else {
+ *--ptr = '\0';
+ }
+
+ strncpy (buffer, tmpbuf, buflen);
+ }
+ break;
+#endif /* AF_INET6 */
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+static int
+string_from_sockaddr (struct sockaddr *addr,
+ char *buffer,
+ int buflen)
+{
+ struct sockaddr* bigaddr = 0;
+ int failure;
+ struct sockaddr* gniaddr;
+ socklen_t gnilen;
+
+ if (!addr || addr->sa_family == AF_UNSPEC)
+ return -1;
+
+ if (SA_LEN(addr) < af_to_len(addr->sa_family)) {
+ /* Sometimes ifa_netmask can be truncated. So let's detruncate it. FreeBSD
+ PR: kern/152036: getifaddrs(3) returns truncated sockaddrs for netmasks
+ -- http://www.freebsd.org/cgi/query-pr.cgi?pr=152036 */
+ gnilen = af_to_len(addr->sa_family);
+ bigaddr = calloc(1, gnilen);
+ if (!bigaddr)
+ return -1;
+ memcpy(bigaddr, addr, SA_LEN(addr));
+#if HAVE_SOCKADDR_SA_LEN
+ bigaddr->sa_len = gnilen;
+#endif
+ gniaddr = bigaddr;
+ } else {
+ gnilen = SA_LEN(addr);
+ gniaddr = addr;
+ }
+
+ failure = getnameinfo (gniaddr, gnilen,
+ buffer, buflen,
+ NULL, 0,
+ NI_NUMERICHOST);
+
+ if (bigaddr) {
+ free(bigaddr);
+ bigaddr = 0;
+ }
+
+ if (failure) {
+ size_t n, len;
+ char *ptr;
+ const char *data;
+
+ len = SA_LEN(addr);
+
+#if HAVE_AF_LINK
+ /* BSD-like systems have AF_LINK */
+ if (addr->sa_family == AF_LINK) {
+ struct sockaddr_dl *dladdr = (struct sockaddr_dl *)addr;
+ len = dladdr->sdl_alen;
+ data = LLADDR(dladdr);
+ } else {
+#endif
+#if defined(AF_PACKET)
+ /* Linux has AF_PACKET instead */
+ if (addr->sa_family == AF_PACKET) {
+ struct sockaddr_ll *lladdr = (struct sockaddr_ll *)addr;
+ len = lladdr->sll_halen;
+ data = (const char *)lladdr->sll_addr;
+ } else {
+#endif
+ /* We don't know anything about this sockaddr, so just display
+ the entire data area in binary. */
+ len -= (sizeof (struct sockaddr) - sizeof (addr->sa_data));
+ data = addr->sa_data;
+#if defined(AF_PACKET)
+ }
+#endif
+#if HAVE_AF_LINK
+ }
+#endif
+
+ if (buflen < 3 * len)
+ return -1;
+
+ ptr = buffer;
+ buffer[0] = '\0';
+
+ for (n = 0; n < len; ++n) {
+ sprintf (ptr, "%02x:", data[n] & 0xff);
+ ptr += 3;
+ }
+ *--ptr = '\0';
+ }
+
+ if (!buffer[0])
+ return -1;
+
+ return 0;
+}
+#endif /* !defined(WIN32) */
+
+#if defined(WIN32)
+static int
+compare_bits (const void *pva,
+ const void *pvb,
+ unsigned bits)
+{
+ const unsigned char *pa = (const unsigned char *)pva;
+ const unsigned char *pb = (const unsigned char *)pvb;
+ unsigned char a, b;
+ static unsigned char masks[] = {
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
+ };
+ while (bits >= 8) {
+ a = *pa++;
+ b = *pb++;
+ if (a < b)
+ return -1;
+ else if (a > b)
+ return +1;
+ bits -= 8;
+ }
+
+ if (bits) {
+ a = *pa++ & masks[bits];
+ b = *pb++ & masks[bits];
+ if (a < b)
+ return -1;
+ else if (a > b)
+ return +1;
+ }
+
+ return 0;
+}
+#endif
+
+static int
+add_to_family (PyObject *result, int family, PyObject *obj)
+{
+ PyObject *py_family;
+ PyObject *list;
+
+ if (!PyObject_Size (obj))
+ return TRUE;
+
+ py_family = PyInt_FromLong (family);
+ list = PyDict_GetItem (result, py_family);
+
+ if (!py_family) {
+ Py_DECREF (obj);
+ Py_XDECREF (list);
+ return FALSE;
+ }
+
+ if (!list) {
+ list = PyList_New (1);
+ if (!list) {
+ Py_DECREF (obj);
+ Py_DECREF (py_family);
+ return FALSE;
+ }
+
+ PyList_SET_ITEM (list, 0, obj);
+ PyDict_SetItem (result, py_family, list);
+ Py_DECREF (list);
+ } else {
+ PyList_Append (list, obj);
+ Py_DECREF (obj);
+ }
+
+ return TRUE;
+}
+
+/* -- ifaddresses() --------------------------------------------------------- */
+
+static PyObject *
+ifaddrs (PyObject *self, PyObject *args)
+{
+ const char *ifname;
+ PyObject *result;
+ int found = FALSE;
+#if defined(WIN32)
+ PIP_ADAPTER_ADDRESSES pAdapterAddresses = NULL, pInfo = NULL;
+ ULONG ulBufferLength = 0;
+ DWORD dwRet;
+ PIP_ADAPTER_UNICAST_ADDRESS pUniAddr;
+#elif HAVE_GETIFADDRS
+ struct ifaddrs *addrs = NULL;
+ struct ifaddrs *addr = NULL;
+#endif
+
+ if (!PyArg_ParseTuple (args, "s", &ifname))
+ return NULL;
+
+ result = PyDict_New ();
+
+ if (!result)
+ return NULL;
+
+#if defined(WIN32)
+ /* .. Win32 ............................................................... */
+
+ /* First, retrieve the adapter information. We do this in a loop, in
+ case someone adds or removes adapters in the meantime. */
+ do {
+ dwRet = GetAdaptersAddresses (AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL,
+ pAdapterAddresses, &ulBufferLength);
+
+ if (dwRet == ERROR_BUFFER_OVERFLOW) {
+ if (pAdapterAddresses)
+ free (pAdapterAddresses);
+ pAdapterAddresses = (PIP_ADAPTER_ADDRESSES)malloc (ulBufferLength);
+
+ if (!pAdapterAddresses) {
+ Py_DECREF (result);
+ PyErr_SetString (PyExc_MemoryError, "Not enough memory");
+ return NULL;
+ }
+ }
+ } while (dwRet == ERROR_BUFFER_OVERFLOW);
+
+ /* If we failed, then fail in Python too */
+ if (dwRet != ERROR_SUCCESS && dwRet != ERROR_NO_DATA) {
+ Py_DECREF (result);
+ if (pAdapterAddresses)
+ free (pAdapterAddresses);
+
+ PyErr_SetString (PyExc_OSError,
+ "Unable to obtain adapter information.");
+ return NULL;
+ }
+
+ for (pInfo = pAdapterAddresses; pInfo; pInfo = pInfo->Next) {
+ char buffer[256];
+
+ if (strcmp (pInfo->AdapterName, ifname) != 0)
+ continue;
+
+ found = TRUE;
+
+ /* Do the physical address */
+ if (256 >= 3 * pInfo->PhysicalAddressLength) {
+ PyObject *hwaddr, *dict;
+ char *ptr = buffer;
+ unsigned n;
+
+ *ptr = '\0';
+ for (n = 0; n < pInfo->PhysicalAddressLength; ++n) {
+ sprintf (ptr, "%02x:", pInfo->PhysicalAddress[n] & 0xff);
+ ptr += 3;
+ }
+ *--ptr = '\0';
+
+ hwaddr = PyString_FromString (buffer);
+ dict = PyDict_New ();
+
+ if (!dict) {
+ Py_XDECREF (hwaddr);
+ Py_DECREF (result);
+ free (pAdapterAddresses);
+ return NULL;
+ }
+
+ PyDict_SetItemString (dict, "addr", hwaddr);
+ Py_DECREF (hwaddr);
+
+ if (!add_to_family (result, AF_LINK, dict)) {
+ Py_DECREF (result);
+ free (pAdapterAddresses);
+ return NULL;
+ }
+ }
+
+ for (pUniAddr = pInfo->FirstUnicastAddress;
+ pUniAddr;
+ pUniAddr = pUniAddr->Next) {
+ DWORD dwLen = sizeof (buffer);
+ INT iRet = WSAAddressToStringA (pUniAddr->Address.lpSockaddr,
+ pUniAddr->Address.iSockaddrLength,
+ NULL,
+ buffer,
+ &dwLen);
+ PyObject *addr;
+ PyObject *mask = NULL;
+ PyObject *bcast = NULL;
+ PIP_ADAPTER_PREFIX pPrefix;
+ short family = pUniAddr->Address.lpSockaddr->sa_family;
+
+ if (iRet)
+ continue;
+
+ addr = PyString_FromString (buffer);
+
+ /* Find the netmask, where possible */
+ if (family == AF_INET) {
+ struct sockaddr_in *pAddr
+ = (struct sockaddr_in *)pUniAddr->Address.lpSockaddr;
+
+ for (pPrefix = pInfo->FirstPrefix;
+ pPrefix;
+ pPrefix = pPrefix->Next) {
+ struct sockaddr_in *pPrefixAddr
+ = (struct sockaddr_in *)pPrefix->Address.lpSockaddr;
+ struct sockaddr_in maskAddr, bcastAddr;
+ unsigned toDo;
+ unsigned wholeBytes, remainingBits;
+ unsigned char *pMaskBits, *pBcastBits;
+
+ if (pPrefixAddr->sin_family != AF_INET)
+ continue;
+
+ if (compare_bits (&pPrefixAddr->sin_addr,
+ &pAddr->sin_addr,
+ pPrefix->PrefixLength) != 0)
+ continue;
+
+ memcpy (&maskAddr,
+ pPrefix->Address.lpSockaddr,
+ sizeof (maskAddr));
+ memcpy (&bcastAddr,
+ pPrefix->Address.lpSockaddr,
+ sizeof (bcastAddr));
+
+ wholeBytes = pPrefix->PrefixLength >> 3;
+ remainingBits = pPrefix->PrefixLength & 7;
+
+ if (wholeBytes >= 4)
+ continue;
+
+ toDo = wholeBytes;
+ pMaskBits = (unsigned char *)&maskAddr.sin_addr;
+
+ while (toDo--)
+ *pMaskBits++ = 0xff;
+
+ toDo = 4 - wholeBytes;
+
+ pBcastBits = (unsigned char *)&bcastAddr.sin_addr + wholeBytes;
+
+ if (remainingBits) {
+ static const unsigned char masks[] = {
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
+ };
+ *pMaskBits++ = masks[remainingBits];
+ *pBcastBits &= masks[remainingBits];
+ *pBcastBits++ |= ~masks[remainingBits];
+ --toDo;
+ }
+
+ while (toDo--) {
+ *pMaskBits++ = 0;
+ *pBcastBits++ = 0xff;
+ }
+
+ dwLen = sizeof (buffer);
+ iRet = WSAAddressToStringA ((SOCKADDR *)&maskAddr,
+ sizeof (maskAddr),
+ NULL,
+ buffer,
+ &dwLen);
+
+ if (iRet == 0)
+ mask = PyString_FromString (buffer);
+
+ dwLen = sizeof (buffer);
+ iRet = WSAAddressToStringA ((SOCKADDR *)&bcastAddr,
+ sizeof (bcastAddr),
+ NULL,
+ buffer,
+ &dwLen);
+
+ if (iRet == 0)
+ bcast = PyString_FromString (buffer);
+
+ break;
+ }
+ } else if (family == AF_INET6) {
+ struct sockaddr_in6 *pAddr
+ = (struct sockaddr_in6 *)pUniAddr->Address.lpSockaddr;
+
+ for (pPrefix = pInfo->FirstPrefix;
+ pPrefix;
+ pPrefix = pPrefix->Next) {
+ struct sockaddr_in6 *pPrefixAddr
+ = (struct sockaddr_in6 *)pPrefix->Address.lpSockaddr;
+ struct sockaddr_in6 maskAddr, bcastAddr;
+ unsigned toDo;
+ unsigned wholeBytes, remainingBits;
+ unsigned char *pMaskBits, *pBcastBits;
+
+ if (pPrefixAddr->sin6_family != AF_INET6)
+ continue;
+
+ if (compare_bits (&pPrefixAddr->sin6_addr,
+ &pAddr->sin6_addr,
+ pPrefix->PrefixLength) != 0)
+ continue;
+
+ memcpy (&maskAddr,
+ pPrefix->Address.lpSockaddr,
+ sizeof (maskAddr));
+ memcpy (&bcastAddr,
+ pPrefix->Address.lpSockaddr,
+ sizeof (bcastAddr));
+
+ wholeBytes = pPrefix->PrefixLength >> 3;
+ remainingBits = pPrefix->PrefixLength & 7;
+
+ if (wholeBytes >= 8)
+ continue;
+
+ toDo = wholeBytes;
+ pMaskBits = (unsigned char *)&maskAddr.sin6_addr;
+
+ while (toDo--)
+ *pMaskBits++ = 0xff;
+
+ toDo = 8 - wholeBytes;
+
+ pBcastBits = (unsigned char *)&bcastAddr.sin6_addr + wholeBytes;
+
+ if (remainingBits) {
+ static const unsigned char masks[] = {
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
+ };
+ *pMaskBits++ = masks[remainingBits];
+ *pBcastBits &= masks[remainingBits];
+ *pBcastBits++ |= ~masks[remainingBits];
+ --toDo;
+ }
+
+ while (toDo--) {
+ *pMaskBits++ = 0;
+ *pBcastBits++ = 0xff;
+ }
+
+ dwLen = sizeof (buffer);
+ iRet = WSAAddressToStringA ((SOCKADDR *)&maskAddr,
+ sizeof (maskAddr),
+ NULL,
+ buffer,
+ &dwLen);
+
+ if (iRet == 0)
+ mask = PyString_FromString (buffer);
+
+ dwLen = sizeof (buffer);
+ iRet = WSAAddressToStringA ((SOCKADDR *)&bcastAddr,
+ sizeof (bcastAddr),
+ NULL,
+ buffer,
+ &dwLen);
+
+ if (iRet == 0)
+ bcast = PyString_FromString (buffer);
+
+ break;
+ }
+ }
+
+ {
+ PyObject *dict;
+
+ dict = PyDict_New ();
+
+ if (!dict) {
+ Py_XDECREF (addr);
+ Py_XDECREF (mask);
+ Py_XDECREF (bcast);
+ Py_DECREF (result);
+ free (pAdapterAddresses);
+ return NULL;
+ }
+
+ if (addr)
+ PyDict_SetItemString (dict, "addr", addr);
+ if (mask)
+ PyDict_SetItemString (dict, "netmask", mask);
+ if (bcast)
+ PyDict_SetItemString (dict, "broadcast", bcast);
+
+ Py_XDECREF (addr);
+ Py_XDECREF (mask);
+ Py_XDECREF (bcast);
+
+ if (!add_to_family (result, family, dict)) {
+ Py_DECREF (result);
+ free ((void *)pAdapterAddresses);
+ return NULL;
+ }
+ }
+ }
+ }
+
+ free ((void *)pAdapterAddresses);
+#elif HAVE_GETIFADDRS
+ /* .. UNIX, with getifaddrs() ............................................. */
+
+ if (getifaddrs (&addrs) < 0) {
+ Py_DECREF (result);
+ PyErr_SetFromErrno (PyExc_OSError);
+ return NULL;
+ }
+
+ for (addr = addrs; addr; addr = addr->ifa_next) {
+ char buffer[256];
+ PyObject *pyaddr = NULL, *netmask = NULL, *braddr = NULL;
+
+ if (strcmp (addr->ifa_name, ifname) != 0)
+ continue;
+
+ /* We mark the interface as found, even if there are no addresses;
+ this results in sensible behaviour for these few cases. */
+ found = TRUE;
+
+ /* Sometimes there are records without addresses (e.g. in the case of a
+ dial-up connection via ppp, which on Linux can have a link address
+ record with no actual address). We skip these as they aren't useful.
+ Thanks to Christian Kauhaus for reporting this issue. */
+ if (!addr->ifa_addr)
+ continue;
+
+ if (string_from_sockaddr (addr->ifa_addr, buffer, sizeof (buffer)) == 0)
+ pyaddr = PyString_FromString (buffer);
+
+ if (string_from_sockaddr (addr->ifa_netmask, buffer, sizeof (buffer)) == 0)
+ netmask = PyString_FromString (buffer);
+
+ if (string_from_sockaddr (addr->ifa_broadaddr, buffer, sizeof (buffer)) == 0)
+ braddr = PyString_FromString (buffer);
+
+ {
+ PyObject *dict = PyDict_New();
+
+ if (!dict) {
+ Py_XDECREF (pyaddr);
+ Py_XDECREF (netmask);
+ Py_XDECREF (braddr);
+ Py_DECREF (result);
+ freeifaddrs (addrs);
+ return NULL;
+ }
+
+ if (pyaddr)
+ PyDict_SetItemString (dict, "addr", pyaddr);
+ if (netmask)
+ PyDict_SetItemString (dict, "netmask", netmask);
+
+ if (braddr) {
+ if (addr->ifa_flags & (IFF_POINTOPOINT | IFF_LOOPBACK))
+ PyDict_SetItemString (dict, "peer", braddr);
+ else
+ PyDict_SetItemString (dict, "broadcast", braddr);
+ }
+
+ Py_XDECREF (pyaddr);
+ Py_XDECREF (netmask);
+ Py_XDECREF (braddr);
+
+ if (!add_to_family (result, addr->ifa_addr->sa_family, dict)) {
+ Py_DECREF (result);
+ freeifaddrs (addrs);
+ return NULL;
+ }
+ }
+ }
+
+ freeifaddrs (addrs);
+#elif HAVE_SOCKET_IOCTLS
+ /* .. UNIX, with SIOC ioctls() ............................................ */
+
+ int sock = socket(AF_INET, SOCK_DGRAM, 0);
+
+ if (sock < 0) {
+ Py_DECREF (result);
+ PyErr_SetFromErrno (PyExc_OSError);
+ return NULL;
+ }
+
+ struct CNAME(ifreq) ifr;
+ PyObject *addr = NULL, *netmask = NULL, *braddr = NULL, *dstaddr = NULL;
+ int is_p2p = FALSE;
+ char buffer[256];
+
+ strncpy (ifr.CNAME(ifr_name), ifname, IFNAMSIZ);
+
+#if HAVE_SIOCGIFHWADDR
+ if (ioctl (sock, SIOCGIFHWADDR, &ifr) == 0) {
+ found = TRUE;
+
+ if (string_from_sockaddr ((struct sockaddr *)&ifr.CNAME(ifr_addr), buffer, sizeof (buffer)) == 0) {
+ PyObject *hwaddr = PyString_FromString (buffer);
+ PyObject *dict = PyDict_New ();
+
+ if (!hwaddr || !dict) {
+ Py_XDECREF (hwaddr);
+ Py_XDECREF (dict);
+ Py_XDECREF (result);
+ close (sock);
+ return NULL;
+ }
+
+ PyDict_SetItemString (dict, "addr", hwaddr);
+ Py_DECREF (hwaddr);
+
+ if (!add_to_family (result, AF_LINK, dict)) {
+ Py_DECREF (result);
+ close (sock);
+ return NULL;
+ }
+ }
+ }
+#endif
+
+#if HAVE_SIOCGIFADDR
+#if HAVE_SIOCGLIFNUM
+ if (ioctl (sock, SIOCGLIFADDR, &ifr) == 0) {
+#else
+ if (ioctl (sock, SIOCGIFADDR, &ifr) == 0) {
+#endif
+ found = TRUE;
+
+ if (string_from_sockaddr ((struct sockaddr *)&ifr.CNAME(ifr_addr), buffer, sizeof (buffer)) == 0)
+ addr = PyString_FromString (buffer);
+ }
+#endif
+
+#if HAVE_SIOCGIFNETMASK
+#if HAVE_SIOCGLIFNUM
+ if (ioctl (sock, SIOCGLIFNETMASK, &ifr) == 0) {
+#else
+ if (ioctl (sock, SIOCGIFNETMASK, &ifr) == 0) {
+#endif
+ found = TRUE;
+
+ if (string_from_sockaddr ((struct sockaddr *)&ifr.CNAME(ifr_addr), buffer, sizeof (buffer)) == 0)
+ netmask = PyString_FromString (buffer);
+ }
+#endif
+
+#if HAVE_SIOCGIFFLAGS
+#if HAVE_SIOCGLIFNUM
+ if (ioctl (sock, SIOCGLIFFLAGS, &ifr) == 0) {
+#else
+ if (ioctl (sock, SIOCGIFFLAGS, &ifr) == 0) {
+#endif
+ found = TRUE;
+
+ if (ifr.CNAME(ifr_flags) & IFF_POINTOPOINT)
+ is_p2p = TRUE;
+ }
+#endif
+
+#if HAVE_SIOCGIFBRDADDR
+#if HAVE_SIOCGLIFNUM
+ if (!is_p2p && ioctl (sock, SIOCGLIFBRDADDR, &ifr) == 0) {
+#else
+ if (!is_p2p && ioctl (sock, SIOCGIFBRDADDR, &ifr) == 0) {
+#endif
+ found = TRUE;
+
+ if (string_from_sockaddr ((struct sockaddr *)&ifr.CNAME(ifr_addr), buffer, sizeof (buffer)) == 0)
+ braddr = PyString_FromString (buffer);
+ }
+#endif
+
+#if HAVE_SIOCGIFDSTADDR
+#if HAVE_SIOCGLIFNUM
+ if (is_p2p && ioctl (sock, SIOCGLIFBRDADDR, &ifr) == 0) {
+#else
+ if (is_p2p && ioctl (sock, SIOCGIFBRDADDR, &ifr) == 0) {
+#endif
+ found = TRUE;
+
+ if (string_from_sockaddr ((struct sockaddr *)&ifr.CNAME(ifr_addr), buffer, sizeof (buffer)) == 0)
+ dstaddr = PyString_FromString (buffer);
+ }
+#endif
+
+ {
+ PyObject *dict = PyDict_New();
+
+ if (!dict) {
+ Py_XDECREF (addr);
+ Py_XDECREF (netmask);
+ Py_XDECREF (braddr);
+ Py_XDECREF (dstaddr);
+ Py_DECREF (result);
+ close (sock);
+ return NULL;
+ }
+
+ if (addr)
+ PyDict_SetItemString (dict, "addr", addr);
+ if (netmask)
+ PyDict_SetItemString (dict, "netmask", netmask);
+ if (braddr)
+ PyDict_SetItemString (dict, "broadcast", braddr);
+ if (dstaddr)
+ PyDict_SetItemString (dict, "peer", dstaddr);
+
+ Py_XDECREF (addr);
+ Py_XDECREF (netmask);
+ Py_XDECREF (braddr);
+ Py_XDECREF (dstaddr);
+
+ if (!add_to_family (result, AF_INET, dict)) {
+ Py_DECREF (result);
+ close (sock);
+ return NULL;
+ }
+ }
+
+ close (sock);
+#endif /* HAVE_SOCKET_IOCTLS */
+
+ if (found)
+ return result;
+ else {
+ Py_DECREF (result);
+ PyErr_SetString (PyExc_ValueError,
+ "You must specify a valid interface name.");
+ return NULL;
+ }
+}
+
+/* -- interfaces() ---------------------------------------------------------- */
+
+static PyObject *
+interfaces (PyObject *self)
+{
+ PyObject *result;
+
+#if defined(WIN32)
+ /* .. Win32 ............................................................... */
+
+ PIP_ADAPTER_ADDRESSES pAdapterAddresses = NULL, pInfo = NULL;
+ ULONG ulBufferLength = 0;
+ DWORD dwRet;
+
+ /* First, retrieve the adapter information */
+ do {
+ dwRet = GetAdaptersAddresses(AF_UNSPEC, 0, NULL,
+ pAdapterAddresses, &ulBufferLength);
+
+ if (dwRet == ERROR_BUFFER_OVERFLOW) {
+ if (pAdapterAddresses)
+ free (pAdapterAddresses);
+ pAdapterAddresses = (PIP_ADAPTER_ADDRESSES)malloc (ulBufferLength);
+
+ if (!pAdapterAddresses) {
+ PyErr_SetString (PyExc_MemoryError, "Not enough memory");
+ return NULL;
+ }
+ }
+ } while (dwRet == ERROR_BUFFER_OVERFLOW);
+
+ /* If we failed, then fail in Python too */
+ if (dwRet != ERROR_SUCCESS && dwRet != ERROR_NO_DATA) {
+ if (pAdapterAddresses)
+ free (pAdapterAddresses);
+
+ PyErr_SetString (PyExc_OSError,
+ "Unable to obtain adapter information.");
+ return NULL;
+ }
+
+ result = PyList_New(0);
+
+ if (dwRet == ERROR_NO_DATA) {
+ free (pAdapterAddresses);
+ return result;
+ }
+
+ for (pInfo = pAdapterAddresses; pInfo; pInfo = pInfo->Next) {
+ PyObject *ifname = (PyObject *)PyString_FromString (pInfo->AdapterName);
+
+ PyList_Append (result, ifname);
+ Py_DECREF (ifname);
+ }
+
+ free (pAdapterAddresses);
+#elif HAVE_GETIFADDRS
+ /* .. UNIX, with getifaddrs() ............................................. */
+
+ const char *prev_name = NULL;
+ struct ifaddrs *addrs = NULL;
+ struct ifaddrs *addr = NULL;
+
+ result = PyList_New (0);
+
+ if (getifaddrs (&addrs) < 0) {
+ Py_DECREF (result);
+ PyErr_SetFromErrno (PyExc_OSError);
+ return NULL;
+ }
+
+ for (addr = addrs; addr; addr = addr->ifa_next) {
+ if (!prev_name || strncmp (addr->ifa_name, prev_name, IFNAMSIZ) != 0) {
+ PyObject *ifname = PyString_FromString (addr->ifa_name);
+
+ if (!PySequence_Contains (result, ifname))
+ PyList_Append (result, ifname);
+ Py_DECREF (ifname);
+ prev_name = addr->ifa_name;
+ }
+ }
+
+ freeifaddrs (addrs);
+#elif HAVE_SIOCGIFCONF
+ /* .. UNIX, with SIOC ioctl()s ............................................ */
+
+ const char *prev_name = NULL;
+ int fd = socket (AF_INET, SOCK_DGRAM, 0);
+ struct CNAME(ifconf) ifc;
+ int len = -1;
+
+ if (fd < 0) {
+ PyErr_SetFromErrno (PyExc_OSError);
+ return NULL;
+ }
+
+ // Try to find out how much space we need
+#if HAVE_SIOCGSIZIFCONF
+ if (ioctl (fd, SIOCGSIZIFCONF, &len) < 0)
+ len = -1;
+#elif HAVE_SIOCGLIFNUM
+ { struct lifnum lifn;
+ lifn.lifn_family = AF_UNSPEC;
+ lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
+ ifc.lifc_family = AF_UNSPEC;
+ ifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
+ if (ioctl (fd, SIOCGLIFNUM, (char *)&lifn) < 0)
+ len = -1;
+ else
+ len = lifn.lifn_count;
+ }
+#endif
+
+ // As a last resort, guess
+ if (len < 0)
+ len = 64;
+
+ ifc.CNAME(ifc_len) = (int)(len * sizeof (struct CNAME(ifreq)));
+ ifc.CNAME(ifc_buf) = malloc (ifc.CNAME(ifc_len));
+
+ if (!ifc.CNAME(ifc_buf)) {
+ PyErr_SetString (PyExc_MemoryError, "Not enough memory");
+ close (fd);
+ return NULL;
+ }
+
+#if HAVE_SIOCGLIFNUM
+ if (ioctl (fd, SIOCGLIFCONF, &ifc) < 0) {
+#else
+ if (ioctl (fd, SIOCGIFCONF, &ifc) < 0) {
+#endif
+ free (ifc.CNAME(ifc_req));
+ PyErr_SetFromErrno (PyExc_OSError);
+ close (fd);
+ return NULL;
+ }
+
+ result = PyList_New (0);
+ struct CNAME(ifreq) *pfreq = ifc.CNAME(ifc_req);
+ struct CNAME(ifreq) *pfreqend = (struct CNAME(ifreq) *)((char *)pfreq
+ + ifc.CNAME(ifc_len));
+ while (pfreq < pfreqend) {
+ if (!prev_name || strncmp (prev_name, pfreq->CNAME(ifr_name), IFNAMSIZ) != 0) {
+ PyObject *name = PyString_FromString (pfreq->CNAME(ifr_name));
+
+ if (!PySequence_Contains (result, name))
+ PyList_Append (result, name);
+ Py_XDECREF (name);
+
+ prev_name = pfreq->CNAME(ifr_name);
+ }
+
+#if !HAVE_SOCKADDR_SA_LEN
+ ++pfreq;
+#else
+ /* On some platforms, the ifreq struct can *grow*(!) if the socket address
+ is very long. Mac OS X is such a platform. */
+ {
+ size_t len = sizeof (struct CNAME(ifreq));
+ if (pfreq->ifr_addr.sa_len > sizeof (struct sockaddr))
+ len = len - sizeof (struct sockaddr) + pfreq->ifr_addr.sa_len;
+ pfreq = (struct CNAME(ifreq) *)((char *)pfreq + len);
+ }
+#endif
+ }
+
+ free (ifc.CNAME(ifc_buf));
+ close (fd);
+#endif /* HAVE_SIOCGIFCONF */
+
+ return result;
+}
+
+/* -- gateways() ------------------------------------------------------------ */
+
+static PyObject *
+gateways (PyObject *self)
+{
+ PyObject *result, *defaults;
+
+#if defined(WIN32)
+ /* .. Win32 ............................................................... */
+
+ /* We try to access GetIPForwardTable2() and FreeMibTable() through
+ function pointers so that this code will still run on machines
+ running Windows versions prior to Vista. On those systems, we
+ fall back to the older GetIPForwardTable() API (and can only find
+ IPv4 gateways as a result).
+
+ We also fall back to the older API if the newer code fails for
+ some reason. */
+
+ HANDLE hIpHelper;
+ typedef NTSTATUS (WINAPI *PGETIPFORWARDTABLE2)(ADDRESS_FAMILY Family,
+ PMIB_IPFORWARD_TABLE2 *pTable);
+ typedef VOID (WINAPI *PFREEMIBTABLE)(PVOID Memory);
+
+ PGETIPFORWARDTABLE2 pGetIpForwardTable2;
+ PFREEMIBTABLE pFreeMibTable;
+
+ hIpHelper = GetModuleHandle (TEXT("iphlpapi.dll"));
+
+ result = NULL;
+ pGetIpForwardTable2 = (PGETIPFORWARDTABLE2)
+ GetProcAddress (hIpHelper, "GetIpForwardTable2");
+ pFreeMibTable = (PFREEMIBTABLE)
+ GetProcAddress (hIpHelper, "FreeMibTable");
+
+ if (pGetIpForwardTable2) {
+ PMIB_IPFORWARD_TABLE2 table;
+ DWORD dwErr = pGetIpForwardTable2 (AF_UNSPEC, &table);
+
+ if (dwErr == NO_ERROR) {
+ DWORD n;
+ BOOL bFirstInet = TRUE, bFirstInet6 = TRUE;
+
+ result = PyDict_New();
+ defaults = PyDict_New();
+ PyDict_SetItemString (result, "default", defaults);
+ Py_DECREF(defaults);
+
+ /* This prevents a crash on PyPy */
+ defaults = PyDict_GetItemString (result, "default");
+
+ for (n = 0; n < table->NumEntries; ++n) {
+ MIB_IFROW ifRow;
+ PyObject *ifname;
+ PyObject *gateway;
+ PyObject *isdefault;
+ PyObject *tuple, *deftuple = NULL;
+ char gwbuf[256];
+ WCHAR *pwcsName;
+ DWORD dwFamily = table->Table[n].NextHop.si_family;
+ BOOL bFirst;
+ DWORD dwLen;
+ INT iRet;
+
+ if (table->Table[n].DestinationPrefix.PrefixLength)
+ continue;
+
+ switch (dwFamily) {
+ case AF_INET:
+ if (!table->Table[n].NextHop.Ipv4.sin_addr.s_addr)
+ continue;
+ break;
+ case AF_INET6:
+ if (memcmp (&table->Table[n].NextHop.Ipv6.sin6_addr,
+ &in6addr_any,
+ sizeof (struct in6_addr)) == 0)
+ continue;
+ break;
+ default:
+ continue;
+ }
+
+ memset (&ifRow, 0, sizeof (ifRow));
+ ifRow.dwIndex = table->Table[n].InterfaceIndex;
+ if (GetIfEntry (&ifRow) != NO_ERROR)
+ continue;
+
+ dwLen = sizeof (gwbuf);
+ iRet = WSAAddressToStringA ((SOCKADDR *)&table->Table[n].NextHop,
+ sizeof (table->Table[n].NextHop),
+ NULL,
+ gwbuf,
+ &dwLen);
+
+ if (iRet != NO_ERROR)
+ continue;
+
+ /* Strip the prefix from the interface name */
+ pwcsName = ifRow.wszName;
+ if (_wcsnicmp (L"\\DEVICE\\TCPIP_", pwcsName, 14) == 0)
+ pwcsName += 14;
+
+ switch (dwFamily) {
+ case AF_INET:
+ bFirst = bFirstInet;
+ bFirstInet = FALSE;
+ break;
+ case AF_INET6:
+ bFirst = bFirstInet6;
+ bFirstInet6 = FALSE;
+ break;
+ }
+
+ ifname = PyUnicode_FromUnicode (pwcsName, wcslen (pwcsName));
+ gateway = PyString_FromString (gwbuf);
+ isdefault = bFirst ? Py_True : Py_False;
+
+ tuple = PyTuple_Pack (3, gateway, ifname, isdefault);
+
+ if (PyObject_IsTrue (isdefault))
+ deftuple = PyTuple_Pack (2, gateway, ifname);
+
+ Py_DECREF (gateway);
+ Py_DECREF (ifname);
+
+ if (tuple && !add_to_family (result, dwFamily, tuple)) {
+ Py_DECREF (deftuple);
+ Py_DECREF (result);
+ free (table);
+ return NULL;
+ }
+
+ if (deftuple) {
+ PyObject *pyfamily = PyInt_FromLong (dwFamily);
+
+ PyDict_SetItem (defaults, pyfamily, deftuple);
+
+ Py_DECREF (pyfamily);
+ Py_DECREF (deftuple);
+ }
+ }
+
+ pFreeMibTable (table);
+ }
+ }
+
+ if (!result) {
+ PMIB_IPFORWARDTABLE table = NULL;
+ DWORD dwRet;
+ DWORD dwSize = 0;
+ DWORD n;
+ BOOL bFirst = TRUE;
+
+ do {
+ dwRet = GetIpForwardTable (table, &dwSize, FALSE);
+
+ if (dwRet == ERROR_INSUFFICIENT_BUFFER) {
+ PMIB_IPFORWARDTABLE tbl = (PMIB_IPFORWARDTABLE)realloc (table, dwSize);
+
+ if (!tbl) {
+ free (table);
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ table = tbl;
+ }
+ } while (dwRet == ERROR_INSUFFICIENT_BUFFER);
+
+ if (dwRet != NO_ERROR) {
+ free (table);
+ PyErr_SetFromWindowsErr (dwRet);
+ return NULL;
+ }
+
+ result = PyDict_New();
+ defaults = PyDict_New();
+ PyDict_SetItemString (result, "default", defaults);
+ Py_DECREF(defaults);
+
+ /* This prevents a crash on PyPy */
+ defaults = PyDict_GetItemString (result, "default");
+
+ for (n = 0; n < table->dwNumEntries; ++n) {
+ MIB_IFROW ifRow;
+ PyObject *ifname;
+ PyObject *gateway;
+ PyObject *isdefault;
+ PyObject *tuple, *deftuple = NULL;
+ DWORD dwGateway;
+ char gwbuf[16];
+ WCHAR *pwcsName;
+
+ if (table->table[n].dwForwardDest
+ || !table->table[n].dwForwardNextHop
+ || table->table[n].dwForwardType != MIB_IPROUTE_TYPE_INDIRECT)
+ continue;
+
+ memset (&ifRow, 0, sizeof (ifRow));
+ ifRow.dwIndex = table->table[n].dwForwardIfIndex;
+ if (GetIfEntry (&ifRow) != NO_ERROR)
+ continue;
+
+ dwGateway = ntohl (table->table[n].dwForwardNextHop);
+
+ sprintf (gwbuf, "%u.%u.%u.%u",
+ (dwGateway >> 24) & 0xff,
+ (dwGateway >> 16) & 0xff,
+ (dwGateway >> 8) & 0xff,
+ dwGateway & 0xff);
+
+ /* Strip the prefix from the interface name */
+ pwcsName = ifRow.wszName;
+ if (_wcsnicmp (L"\\DEVICE\\TCPIP_", pwcsName, 14) == 0)
+ pwcsName += 14;
+
+ ifname = PyUnicode_FromUnicode (pwcsName, wcslen (pwcsName));
+ gateway = PyString_FromString (gwbuf);
+ isdefault = bFirst ? Py_True : Py_False;
+ bFirst = FALSE;
+
+ tuple = PyTuple_Pack (3, gateway, ifname, isdefault);
+
+ if (PyObject_IsTrue (isdefault))
+ deftuple = PyTuple_Pack (2, gateway, ifname);
+
+ Py_DECREF (gateway);
+ Py_DECREF (ifname);
+
+ if (tuple && !add_to_family (result, AF_INET, tuple)) {
+ Py_DECREF (deftuple);
+ Py_DECREF (result);
+ free (table);
+ return NULL;
+ }
+
+ if (deftuple) {
+ PyObject *pyfamily = PyInt_FromLong (AF_INET);
+
+ PyDict_SetItem (defaults, pyfamily, deftuple);
+
+ Py_DECREF (pyfamily);
+ Py_DECREF (deftuple);
+ }
+ }
+ }
+#elif defined(HAVE_PF_NETLINK)
+ /* .. Linux (PF_NETLINK socket) ........................................... */
+
+ /* PF_NETLINK is pretty poorly documented and it looks to be quite easy to
+ get wrong. This *appears* to be the right way to do it, even though a
+ lot of the code out there on the 'Net is very different! */
+
+ struct routing_msg {
+ struct nlmsghdr hdr;
+ struct rtmsg rt;
+ char data[0];
+ } *pmsg, *msgbuf;
+ int s;
+ int seq = 0;
+ ssize_t ret;
+ struct sockaddr_nl sanl;
+ static const struct sockaddr_nl sanl_kernel = { .nl_family = AF_NETLINK };
+ socklen_t sanl_len;
+ int pagesize = getpagesize();
+ int bufsize = pagesize < 8192 ? pagesize : 8192;
+ int is_multi = 0;
+ int interrupted = 0;
+
+ result = PyDict_New();
+ defaults = PyDict_New();
+ PyDict_SetItemString (result, "default", defaults);
+ Py_DECREF (defaults);
+
+ /* This prevents a crash on PyPy */
+ defaults = PyDict_GetItemString (result, "default");
+
+ msgbuf = (struct routing_msg *)malloc (bufsize);
+
+ if (!msgbuf) {
+ PyErr_NoMemory ();
+ Py_DECREF (result);
+ return NULL;
+ }
+
+ s = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+
+ if (s < 0) {
+ PyErr_SetFromErrno (PyExc_OSError);
+ Py_DECREF (result);
+ free (msgbuf);
+ return NULL;
+ }
+
+ sanl.nl_family = AF_NETLINK;
+ sanl.nl_groups = 0;
+ sanl.nl_pid = 0;
+
+ if (bind (s, (struct sockaddr *)&sanl, sizeof (sanl)) < 0) {
+ PyErr_SetFromErrno (PyExc_OSError);
+ Py_DECREF (result);
+ free (msgbuf);
+ close (s);
+ return NULL;
+ }
+
+ sanl_len = sizeof (sanl);
+ if (getsockname (s, (struct sockaddr *)&sanl, &sanl_len) < 0) {
+ PyErr_SetFromErrno (PyExc_OSError);
+ Py_DECREF (result);
+ free (msgbuf);
+ close (s);
+ return NULL;
+ }
+
+ do {
+ interrupted = 0;
+
+ pmsg = msgbuf;
+ memset (pmsg, 0, sizeof (struct routing_msg));
+ pmsg->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+ pmsg->hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+ pmsg->hdr.nlmsg_seq = ++seq;
+ pmsg->hdr.nlmsg_type = RTM_GETROUTE;
+ pmsg->hdr.nlmsg_pid = 0;
+
+ pmsg->rt.rtm_family = 0;
+
+ if (sendto (s, pmsg, pmsg->hdr.nlmsg_len, 0,
+ (struct sockaddr *)&sanl_kernel, sizeof(sanl_kernel)) < 0) {
+ PyErr_SetFromErrno (PyExc_OSError);
+ Py_DECREF (result);
+ free (msgbuf);
+ close (s);
+ return NULL;
+ }
+
+ do {
+ struct sockaddr_nl sanl_from;
+ struct iovec iov = { msgbuf, bufsize };
+ struct msghdr msghdr = {
+ &sanl_from,
+ sizeof(sanl_from),
+ &iov,
+ 1,
+ NULL,
+ 0,
+ 0
+ };
+ int nllen;
+
+ ret = recvmsg (s, &msghdr, 0);
+
+ if (msghdr.msg_flags & MSG_TRUNC) {
+ PyErr_SetString (PyExc_OSError, "netlink message truncated");
+ Py_DECREF (result);
+ free (msgbuf);
+ close (s);
+ return NULL;
+ }
+
+ if (ret < 0) {
+ PyErr_SetFromErrno (PyExc_OSError);
+ Py_DECREF (result);
+ free (msgbuf);
+ close (s);
+ return NULL;
+ }
+
+ nllen = ret;
+ pmsg = msgbuf;
+ while (NLMSG_OK (&pmsg->hdr, nllen)) {
+ void *dst = NULL;
+ void *gw = NULL;
+ int ifndx = -1;
+ struct rtattr *attrs, *attr;
+ int len;
+
+ /* Ignore messages not for us */
+ if (pmsg->hdr.nlmsg_seq != seq || pmsg->hdr.nlmsg_pid != sanl.nl_pid)
+ goto next;
+
+ /* This is only defined on Linux kernel versions 3.1 and higher */
+#ifdef NLM_F_DUMP_INTR
+ if (pmsg->hdr.nlmsg_flags & NLM_F_DUMP_INTR) {
+ /* The dump was interrupted by a signal; we need to go round again */
+ interrupted = 1;
+ is_multi = 0;
+ break;
+ }
+#endif
+
+ is_multi = pmsg->hdr.nlmsg_flags & NLM_F_MULTI;
+
+ if (pmsg->hdr.nlmsg_type == NLMSG_DONE) {
+ is_multi = interrupted = 0;
+ break;
+ }
+
+ if (pmsg->hdr.nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *perr = (struct nlmsgerr *)&pmsg->rt;
+ errno = -perr->error;
+ PyErr_SetFromErrno (PyExc_OSError);
+ Py_DECREF (result);
+ free (msgbuf);
+ close (s);
+ return NULL;
+ }
+
+ attr = attrs = RTM_RTA(&pmsg->rt);
+ len = RTM_PAYLOAD(&pmsg->hdr);
+
+ while (RTA_OK(attr, len)) {
+ switch (attr->rta_type) {
+ case RTA_GATEWAY:
+ gw = RTA_DATA(attr);
+ break;
+ case RTA_DST:
+ dst = RTA_DATA(attr);
+ break;
+ case RTA_OIF:
+ ifndx = *(int *)RTA_DATA(attr);
+ break;
+ default:
+ break;
+ }
+
+ attr = RTA_NEXT(attr, len);
+ }
+
+ /* We're looking for gateways with no destination */
+ if (!dst && gw && ifndx >= 0) {
+ char buffer[256];
+ char ifnamebuf[IF_NAMESIZE];
+ char *ifname;
+ const char *addr;
+ PyObject *pyifname;
+ PyObject *pyaddr;
+ PyObject *isdefault;
+ PyObject *tuple = NULL, *deftuple = NULL;
+
+ ifname = if_indextoname (ifndx, ifnamebuf);
+
+ if (!ifname)
+ goto next;
+
+ addr = inet_ntop (pmsg->rt.rtm_family, gw, buffer, sizeof (buffer));
+
+ if (!addr)
+ goto next;
+
+ /* We set isdefault to True if this route came from the main table;
+ this should correspond with the way most people set up alternate
+ routing tables on Linux. */
+
+ isdefault = pmsg->rt.rtm_table == RT_TABLE_MAIN ? Py_True : Py_False;
+ pyifname = PyString_FromString (ifname);
+ pyaddr = PyString_FromString (buffer);
+
+ tuple = PyTuple_Pack (3, pyaddr, pyifname, isdefault);
+
+ if (PyObject_IsTrue (isdefault))
+ deftuple = PyTuple_Pack (2, pyaddr, pyifname);
+
+ Py_DECREF (pyaddr);
+ Py_DECREF (pyifname);
+
+ if (tuple && !add_to_family (result, pmsg->rt.rtm_family, tuple)) {
+ Py_XDECREF (deftuple);
+ Py_DECREF (result);
+ free (msgbuf);
+ close (s);
+ return NULL;
+ }
+
+ if (deftuple) {
+ PyObject *pyfamily = PyInt_FromLong (pmsg->rt.rtm_family);
+
+ PyDict_SetItem (defaults, pyfamily, deftuple);
+
+ Py_DECREF (pyfamily);
+ Py_DECREF (deftuple);
+ }
+ }
+
+ next:
+ pmsg = (struct routing_msg *)NLMSG_NEXT(&pmsg->hdr, nllen);
+ }
+ } while (is_multi);
+ } while (interrupted);
+
+ free (msgbuf);
+ close (s);
+#elif defined(HAVE_SYSCTL_CTL_NET)
+ /* .. UNIX, via sysctl() .................................................. */
+
+ int mib[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_FLAGS,
+ RTF_UP | RTF_GATEWAY };
+ size_t len;
+ char *buffer = NULL, *ptr, *end;
+ int ret;
+ char ifnamebuf[IF_NAMESIZE];
+ char *ifname;
+
+ result = PyDict_New();
+ defaults = PyDict_New();
+ PyDict_SetItemString (result, "default", defaults);
+ Py_DECREF (defaults);
+
+ /* This prevents a crash on PyPy */
+ defaults = PyDict_GetItemString (result, "default");
+
+ /* Remembering that the routing table may change while we're reading it,
+ we need to do this in a loop until we succeed. */
+ do {
+ if (sysctl (mib, 6, 0, &len, 0, 0) < 0) {
+ PyErr_SetFromErrno (PyExc_OSError);
+ free (buffer);
+ Py_DECREF (result);
+ return NULL;
+ }
+
+ ptr = realloc(buffer, len);
+ if (!ptr) {
+ PyErr_NoMemory();
+ free (buffer);
+ Py_DECREF (result);
+ return NULL;
+ }
+
+ buffer = ptr;
+
+ ret = sysctl (mib, 6, buffer, &len, 0, 0);
+ } while (ret != 0 || errno == ENOMEM || errno == EINTR);
+
+ if (ret < 0) {
+ PyErr_SetFromErrno (PyExc_OSError);
+ free (buffer);
+ Py_DECREF (result);
+ return NULL;
+ }
+
+ ptr = buffer;
+ end = buffer + len;
+
+ while (ptr + sizeof (struct rt_msghdr) <= end) {
+ struct rt_msghdr *msg = (struct rt_msghdr *)ptr;
+ char *msgend = (char *)msg + msg->rtm_msglen;
+ int addrs = msg->rtm_addrs;
+ int addr = RTA_DST;
+ PyObject *pyifname;
+
+ if (msgend > end)
+ break;
+
+ ifname = if_indextoname (msg->rtm_index, ifnamebuf);
+
+ if (!ifname) {
+ ptr = msgend;
+ continue;
+ }
+
+ pyifname = PyString_FromString (ifname);
+
+ ptr = (char *)(msg + 1);
+ while (ptr + sizeof (struct sockaddr) <= msgend && addrs) {
+ struct sockaddr *sa = (struct sockaddr *)ptr;
+ int len = SA_LEN(sa);
+
+ if (!len)
+ len = 4;
+ else
+ len = (len + 3) & ~3;
+
+ if (ptr + len > msgend)
+ break;
+
+ while (!(addrs & addr))
+ addr <<= 1;
+
+ addrs &= ~addr;
+
+ if (addr == RTA_DST) {
+ if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+ if (sin->sin_addr.s_addr != INADDR_ANY)
+ break;
+#ifdef AF_INET6
+ } else if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+ if (memcmp (&sin6->sin6_addr, &in6addr_any, sizeof (in6addr_any)) != 0)
+ break;
+#endif
+ } else {
+ break;
+ }
+ }
+
+ if (addr == RTA_GATEWAY) {
+ char buffer[256];
+ PyObject *tuple = NULL;
+ PyObject *deftuple = NULL;
+
+ if (string_from_sockaddr (sa, buffer, sizeof(buffer)) == 0) {
+ PyObject *pyaddr = PyString_FromString (buffer);
+#ifdef RTF_IFSCOPE
+ PyObject *isdefault = PyBool_FromLong (!(msg->rtm_flags & RTF_IFSCOPE));
+#else
+ Py_INCREF(Py_True);
+ PyObject *isdefault = Py_True;
+#endif
+ tuple = PyTuple_Pack (3, pyaddr, pyifname, isdefault);
+
+ if (PyObject_IsTrue (isdefault))
+ deftuple = PyTuple_Pack (2, pyaddr, pyifname);
+
+ Py_DECREF (pyaddr);
+ Py_DECREF (isdefault);
+ }
+
+ if (tuple && !add_to_family (result, sa->sa_family, tuple)) {
+ Py_DECREF (deftuple);
+ Py_DECREF (result);
+ Py_DECREF (pyifname);
+ free (buffer);
+ return NULL;
+ }
+
+ if (deftuple) {
+ PyObject *pyfamily = PyInt_FromLong (sa->sa_family);
+
+ PyDict_SetItem (defaults, pyfamily, deftuple);
+
+ Py_DECREF (pyfamily);
+ Py_DECREF (deftuple);
+ }
+ }
+
+ /* These are aligned on a 4-byte boundary */
+ ptr += len;
+ }
+
+ Py_DECREF (pyifname);
+ ptr = msgend;
+ }
+
+ free (buffer);
+#elif defined(HAVE_PF_ROUTE)
+ /* .. UNIX, via PF_ROUTE socket ........................................... */
+
+ /* The PF_ROUTE code will only retrieve gateway information for AF_INET and
+ AF_INET6. This is because it would need to loop through all possible
+ values, and the messages it needs to send in each case are potentially
+ different. It is also very likely to return a maximum of one gateway
+ in each case (since we can't read the entire routing table this way, we
+ can only ask about routes). */
+
+ int pagesize = getpagesize();
+ int bufsize = pagesize < 8192 ? 8192 : pagesize;
+ struct rt_msghdr *pmsg;
+ int s;
+ int seq = 0;
+ int pid = getpid();
+ ssize_t ret;
+ struct sockaddr_in *sin_dst, *sin_netmask;
+ struct sockaddr_dl *sdl_ifp;
+ struct sockaddr_in6 *sin6_dst;
+ size_t msglen;
+ char ifnamebuf[IF_NAMESIZE];
+ char *ifname;
+ int skip;
+
+ result = PyDict_New();
+ defaults = PyDict_New();
+ PyDict_SetItemString (result, "default", defaults);
+ Py_DECREF(defaults);
+
+ pmsg = (struct rt_msghdr *)malloc (bufsize);
+
+ if (!pmsg) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ s = socket (PF_ROUTE, SOCK_RAW, 0);
+
+ if (s < 0) {
+ PyErr_SetFromErrno (PyExc_OSError);
+ free (pmsg);
+ return NULL;
+ }
+
+ msglen = (sizeof (struct rt_msghdr)
+ + 2 * sizeof (struct sockaddr_in)
+ + sizeof (struct sockaddr_dl));
+ memset (pmsg, 0, msglen);
+
+ /* AF_INET first */
+ pmsg->rtm_msglen = msglen;
+ pmsg->rtm_type = RTM_GET;
+ pmsg->rtm_index = 0;
+ pmsg->rtm_flags = RTF_UP | RTF_GATEWAY;
+ pmsg->rtm_version = RTM_VERSION;
+ pmsg->rtm_seq = ++seq;
+ pmsg->rtm_pid = 0;
+ pmsg->rtm_addrs = RTA_DST | RTA_NETMASK | RTA_IFP;
+
+ sin_dst = (struct sockaddr_in *)(pmsg + 1);
+ sin_netmask = (struct sockaddr_in *)(sin_dst + 1);
+ sdl_ifp = (struct sockaddr_dl *)(sin_netmask + 1);
+
+ sin_dst->sin_family = AF_INET;
+ sin_netmask->sin_family = AF_INET;
+ sdl_ifp->sdl_family = AF_LINK;
+
+#if HAVE_SOCKADDR_SA_LEN
+ sin_dst->sin_len = sizeof (struct sockaddr_in);
+ sin_netmask->sin_len = sizeof (struct sockaddr_in);
+ sdl_ifp->sdl_len = sizeof (struct sockaddr_dl);
+#endif
+
+ skip = 0;
+ if (send (s, pmsg, msglen, 0) < 0) {
+ if (errno == ESRCH)
+ skip = 1;
+ else {
+ PyErr_SetFromErrno (PyExc_OSError);
+ close (s);
+ free (pmsg);
+ return NULL;
+ }
+ }
+
+ while (!skip && !(pmsg->rtm_flags & RTF_DONE)) {
+ char *ptr;
+ char *msgend;
+ int addrs;
+ int addr;
+ struct sockaddr_in *dst = NULL;
+ struct sockaddr_in *gw = NULL;
+ struct sockaddr_dl *ifp = NULL;
+ PyObject *tuple = NULL;
+ PyObject *deftuple = NULL;
+
+ do {
+ ret = recv (s, pmsg, bufsize, 0);
+ } while ((ret < 0 && errno == EINTR)
+ || (ret > 0 && (pmsg->rtm_seq != seq || pmsg->rtm_pid != pid)));
+
+ if (ret < 0) {
+ PyErr_SetFromErrno (PyExc_OSError);
+ close (s);
+ free (pmsg);
+ return NULL;
+ }
+
+ if (pmsg->rtm_errno != 0) {
+ if (pmsg->rtm_errno == ESRCH)
+ skip = 1;
+ else {
+ errno = pmsg->rtm_errno;
+ PyErr_SetFromErrno (PyExc_OSError);
+ close (s);
+ free (pmsg);
+ return NULL;
+ }
+ }
+
+ if (skip)
+ break;
+
+ ptr = (char *)(pmsg + 1);
+ msgend = (char *)pmsg + pmsg->rtm_msglen;
+ addrs = pmsg->rtm_addrs;
+ addr = RTA_DST;
+ while (ptr + sizeof (struct sockaddr) <= msgend && addrs) {
+ struct sockaddr *sa = (struct sockaddr *)ptr;
+ int len = SA_LEN(sa);
+
+ if (!len)
+ len = 4;
+ else
+ len = (len + 3) & ~3;
+
+ if (ptr + len > msgend)
+ break;
+
+ while (!(addrs & addr))
+ addr <<= 1;
+
+ addrs &= ~addr;
+
+ switch (addr) {
+ case RTA_DST:
+ dst = (struct sockaddr_in *)sa;
+ break;
+ case RTA_GATEWAY:
+ gw = (struct sockaddr_in *)sa;
+ break;
+ case RTA_IFP:
+ ifp = (struct sockaddr_dl *)sa;
+ break;
+ }
+
+ ptr += len;
+ }
+
+ if ((dst && dst->sin_family != AF_INET)
+ || (gw && gw->sin_family != AF_INET)
+ || (ifp && ifp->sdl_family != AF_LINK)) {
+ dst = gw = NULL;
+ ifp = NULL;
+ }
+
+ if (dst && dst->sin_addr.s_addr == INADDR_ANY)
+ dst = NULL;
+
+ if (!dst && gw && ifp) {
+ char buffer[256];
+
+ if (ifp->sdl_index)
+ ifname = if_indextoname (ifp->sdl_index, ifnamebuf);
+ else {
+ memcpy (ifnamebuf, ifp->sdl_data, ifp->sdl_nlen);
+ ifnamebuf[ifp->sdl_nlen] = '\0';
+ ifname = ifnamebuf;
+ }
+
+ if (string_from_sockaddr ((struct sockaddr *)gw,
+ buffer, sizeof(buffer)) == 0) {
+ PyObject *pyifname = PyString_FromString (ifname);
+ PyObject *pyaddr = PyString_FromString (buffer);
+#ifdef RTF_IFSCOPE
+ PyObject *isdefault = PyBool_FromLong (!(pmsg->rtm_flags & RTF_IFSCOPE));
+#else
+ PyObject *isdefault = Py_True;
+ Py_INCREF(isdefault);
+#endif
+
+ tuple = PyTuple_Pack (3, pyaddr, pyifname, isdefault);
+
+ if (PyObject_IsTrue (isdefault))
+ deftuple = PyTuple_Pack (2, pyaddr, pyifname);
+
+ Py_DECREF (pyaddr);
+ Py_DECREF (pyifname);
+ Py_DECREF (isdefault);
+ }
+
+ if (tuple && !add_to_family (result, AF_INET, tuple)) {
+ Py_DECREF (deftuple);
+ Py_DECREF (result);
+ free (pmsg);
+ return NULL;
+ }
+
+ if (deftuple) {
+ PyObject *pyfamily = PyInt_FromLong (AF_INET);
+
+ PyDict_SetItem (defaults, pyfamily, deftuple);
+
+ Py_DECREF (pyfamily);
+ Py_DECREF (deftuple);
+ }
+ }
+ }
+
+ /* The code below is very similar to, but not identical to, the code above.
+ We could probably refactor some of it, but take care---there are subtle
+ differences! */
+
+#ifdef AF_INET6
+ /* AF_INET6 now */
+ msglen = (sizeof (struct rt_msghdr)
+ + sizeof (struct sockaddr_in6)
+ + sizeof (struct sockaddr_dl));
+ memset (pmsg, 0, msglen);
+
+ pmsg->rtm_msglen = msglen;
+ pmsg->rtm_type = RTM_GET;
+ pmsg->rtm_index = 0;
+ pmsg->rtm_flags = RTF_UP | RTF_GATEWAY;
+ pmsg->rtm_version = RTM_VERSION;
+ pmsg->rtm_seq = ++seq;
+ pmsg->rtm_pid = 0;
+ pmsg->rtm_addrs = RTA_DST | RTA_IFP;
+
+ sin6_dst = (struct sockaddr_in6 *)(pmsg + 1);
+ sdl_ifp = (struct sockaddr_dl *)(sin6_dst + 1);
+
+ sin6_dst->sin6_family = AF_INET6;
+ sin6_dst->sin6_addr = in6addr_any;
+ sdl_ifp->sdl_family = AF_LINK;
+
+#if HAVE_SOCKADDR_SA_LEN
+ sin6_dst->sin6_len = sizeof (struct sockaddr_in6);
+ sdl_ifp->sdl_len = sizeof (struct sockaddr_dl);
+#endif
+
+ skip = 0;
+ if (send (s, pmsg, msglen, 0) < 0) {
+ if (errno == ESRCH)
+ skip = 1;
+ else {
+ PyErr_SetFromErrno (PyExc_OSError);
+ close (s);
+ free (pmsg);
+ return NULL;
+ }
+ }
+
+ while (!skip && !(pmsg->rtm_flags & RTF_DONE)) {
+ char *ptr;
+ char *msgend;
+ int addrs;
+ int addr;
+ struct sockaddr_in6 *dst = NULL;
+ struct sockaddr_in6 *gw = NULL;
+ struct sockaddr_dl *ifp = NULL;
+ PyObject *tuple = NULL;
+ PyObject *deftuple = NULL;
+
+ do {
+ ret = recv (s, pmsg, bufsize, 0);
+ } while ((ret < 0 && errno == EINTR)
+ || (ret > 0 && (pmsg->rtm_seq != seq || pmsg->rtm_pid != pid)));
+
+ if (ret < 0) {
+ PyErr_SetFromErrno (PyExc_OSError);
+ close (s);
+ free (pmsg);
+ return NULL;
+ }
+
+ if (pmsg->rtm_errno != 0) {
+ if (pmsg->rtm_errno == ESRCH)
+ skip = 1;
+ else {
+ errno = pmsg->rtm_errno;
+ PyErr_SetFromErrno (PyExc_OSError);
+ close (s);
+ free (pmsg);
+ return NULL;
+ }
+ }
+
+ if (skip)
+ break;
+
+ ptr = (char *)(pmsg + 1);
+ msgend = (char *)pmsg + pmsg->rtm_msglen;
+ addrs = pmsg->rtm_addrs;
+ addr = RTA_DST;
+ while (ptr + sizeof (struct sockaddr) <= msgend && addrs) {
+ struct sockaddr *sa = (struct sockaddr *)ptr;
+ int len = SA_LEN(sa);
+
+ if (!len)
+ len = 4;
+ else
+ len = (len + 3) & ~3;
+
+ if (ptr + len > msgend)
+ break;
+
+ while (!(addrs & addr))
+ addr <<= 1;
+
+ addrs &= ~addr;
+
+ switch (addr) {
+ case RTA_DST:
+ dst = (struct sockaddr_in6 *)sa;
+ break;
+ case RTA_GATEWAY:
+ gw = (struct sockaddr_in6 *)sa;
+ break;
+ case RTA_IFP:
+ ifp = (struct sockaddr_dl *)sa;
+ break;
+ }
+
+ ptr += len;
+ }
+
+ if ((dst && dst->sin6_family != AF_INET6)
+ || (gw && gw->sin6_family != AF_INET6)
+ || (ifp && ifp->sdl_family != AF_LINK)) {
+ dst = gw = NULL;
+ ifp = NULL;
+ }
+
+ if (dst && memcmp (&dst->sin6_addr, &in6addr_any,
+ sizeof(struct in6_addr)) == 0)
+ dst = NULL;
+
+ if (!dst && gw && ifp) {
+ char buffer[256];
+
+ if (ifp->sdl_index)
+ ifname = if_indextoname (ifp->sdl_index, ifnamebuf);
+ else {
+ memcpy (ifnamebuf, ifp->sdl_data, ifp->sdl_nlen);
+ ifnamebuf[ifp->sdl_nlen] = '\0';
+ ifname = ifnamebuf;
+ }
+
+ if (string_from_sockaddr ((struct sockaddr *)gw,
+ buffer, sizeof(buffer)) == 0) {
+ PyObject *pyifname = PyString_FromString (ifname);
+ PyObject *pyaddr = PyString_FromString (buffer);
+#ifdef RTF_IFSCOPE
+ PyObject *isdefault = PyBool_FromLong (!(pmsg->rtm_flags & RTF_IFSCOPE));
+#else
+ PyObject *isdefault = Py_True;
+ Py_INCREF (isdefault);
+#endif
+
+ tuple = PyTuple_Pack (3, pyaddr, pyifname, isdefault);
+
+ if (PyObject_IsTrue (isdefault))
+ deftuple = PyTuple_Pack (2, pyaddr, pyifname);
+
+ Py_DECREF (pyaddr);
+ Py_DECREF (pyifname);
+ Py_DECREF (isdefault);
+ }
+
+ if (tuple && !add_to_family (result, AF_INET6, tuple)) {
+ Py_DECREF (deftuple);
+ Py_DECREF (result);
+ free (pmsg);
+ return NULL;
+ }
+
+ if (deftuple) {
+ PyObject *pyfamily = PyInt_FromLong (AF_INET6);
+
+ PyDict_SetItem (defaults, pyfamily, deftuple);
+
+ Py_DECREF (pyfamily);
+ Py_DECREF (deftuple);
+ }
+ }
+ }
+#endif /* AF_INET6 */
+
+ free (pmsg);
+#else
+ /* If we don't know how to implement this on your platform, we raise an
+ exception. */
+ PyErr_SetString (PyExc_OSError,
+ "Unable to obtain gateway information on your platform.");
+#endif
+
+ return result;
+}
+
+/* -- Python Module --------------------------------------------------------- */
+
+static PyMethodDef methods[] = {
+ { "ifaddresses", (PyCFunction)ifaddrs, METH_VARARGS,
+ "Obtain information about the specified network interface.\n"
+"\n"
+"Returns a dict whose keys are equal to the address family constants,\n"
+"e.g. netifaces.AF_INET, and whose values are a list of addresses in\n"
+"that family that are attached to the network interface." },
+ { "interfaces", (PyCFunction)interfaces, METH_NOARGS,
+ "Obtain a list of the interfaces available on this machine." },
+ { "gateways", (PyCFunction)gateways, METH_NOARGS,
+ "Obtain a list of the gateways on this machine.\n"
+"\n"
+"Returns a dict whose keys are equal to the address family constants,\n"
+"e.g. netifaces.AF_INET, and whose values are a list of tuples of the\n"
+"format (<address>, <interface>, <is_default>).\n"
+"\n"
+"There is also a special entry with the key 'default', which you can use\n"
+"to quickly obtain the default gateway for a particular address family.\n"
+"\n"
+"There may in general be multiple gateways; different address\n"
+"families may have different gateway settings (e.g. AF_INET vs AF_INET6)\n"
+"and on some systems it's also possible to have interface-specific\n"
+"default gateways.\n" },
+ { NULL, NULL, 0, NULL }
+};
+
+MODULE_DEF("netifaces", NULL, methods);
+
+MODULE_INIT(netifaces)
+{
+ PyObject *address_family_dict;
+ PyObject *m;
+
+#ifdef WIN32
+ WSADATA wsad;
+
+ WSAStartup(MAKEWORD (2, 2), &wsad);
+#endif
+
+ MODULE_CREATE(m, "netifaces", NULL, methods);
+ if (!m)
+ return MODULE_ERROR;
+
+ /* Address families (auto-detect using #ifdef) */
+ address_family_dict = PyDict_New();
+#ifdef AF_UNSPEC
+ PyModule_AddIntConstant (m, "AF_UNSPEC", AF_UNSPEC);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_UNSPEC),
+ PyString_FromString("AF_UNSPEC"));
+#endif
+#ifdef AF_UNIX
+ PyModule_AddIntConstant (m, "AF_UNIX", AF_UNIX);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_UNIX),
+ PyString_FromString("AF_UNIX"));
+#endif
+#ifdef AF_FILE
+ PyModule_AddIntConstant (m, "AF_FILE", AF_FILE);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_FILE),
+ PyString_FromString("AF_FILE"));
+#endif
+#ifdef AF_INET
+ PyModule_AddIntConstant (m, "AF_INET", AF_INET);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_INET),
+ PyString_FromString("AF_INET"));
+#endif
+#ifdef AF_AX25
+ PyModule_AddIntConstant (m, "AF_AX25", AF_AX25);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_AX25),
+ PyString_FromString("AF_AX25"));
+#endif
+#ifdef AF_IMPLINK
+ PyModule_AddIntConstant (m, "AF_IMPLINK", AF_IMPLINK);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_IMPLINK),
+ PyString_FromString("AF_IMPLINK"));
+#endif
+#ifdef AF_PUP
+ PyModule_AddIntConstant (m, "AF_PUP", AF_PUP);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_PUP),
+ PyString_FromString("AF_PUP"));
+#endif
+#ifdef AF_CHAOS
+ PyModule_AddIntConstant (m, "AF_CHAOS", AF_CHAOS);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_CHAOS),
+ PyString_FromString("AF_CHAOS"));
+#endif
+#ifdef AF_NS
+ PyModule_AddIntConstant (m, "AF_NS", AF_NS);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_NS),
+ PyString_FromString("AF_NS"));
+#endif
+#ifdef AF_ISO
+ PyModule_AddIntConstant (m, "AF_ISO", AF_ISO);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_ISO),
+ PyString_FromString("AF_ISO"));
+#endif
+#ifdef AF_ECMA
+ PyModule_AddIntConstant (m, "AF_ECMA", AF_ECMA);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_ECMA),
+ PyString_FromString("AF_ECMA"));
+#endif
+#ifdef AF_DATAKIT
+ PyModule_AddIntConstant (m, "AF_DATAKIT", AF_DATAKIT);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_DATAKIT),
+ PyString_FromString("AF_DATAKIT"));
+#endif
+#ifdef AF_CCITT
+ PyModule_AddIntConstant (m, "AF_CCITT", AF_CCITT);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_CCITT),
+ PyString_FromString("AF_CCITT"));
+#endif
+#ifdef AF_SNA
+ PyModule_AddIntConstant (m, "AF_SNA", AF_SNA);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_SNA),
+ PyString_FromString("AF_SNA"));
+#endif
+#ifdef AF_DECnet
+ PyModule_AddIntConstant (m, "AF_DECnet", AF_DECnet);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_DECnet),
+ PyString_FromString("AF_DECnet"));
+#endif
+#ifdef AF_DLI
+ PyModule_AddIntConstant (m, "AF_DLI", AF_DLI);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_DLI),
+ PyString_FromString("AF_DLI"));
+#endif
+#ifdef AF_LAT
+ PyModule_AddIntConstant (m, "AF_LAT", AF_LAT);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_LAT),
+ PyString_FromString("AF_LAT"));
+#endif
+#ifdef AF_HYLINK
+ PyModule_AddIntConstant (m, "AF_HYLINK", AF_HYLINK);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_HYLINK),
+ PyString_FromString("AF_HYLINK"));
+#endif
+#ifdef AF_APPLETALK
+ PyModule_AddIntConstant (m, "AF_APPLETALK", AF_APPLETALK);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_APPLETALK),
+ PyString_FromString("AF_APPLETALK"));
+#endif
+#ifdef AF_ROUTE
+ PyModule_AddIntConstant (m, "AF_ROUTE", AF_ROUTE);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_ROUTE),
+ PyString_FromString("AF_ROUTE"));
+#endif
+#ifdef AF_LINK
+ PyModule_AddIntConstant (m, "AF_LINK", AF_LINK);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_LINK),
+ PyString_FromString("AF_LINK"));
+#endif
+#ifdef AF_PACKET
+ PyModule_AddIntConstant (m, "AF_PACKET", AF_PACKET);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_PACKET),
+ PyString_FromString("AF_PACKET"));
+#endif
+#ifdef AF_COIP
+ PyModule_AddIntConstant (m, "AF_COIP", AF_COIP);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_COIP),
+ PyString_FromString("AF_COIP"));
+#endif
+#ifdef AF_CNT
+ PyModule_AddIntConstant (m, "AF_CNT", AF_CNT);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_CNT),
+ PyString_FromString("AF_CNT"));
+#endif
+#ifdef AF_IPX
+ PyModule_AddIntConstant (m, "AF_IPX", AF_IPX);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_IPX),
+ PyString_FromString("AF_IPX"));
+#endif
+#ifdef AF_SIP
+ PyModule_AddIntConstant (m, "AF_SIP", AF_SIP);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_SIP),
+ PyString_FromString("AF_SIP"));
+#endif
+#ifdef AF_NDRV
+ PyModule_AddIntConstant (m, "AF_NDRV", AF_NDRV);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_NDRV),
+ PyString_FromString("AF_NDRV"));
+#endif
+#ifdef AF_ISDN
+ PyModule_AddIntConstant (m, "AF_ISDN", AF_ISDN);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_ISDN),
+ PyString_FromString("AF_ISDN"));
+#endif
+#ifdef AF_INET6
+ PyModule_AddIntConstant (m, "AF_INET6", AF_INET6);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_INET6),
+ PyString_FromString("AF_INET6"));
+#endif
+#ifdef AF_NATM
+ PyModule_AddIntConstant (m, "AF_NATM", AF_NATM);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_NATM),
+ PyString_FromString("AF_NATM"));
+#endif
+#ifdef AF_SYSTEM
+ PyModule_AddIntConstant (m, "AF_SYSTEM", AF_SYSTEM);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_SYSTEM),
+ PyString_FromString("AF_SYSTEM"));
+#endif
+#ifdef AF_NETBIOS
+ PyModule_AddIntConstant (m, "AF_NETBIOS", AF_NETBIOS);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_NETBIOS),
+ PyString_FromString("AF_NETBIOS"));
+#endif
+#ifdef AF_NETBEUI
+ PyModule_AddIntConstant (m, "AF_NETBEUI", AF_NETBEUI);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_NETBEUI),
+ PyString_FromString("AF_NETBEUI"));
+#endif
+#ifdef AF_PPP
+ PyModule_AddIntConstant (m, "AF_PPP", AF_PPP);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_PPP),
+ PyString_FromString("AF_PPP"));
+#endif
+#ifdef AF_ATM
+ PyModule_AddIntConstant (m, "AF_ATM", AF_ATM);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_ATM),
+ PyString_FromString("AF_ATM"));
+#endif
+#ifdef AF_ATMPVC
+ PyModule_AddIntConstant (m, "AF_ATMPVC", AF_ATMPVC);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_ATMPVC),
+ PyString_FromString("AF_ATMPVC"));
+#endif
+#ifdef AF_ATMSVC
+ PyModule_AddIntConstant (m, "AF_ATMSVC", AF_ATMSVC);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_ATMSVC),
+ PyString_FromString("AF_ATMSVC"));
+#endif
+#ifdef AF_NETGRAPH
+ PyModule_AddIntConstant (m, "AF_NETGRAPH", AF_NETGRAPH);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_NETGRAPH),
+ PyString_FromString("AF_NETGRAPH"));
+#endif
+#ifdef AF_VOICEVIEW
+ PyModule_AddIntConstant (m, "AF_VOICEVIEW", AF_VOICEVIEW);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_VOICEVIEW),
+ PyString_FromString("AF_VOICEVIEW"));
+#endif
+#ifdef AF_FIREFOX
+ PyModule_AddIntConstant (m, "AF_FIREFOX", AF_FIREFOX);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_FIREFOX),
+ PyString_FromString("AF_FIREFOX"));
+#endif
+#ifdef AF_UNKNOWN1
+ PyModule_AddIntConstant (m, "AF_UNKNOWN1", AF_UNKNOWN1);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_UNKNOWN1),
+ PyString_FromString("AF_UNKNOWN1"));
+#endif
+#ifdef AF_BAN
+ PyModule_AddIntConstant (m, "AF_BAN", AF_BAN);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_BAN),
+ PyString_FromString("AF_BAN"));
+#endif
+#ifdef AF_CLUSTER
+ PyModule_AddIntConstant (m, "AF_CLUSTER", AF_CLUSTER);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_CLUSTER),
+ PyString_FromString("AF_CLUSTER"));
+#endif
+#ifdef AF_12844
+ PyModule_AddIntConstant (m, "AF_12844", AF_12844);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_12844),
+ PyString_FromString("AF_12844"));
+#endif
+#ifdef AF_IRDA
+ PyModule_AddIntConstant (m, "AF_IRDA", AF_IRDA);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_IRDA),
+ PyString_FromString("AF_IRDA"));
+#endif
+#ifdef AF_NETDES
+ PyModule_AddIntConstant (m, "AF_NETDES", AF_NETDES);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_NETDES),
+ PyString_FromString("AF_NETDES"));
+#endif
+#ifdef AF_NETROM
+ PyModule_AddIntConstant (m, "AF_NETROM", AF_NETROM);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_NETROM),
+ PyString_FromString("AF_NETROM"));
+#endif
+#ifdef AF_BRIDGE
+ PyModule_AddIntConstant (m, "AF_BRIDGE", AF_BRIDGE);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_BRIDGE),
+ PyString_FromString("AF_BRIDGE"));
+#endif
+#ifdef AF_X25
+ PyModule_AddIntConstant (m, "AF_X25", AF_X25);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_X25),
+ PyString_FromString("AF_X25"));
+#endif
+#ifdef AF_ROSE
+ PyModule_AddIntConstant (m, "AF_ROSE", AF_ROSE);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_ROSE),
+ PyString_FromString("AF_ROSE"));
+#endif
+#ifdef AF_SECURITY
+ PyModule_AddIntConstant (m, "AF_SECURITY", AF_SECURITY);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_SECURITY),
+ PyString_FromString("AF_SECURITY"));
+#endif
+#ifdef AF_KEY
+ PyModule_AddIntConstant (m, "AF_KEY", AF_KEY);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_KEY),
+ PyString_FromString("AF_KEY"));
+#endif
+#ifdef AF_NETLINK
+ PyModule_AddIntConstant (m, "AF_NETLINK", AF_NETLINK);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_NETLINK),
+ PyString_FromString("AF_NETLINK"));
+#endif
+#ifdef AF_ASH
+ PyModule_AddIntConstant (m, "AF_ASH", AF_ASH);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_ASH),
+ PyString_FromString("AF_ASH"));
+#endif
+#ifdef AF_ECONET
+ PyModule_AddIntConstant (m, "AF_ECONET", AF_ECONET);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_ECONET),
+ PyString_FromString("AF_ECONET"));
+#endif
+#ifdef AF_SNA
+ PyModule_AddIntConstant (m, "AF_SNA", AF_SNA);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_SNA),
+ PyString_FromString("AF_SNA"));
+#endif
+#ifdef AF_PPPOX
+ PyModule_AddIntConstant (m, "AF_PPPOX", AF_PPPOX);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_PPPOX),
+ PyString_FromString("AF_PPPOX"));
+#endif
+#ifdef AF_WANPIPE
+ PyModule_AddIntConstant (m, "AF_WANPIPE", AF_WANPIPE);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_WANPIPE),
+ PyString_FromString("AF_WANPIPE"));
+#endif
+#ifdef AF_BLUETOOTH
+ PyModule_AddIntConstant (m, "AF_BLUETOOTH", AF_BLUETOOTH);
+ PyDict_SetItem(address_family_dict, PyInt_FromLong(AF_BLUETOOTH),
+ PyString_FromString("AF_BLUETOOTH"));
+#endif
+ PyModule_AddObject(m, "address_families", address_family_dict);
+
+ // Add-in the version number from setup.py
+#undef STR
+#undef _STR
+#define _STR(x) #x
+#define STR(x) _STR(x)
+
+ PyModule_AddStringConstant(m, "version", STR(NETIFACES_VERSION));
+
+ MODULE_RETURN(m);
+}
diff --git a/pypi_windows_packages.bat b/pypi_windows_packages.bat
new file mode 100644
index 0000000..297e387
--- /dev/null
+++ b/pypi_windows_packages.bat
@@ -0,0 +1,4 @@
+C:\Python26\python.exe setup.py clean bdist_egg bdist_wininst bdist_wheel upload
+C:\Python27\python.exe setup.py clean bdist_egg bdist_wininst bdist_wheel upload
+C:\Python33\python.exe setup.py clean bdist_egg bdist_wininst bdist_wheel upload
+C:\Python34\python.exe setup.py clean bdist_egg bdist_wininst bdist_wheel upload
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..861a9f5
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,5 @@
+[egg_info]
+tag_build =
+tag_date = 0
+tag_svn_revision = 0
+
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..30d7915
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,539 @@
+import setuptools
+import os
+import sys
+import distutils.spawn
+from setuptools import setup, Extension
+from setuptools.command.build_ext import build_ext
+from distutils.errors import *
+import pickle
+
+if sys.version_info[0] == 2:
+ def output(*args, **kwargs):
+ end = kwargs.get('end', '\n')
+ f = kwargs.get('file', sys.stdout)
+ f.write(' '.join(str(a) for a in args))
+ f.write(end)
+else:
+ try:
+ import builtins
+ except ImportError:
+ import __builtin__
+ builtins = __builtin__
+
+ output = getattr(builtins, 'print')
+
+__version__ = "0.10.4"
+
+# Disable hard links, otherwise building distributions fails on OS X
+try:
+ del os.link
+except:
+ pass
+
+# On Windows, we need ws2_32 and iphlpapi
+if getattr(sys, 'getwindowsversion', None):
+ libraries = ['ws2_32', 'iphlpapi']
+ def_macros = [('WIN32', 1)]
+else:
+ mos = getattr(sys, 'platform', None)
+ libraries = []
+ if mos.startswith('sunos'):
+ libraries = ['socket', 'nsl']
+ def_macros = []
+
+def_macros.append(("NETIFACES_VERSION", __version__))
+
+iface_mod = Extension('netifaces', sources=['netifaces.c'],
+ libraries=libraries,
+ define_macros=def_macros)
+
+#
+# There must be a better way to do this...
+#
+class my_build_ext(build_ext):
+ def build_extensions(self):
+ self.check_requirements()
+ build_ext.build_extensions(self)
+
+ def test_build(self, contents, link=True, execute=False, libraries=None,
+ include_dirs=None, library_dirs=None):
+ name = os.path.join(self.build_temp, 'conftest-%s.c' % self.conftestidx)
+ self.conftestidx += 1
+ if os.path.exists(name):
+ os.unlink(name)
+ thefile = open(name, 'w')
+ thefile.write(contents)
+ thefile.close()
+
+ sys.stdout.flush()
+ sys.stderr.flush()
+ mystdout = os.dup(1)
+ mystderr = os.dup(2)
+ result = True
+ try:
+ os.dup2(self.ctout, 1)
+ os.dup2(self.ctout, 2)
+ try:
+ objects = self.compiler.compile([name],
+ output_dir=self.build_temp,
+ include_dirs=include_dirs,
+ debug=self.debug)
+ if link:
+ self.compiler.link_executable(objects,
+ 'conftest',
+ output_dir=self.build_temp,
+ library_dirs=library_dirs,
+ libraries=libraries,
+ debug=self.debug)
+ if execute:
+ abspath = os.path.abspath(os.path.join(self.build_temp,
+ 'conftest'))
+ pipe = os.popen(abspath, 'r')
+ result = pipe.read().strip()
+ status = pipe.close()
+ if status is None:
+ status = 0
+ if result == '':
+ result = True
+ if status != 0:
+ result = False
+
+ finally:
+ os.dup2(mystdout, 1)
+ os.dup2(mystderr, 2)
+ except CompileError:
+ return False
+ except LinkError:
+ return False
+ except DistutilsExecError:
+ return False
+ return result
+
+ def check_requirements(self):
+ # Load the cached config data from a previous run if possible; compiling
+ # things to test for features is slow
+ cache_file = os.path.join(self.build_temp, 'config.cache')
+ if os.path.exists(cache_file):
+ myfile = open(cache_file, 'rb')
+ try:
+ results = pickle.load(myfile)
+ finally:
+ myfile.close()
+ else:
+ results = {}
+
+ self.conftestidx = 0
+
+ output("checking for getifaddrs...", end='')
+
+ result = results.get('have_getifaddrs', None)
+ if result is not None:
+ cached = '(cached)'
+ else:
+ cached = ''
+
+ if not os.path.exists(self.build_temp):
+ os.makedirs(self.build_temp)
+ outname = os.path.join(self.build_temp, 'conftest.out')
+ self.ctout = os.open(outname, os.O_RDWR | os.O_CREAT | os.O_TRUNC)
+ testrig = """
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <ifaddrs.h>
+ int main(void) {
+ struct ifaddrs *addrs;
+ int ret;
+ ret = getifaddrs(&addrs);
+ freeifaddrs (addrs);
+ return 0;
+ }
+ """
+ if self.test_build(testrig):
+ result = True
+ else:
+ result = False
+
+ if result:
+ output("found. %s" % cached)
+ self.compiler.define_macro('HAVE_GETIFADDRS', 1)
+ else:
+ output("not found. %s" % cached)
+
+ results['have_getifaddrs'] = result
+
+ output("checking for getnameinfo...", end='')
+
+ result = results.get('have_getnameinfo', None)
+ if result is not None:
+ cached = '(cached)'
+ else:
+ cached = ''
+
+ if not os.path.exists(self.build_temp):
+ os.makedirs(self.build_temp)
+ outname = os.path.join(self.build_temp, 'conftest2.out')
+ self.ctout = os.open(outname, os.O_RDWR | os.O_CREAT | os.O_TRUNC)
+ testrig = """
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <arpa/inet.h>
+ #include <netdb.h>
+ #include <stdlib.h>
+ int main(void) {
+ struct sockaddr_in sin;
+ char buffer[256];
+ int ret;
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = 0;
+ sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+ ret = getnameinfo ((struct sockaddr *)&sin, sizeof (sin),
+ buffer, sizeof (buffer),
+ NULL, 0,
+ NI_NUMERICHOST);
+
+ return 0;
+ }
+ """
+ if self.test_build(testrig,libraries=libraries):
+ result = True
+ else:
+ result = False
+
+ if result:
+ output("found. %s" % cached)
+ self.compiler.define_macro('HAVE_GETNAMEINFO', 1)
+ else:
+ output("not found. %s" % cached)
+
+ results['have_getnameinfo'] = result
+
+ if not results['have_getifaddrs']:
+ output("checking for socket IOCTLs...", end='')
+
+ result = results.get('have_socket_ioctls', None)
+ if result is not None:
+ cached = '(cached)'
+ else:
+ cached = ''
+
+ if not os.path.exists(self.build_temp):
+ os.makedirs(self.build_temp)
+ outname = os.path.join(self.build_temp, 'conftest3.out')
+ self.ctout = os.open(outname, os.O_RDWR | os.O_CREAT | os.O_TRUNC)
+
+ result = []
+ ioctls = ('SIOCGIFCONF',
+ 'SIOCGSIZIFCONF',
+ 'SIOCGIFHWADDR',
+ 'SIOCGIFADDR',
+ 'SIOCGIFFLAGS',
+ 'SIOCGIFDSTADDR',
+ 'SIOCGIFBRDADDR',
+ 'SIOCGIFNETMASK',
+ 'SIOCGLIFNUM',
+ 'SIOCGLIFCONF',
+ 'SIOCGLIFFLAGS')
+ added_includes = ""
+ if mos.startswith('sunos'):
+ added_includes = """
+ #include <unistd.h>
+ #include <stropts.h>
+ #include <sys/sockio.h>
+ """
+
+ for ioctl in ioctls:
+ testrig = """
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <sys/ioctl.h>
+ #include <net/if.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ %(addedinc)s
+ int main(void) {
+ int fd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ struct ifreq ifreq;
+
+ ioctl(fd, %(ioctl)s, &ifreq);
+
+ return 0;
+ }
+ """ % { 'ioctl': ioctl , 'addedinc': added_includes}
+
+ if self.test_build(testrig,libraries=libraries):
+ result.append(ioctl)
+
+ if result:
+ output("%r. %s" % (result, cached))
+ for ioctl in result:
+ self.compiler.define_macro('HAVE_%s' % ioctl, 1)
+ self.compiler.define_macro('HAVE_SOCKET_IOCTLS', 1)
+ else:
+ output("not found. %s" % cached)
+
+ results['have_socket_ioctls'] = result
+
+ output("checking for optional header files...", end='')
+
+ result = results.get('have_headers', None)
+ if result is not None:
+ cached = '(cached)'
+ else:
+ cached = ''
+
+ result =[]
+ headers = ('net/if_dl.h', 'netash/ash.h',
+ 'netatalk/at.h', 'netax25/ax25.h',
+ 'neteconet/ec.h', 'netipx/ipx.h',
+ 'netpacket/packet.h', 'netrose/rose.h',
+ 'linux/irda.h', 'linux/atm.h',
+ 'linux/llc.h', 'linux/tipc.h',
+ 'linux/dn.h')
+
+ for header in headers:
+ testrig = """
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <net/if.h>
+ #include <%s>
+ int main (void) { return 0; }
+ """ % header
+
+ if self.test_build(testrig, link=False):
+ result.append(header)
+
+ if result:
+ output("%s. %s" % (' '.join(result), cached))
+ for header in result:
+ macro = header.upper().replace('.', '_').replace('/', '_')
+ self.compiler.define_macro('HAVE_%s' % macro, 1)
+ else:
+ output("none found. %s" % cached)
+
+ optional_headers = result
+ results['have_headers'] = result
+
+ output("checking whether struct sockaddr has a length field...", end='')
+
+ result = results.get('have_sockaddr_sa_len', None)
+ if result is not None:
+ cached = '(cached)'
+ else:
+ cached = ''
+
+ testrig = """
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <net/if.h>
+
+ int main (void) {
+ struct sockaddr sa;
+ sa.sa_len = 5;
+ return 0;
+ }
+ """
+
+ result = self.test_build(testrig)
+
+ if result:
+ output('yes. %s' % cached)
+ self.compiler.define_macro('HAVE_SOCKADDR_SA_LEN', 1)
+ else:
+ output('no. %s' % cached)
+
+ results['have_sockaddr_sa_len'] = result
+
+ if not results['have_sockaddr_sa_len']:
+ # GAK! On certain stupid platforms (Linux), there's no sa_len.
+ # Macho Linux programmers apparently think that it's not needed,
+ # however, unfortunately, getifaddrs() doesn't return the
+ # lengths, because they're in the sa_len field on just about
+ # everything but Linux.
+ output("checking which sockaddr_xxx structs are defined...", end='')
+
+ result = results.get('have_sockaddrs', None)
+ if result is not None:
+ cached = '(cached)'
+ else:
+ cached = ''
+
+ if not os.path.exists(self.build_temp):
+ os.makedirs(self.build_temp)
+ outname = os.path.join(self.build_temp, 'conftest4.out')
+ self.ctout = os.open(outname, os.O_RDWR | os.O_CREAT | os.O_TRUNC)
+
+ sockaddrs = ('at', 'ax25', 'dl', 'eon', 'in', 'in6',
+ 'inarp', 'ipx', 'iso', 'ns', 'un', 'x25',
+ 'rose', 'ash', 'ec', 'll', 'atmpvc', 'atmsvc',
+ 'dn', 'irda', 'llc')
+ result = []
+ for sockaddr in sockaddrs:
+ testrig = """
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
+ #include <net/if.h>
+ #include <netinet/in.h>
+ %(includes)s
+
+ int main (void) {
+ struct sockaddr_%(sockaddr)s sa;
+ return 0;
+ }
+ """ % { 'includes': '\n'.join(["#include <%s>" % header
+ for header
+ in optional_headers]),
+ 'sockaddr': sockaddr }
+
+ if self.test_build(testrig):
+ result.append(sockaddr)
+
+ if result:
+ output('%s. %s' % (' '.join(result), cached))
+ for sockaddr in result:
+ self.compiler.define_macro('HAVE_SOCKADDR_%s' \
+ % sockaddr.upper(), 1)
+ else:
+ output('none! %s' % cached)
+
+ results['have_sockaddrs'] = result
+
+ # Reading routing tables is very OS dependent; check for a few
+ # different approaches.
+ output("checking for routing socket support...", end='')
+
+ result = results.get('have_pf_route', None)
+ if result is not None:
+ cached = '(cached)'
+ else:
+ cached = ''
+
+ testrig = """
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <net/route.h>
+
+ int main (void) {
+ struct rt_msghdr msg;
+ int s = socket (PF_ROUTE, SOCK_RAW, 0);
+ return 0;
+ }
+ """
+
+ result = self.test_build(testrig)
+
+ if result:
+ output('yes. %s' % cached)
+ self.compiler.define_macro('HAVE_PF_ROUTE', 1)
+ else:
+ output('no. %s' % cached)
+
+ results['have_pf_route'] = result
+
+ output("checking for sysctl(CTL_NET...) support...", end='')
+
+ result = results.get('have_sysctl_ctl_net', None)
+ if result is not None:
+ cached = '(cached)'
+ else:
+ cached = ''
+
+ testrig = """
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <sys/sysctl.h>
+ #include <net/route.h>
+
+ int main (void) {
+ int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS,
+ RTF_UP | RTF_GATEWAY };
+ return 0;
+ }
+ """
+
+ result = self.test_build(testrig)
+
+ if result:
+ output('yes. %s' % cached)
+ self.compiler.define_macro('HAVE_SYSCTL_CTL_NET', 1)
+ else:
+ output('no. %s' % cached)
+
+ results['have_sysctl_ctl_net'] = result
+
+ output("checking for netlink support...", end='')
+
+ result = results.get('have_pf_netlink', None)
+ if result is not None:
+ cached = '(cached)'
+ else:
+ cached = ''
+
+ testrig = """
+ #include <asm/types.h>
+ #include <sys/socket.h>
+ #include <linux/netlink.h>
+ #include <linux/rtnetlink.h>
+
+ int main (void) {
+ int s = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ return 0;
+ }
+ """
+
+ result = self.test_build(testrig)
+
+ if result:
+ output('yes. %s' % cached)
+ self.compiler.define_macro('HAVE_PF_NETLINK', 1)
+ else:
+ output('no. %s' % cached)
+
+ results['have_pf_netlink'] = result
+
+ if results['have_pf_netlink']:
+ output('will use netlink to read routing table')
+ elif results['have_sysctl_ctl_net']:
+ output('will use sysctl() to read routing table')
+ elif results['have_pf_route']:
+ output('will use routing socket to read routing table')
+
+ # Save the results to our config.cache file
+ myfile = open(cache_file, 'wb')
+ try:
+ pickle.dump(results, myfile)
+ finally:
+ myfile.close()
+
+# Don't bother detecting socket ioctls on Windows
+if not getattr(sys, 'getwindowsversion', None):
+ setuptools.command.build_ext.build_ext = my_build_ext
+
+readme_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
+ 'README.rst')
+long_desc = open(readme_path, 'r').read()
+
+setup (name='netifaces',
+ version=__version__,
+ zip_safe=True,
+ description="Portable network interface information.",
+ license="MIT License",
+ long_description=long_desc,
+ author='Alastair Houghton',
+ author_email='alastair@alastairs-place.net',
+ url='https://bitbucket.org/al45tair/netifaces',
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: MIT License',
+ 'Topic :: System :: Networking',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.5',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ ],
+ ext_modules=[iface_mod])
diff --git a/test.py b/test.py
new file mode 100644
index 0000000..ccaba0e
--- /dev/null
+++ b/test.py
@@ -0,0 +1,50 @@
+import netifaces
+
+print('Found interfaces:')
+for iface in netifaces.interfaces():
+ print(' %s' % iface)
+
+print('')
+
+for iface in netifaces.interfaces():
+ allAddrs = netifaces.ifaddresses(iface)
+
+ print('Interface %s:' % iface)
+
+ for family in allAddrs:
+ addrs = allAddrs[family]
+ fam_name = netifaces.address_families[family]
+ print(' Address family: %s' % fam_name)
+ for addr in addrs:
+ print(' Address : %s' % addr['addr'])
+ nmask = addr.get('netmask', None)
+ if nmask:
+ print(' Netmask : %s' % nmask)
+ bcast = addr.get('broadcast', None)
+ if bcast:
+ print(' Broadcast: %s' % bcast)
+
+ print('')
+
+print('Found gateways:')
+gateway_info = netifaces.gateways()
+for family in gateway_info:
+ if family == 'default':
+ continue
+
+ fam_name = netifaces.address_families[family]
+ print(' Family: %s' % fam_name)
+ for gateway,interface,default in gateway_info[family]:
+ if default:
+ def_text = ', default'
+ else:
+ def_text = ''
+ print(' %s (via %s%s)' % (gateway, interface, def_text))
+ print('')
+
+print('Default gateways:')
+default_gateways = gateway_info['default']
+for family in default_gateways:
+ fam_name = netifaces.address_families[family]
+ gateway, interface = default_gateways[family]
+ print(' %s: %s (via %s)' % (fam_name, gateway, interface))