1 /**
2 * @file protoRouteMgr.cpp
3 *
4 * @brief Base class for providing a consistent interface to manage operating system (or other) routing engines
5 */
6 #include "protoRouteMgr.h"
7 #include "protoDebug.h"
8
ProtoRouteMgr()9 ProtoRouteMgr::ProtoRouteMgr()
10 : savedRoutesIPv4(NULL), savedRoutesIPv6(NULL)
11 {
12 }
13
~ProtoRouteMgr()14 ProtoRouteMgr::~ProtoRouteMgr()
15 {
16 if(NULL != savedRoutesIPv4) delete savedRoutesIPv4;
17 if(NULL != savedRoutesIPv6) delete savedRoutesIPv6;
18 }
19
20
DeleteAllRoutes()21 bool ProtoRouteMgr::DeleteAllRoutes()
22 {
23 return DeleteAllRoutes(ProtoAddress::IPv4) && DeleteAllRoutes(ProtoAddress::IPv6);
24 }
25
DeleteAllRoutes(ProtoAddress::Type addrType,unsigned int maxIterations)26 bool ProtoRouteMgr::DeleteAllRoutes(ProtoAddress::Type addrType, unsigned int maxIterations)
27 {
28 ProtoRouteTable rt;
29 // Make multiple passes to get rid of possible
30 // multiple routes to destinations
31 // (TBD) extend ProtoRouteTable to support multiple routes per destination
32 while (maxIterations-- > 0)
33 {
34 if (!GetAllRoutes(addrType, rt))
35 {
36 PLOG(PL_ERROR, "ProtoRouteMgr::DeleteAllRoutes() error getting routes\n");
37 return false;
38 }
39 if (rt.IsEmpty()) break;
40 if (!DeleteRoutes(rt))
41 {
42 PLOG(PL_ERROR, "ProtoRouteMgr::DeleteAllRoutes() error deleting routes\n");
43 return false;
44 }
45 rt.Destroy();
46 }
47
48 if (0 == maxIterations)
49 {
50 PLOG(PL_ERROR, "ProtoRouteMgr::DeleteAllRoutes() couldn't seem to delete everything!\n");
51 return false;
52 }
53 else
54 {
55 return true;
56 }
57 } // end ProtoRouteMgr::DeleteAllRoutes()
58
59 /**
60 * Set direct (interface) routes and gateway routes.
61 */
SetRoutes(ProtoRouteTable & routeTable)62 bool ProtoRouteMgr::SetRoutes(ProtoRouteTable& routeTable)
63 {
64 bool result = true;
65 ProtoRouteTable::Iterator iterator(routeTable);
66 ProtoRouteTable::Entry* entry;
67 // First, set direct (interface) routes
68 while ((entry = iterator.GetNextEntry()))
69 {
70 if (entry->IsDirectRoute())
71 {
72 if (!SetRoute(entry->GetDestination(),
73 entry->GetPrefixSize(),
74 entry->GetGateway(),
75 entry->GetInterfaceIndex(),
76 entry->GetMetric()))
77 {
78 PLOG(PL_ERROR, "ProtoRouteMgr::SetAllRoutes() failed to set direct route to: %s\n",
79 entry->GetDestination().GetHostString());
80 result = false;
81 }
82 }
83 }
84 // Second, set gateway routes
85 iterator.Reset();
86 while ((entry = iterator.GetNextEntry()))
87 {
88 if (entry->IsGatewayRoute())
89 {
90 if (!SetRoute(entry->GetDestination(),
91 entry->GetPrefixSize(),
92 entry->GetGateway(),
93 entry->GetInterfaceIndex(),
94 entry->GetMetric()))
95 {
96 PLOG(PL_ERROR, "ProtoRouteMgr::SetAllRoutes() failed to set gateway route to: %s\n",
97 entry->GetDestination().GetHostString());
98 result = false;
99 }
100 }
101 }
102
103 return result;
104 } // end ProtoRouteMgr::SetRoutes()
105 bool
GetDiff(ProtoRouteTable & oldRouteTable,ProtoRouteTable & newRouteTable,ProtoRouteTable & settedRouteTable,ProtoRouteTable & deletedRouteTable)106 ProtoRouteMgr::GetDiff(ProtoRouteTable& oldRouteTable, ProtoRouteTable& newRouteTable, ProtoRouteTable& settedRouteTable, ProtoRouteTable& deletedRouteTable)
107 {
108 //this can be sped up by only going through a single list instead of both and adding routes directly instead of in sets. TBD
109 ProtoRouteTable updateRoutesMetric; //this was added so we only get a diff on changed routes via the settedRoute table
110
111 settedRouteTable.Init();
112 deletedRouteTable.Init();
113 ProtoRouteTable::Iterator it_old(oldRouteTable);
114 ProtoRouteTable::Iterator it_new(newRouteTable);
115 ProtoRouteTable::Entry* entry;
116
117 ProtoAddress gwAddrLookup;
118 unsigned int ifaceIndexLookup;
119 int metricLookup;
120
121 while(NULL != (entry = it_old.GetNextEntry()))
122 {
123 ProtoAddress dstAddr = entry->GetDestination();
124 ProtoAddress gwAddr = entry->GetGateway();
125 unsigned int prefixLen = entry->GetPrefixSize();
126 unsigned int ifaceIndex = entry->GetInterfaceIndex();
127 int metric = entry->GetMetric();
128 if(!newRouteTable.FindRoute(dstAddr,prefixLen,gwAddrLookup,ifaceIndexLookup,metricLookup))
129 {
130 if(!deletedRouteTable.SetRoute(dstAddr,prefixLen,gwAddr,ifaceIndex,metric))
131 {
132 PLOG(PL_ERROR,"ProtoRouteMgr::UpdateRoutes() failed add an old route to the removeRoutes table\n");
133 return false;
134 }
135 }
136 }
137 while(NULL != (entry = it_new.GetNextEntry()))
138 {
139 ProtoAddress dstAddr = entry->GetDestination();
140 ProtoAddress gwAddr = entry->GetGateway();
141 unsigned int prefixLen = entry->GetPrefixSize();
142 unsigned int ifaceIndex = entry->GetInterfaceIndex();
143 int metric = entry->GetMetric();
144 if(!oldRouteTable.FindRoute(dstAddr,prefixLen,gwAddrLookup,ifaceIndexLookup,metricLookup))
145 {
146 if(!settedRouteTable.SetRoute(dstAddr,prefixLen,gwAddr,ifaceIndex,metric))
147 {
148 PLOG(PL_ERROR,"ProtoRouteMgr::UpdateRoutes() failed add an old route to the removeRoutes table in new section\n");
149 return false;
150 }
151 } else if((gwAddrLookup != gwAddr) || (ifaceIndexLookup != ifaceIndex)) {
152 if(!settedRouteTable.SetRoute(dstAddr,prefixLen,gwAddr,ifaceIndex,metric))
153 {
154 PLOG(PL_ERROR,"ProtoRouteMgr::UpdateRoutes() failed add an old route to the removeRoutes table in change section\n");
155 return false;
156 }
157 } else if(metricLookup != metric) {
158 if(!updateRoutesMetric.SetRoute(dstAddr,prefixLen,gwAddr,ifaceIndex,metric))
159 {
160 PLOG(PL_ERROR,"ProtoRouteMgr::UpdateRoutes() failed add an old route to the removeRoutes table in change section\n");
161 return false;
162 }
163 }
164 }
165 return true;
166 }
167 bool
UpdateRoutes(ProtoRouteTable & oldRouteTable,ProtoRouteTable & newRouteTable,ProtoRouteTable * settedRouteTable,ProtoRouteTable * deletedRouteTable)168 ProtoRouteMgr::UpdateRoutes(ProtoRouteTable& oldRouteTable, ProtoRouteTable& newRouteTable, ProtoRouteTable* settedRouteTable, ProtoRouteTable* deletedRouteTable)
169 {
170 //this can be sped up by only going through a single list instead of both and adding routes directly instead of in sets. TBD
171 ProtoRouteTable removeRoutes;
172 ProtoRouteTable updateRoutes;
173 ProtoRouteTable updateRoutesMetric; //this was added so we only get a diff on changed routes via the settedRoute table
174 ProtoRouteTable* removeRoutesPtr = &removeRoutes;
175 ProtoRouteTable* updateRoutesPtr = &updateRoutes;
176 if( NULL != settedRouteTable)
177 {
178 updateRoutesPtr = settedRouteTable;
179 }
180 if( NULL != deletedRouteTable)
181 {
182 removeRoutesPtr = deletedRouteTable;
183 }
184 removeRoutesPtr->Init();
185 updateRoutesPtr->Init();
186 ProtoRouteTable::Iterator it_old(oldRouteTable);
187 ProtoRouteTable::Iterator it_new(newRouteTable);
188 ProtoRouteTable::Entry* entry;
189
190 ProtoAddress gwAddrLookup;
191 unsigned int ifaceIndexLookup;
192 int metricLookup;
193
194 while(NULL != (entry = it_old.GetNextEntry()))
195 {
196 ProtoAddress dstAddr = entry->GetDestination();
197 ProtoAddress gwAddr = entry->GetGateway();
198 unsigned int prefixLen = entry->GetPrefixSize();
199 unsigned int ifaceIndex = entry->GetInterfaceIndex();
200 int metric = entry->GetMetric();
201 if(!newRouteTable.FindRoute(dstAddr,prefixLen,gwAddrLookup,ifaceIndexLookup,metricLookup))
202 {
203 if(!removeRoutesPtr->SetRoute(dstAddr,prefixLen,gwAddr,ifaceIndex,metric))
204 {
205 PLOG(PL_ERROR,"ProtoRouteMgr::UpdateRoutes() failed add an old route to the removeRoutes table\n");
206 return false;
207 }
208 }
209 }
210 while(NULL != (entry = it_new.GetNextEntry()))
211 {
212 ProtoAddress dstAddr = entry->GetDestination();
213 ProtoAddress gwAddr = entry->GetGateway();
214 unsigned int prefixLen = entry->GetPrefixSize();
215 unsigned int ifaceIndex = entry->GetInterfaceIndex();
216 int metric = entry->GetMetric();
217 if(!oldRouteTable.FindRoute(dstAddr,prefixLen,gwAddrLookup,ifaceIndexLookup,metricLookup))
218 {
219 if(!updateRoutesPtr->SetRoute(dstAddr,prefixLen,gwAddr,ifaceIndex,metric))
220 {
221 PLOG(PL_ERROR,"ProtoRouteMgr::UpdateRoutes() failed add an old route to the removeRoutes table in new section\n");
222 return false;
223 }
224 } else if((gwAddrLookup != gwAddr) || (ifaceIndexLookup != ifaceIndex)) {
225 if(!updateRoutesPtr->SetRoute(dstAddr,prefixLen,gwAddr,ifaceIndex,metric))
226 {
227 PLOG(PL_ERROR,"ProtoRouteMgr::UpdateRoutes() failed add an old route to the removeRoutes table in change section\n");
228 return false;
229 }
230 } else if(metricLookup != metric) {
231 if(!updateRoutesMetric.SetRoute(dstAddr,prefixLen,gwAddr,ifaceIndex,metric))
232 {
233 PLOG(PL_ERROR,"ProtoRouteMgr::UpdateRoutes() failed add an old route to the removeRoutes table in change section\n");
234 return false;
235 }
236 }
237 }
238 if(!DeleteRoutes(*removeRoutesPtr)) {
239 PLOG(PL_ERROR,"ProtoRouteMgr::UpdateRoutes() failed delete old routes\n");
240 return false;
241 }
242 if(!SetRoutes(*updateRoutesPtr)) {
243 PLOG(PL_ERROR,"ProtoRouteMgr::UpdateRoutes() failed update routes\n");
244 return false;
245 }
246 if(!SetRoutes(updateRoutesMetric)) {
247 PLOG(PL_ERROR,"ProtoRouteMgr::UpdateRoutes() failed update routes metric only\n");
248 return false;
249 }
250 return true;
251 }
252 /**
253 * Deletes gateway and direct (interface) routes and the
254 * default entry if one exists.
255 */
DeleteRoutes(ProtoRouteTable & routeTable)256 bool ProtoRouteMgr::DeleteRoutes(ProtoRouteTable& routeTable)
257 {
258 bool result = true;
259 ProtoRouteTable::Iterator iterator(routeTable);
260 const ProtoRouteTable::Entry* entry;
261 // First, delete gateway routes
262 while ((entry = iterator.GetNextEntry()))
263 {
264 if (entry->IsGatewayRoute())
265 {
266 if (!DeleteRoute(entry->GetDestination(),
267 entry->GetPrefixSize(),
268 entry->GetGateway(),
269 entry->GetInterfaceIndex()))
270 {
271 PLOG(PL_ERROR, "ProtoRouteMgr::DeleteAllRoutes() failed to delete gateway route to: %s\n",
272 entry->GetDestination().GetHostString());
273 result = false;
274 }
275 }
276 }
277 // Second, delete direct (interface) routes
278 iterator.Reset();
279 while ((entry = iterator.GetNextEntry()))
280 {
281 if (entry->IsDirectRoute())
282 {
283 if (!DeleteRoute(entry->GetDestination(),
284 entry->GetPrefixSize(),
285 entry->GetGateway(),
286 entry->GetInterfaceIndex()))
287 {
288 PLOG(PL_ERROR, "ProtoRouteMgr::DeleteAllRoutes() failed to delete direct route to: %s\n",
289 entry->GetDestination().GetHostString());
290 result = false;
291 }
292 }
293 }
294 // If there's a default entry delete it, too
295 entry = routeTable.GetDefaultEntry();
296 if (entry)
297 {
298 if (!DeleteRoute(entry->GetDestination(),
299 entry->GetPrefixSize(),
300 entry->GetGateway(),
301 entry->GetInterfaceIndex()))
302 {
303 PLOG(PL_ERROR, "ProtoRouteMgr::DeleteAllRoutes() failed to delete default route\n");
304 result = false;
305 }
306 }
307 return result;
308 } // end ProtoRouteMgr::DeleteRoutes()
309
SaveAllRoutes()310 bool ProtoRouteMgr::SaveAllRoutes()
311 {
312 return SaveAllRoutes(ProtoAddress::IPv4) || SaveAllRoutes(ProtoAddress::IPv6);
313 } // end ProtoRouteMgr::SaveAllRoutes()
314
SaveAllRoutes(ProtoAddress::Type addrType)315 bool ProtoRouteMgr::SaveAllRoutes(ProtoAddress::Type addrType)
316 {
317 switch (addrType)
318 {
319 case ProtoAddress::IPv4:
320 if (NULL == savedRoutesIPv4)
321 {
322 savedRoutesIPv4 = new ProtoRouteTable();
323 if (NULL == savedRoutesIPv4)
324 {
325 PLOG(PL_ERROR, "ProtoRouteMgr::SaveAllRoutes() failed allocating a ProtoRouteTable\n");
326 return false;
327 }
328 }
329 savedRoutesIPv4->Init();
330 if (!GetAllRoutes(ProtoAddress::IPv4, *savedRoutesIPv4))
331 {
332 PLOG(PL_ERROR, "ProtoRouteMgr::SaveAllRoutes() failed getting all of the IPv4 routes");
333 return false;
334 }
335 break;
336 case ProtoAddress::IPv6:
337 if (NULL == savedRoutesIPv6)
338 {
339 savedRoutesIPv6 = new ProtoRouteTable();
340 if (NULL == savedRoutesIPv6)
341 {
342 PLOG(PL_ERROR, "ProtoRouteMgr::SaveAllRoutes() failed allocating a ProtoRouteTable\n");
343 return false;
344 }
345 }
346 savedRoutesIPv6->Init();
347 if (!GetAllRoutes(ProtoAddress::IPv4, *savedRoutesIPv6))
348 {
349 PLOG(PL_ERROR, "ProtoRouteMgr::SaveAllRoutes() failed getting all of the IPv6 routes");
350 return false;
351 }
352 break;
353 default:
354 PLOG(PL_ERROR, "ProtoRouteMgr::SaveAllRoutes() only supports saving route tables of types IPv6 and IPv4\n");
355 return false;
356 }
357 return true;
358 } // ProtoRouteMgr::SaveAllRoutes()
359
RestoreSavedRoutes()360 bool ProtoRouteMgr::RestoreSavedRoutes()
361 {
362 bool returnvalue = false;
363 if(NULL != savedRoutesIPv6)
364 {
365 returnvalue = RestoreSavedRoutes(ProtoAddress::IPv6);
366 }
367 if(NULL != savedRoutesIPv4)
368 {
369 returnvalue = returnvalue || RestoreSavedRoutes(ProtoAddress::IPv4);
370 }
371 if(!returnvalue)
372 {
373 PLOG(PL_ERROR,"ProtoRouteMgr::RestoreSavedRoutes() couldn't restore routes, did you save any first?");
374 }
375 return returnvalue;
376 } // end ProtoRouteMgr::RestoreSavedRoutes()
377
RestoreSavedRoutes(ProtoAddress::Type addrType)378 bool ProtoRouteMgr::RestoreSavedRoutes(ProtoAddress::Type addrType)
379 {
380 switch(addrType)
381 {
382 case ProtoAddress::IPv4:
383 if(NULL == savedRoutesIPv4)
384 {
385 PLOG(PL_ERROR,"ProtoRouteMgr::RestoreSavedRoutes() can not restore IPv4 routes as none have been saved.\n");
386 return false;
387 }
388 return SetRoutes(*savedRoutesIPv4);
389 break;
390 case ProtoAddress::IPv6:
391 if(NULL == savedRoutesIPv6)
392 {
393 PLOG(PL_ERROR,"ProtoRouteMgr::RestoreSavedRoutes() can not restore IPv6 routes as none have been saved.\n");
394 return false;
395 }
396 return SetRoutes(*savedRoutesIPv6);
397 break;
398 default:
399 PLOG(PL_ERROR, "ProtoRouteMgr::RestoreSavedRoutes() only supports restoring route tables of types IPv6 and IPv4\n");
400 return false;
401 }
402 return true;
403 } // end ProtoRouteMgr::RestoreSavedRoutes()
404
ClearSavedRoutes()405 void ProtoRouteMgr::ClearSavedRoutes()
406 {
407 // the ProtoRouteMgr base class constructor now inits
408 // these pointers to NULL as it should, so the Init()
409 // method here is probably unecessary, but now can be
410 // used to "clear" any saved route info
411 if (NULL != savedRoutesIPv4)
412 {
413 delete savedRoutesIPv4;
414 savedRoutesIPv4 = NULL;
415 }
416 if (NULL != savedRoutesIPv6)
417 {
418 delete savedRoutesIPv6;
419 savedRoutesIPv6 = NULL;
420 }
421 } // end ProtoRouteMgr::ClearSavedRoutes()
422