~ubuntu-branches/ubuntu/jaunty/landscape-client/jaunty-proposed

« back to all changes in this revision

Viewing changes to landscape/lib/network.py

  • Committer: Bazaar Package Importer
  • Author(s): Free Ekanayaka
  • Date: 2010-06-28 18:07:18 UTC
  • mfrom: (1.2.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20100628180718-m3t2ttgg8efbg19d
Tags: 1.5.2.1-0ubuntu0.9.04.0
Filter duplicate network interfaces in get_active_interfaces (LP: #597000)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
Network introspection utilities using ioctl and the /proc filesystem.
 
3
"""
 
4
import array
 
5
import fcntl
 
6
import socket
 
7
import struct
 
8
 
 
9
__all__ = ["get_active_device_info", "get_network_traffic"]
 
10
 
 
11
# from header /usr/include/bits/ioctls.h
 
12
SIOCGIFCONF = 0x8912
 
13
SIOCGIFFLAGS = 0x8913
 
14
SIOCGIFNETMASK = 0x891b
 
15
SIOCGIFBRDADDR = 0x8919
 
16
SIOCGIFADDR = 0x8915
 
17
SIOCGIFHWADDR = 0x8927
 
18
 
 
19
 
 
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.
 
24
"""
 
25
#include <linux/if.h>
 
26
int main() {
 
27
  printf("Size of struct %lu\n", sizeof(struct ifreq));
 
28
}
 
29
"""
 
30
 
 
31
IF_STRUCT_SIZE_32 = 32
 
32
IF_STRUCT_SIZE_64 = 40
 
33
 
 
34
 
 
35
def is_64():
 
36
    """Returns C{True} if the platform is 64-bit, otherwise C{False}."""
 
37
    return struct.calcsize("l") == 8
 
38
 
 
39
 
 
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
 
42
 
 
43
 
 
44
def get_active_interfaces(sock):
 
45
    """Generator yields active network interface names.
 
46
 
 
47
    @param sock: a socket instance.
 
48
    """
 
49
    max_interfaces = 128
 
50
 
 
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)
 
56
 
 
57
    byte_length = struct.unpack(
 
58
        "iL", fcntl.ioctl(sock.fileno(), SIOCGIFCONF, packed_bytes))[0]
 
59
 
 
60
    result = interfaces.tostring()
 
61
 
 
62
    # Generator over the interface names
 
63
    already_found = set()
 
64
    for index in range(0, byte_length, IF_STRUCT_SIZE):
 
65
        ifreq_struct = result[index:index+IF_STRUCT_SIZE]
 
66
        interface_name = ifreq_struct[:ifreq_struct.index("\0")]
 
67
        if interface_name not in already_found:
 
68
            already_found.add(interface_name)
 
69
            yield interface_name
 
70
 
 
71
 
 
72
def get_broadcast_address(sock, interface):
 
73
    """Return the broadcast address associated to an interface.
 
74
 
 
75
    @param sock: a socket instance.
 
76
    @param interface: The name of the interface.
 
77
    """
 
78
    return socket.inet_ntoa(fcntl.ioctl(
 
79
        sock.fileno(),
 
80
        SIOCGIFBRDADDR,
 
81
        struct.pack("256s", interface[:15]))[20:24])
 
82
 
 
83
 
 
84
def get_netmask(sock, interface):
 
85
    """Return the network mask associated to an interface.
 
86
 
 
87
    @param sock: a socket instance.
 
88
    @param interface: The name of the interface.
 
89
    """
 
90
    return socket.inet_ntoa(fcntl.ioctl(
 
91
        sock.fileno(),
 
92
        SIOCGIFNETMASK,
 
93
        struct.pack("256s", interface[:15]))[20:24])
 
94
 
 
95
 
 
96
def get_ip_address(sock, interface):
 
97
    """Return the IP address associated to the interface.
 
98
 
 
99
    @param sock: a socket instance.
 
100
    @param interface: The name of the interface.
 
101
    """
 
102
    return socket.inet_ntoa(fcntl.ioctl(
 
103
        sock.fileno(),
 
104
        SIOCGIFADDR,
 
105
        struct.pack("256s", interface[:15]))[20:24])
 
106
 
 
107
 
 
108
def get_mac_address(sock, interface):
 
109
    """
 
110
    Return the hardware MAC address for an interface in human friendly form,
 
111
    ie. six colon separated groups of two hexadecimal digits.
 
112
 
 
113
    @param sock: a socket instance.
 
114
    @param interface: The name of the interface.
 
115
    """
 
116
    mac_address = fcntl.ioctl(
 
117
        sock.fileno(), SIOCGIFHWADDR, struct.pack("256s", interface[:15]))
 
118
    return "".join(["%02x:" % ord(char) for char in mac_address[18:24]])[:-1]
 
119
 
 
120
 
 
121
def get_flags(sock, interface):
 
122
    """Return the integer value of the interface flags for the given interface.
 
123
 
 
124
    @param sock: a socket instance.
 
125
    @param interface: The name of the interface.
 
126
    @see /usr/include/linux/if.h for the meaning of the flags.
 
127
    """
 
128
    data = fcntl.ioctl(
 
129
        sock.fileno(), SIOCGIFFLAGS, struct.pack("256s", interface[:15]))
 
130
    return struct.unpack("H", data[16:18])[0]
 
131
 
 
132
 
 
133
def get_active_device_info():
 
134
    """
 
135
    Returns a dictionary containing information on each active network
 
136
    interface present on a machine.
 
137
    """
 
138
    results = []
 
139
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_IP)
 
140
    for interface in get_active_interfaces(sock):
 
141
        interface_info = {"interface": interface}
 
142
        interface_info["ip_address"] = get_ip_address(sock, interface)
 
143
        interface_info["mac_address"] = get_mac_address(sock, interface)
 
144
        interface_info["broadcast_address"] = get_broadcast_address(sock,
 
145
                                                                    interface)
 
146
        interface_info["netmask"] = get_netmask(sock, interface)
 
147
        interface_info["flags"] = get_flags(sock, interface)
 
148
        results.append(interface_info)
 
149
    del sock
 
150
    return results
 
151
 
 
152
 
 
153
def get_network_traffic(source_file="/proc/net/dev"):
 
154
    """
 
155
    Retrieves an array of information regarding the network activity per
 
156
    network interface.
 
157
    """
 
158
    netdev = open(source_file, "r")
 
159
    lines = netdev.readlines()
 
160
    netdev.close()
 
161
 
 
162
    # Parse out the column headers as keys.
 
163
    _, receive_columns, transmit_columns = lines[1].split("|")
 
164
    columns = ["recv_%s" % column for column in receive_columns.split()]
 
165
    columns.extend(["send_%s" % column for column in transmit_columns.split()])
 
166
 
 
167
    # Parse out the network devices.
 
168
    devices = {}
 
169
    for line in lines[2:]:
 
170
        if not ":" in line:
 
171
            continue
 
172
        device, data = line.split(":")
 
173
        device = device.strip()
 
174
        devices[device] = dict(zip(columns, map(long, data.split())))
 
175
    return devices
 
176
 
 
177
 
 
178
if __name__ == "__main__":
 
179
    import pprint
 
180
    pprint.pprint(get_active_device_info())