Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

wviproute.cc

Go to the documentation of this file.
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * The WvIPRoute and WvIPRouteList class, a quick (mostly hackish) attempt
00006  * at a way to read the Linux kernel routing table.
00007  */
00008 #include "wviproute.h"
00009 #include "wvpipe.h"
00010 #include "wvinterface.h"
00011 #include "wvfile.h"
00012 #include "wvstringlist.h"
00013 
00014 #include <net/route.h>
00015 #include <ctype.h>
00016 
00017 
00018 
00019 
00020 WvIPRoute::WvIPRoute(const WvString &_ifc, const WvIPNet &_net,
00021                      const WvIPAddr &_gate, int _metric,
00022                      const WvString &_table)
00023         : ifc(_ifc), ip(_net), gateway(_gate), table(_table)
00024 {
00025     ifc.unique();
00026     metric = _metric;
00027 }
00028 
00029 
00030 WvIPRoute::operator WvString() const
00031 {
00032     return WvString("%s via %s %s metric %s%s",
00033                     ip, ifc, gateway, metric,
00034                     (table != "default") 
00035                       ? WvString(" (table %s)", table) : WvString(""));
00036 }
00037 
00038 
00039 bool WvIPRoute::operator== (const WvIPRoute &r2) const
00040 {
00041     return (ip.network() == r2.ip.network() && ip.netmask() == r2.ip.netmask()
00042             && gateway == r2.gateway 
00043             && ifc == r2.ifc && metric == r2.metric
00044             && table == r2.table);
00045 }
00046 
00047 
00048 
00050 
00051 
00052 WvIPRouteList::WvIPRouteList() : log("Route Table", WvLog::Debug)
00053 {
00054     // nothing else to do
00055 }
00056 
00057 
00058 // Reads the kernel routing table, from /proc/net/route, and parses it into
00059 // A WvIPRouteList.  Also reads the kernel 2.1.x "policy routing" tables, 
00060 // (via the "ip" command) and parses those routes.
00061 void WvIPRouteList::get_kernel()
00062 {
00063     char *line;
00064     WvString ifc, table, gate, addr, mask;
00065     int metric, flags;
00066     bool invalid;
00067     WvIPRoute *r;
00068     WvStringList words;
00069     WvStringList::Iter word(words);
00070     
00071     // read each route information line from /proc/net/route; even though
00072     // "ip route list table all" returns all the same information plus more,
00073     // there's no guarantee that the ip command is available on all systems.
00074     WvFile kinfo("/proc/net/route", O_RDONLY);
00075     kinfo.getline(0);
00076     while ((line = kinfo.getline(0)) != NULL)
00077     {
00078         //log(WvLog::Debug2, "get_kern1: line: %s\n", line);
00079         
00080         words.zap();
00081         words.split(line);
00082         
00083         if (words.count() < 10)
00084             continue; // weird entry
00085         
00086         word.rewind();
00087         word.next(); ifc   = *word;
00088         word.next(); addr  = *word;
00089         word.next(); gate  = *word;
00090         word.next(); flags = strtoul(*word, NULL, 16);
00091         word.next(); // refcnt
00092         word.next(); // use
00093         word.next(); metric = atoi(*word);
00094         word.next(); mask   = *word;
00095         
00096         // routes appear in the list even when not "up" -- strange.
00097         if (!(flags & RTF_UP))
00098             continue;
00099         
00100         // the addresses in /proc/net/route are in hex.  This here is some
00101         // pretty sicky type-munging...
00102         __u32 a = strtoul(addr, NULL, 16), m = strtoul(mask, NULL, 16);
00103         __u32 g = strtoul(gate, NULL, 16);
00104         WvIPAddr aa(a), mm(m);
00105         WvIPNet net(aa, mm);
00106         WvIPAddr gw(g);
00107         
00108         r = new WvIPRoute(ifc, net, gw, metric, "default");
00109         append(r, true);
00110         //log(WvLog::Debug2, "get_kern1:  out: %s\n", *r);
00111     }
00112     
00113     // add more data from the kernel "policy routing" default table
00114     const char *argv[] = { "ip", "route", "list", "table", "all", NULL };
00115     WvPipe defaults(argv[0], argv, false, true, false);
00116     while (defaults.isok() && (line = defaults.getline(-1)) != NULL)
00117     {
00118         //log(WvLog::Debug2, "get_kern2: line: %s\n", line);
00119         
00120         invalid = false;
00121         ifc = gate = table = "";
00122         metric = 0;
00123         
00124         words.zap();
00125         words.split(line);
00126         
00127         if (words.count() < 3)
00128             continue; // weird entry
00129         
00130         word.rewind();
00131         word.next();
00132         if (*word == "broadcast" || *word == "local")
00133             continue; // these lines are weird: skip them
00134 
00135         WvIPNet net((*word == "default") ? WvString("0/0") : *word);
00136         
00137         while (word.next())
00138         {
00139             WvString word1(*word);
00140             if (!word.next()) break;
00141             WvString word2(*word);
00142             
00143             if (word1 == "table")
00144             {
00145                 if (word2 == "local")
00146                 {
00147                     invalid = true; // ignore 'local' table - too complex
00148                     break;
00149                 }
00150                 else
00151                     table = word2;
00152             }
00153             else if (word1 == "dev")
00154                 ifc = word2;
00155             else if (word1 == "via")
00156                 gate = word2;
00157             else if (word1 == "metric")
00158                 metric = word2.num();
00159             else if (word1 == "scope")
00160                 ; // ignore
00161             else if (word1 == "proto" && word2 == "kernel")
00162                 ; // ignore
00163             else if (word1 == "src")
00164                 ; // ignore
00165             else
00166                 log(WvLog::Debug, "Unknown keyvalue: '%s' '%s' in (%s)\n",
00167                     word1, word2, line);
00168             
00169             // ignore all other words - just use their defaults.
00170         }
00171         
00172         // if no table keyword was given, it's the default "main" table, which
00173         // we already read from /proc/net/route.  Skip it.
00174         if (!table)
00175             continue;
00176         
00177         if (!ifc)
00178         {
00179             log(WvLog::Debug2, "No interface given for this route; skipped.\n");
00180             continue;
00181         }
00182         
00183         r = new WvIPRoute(ifc, net, gate ? WvIPAddr(gate) : WvIPAddr(),
00184                           metric, table);
00185         append(r, true);
00186         //log(WvLog::Debug2, "get_kern2:  out: %s\n", *r);
00187     }
00188 }
00189 
00190 
00191 // we use an n-squared algorithm here, for no better reason than readability.
00192 void WvIPRouteList::set_kernel()
00193 {
00194     WvIPRouteList old_kern;
00195     old_kern.get_kernel();
00196     
00197     Iter oi(old_kern), ni(*this);
00198     
00199     // FIXME!!
00200     // Kernel 2.1.131: deleting a route with no gateway causes the kernel
00201     // to delete the _first_ route to that network, regardless of its
00202     // gateway.  This is probably to make things like "route del default"
00203     // more convenient.  However, it messes up if we add routes first, then
00204     // delete routes.
00205     //
00206     // Except for this problem, it makes more sense to add and then delete,
00207     // since we avoid races (we never completely remove a route to a host
00208     // we should be routing to).
00209 
00210     // delete outdated routes.
00211     for (oi.rewind(); oi.next(); )
00212     {
00213         if (oi->metric == 99) continue; // "magic" metric for manual override
00214         
00215         for (ni.rewind(); ni.next(); )
00216             if (*ni == *oi) break;
00217         
00218         if (!ni.cur()) // hit end of list without finding a match
00219         {
00220             WvInterface i(oi->ifc);
00221             log("Del %s\n", *oi);
00222             i.delroute(oi->ip, oi->gateway, oi->metric, oi->table);
00223         }
00224     }
00225 
00226     // add any new routes.
00227     for (ni.rewind(); ni.next(); )
00228     {
00229         for (oi.rewind(); oi.next(); )
00230             if (*oi == *ni) break;
00231         
00232         if (!oi.cur()) // hit end of list without finding a match
00233         {
00234             WvInterface i(ni->ifc);
00235             log("Add %s\n", *ni);
00236             i.addroute(ni->ip, ni->gateway, ni->metric, ni->table);
00237         }
00238     }
00239 }
00240 
00241 
00242 WvIPRoute *WvIPRouteList::find(const WvIPAddr &addr)
00243 {
00244     Iter i(*this);
00245     
00246     for (i.rewind(); i.next(); )
00247     {
00248         if (i->ip.includes(addr))
00249             return &i();
00250     }
00251     
00252     return NULL;
00253 }

Generated on Fri Apr 5 15:16:52 2002 for WvStreams by doxygen1.2.15