2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5 * The WvIPRoute and WvIPRouteList class, a quick (mostly hackish) attempt
6 * at a way to read the Linux kernel routing table.
10 #include "wvinterface.h"
12 #include "wvstringlist.h"
14 #include <net/route.h>
17 WvIPRoute::WvIPRoute(WvStringParm _ifc
, const WvIPNet
&_net
,
18 const WvIPAddr
&_gate
, int _metric
,
20 : ifc(_ifc
), ip(_net
), gateway(_gate
), table(_table
), src()
26 WvIPRoute::operator WvString() const
29 return WvString("%s via %s %s %s metric %s%s",
31 (src
!= zero
? WvString("src %s", src
) : WvString("")),
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
)
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()
63 WvString ifc
, table
, gate
, addr
, mask
, src
;
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
);
75 while ((line
= kinfo
.getline()) != NULL
)
77 //log(WvLog::Debug2, "get_kern1: line: %s\n", line);
82 if (words
.count() < 10)
83 continue; // weird entry
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
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
))
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
);
107 r
= new WvIPRoute(ifc
, net
, gw
, metric
, "default");
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);
120 ifc
= gate
= table
= "";
126 if (words
.count() < 3)
127 continue; // weird entry
131 if (*word
== "broadcast" || *word
== "local")
132 continue; // these lines are weird: skip them
134 WvIPNet
net((*word
== "default") ? WvString("0/0") : *word
);
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
152 else if (word1
== "dev")
154 else if (word1
== "via")
156 else if (word1
== "metric")
157 metric
= word2
.num();
158 else if (word1
== "scope")
160 else if (word1
== "proto" && word2
== "kernel")
162 else if (word1
== "src")
165 log(WvLog::Debug
, "Unknown keyvalue: '%s' '%s' in (%s)\n",
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.
178 log(WvLog::Debug2
, "No interface given for this route; skipped.\n");
182 r
= new WvIPRoute(ifc
, net
, gate
? WvIPAddr(gate
) : WvIPAddr(),
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")
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);
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
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
,
253 WvIPRoute
*WvIPRouteList::find(const WvIPAddr
&addr
)
257 for (i
.rewind(); i
.next(); )
259 if (i
->ip
.includes(addr
))