getifaddrs()
. Neither is trivial, though, so I'll save those for a future post.Luckily, MacOS X provides a simpler way to get the local IP addresses: the system configuration dynamic store. Using pyObjC, which comes pre-installed on every Mac, we can write a straight port of Apple's example in Technical Note TN1145 for retrieving a list of all IPv4 addresses assigned to local interfaces:
from SystemConfiguration import * # from pyObjC
import socket
def GetIPv4Addresses():
"""
Get all IPv4 addresses assigned to local interfaces.
Returns a generator object that produces information
about each IPv4 address present at the time that the
function was called.
For each IPv4 address, the returned generator yields
a tuple consisting of the interface name, address
family (always socket.AF_INET), the IP address, and
the netmask. The tuple elements may also be accessed
by the names: "ifname", "family", "address", and
"netmask".
"""
ds = SCDynamicStoreCreate(None, 'GetIPv4Addresses', None, None)
# Get all keys matching pattern State:/Network/Service/[^/]+/IPv4
pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(None,
kSCDynamicStoreDomainState,
kSCCompAnyRegex,
kSCEntNetIPv4)
patterns = CFArrayCreate(None, (pattern, ), 1, kCFTypeArrayCallBacks)
valueDict = SCDynamicStoreCopyMultiple(ds, None, patterns)
ipv4info = namedtuple('ipv4info', 'ifname family address netmask')
for serviceDict in valueDict.values():
ifname = serviceDict[u'InterfaceName']
for address, netmask in zip(serviceDict[u'Addresses'], serviceDict[u'SubnetMasks']):
yield ipv4info(ifname, socket.AF_INET, address, netmask)
One interesting point regarding this code is that it doesn't actually inspect interface information in the system configuration dynamic store. The interface-related keys are stored under State:/Network/Interface/, but this code (and Apple's example on which it is based) inspect keys under State:/Network/Service/ instead. However, if you want to get IPv6 addresses then you do have to inspect the system configuration's interface information:
from SystemConfiguration import * # from pyObjC
import socket
import re
ifnameExtractor = re.compile(r'/Interface/([^/]+)/')
def GetIPv6Addresses():
"""
Get all IPv6 addresses assigned to local interfaces.
Returns a generator object that produces information
about each IPv6 address present at the time that the
function was called.
For each IPv6 address, the returned generator yields
a tuple consisting of the interface name, address
family (always socket.AF_INET6), the IP address, and
the prefix length. The tuple elements may also be
accessed by the names: "ifname", "family", "address",
and "prefixlen".
"""
ds = SCDynamicStoreCreate(None, 'GetIPv6Addresses', None, None)
# Get all keys matching pattern State:/Network/Interface/[^/]+/IPv6
pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(None,
kSCDynamicStoreDomainState,
kSCCompAnyRegex,
kSCEntNetIPv6)
patterns = CFArrayCreate(None, (pattern, ), 1, kCFTypeArrayCallBacks)
valueDict = SCDynamicStoreCopyMultiple(ds, None, patterns)
ipv6info = namedtuple('ipv6info', 'ifname family address prefixlen')
for key, ifDict in valueDict.items():
ifname = ifnameExtractor.search(key).group(1)
for address, prefixlen in zip(ifDict[u'Addresses'], ifDict[u'PrefixLength']):
yield ipv6info(ifname, socket.AF_INET6, address, prefixlen)
In fact, you could easily adapt the above function to be able to fetch IPv4 addresses from the interface configuration.
On Unix based systems like Mac OS X, you could execute the following using popen and get a list of IPs:
ReplyDelete/sbin/ifconfig -a | awk \'/(cast)/ { print $2 }\' | cut -d\':\' -f2