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