WvStreams
wviproute.cc
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"
13
14#include <net/route.h>
15#include <ctype.h>
16
17WvIPRoute::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()
21{
22 metric = _metric;
23}
24
25
26WvIPRoute::operator WvString() const
27{
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(""));
35}
36
37
38bool WvIPRoute::operator== (const WvIPRoute &r2) const
39{
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);
44}
45
46
47
49
50
51WvIPRouteList::WvIPRouteList() : log("Route Table", WvLog::Debug)
52{
53 // nothing else to do
54}
55
56
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.
61{
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);
69
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)
76 {
77 //log(WvLog::Debug2, "get_kern1: line: %s\n", line);
78
79 words.zap();
80 words.split(line);
81
82 if (words.count() < 10)
83 continue; // weird entry
84
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;
94
95 // routes appear in the list even when not "up" -- strange.
96 if (!(flags & RTF_UP))
97 continue;
98
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);
106
107 r = new WvIPRoute(ifc, net, gw, metric, "default");
108 append(r, true);
109 //log(WvLog::Debug2, "get_kern1: out: %s\n", *r);
110 }
111
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)
116 {
117 //log(WvLog::Debug2, "get_kern2: line: %s\n", line);
118
119 invalid = false;
120 ifc = gate = table = "";
121 metric = 0;
122
123 words.zap();
124 words.split(line);
125
126 if (words.count() < 3)
127 continue; // weird entry
128
129 word.rewind();
130 word.next();
131 if (*word == "broadcast" || *word == "local")
132 continue; // these lines are weird: skip them
133
134 WvIPNet net((*word == "default") ? WvString("0/0") : *word);
135
136 while (word.next())
137 {
138 WvString word1(*word);
139 if (!word.next()) break;
140 WvString word2(*word);
141
142 if (word1 == "table")
143 {
144 if (word2 == "local")
145 {
146 invalid = true; // ignore 'local' table - too complex
147 break;
148 }
149 else
150 table = word2;
151 }
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);
167
168 // ignore all other words - just use their defaults.
169 }
170
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;
175
176 if (!ifc)
177 {
178 log(WvLog::Debug2, "No interface given for this route; skipped.\n");
179 continue;
180 }
181
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);
188 }
189}
190
191
192static WvString realtable(WvIPRoute &r)
193{
194 if (!r.ip.is_default() && r.table == "default")
195 return "main";
196 else
197 return r.table;
198}
199
200
201// we use an n-squared algorithm here, for no better reason than readability.
203{
204 WvIPRouteList old_kern;
205 old_kern.get_kernel();
206
207 Iter oi(old_kern), ni(*this);
208
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.
215 //
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).
219
220 // delete outdated routes.
221 for (oi.rewind(); oi.next(); )
222 {
223 if (oi->metric == 99) continue; // "magic" metric for manual override
224
225 for (ni.rewind(); ni.next(); )
226 if (*ni == *oi) break;
227
228 if (!ni.cur()) // hit end of list without finding a match
229 {
230 WvInterface i(oi->ifc);
231 log("Del %s\n", *oi);
232 i.delroute(oi->ip, oi->gateway, oi->metric, realtable(*oi));
233 }
234 }
235
236 // add any new routes.
237 for (ni.rewind(); ni.next(); )
238 {
239 for (oi.rewind(); oi.next(); )
240 if (*oi == *ni) break;
241
242 if (!oi.cur()) // hit end of list without finding a match
243 {
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));
248 }
249 }
250}
251
252
254{
255 Iter i(*this);
256
257 for (i.rewind(); i.next(); )
258 {
259 if (i->ip.includes(addr))
260 return &i();
261 }
262
263 return NULL;
264}
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition: wvstring.h:94
int num() const
Return a stdc++ string with the contents of this string.
Definition: wvstring.h:286
virtual bool isok() const
return true if the stream is actually usable right now
Definition: wvfdstream.cc:134
WvFile implements a stream connected to a file or Unix device.
Definition: wvfile.h:29
An IP address is made up of a "dotted quad" – four decimal numbers in the form www....
Definition: wvaddr.h:250
An IP network comprises two WvIPAddr structures: an address and a netmask.
Definition: wvaddr.h:313
bool is_default() const
is this net the default gateway? (0.0.0.0/0)
Definition: wvaddr.h:376
List of IP Routes currently in effect.
Definition: wviproute.h:37
void set_kernel()
automatically set the kernel to the values in the RouteList
Definition: wviproute.cc:202
WvIPRoute * find(const WvIPAddr &addr)
find the routing entry that matches 'addr'
Definition: wviproute.cc:253
void get_kernel()
automatically fill the list with appropriate data from the kernel
Definition: wviproute.cc:60
Manipulate the kernel routing table in strange and interesting ways ;)
Definition: wviproute.h:17
A WvInterface manages a particular network interface.
Definition: wvinterface.h:25
int delroute(const WvIPNet &dest, int metric=0, WvStringParm table="default")
delete a route to the given network through this interface.
Definition: wvinterface.cc:532
int addroute(const WvIPNet &dest, int metric=0, WvStringParm table="default")
add a route to the given network through this interface.
Definition: wvinterface.cc:472
A WvLog stream accepts log messages from applications and forwards them to all registered WvLogRcv's.
Definition: wvlog.h:57
Implementation of a WvPipe stream.
Definition: wvpipe.h:33
char * blocking_getline(time_t wait_msec, int separator='\n', int readahead=1024)
This is a version of getline() that allows you to block for more data to arrive.
Definition: wvstream.cc:602
char * getline(time_t wait_msec=0, char separator='\n', int readahead=1024)
Read up to one line of data from the stream and return a pointer to the internal buffer containing th...
Definition: wvstream.h:175
This is a WvList of WvStrings, and is a really handy way to parse strings.
Definition: wvstringlist.h:28
void split(WvStringParm s, const char *splitchars=" \t\r\n", int limit=0)
split s and form a list ignoring splitchars (except at beginning and end) ie.
Definition: wvstringlist.cc:19
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:330