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