2
Network introspection utilities using ioctl and the /proc filesystem.
9
__all__ = ["get_active_device_info", "get_network_traffic"]
11
# from header /usr/include/bits/ioctls.h
14
SIOCGIFNETMASK = 0x891b
15
SIOCGIFBRDADDR = 0x8919
17
SIOCGIFHWADDR = 0x8927
20
# struct definition from header /usr/include/net/if.h
21
# the struct size varies according to the platform arch size
22
# a minimal c program was used to determine the size of the
23
# struct, standard headers removed for brevity.
27
printf("Size of struct %lu\n", sizeof(struct ifreq));
31
IF_STRUCT_SIZE_32 = 32
32
IF_STRUCT_SIZE_64 = 40
36
"""Returns C{True} if the platform is 64-bit, otherwise C{False}."""
37
return struct.calcsize("l") == 8
40
# initialize the struct size as per the machine's archictecture
41
IF_STRUCT_SIZE = is_64() and IF_STRUCT_SIZE_64 or IF_STRUCT_SIZE_32
44
def get_active_interfaces(sock):
45
"""Generator yields active network interface names.
47
@param sock: a socket instance.
51
# setup an an array to hold our response, and initialized to null strings.
52
interfaces = array.array("B", "\0" * max_interfaces * IF_STRUCT_SIZE)
53
buffer_size = interfaces.buffer_info()[0]
54
packed_bytes = struct.pack(
55
"iL", max_interfaces * IF_STRUCT_SIZE, buffer_size)
57
byte_length = struct.unpack(
58
"iL", fcntl.ioctl(sock.fileno(), SIOCGIFCONF, packed_bytes))[0]
60
result = interfaces.tostring()
62
# generator over the interface names
63
for index in range(0, byte_length, IF_STRUCT_SIZE):
64
ifreq_struct = result[index:index+IF_STRUCT_SIZE]
65
interface_name = ifreq_struct[:ifreq_struct.index("\0")]
69
def get_broadcast_address(sock, interface):
70
"""Return the broadcast address associated to an interface.
72
@param sock: a socket instance.
73
@param interface: The name of the interface.
75
return socket.inet_ntoa(fcntl.ioctl(
78
struct.pack("256s", interface[:15]))[20:24])
81
def get_netmask(sock, interface):
82
"""Return the network mask associated to an interface.
84
@param sock: a socket instance.
85
@param interface: The name of the interface.
87
return socket.inet_ntoa(fcntl.ioctl(
90
struct.pack("256s", interface[:15]))[20:24])
93
def get_ip_address(sock, interface):
94
"""Return the IP address associated to the interface.
96
@param sock: a socket instance.
97
@param interface: The name of the interface.
99
return socket.inet_ntoa(fcntl.ioctl(
102
struct.pack("256s", interface[:15]))[20:24])
105
def get_mac_address(sock, interface):
107
Return the hardware MAC address for an interface in human friendly form,
108
ie. six colon separated groups of two hexadecimal digits.
110
@param sock: a socket instance.
111
@param interface: The name of the interface.
113
mac_address = fcntl.ioctl(
114
sock.fileno(), SIOCGIFHWADDR, struct.pack("256s", interface[:15]))
115
return "".join(["%02x:" % ord(char) for char in mac_address[18:24]])[:-1]
118
def get_flags(sock, interface):
119
"""Return the integer value of the interface flags for the given interface.
121
@param sock: a socket instance.
122
@param interface: The name of the interface.
123
@see /usr/include/linux/if.h for the meaning of the flags.
126
sock.fileno(), SIOCGIFFLAGS, struct.pack("256s", interface[:15]))
127
return struct.unpack("H", data[16:18])[0]
130
def get_active_device_info():
132
Returns a dictionary containing information on each active network
133
interface present on a machine.
136
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_IP)
137
for interface in get_active_interfaces(sock):
138
interface_info = {"interface": interface}
139
interface_info["ip_address"] = get_ip_address(sock, interface)
140
interface_info["mac_address"] = get_mac_address(sock, interface)
141
interface_info["broadcast_address"] = get_broadcast_address(sock,
143
interface_info["netmask"] = get_netmask(sock, interface)
144
interface_info["flags"] = get_flags(sock, interface)
145
results.append(interface_info)
150
def get_network_traffic(source_file="/proc/net/dev"):
152
Retrieves an array of information regarding the network activity per
155
netdev = open(source_file, "r")
156
lines = netdev.readlines()
159
# Parse out the column headers as keys.
160
_, receive_columns, transmit_columns = lines[1].split("|")
161
columns = ["recv_%s" % column for column in receive_columns.split()]
162
columns.extend(["send_%s" % column for column in transmit_columns.split()])
164
# Parse out the network devices.
166
for line in lines[2:]:
169
device, data = line.split(":")
170
device = device.strip()
171
devices[device] = dict(zip(columns, map(long, data.split())))
175
if __name__ == "__main__":
177
pprint.pprint(get_active_device_info())