routing.py revision 2f48d9572459c2c90d68e8b017b86eb843fe2a74
1#!/usr/bin/env python
2# Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Return information about routing table entries
7
8Read and parse the system routing table. There are
9two classes defined here: NetworkRoutes, which contains
10information about all routes, and Route, which describes
11a single routing table entry.
12"""
13
14ROUTES_FILE = "/proc/net/route"
15# The following constants are from <net/route.h>
16RTF_UP      = 0x0001
17RTF_GATEWAY = 0x0002
18RTF_HOST    = 0x0004
19
20import socket
21import struct
22
23def intToDottedQuad(addr):
24    return socket.inet_ntoa(struct.pack('@I', addr))
25
26def convertIpToInt(i):
27    """Convert the supplied argument to an int representing an IP address."""
28    if isinstance(i, int):
29        return i
30    return struct.unpack('I', socket.inet_aton(i))[0]
31
32class Route(object):
33    def __init__(self, iface, dest, gway, flags, mask):
34        self.interface = iface
35        self.destination = int(dest, 16)
36        self.gateway = int(gway, 16)
37        self.flagbits = int(flags, 16)
38        self.netmask = int(mask, 16)
39
40    def __str__(self):
41        flags = ""
42        if self.flagbits & RTF_UP:
43            flags += "U"
44        if self.flagbits & RTF_GATEWAY:
45            flags += "G"
46        if self.flagbits & RTF_HOST:
47            flags += "H"
48        return "<%s dest: %s gway: %s mask: %s flags: %s>" % (
49                self.interface,
50                intToDottedQuad(self.destination),
51                intToDottedQuad(self.gateway),
52                intToDottedQuad(self.netmask),
53                flags)
54
55    def isUsable(self):
56        return self.flagbits & RTF_UP
57
58    def isHostRoute(self):
59        return self.flagbits & RTF_HOST
60
61    def isGatewayRoute(self):
62        return self.flagbits & RTF_GATEWAY
63
64    def isInterfaceRoute(self):
65        return (self.flagbits & RTF_GATEWAY) == 0
66
67    def isDefaultRoute(self):
68        return (self.flagbits & RTF_GATEWAY) and self.destination == 0
69
70    def matches(self, ip):
71        return (ip & self.netmask) == self.destination
72
73class NetworkRoutes(object):
74    def __init__(self, routelist=None):
75        if not routelist:
76            routef = open(ROUTES_FILE)
77            routelist = routef.readlines()
78            routef.close()
79
80        # The first line is headers that will allow us
81        # to correctly interpret the values in the following
82        # lines
83        colMap = {}
84        headers = routelist[0].split()
85        for (pos, token) in enumerate(headers):
86            colMap[token] = pos
87
88        self.routes = []
89        for routeline in routelist[1:]:
90            route = routeline.split()
91            interface = route[colMap["Iface"]]
92            destination = route[colMap["Destination"]]
93            gateway = route[colMap["Gateway"]]
94            flags = route[colMap["Flags"]]
95            mask = route[colMap["Mask"]]
96            self.routes.append(
97                    Route(interface, destination, gateway, flags, mask))
98
99    def hasDefaultRoute(self, interface):
100        for rr in self.routes:
101            if (rr.isUsable() and
102                    rr.interface == interface and
103                    rr.isDefaultRoute()):
104                return True
105        return False
106
107    def getDefaultRoutes(self):
108        defroutes = []
109        for rr in self.routes:
110            if rr.isUsable() and rr.isDefaultRoute():
111                defroutes.append(rr)
112        return defroutes
113
114    def hasInterfaceRoute(self, interface):
115        for rr in self.routes:
116            if (rr.isUsable() and
117                    rr.interface == interface and
118                    rr.isInterfaceRoute()):
119                return True
120            return False
121
122    def getRouteFor(self, ip_as_int_or_string):
123        ip = convertIpToInt(ip_as_int_or_string)
124        for rr in self.routes:
125            if rr.isUsable() and rr.matches(ip):
126                return rr
127        return None
128
129
130if __name__ == "__main__":
131    routes = NetworkRoutes()
132    if routes == None:
133        print "Failed to read routing table"
134    else:
135        for each_route in routes.routes:
136            print each_route
137
138        print "hasDefaultRoute(\"eth0\"):", routes.hasDefaultRoute("eth0")
139
140        dflts = routes.getDefaultRoutes()
141        if dflts == None:
142            print "There are no default routes"
143        else:
144            print "There are %d default routes" % (len(dflts))
145
146
147        print "hasInterfaceRoute(\"eth0\"):", routes.hasInterfaceRoute("eth0")
148
149    routes = NetworkRoutes([
150        "Iface Destination Gateway  Flags RefCnt "
151        "Use Metric Mask MTU Window IRTT",
152        "ones 00010203 FE010203 0007 0 0 0 00FFFFFF 0 0 0\n",
153        "default 00000000 09080706 0007 0 0 0 00000000 0 0 0\n",
154        ])
155
156    print routes.getRouteFor(0x01010203)
157    print routes.getRouteFor("3.2.1.1")
158    print routes.getRouteFor(0x08010209)
159