Make WvStreams compile with gcc 4.4.
[wvstreams.git] / linuxstreams / wviproute.cc
blob3a4b64dcf7d32b5bc33a924fc6f68b6ea4e59f15
1 /*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 * The WvIPRoute and WvIPRouteList class, a quick (mostly hackish) attempt
6 * at a way to read the Linux kernel routing table.
7 */
8 #include "wviproute.h"
9 #include "wvpipe.h"
10 #include "wvinterface.h"
11 #include "wvfile.h"
12 #include "wvstringlist.h"
14 #include <net/route.h>
15 #include <ctype.h>
17 WvIPRoute::WvIPRoute(WvStringParm _ifc, const WvIPNet &_net,
18 const WvIPAddr &_gate, int _metric,
19 WvStringParm _table)
20 : ifc(_ifc), ip(_net), gateway(_gate), table(_table), src()
22 metric = _metric;
26 WvIPRoute::operator WvString() const
28 WvIPAddr zero;
29 return WvString("%s via %s %s %s metric %s%s",
30 ip, ifc, gateway,
31 (src != zero ? WvString("src %s", src) : WvString("")),
32 metric,
33 (table != "default")
34 ? WvString(" (table %s)", table) : WvString(""));
38 bool WvIPRoute::operator== (const WvIPRoute &r2) const
40 return (ip.network() == r2.ip.network() && ip.netmask() == r2.ip.netmask()
41 && gateway == r2.gateway
42 && ifc == r2.ifc && metric == r2.metric
43 && table == r2.table);
48 /////////////////////////////////////// WvIPRouteList
51 WvIPRouteList::WvIPRouteList() : log("Route Table", WvLog::Debug)
53 // nothing else to do
57 // Reads the kernel routing table, from /proc/net/route, and parses it into
58 // A WvIPRouteList. Also reads the kernel 2.1.x "policy routing" tables,
59 // (via the "ip" command) and parses those routes.
60 void WvIPRouteList::get_kernel()
62 char *line;
63 WvString ifc, table, gate, addr, mask, src;
64 int metric, flags;
65 bool invalid;
66 WvIPRoute *r;
67 WvStringList words;
68 WvStringList::Iter word(words);
70 // read each route information line from /proc/net/route; even though
71 // "ip route list table all" returns all the same information plus more,
72 // there's no guarantee that the ip command is available on all systems.
73 WvFile kinfo("/proc/net/route", O_RDONLY);
74 kinfo.getline();
75 while ((line = kinfo.getline()) != NULL)
77 //log(WvLog::Debug2, "get_kern1: line: %s\n", line);
79 words.zap();
80 words.split(line);
82 if (words.count() < 10)
83 continue; // weird entry
85 word.rewind();
86 word.next(); ifc = *word;
87 word.next(); addr = *word;
88 word.next(); gate = *word;
89 word.next(); flags = strtoul(*word, NULL, 16);
90 word.next(); // refcnt
91 word.next(); // use
92 word.next(); metric = atoi(*word);
93 word.next(); mask = *word;
95 // routes appear in the list even when not "up" -- strange.
96 if (!(flags & RTF_UP))
97 continue;
99 // the addresses in /proc/net/route are in hex. This here is some
100 // pretty sicky type-munging...
101 uint32_t a = strtoul(addr, NULL, 16), m = strtoul(mask, NULL, 16);
102 uint32_t g = strtoul(gate, NULL, 16);
103 WvIPAddr aa(a), mm(m);
104 WvIPNet net(aa, mm);
105 WvIPAddr gw(g);
107 r = new WvIPRoute(ifc, net, gw, metric, "default");
108 append(r, true);
109 //log(WvLog::Debug2, "get_kern1: out: %s\n", *r);
112 // add more data from the kernel "policy routing" default table
113 const char *argv[] = { "ip", "route", "list", "table", "all", NULL };
114 WvPipe defaults(argv[0], argv, false, true, false);
115 while (defaults.isok() && (line = defaults.blocking_getline(-1)) != NULL)
117 //log(WvLog::Debug2, "get_kern2: line: %s\n", line);
119 invalid = false;
120 ifc = gate = table = "";
121 metric = 0;
123 words.zap();
124 words.split(line);
126 if (words.count() < 3)
127 continue; // weird entry
129 word.rewind();
130 word.next();
131 if (*word == "broadcast" || *word == "local")
132 continue; // these lines are weird: skip them
134 WvIPNet net((*word == "default") ? WvString("0/0") : *word);
136 while (word.next())
138 WvString word1(*word);
139 if (!word.next()) break;
140 WvString word2(*word);
142 if (word1 == "table")
144 if (word2 == "local")
146 invalid = true; // ignore 'local' table - too complex
147 break;
149 else
150 table = word2;
152 else if (word1 == "dev")
153 ifc = word2;
154 else if (word1 == "via")
155 gate = word2;
156 else if (word1 == "metric")
157 metric = word2.num();
158 else if (word1 == "scope")
159 ; // ignore
160 else if (word1 == "proto" && word2 == "kernel")
161 ; // ignore
162 else if (word1 == "src")
163 src = word2;
164 else
165 log(WvLog::Debug, "Unknown keyvalue: '%s' '%s' in (%s)\n",
166 word1, word2, line);
168 // ignore all other words - just use their defaults.
171 // if no table keyword was given, it's the default "main" table, which
172 // we already read from /proc/net/route. Skip it.
173 if (!table)
174 continue;
176 if (!ifc)
178 log(WvLog::Debug2, "No interface given for this route; skipped.\n");
179 continue;
182 r = new WvIPRoute(ifc, net, gate ? WvIPAddr(gate) : WvIPAddr(),
183 metric, table);
184 if (!!src)
185 r->src = src;
186 append(r, true);
187 //log(WvLog::Debug2, "get_kern2: out: %s\n", *r);
192 static WvString realtable(WvIPRoute &r)
194 if (!r.ip.is_default() && r.table == "default")
195 return "main";
196 else
197 return r.table;
201 // we use an n-squared algorithm here, for no better reason than readability.
202 void WvIPRouteList::set_kernel()
204 WvIPRouteList old_kern;
205 old_kern.get_kernel();
207 Iter oi(old_kern), ni(*this);
209 // FIXME!!
210 // Kernel 2.1.131: deleting a route with no gateway causes the kernel
211 // to delete the _first_ route to that network, regardless of its
212 // gateway. This is probably to make things like "route del default"
213 // more convenient. However, it messes up if we add routes first, then
214 // delete routes.
216 // Except for this problem, it makes more sense to add and then delete,
217 // since we avoid races (we never completely remove a route to a host
218 // we should be routing to).
220 // delete outdated routes.
221 for (oi.rewind(); oi.next(); )
223 if (oi->metric == 99) continue; // "magic" metric for manual override
225 for (ni.rewind(); ni.next(); )
226 if (*ni == *oi) break;
228 if (!ni.cur()) // hit end of list without finding a match
230 WvInterface i(oi->ifc);
231 log("Del %s\n", *oi);
232 i.delroute(oi->ip, oi->gateway, oi->metric, realtable(*oi));
236 // add any new routes.
237 for (ni.rewind(); ni.next(); )
239 for (oi.rewind(); oi.next(); )
240 if (*oi == *ni) break;
242 if (!oi.cur()) // hit end of list without finding a match
244 WvInterface i(ni->ifc);
245 log("Add %s\n", *ni);
246 i.addroute(ni->ip, ni->gateway, ni->src, ni->metric,
247 realtable(*ni));
253 WvIPRoute *WvIPRouteList::find(const WvIPAddr &addr)
255 Iter i(*this);
257 for (i.rewind(); i.next(); )
259 if (i->ip.includes(addr))
260 return &i();
263 return NULL;