1 #include "protoRouteMgr.h"
2 #include "protoDebug.h"
3
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <sys/ioctl.h>
8 #include <netinet/in.h>
9 #include <arpa/inet.h>
10 #include <net/if.h>
11 #include <errno.h>
12
13 // BSD specific includes
14 #include <sys/sysctl.h>
15 #include <net/route.h>
16 #include <net/if_dl.h>
17
18 class BsdRouteMgr : public ProtoRouteMgr
19 {
20 public:
21 BsdRouteMgr();
22 virtual ~BsdRouteMgr();
23
24 virtual bool Open(const void* userData = NULL);
IsOpen() const25 virtual bool IsOpen() const {return (descriptor >= 0);}
26 virtual void Close();
27
28 virtual bool GetAllRoutes(ProtoAddress::Type addrType,
29 ProtoRouteTable& routeTable);
30
31 virtual bool GetRoute(const ProtoAddress& dst,
32 unsigned int prefixLen,
33 ProtoAddress& gw,
34 unsigned int& ifIndex,
35 int& metric);
36
37 virtual bool SetRoute(const ProtoAddress& dst,
38 unsigned int prefixLen,
39 const ProtoAddress& gw,
40 unsigned int ifIndex,
41 int metric);
42
43 virtual bool DeleteRoute(const ProtoAddress& dst,
44 unsigned int prefixLen,
45 const ProtoAddress& gw,
46 unsigned int ifIndex);
47
48 // (TBD) make this actually do something
SetForwarding(bool)49 virtual bool SetForwarding(bool /*state*/) {return true;}
50
GetInterfaceIndex(const char * interfaceName)51 virtual unsigned int GetInterfaceIndex(const char* interfaceName)
52 {
53 return ProtoSocket::GetInterfaceIndex(interfaceName);
54 }
55 virtual bool GetInterfaceAddressList(unsigned int ifIndex,
56 ProtoAddress::Type addrType,
57 ProtoAddressList& addrList);
GetInterfaceName(unsigned int interfaceIndex,char * buffer,unsigned int buflen)58 virtual bool GetInterfaceName(unsigned int interfaceIndex,
59 char* buffer,
60 unsigned int buflen)
61 {
62 return ProtoSocket::GetInterfaceName(interfaceIndex, buffer, buflen);
63 }
64
65
66 private:
67 int descriptor;
68 pid_t pid;
69 UINT32 sequence;
70
71 }; // end class BsdRouteMgr
72
73
Create(Type)74 ProtoRouteMgr* ProtoRouteMgr::Create(Type /*type*/)
75 {
76 // TBD - support alternative route mgr "types" (e.g. ZEBRA)
77 return (static_cast<ProtoRouteMgr*>(new BsdRouteMgr));
78 }
79
BsdRouteMgr()80 BsdRouteMgr::BsdRouteMgr()
81 : descriptor(-1), sequence(0)
82 {
83
84 }
85
~BsdRouteMgr()86 BsdRouteMgr::~BsdRouteMgr()
87 {
88 Close();
89 }
90
Open(const void *)91 bool BsdRouteMgr::Open(const void* /*userData*/)
92 {
93 if (IsOpen()) Close();
94 if ((descriptor = socket(AF_ROUTE, SOCK_RAW, 0)) < 0)
95 {
96 PLOG(PL_ERROR, "BsdRouteMgr::Open() socket(AF_ROUTE) error: %s\n",
97 strerror(errno));
98 return false;
99 }
100 else
101 {
102 pid = (UINT32)getpid();
103 return true;
104 }
105 } // end BsdRouteMgr::Open()
106
Close()107 void BsdRouteMgr::Close()
108 {
109 if (IsOpen())
110 {
111 close(descriptor);
112 descriptor = -1;
113 }
114 } // end BsdRouteMgr::Close()
115
116 /*
117 #define ROUNDUP(a, size) (((a) & ((size)-1)) ? \
118 (1 + ((a) | ((size)-1))) \
119 : (a))
120
121 #define NEXT_SA(sa) sa = (struct sockaddr *) ((caddr_t) (sa) + ((sa)->sa_len ? \
122 ROUNDUP((sa)->sa_len, sizeof(u_long)) \
123 : sizeof(u_long)));
124 */
125
126 // IMPORTANT NOTE: These "oldie but goodie macros above are wrong on a 64-bit machine!!!
127 // The ones below do the right thing.
128
129 #define ROUNDUP(a, size) (((a) & ((size)-1)) ? \
130 (1 + ((a) | ((size)-1))) \
131 : (a))
132
133 #define NEXT_SA(sa) sa = (struct sockaddr *) ((caddr_t) (sa) + ((sa)->sa_len ? \
134 ROUNDUP((sa)->sa_len, sizeof(UINT32)) \
135 : sizeof(UINT32)));
136
GetAllRoutes(ProtoAddress::Type addrType,ProtoRouteTable & routeTable)137 bool BsdRouteMgr::GetAllRoutes(ProtoAddress::Type addrType,
138 ProtoRouteTable& routeTable)
139 {
140 int mib[6];
141 mib[0] = CTL_NET;
142 mib[1] = PF_ROUTE;
143 mib[2] = 0;
144
145 switch (addrType)
146 {
147 case ProtoAddress::IPv4:
148 mib[3] = PF_INET;
149 break;
150 #ifdef HAVE_IPV6
151 case ProtoAddress::IPv6:
152 mib[3] = PF_INET6;
153 break;
154 #endif // HAVE_IPV6
155 default:
156 PLOG(PL_ERROR, "BsdRouteMgr::GetAllRoutes() unsupported addr family\n");
157 return false;
158 }
159 mib[4] = NET_RT_DUMP;
160 mib[5] = 0;
161
162 char* buf;;
163 size_t len;
164 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
165 {
166 PLOG(PL_ERROR, "BsdRouteMgr::GetAllRoutes() sysctl() error: %s\n",
167 strerror(errno));
168 return false;
169 }
170
171 if (!(buf = new char[len]))
172 {
173 PLOG(PL_ERROR, "BsdRouteMgr::GetAllRoutes() malloc(%d) error: %s\n",
174 len, strerror(errno));
175 return false;
176 }
177
178 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0)
179 {
180 delete[] buf;
181 PLOG(PL_ERROR, "BsdRouteMgr::GetAllRoutes() sysctl() error: %s\n", strerror(errno));
182 return false;
183 }
184
185 char* end = buf + len;
186 char* next = buf;
187 while (next < end)
188 {
189 // (void*) casts here to avoid cast-align mis-warning
190 struct rt_msghdr* rtm = (struct rt_msghdr*)((void*)next);
191 struct sockaddr* addr = (struct sockaddr*)(rtm + 1);
192 ProtoAddress dst, gw;
193 dst.Invalidate();
194 gw.Invalidate();
195 int prefixLen = -1;
196 for (int i = 0; i < RTAX_MAX; i++)
197 {
198 if (0 != (rtm->rtm_addrs & (0x01 << i)))
199 {
200 switch (i)
201 {
202 case RTAX_DST:
203 {
204 dst.SetSockAddr(*addr);
205 //TRACE("RTAX_DST: %s\t\t", dst.GetHostString());
206 break;
207 }
208 case RTAX_GATEWAY:
209 {
210 gw.SetSockAddr(*addr);
211 //TRACE("RTAX_GWY: %s\n", gw.GetHostString());
212 break;
213 }
214 case RTAX_NETMASK:
215 {
216 const unsigned char* ptr = (const unsigned char*)(&addr->sa_data[2]);
217 if (NULL != ptr)
218 {
219 unsigned int maskSize = addr->sa_len ? (addr->sa_len - (int)(ptr - (unsigned char*)addr)) : 0;
220 prefixLen = 0;
221 for (unsigned int i = 0; i < maskSize; i++)
222 {
223 if (0xff == *ptr)
224 {
225 prefixLen += 8;
226 ptr++;
227 }
228 else
229 {
230 unsigned char bit = 0x80;
231 while (0 != (bit & *ptr))
232 {
233 bit >>= 1;
234 prefixLen += 1;
235 }
236 break;
237 }
238 }
239 }
240 //TRACE("BsdRouteMgr::GetAllRoutes() recvd RTA_NETMASK: %d\n", prefixLen);
241 break;
242 }
243 case RTAX_GENMASK:
244 {
245 PLOG(PL_ERROR, "BsdRouteMgr::GetAllRoutes() recvd RTA_GENMASK ...\n");
246 break;
247 }
248 default:
249 {
250 PLOG(PL_ERROR, "BsdRouteMgr::GetAllRoutes() recvd unhandled RTA: %d\n", i);
251 break;
252 }
253 } // end switch(i)
254 NEXT_SA(addr);
255 } // end if(mask[i] is set)
256 } // end for(i=0..RTAX_MAX)
257 if (dst.IsValid())
258 {
259 bool setRoute = true;
260 #ifdef MACOSX
261 // Don't fetch cloned routes (TBD - investigate further)
262 if (0 != (rtm->rtm_flags & RTF_WASCLONED))
263 setRoute = false;
264 #endif // MACOSX
265 if (0 == prefixLen)
266 {
267 // This makes sure default routes w/ valid gateway "trump" device default route
268 // (TBD - deal with multiple default route entries)
269 if ((NULL != routeTable.GetDefaultEntry()) && !gw.IsValid())
270 setRoute = false;
271 }
272 if (prefixLen < 0) prefixLen = dst.GetLength() << 3;
273 if (0 == (rtm->rtm_flags & RTF_GATEWAY)) gw.Invalidate();
274
275 if (setRoute)
276 {
277 if (!routeTable.SetRoute(dst, prefixLen, gw, rtm->rtm_index))
278 {
279 PLOG(PL_ERROR, "BsdRouteMgr::GetAllRoutes() error creating table entry\n");
280 delete[] buf;
281 return false;
282 }
283 }
284 }
285 next += rtm->rtm_msglen;
286 }
287 delete[] buf;
288 return true;
289
290 } // end BsdRouteMgr::GetAllRoutes()
291
SetRoute(const ProtoAddress & dst,unsigned int prefixLen,const ProtoAddress & gw,unsigned ifIndex,int)292 bool BsdRouteMgr::SetRoute(const ProtoAddress& dst,
293 unsigned int prefixLen,
294 const ProtoAddress& gw,
295 unsigned ifIndex,
296 int /*metric*/)
297 {
298 // Construct a RTM_ADD request
299 int buffer[256]; // we use "int" for alignment safety
300 memset(buffer, 0, 256*sizeof(int));
301 unsigned int sockaddrLen = 0;
302 switch (dst.GetType())
303 {
304 case ProtoAddress::IPv4:
305 sockaddrLen = sizeof(struct sockaddr_in);
306 break;
307 #ifdef HAVE_IPV6
308 case ProtoAddress::IPv6:
309 sockaddrLen = sizeof(struct sockaddr_in6);
310 break;
311 #endif // HAVE_IPV6
312 default:
313 PLOG(PL_ERROR, "BsdRouteMgr::SetRoute() invalid dst address type!\n");
314 return false;
315 }
316 struct rt_msghdr* rtm = (struct rt_msghdr*)buffer;
317 rtm->rtm_msglen = sizeof(struct rt_msghdr);
318 rtm->rtm_version = RTM_VERSION;
319 rtm->rtm_type = RTM_ADD;
320 rtm->rtm_addrs = RTA_DST;
321 rtm->rtm_flags = RTF_UP;
322
323 if (prefixLen < (unsigned int)(dst.GetLength() << 3))
324 {
325 // address bits past mask _must_ be ZERO, so we test for that here
326 unsigned int index = prefixLen >> 3;
327 const char* ptr = dst.GetRawHostAddress();
328 if (0 != ((0x00ff >> (prefixLen & 0x07)) & ptr[index]))
329 {
330 PLOG(PL_ERROR, "BsdRouteMgr::SetRoute() invalid address for given mask\n");
331 return false;
332 }
333 while (++index < dst.GetLength())
334 {
335 if (0 != ptr[index] )
336 {
337 PLOG(PL_ERROR, "BsdRouteMgr::SetRoute() invalid address for given mask\n");
338 return false;
339 }
340 }
341 rtm->rtm_addrs |= RTA_NETMASK;
342 #ifdef RTF_MASK
343 rtm->rtm_flags |= RTF_MASK;
344 #endif // RTF_MASK
345 }
346 else
347 {
348 rtm->rtm_flags |= RTF_HOST;
349 }
350
351 if (gw.IsValid())
352 {
353 rtm->rtm_addrs |= RTA_GATEWAY;
354 rtm->rtm_flags |= RTF_GATEWAY;
355 }
356 else if (ifIndex != 0)
357 {
358 rtm->rtm_addrs |= RTA_GATEWAY;
359 rtm->rtm_index = ifIndex;
360 }
361 else
362 {
363 PLOG(PL_ERROR, "BsdRouteMgr::SetRoute() invalid gateway address\n");
364 return false;
365 }
366
367 rtm->rtm_pid = pid;
368 int seq = sequence++;
369 rtm->rtm_seq = seq;
370
371
372 struct sockaddr* addr = (struct sockaddr*)(rtm + 1);
373 for (int i = 0; i < RTAX_MAX; i++)
374 {
375 if (0 != (rtm->rtm_addrs & (0x01 << i)))
376 {
377 switch (i)
378 {
379 case RTAX_DST:
380 //TRACE("Adding RTAX_DST...\n");
381 memcpy(addr, &dst.GetSockAddr(), sockaddrLen);
382 rtm->rtm_msglen += sockaddrLen;
383 break;
384 case RTAX_GATEWAY:
385 if (0 != (rtm->rtm_flags & RTF_GATEWAY))
386 {
387 //TRACE("Adding RTAX_GATEWAY...\n");
388 memcpy(addr, &gw.GetSockAddr(), sockaddrLen);
389 rtm->rtm_msglen += sockaddrLen;
390 }
391 else
392 {
393 //TRACE("Adding RTAX_GATEWAY (IF)...\n");
394 struct sockaddr_dl* sdl = (struct sockaddr_dl*)((void*)addr);
395 sdl->sdl_len = sizeof(struct sockaddr_dl);
396 sdl->sdl_family = AF_LINK;
397 sdl->sdl_index = ifIndex;
398 sdl->sdl_type = 0;
399 sdl->sdl_nlen = 0;
400 sdl->sdl_alen = 0;
401 sdl->sdl_slen = 0;
402 rtm->rtm_msglen += sizeof(struct sockaddr_dl);
403 }
404 break;
405 case RTAX_NETMASK:
406 {
407 if (prefixLen > 0)
408 {
409 unsigned char* ptr = (unsigned char*)(&addr->sa_data[2]);
410 unsigned int numBytes = prefixLen >> 3;
411 memset(ptr, 0xff, numBytes);
412 unsigned int remainder = prefixLen & 0x07;
413 if (remainder)
414 {
415 ptr[numBytes] = 0xff << (8 - remainder);
416 addr->sa_len = 5 + numBytes;
417 }
418 else
419 {
420 addr->sa_len = (ptr - (unsigned char*)addr) + numBytes;
421 }
422 rtm->rtm_msglen += ROUNDUP(addr->sa_len, sizeof(u_long));
423 }
424 else
425 {
426 rtm->rtm_msglen += sizeof(u_long);
427 addr->sa_len = 4;
428 }
429 break;
430 }
431 default:
432 break;
433 } // end switch(i)
434 NEXT_SA(addr);
435 } // end if (rtm_addrs[i])
436 } // end for(i=0..RTAX_MAX)
437
438
439 // Send RTM_ADD request to routing socket
440 int result = send(descriptor, rtm, rtm->rtm_msglen, 0);
441 if ((result < 0) && (EEXIST == errno))
442 {
443 // route already exists, so "change" it
444 rtm->rtm_type = RTM_CHANGE;
445 // Send RTM_CHANGE request to routing socket
446 result = send(descriptor, rtm, rtm->rtm_msglen, 0);
447 }
448 if ((int)rtm->rtm_msglen != result)
449 {
450 PLOG(PL_ERROR, "BsdRouteMgr::SetRoute() send() error: %s\n",
451 strerror(errno));
452 return false;
453 }
454
455 // Recv the result
456 while (1)
457 {
458 ProtoAddress destination, gateway;
459 destination.Invalidate();
460 gateway.Invalidate();
461 int msgLen = recv(descriptor, rtm, 256*sizeof(int), 0);
462 if (msgLen < 0)
463 {
464 if (errno != EINTR)
465 {
466 PLOG(PL_ERROR, "BsdRouteMgr::SetRoute() recv() error: %s\n", strerror(errno));
467 return false;
468 }
469 else
470 {
471 continue;
472 }
473 }
474 if ((seq == rtm->rtm_seq) &&
475 (pid == rtm->rtm_pid))
476 {
477 TRACE("matching response ...\n");
478 struct sockaddr* addr = (struct sockaddr*)(rtm + 1);
479 for (int i = 0; i < RTAX_MAX; i++)
480 {
481 if (0 != (rtm->rtm_addrs & (0x01 << i)))
482 {
483 switch (i)
484 {
485 case RTAX_DST:
486 {
487 destination.SetSockAddr(*addr);
488 //TRACE("RTAX_DST: %s\t\t", dst.GetHostString());
489 break;
490 }
491 case RTAX_GATEWAY:
492 {
493 gateway.SetSockAddr(*addr);
494 //TRACE("RTAX_GWY: %s\n", gw.GetHostString());
495 break;
496 }
497 case RTAX_NETMASK:
498 {
499 const unsigned char* ptr = (const unsigned char*)(&addr->sa_data[2]);
500 if (ptr)
501 {
502 unsigned int maskSize = addr->sa_len ? (addr->sa_len - (int)(ptr - (unsigned char*)addr)) : 0;
503 prefixLen = 0;
504 for (unsigned int i = 0; i < maskSize; i++)
505 {
506 if (0xff == *ptr)
507 {
508 prefixLen += 8;
509 ptr++;
510 }
511 else
512 {
513 unsigned char bit = 0x80;
514 while (0 != (bit & *ptr))
515 {
516 bit >>= 1;
517 prefixLen += 1;
518 }
519 }
520 }
521 }
522 //TRACE("RTAX_NMSK: %d\t\t", prefixLen);
523 break;
524 }
525 case RTAX_GENMASK:
526 {
527 TRACE("BsdRouteMgr::SetRoute() recvd RTA_GENMASK ...\n");
528 break;
529 }
530 default:
531 {
532 TRACE("BsdRouteMgr::SetRoute() recvd unhandled RTA: %d\n", i);
533 break;
534 }
535 } // end switch(i)
536 NEXT_SA(addr);
537 } // end if(mask(i) is set)
538 } // end for (i=0..RTAX_MAX)
539 if (0 != (rtm->rtm_flags & RTF_DONE))
540 {
541 if (destination.IsValid())
542 {
543 //TRACE("BsdRouteMgr::SetRoute() successfully added route\n");
544 return true;
545 }
546 else
547 {
548 PLOG(PL_ERROR, "BsdRouteMgr::SetRoute() completed with invalid dst\n");
549 return false;
550 }
551 }
552 }
553 else
554 {
555 TRACE("BsdRouteMgr::SetRoute() recvd non-matching response\n");
556 }
557 } // end while (1)
558 return false;
559 } // end BsdRouteMgr::SetRoute()
560
561 // Currently deletes _all_ routes regardless of gateway or index
DeleteRoute(const ProtoAddress & dst,unsigned int prefixLen,const ProtoAddress &,unsigned int ifIndex)562 bool BsdRouteMgr::DeleteRoute(const ProtoAddress& dst,
563 unsigned int prefixLen,
564 const ProtoAddress& /*gateway*/,
565 unsigned int ifIndex)
566 {
567 ProtoAddress gw;
568 int metric;
569 while (GetRoute(dst, prefixLen, gw, ifIndex, metric))
570 {
571 // Construct a RTM_DELETE request
572 int buffer[256]; // we use "int" for alignment safety
573 memset(buffer, 0, 256*sizeof(int));
574 unsigned int sockaddrLen = 0;
575 switch (dst.GetType())
576 {
577 case ProtoAddress::IPv4:
578 sockaddrLen = sizeof(struct sockaddr_in);
579 break;
580 #ifdef HAVE_IPV6
581 case ProtoAddress::IPv6:
582 sockaddrLen = sizeof(struct sockaddr_in6);
583 break;
584 #endif // HAVE_IPV6
585 default:
586 PLOG(PL_ERROR, "BsdRouteMgr::DeleteRoute() invalid dst address type!\n");
587 return false;
588 }
589 struct rt_msghdr* rtm = (struct rt_msghdr*)buffer;
590 rtm->rtm_msglen = sizeof(struct rt_msghdr);
591 rtm->rtm_version = RTM_VERSION;
592 rtm->rtm_type = RTM_DELETE;
593 rtm->rtm_addrs = RTA_DST;
594 rtm->rtm_flags = 0;
595
596 if (prefixLen < (unsigned int)(dst.GetLength() << 3))
597 {
598 // address bits past mask _must_ be ZERO, so we test for that here
599 unsigned int index = prefixLen >> 3;
600 const char* ptr = dst.GetRawHostAddress();
601 if (0 != ((0x00ff >> (prefixLen & 0x07)) & ptr[index]))
602 {
603 PLOG(PL_ERROR, "BsdRouteMgr::DeleteRoute() invalid address for given mask\n");
604 return false;
605 }
606 while (++index < dst.GetLength())
607 {
608 if (0 != ptr[index] )
609 {
610 PLOG(PL_ERROR, "BsdRouteMgr::DeleteRoute() invalid address for given mask\n");
611 return false;
612 }
613 }
614 rtm->rtm_addrs |= RTA_NETMASK;
615 }
616 else
617 {
618 rtm->rtm_flags |= RTF_HOST;
619 }
620
621 // (TBD) IPv6 host flags???
622 if (gw.IsValid())
623 {
624 rtm->rtm_addrs |= RTA_GATEWAY;
625 rtm->rtm_flags |= RTF_GATEWAY;
626 }
627 else if (ifIndex > 0)
628 {
629 rtm->rtm_addrs |= RTA_GATEWAY;
630 }
631
632 rtm->rtm_pid = pid;
633 int seq = sequence++;
634 rtm->rtm_seq = seq;
635
636 struct sockaddr* addr = (struct sockaddr*)(rtm + 1);
637 for (int i = 0; i < RTAX_MAX; i++)
638 {
639 if (0 != (rtm->rtm_addrs & (0x01 << i)))
640 {
641 switch (i)
642 {
643 case RTAX_DST:
644 memcpy(addr, &dst.GetSockAddr(), sockaddrLen);
645 rtm->rtm_msglen += sockaddrLen;
646 break;
647 case RTAX_GATEWAY:
648 if (0 != (rtm->rtm_flags & RTF_GATEWAY))
649 {
650 //TRACE("Adding RTAX_GATEWAY...\n");
651 memcpy(addr, &gw.GetSockAddr(), sockaddrLen);
652 rtm->rtm_msglen += sockaddrLen;
653 }
654 else
655 {
656 //TRACE("Adding RTAX_GATEWAY (IF)...\n");
657 struct sockaddr_dl* sdl = (struct sockaddr_dl*)((void*)addr);
658 sdl->sdl_len = sizeof(struct sockaddr_dl);
659 sdl->sdl_family = AF_LINK;
660 sdl->sdl_index = ifIndex;
661 sdl->sdl_type = 0;
662 sdl->sdl_nlen = 0;
663 sdl->sdl_alen = 0;
664 sdl->sdl_slen = 0;
665 rtm->rtm_msglen += sizeof(struct sockaddr_dl);
666 }
667 break;
668 case RTAX_NETMASK:
669 {
670 unsigned char* ptr = (unsigned char*)(&addr->sa_data[2]);
671 if (prefixLen > 0)
672 {
673 unsigned int numBytes = prefixLen >> 3;
674 memset(ptr, 0xff, numBytes);
675 unsigned int remainder = prefixLen & 0x07;
676 if (remainder)
677 {
678 ptr[numBytes] = 0xff << (8 - remainder);
679 addr->sa_len = 5 + numBytes;
680 }
681 else
682 {
683 addr->sa_len = (ptr - (unsigned char*)addr) + numBytes;
684 }
685 rtm->rtm_msglen += ROUNDUP(addr->sa_len, sizeof(u_long));
686 }
687 else
688 {
689 rtm->rtm_msglen += sizeof(u_long);
690 addr->sa_len = 4;
691
692 }
693 break;
694 }
695 default:
696 break;
697 } // end switch(i)
698 NEXT_SA(addr);
699 } // end if (rtm_addrs[i])
700 } // end for(i=0..RTAX_MAX)
701
702 // Send RTM_ADD request to netlink socket
703 int result = send(descriptor, rtm, rtm->rtm_msglen, 0);
704 if ((result < 0) && (EEXIST == errno))
705 {
706 // route already exists, so "change" it
707 rtm->rtm_type = RTM_CHANGE;
708 // Send RTM_CHANGE request to netlink socket
709 result = send(descriptor, rtm, rtm->rtm_msglen, 0);
710 }
711 if ((int)rtm->rtm_msglen != result)
712 {
713 // This will occur when there is no matching route to delete
714 PLOG(PL_WARN, "BsdRouteMgr::DeleteRoute() send() warning: %s\n",
715 strerror(errno));
716 return false;
717 }
718
719 // Recv the result
720 bool complete = false;
721 while (!complete)
722 {
723 ProtoAddress destination, gateway, genmask;
724 destination.Invalidate();
725 gateway.Invalidate();
726 genmask.Invalidate();
727 int msgLen = recv(descriptor, rtm, 256*sizeof(int), 0);
728 if (msgLen < 0)
729 {
730 if (errno != EINTR)
731 {
732 PLOG(PL_ERROR, "BsdRouteMgr::DeleteRoute() recv() error: %s\n", strerror(errno));
733 return false;
734 }
735 else
736 {
737 continue;
738 }
739 }
740 if ((seq == rtm->rtm_seq) &&
741 (pid == rtm->rtm_pid))
742 {
743 struct sockaddr* addr = (struct sockaddr*)(rtm + 1);
744 for (int i = 0; i < RTAX_MAX; i++)
745 {
746 if (0 != (rtm->rtm_addrs & (0x01 << i)))
747 {
748 switch (i)
749 {
750 case RTAX_DST:
751 {
752 destination.SetSockAddr(*addr);
753 //TRACE("RTAX_DST: %s\t\t", destination.GetHostString());
754 break;
755 }
756 case RTAX_GATEWAY:
757 {
758 gateway.SetSockAddr(*addr);
759 //TRACE("RTAX_GWY: %s\n", gateway.GetHostString());
760 break;
761 }
762 case RTAX_NETMASK:
763 {
764 const unsigned char* ptr = (const unsigned char*)(&addr->sa_data[2]);
765 if (ptr)
766 {
767 unsigned int maskSize = addr->sa_len ? (addr->sa_len - (int)(ptr - (unsigned char*)addr)) : 0;
768 prefixLen = 0;
769 for (unsigned int i = 0; i < maskSize; i++)
770 {
771 if (0xff == *ptr)
772 {
773 prefixLen += 8;
774 ptr++;
775 }
776 else
777 {
778 unsigned char bit = 0x80;
779 while (0 != (bit & *ptr))
780 {
781 bit >>= 1;
782 prefixLen += 1;
783 }
784 }
785 }
786 }
787 //TRACE("RTAX_NMSK: %d\t\t", prefixLen);
788 break;
789 }
790 case RTAX_GENMASK:
791 {
792 TRACE("BsdRouteMgr::DeleteRoute() recvd RTA_GENMASK ...\n");
793 break;
794 }
795 default:
796 {
797 TRACE("BsdRouteMgr::DeleteRoute() recvd unhandled RTAX: %d\n", i);
798 break;
799 }
800 } // end switch(i)
801 NEXT_SA(addr);
802 } // end if(mask(i) is set)
803 } // end for (i=0..RTAX_MAX)
804 if (0 != (rtm->rtm_flags & RTF_DONE))
805 {
806 if (destination.IsValid())
807 {
808 complete = true;
809 break;
810 }
811 else
812 {
813 PLOG(PL_ERROR, "BsdRouteMgr::DeleteRoute() completed with invalid dst\n");
814 return false;
815 }
816 }
817 }
818 else
819 {
820 TRACE("BsdRouteMgr::DeleteRoute() recvd non-matching response\n");
821 } // if/else (matchingResponse)
822 } // end while (!complete)
823 }
824 return true;
825 } // end BsdRouteMgr::DeleteRoute()
826
GetRoute(const ProtoAddress & dst,unsigned int prefixLen,ProtoAddress & gw,unsigned int & ifIndex,int & metric)827 bool BsdRouteMgr::GetRoute(const ProtoAddress& dst,
828 unsigned int prefixLen,
829 ProtoAddress& gw,
830 unsigned int& ifIndex,
831 int& metric)
832 {
833 // Init return values
834 gw.Invalidate();
835 ifIndex = 0;
836
837 // Construct a RTM_GET request
838 int buffer[256]; // we use "int" for alignment safety
839 memset(buffer, 0, 256*sizeof(int));
840 unsigned int sockaddrLen = 0;
841 switch (dst.GetType())
842 {
843 case ProtoAddress::IPv4:
844 sockaddrLen = sizeof(struct sockaddr_in);
845 break;
846 #ifdef HAVE_IPV6
847 case ProtoAddress::IPv6:
848 sockaddrLen = sizeof(struct sockaddr_in6);
849 break;
850 #endif // HAVE_IPV6
851 default:
852 PLOG(PL_ERROR, "BsdRouteMgr::GetRoute() invalid dst address type!\n");
853 return false;
854 }
855 struct rt_msghdr* rtm = (struct rt_msghdr*)buffer;
856 rtm->rtm_msglen = sizeof(struct rt_msghdr);
857 rtm->rtm_version = RTM_VERSION;
858 rtm->rtm_type = RTM_GET;
859 rtm->rtm_addrs = RTA_DST;
860 rtm->rtm_flags = 0;
861
862 if (prefixLen < (unsigned int)(dst.GetLength() << 3))
863 {
864 // address bits past mask _must_ be ZERO, so we test for that here
865 unsigned int index = prefixLen >> 3;
866 const char* ptr = dst.GetRawHostAddress();
867 if (0 != ((0x00ff >> (prefixLen & 0x07)) & ptr[index]))
868 {
869 PLOG(PL_ERROR, "BsdRouteMgr::GetRoute() invalid address for given mask\n");
870 return false;
871 }
872 while (++index < dst.GetLength())
873 {
874 if (0 != ptr[index] )
875 {
876 PLOG(PL_ERROR, "BsdRouteMgr::GetRoute() invalid address for given mask\n");
877 return false;
878 }
879 }
880 rtm->rtm_addrs |= RTA_NETMASK;
881 }
882 else
883 {
884 rtm->rtm_flags |= RTF_HOST;
885 }
886
887 rtm->rtm_pid = pid;
888 int seq = sequence++;
889 rtm->rtm_seq = seq;
890
891 struct sockaddr* addr = (struct sockaddr*)(rtm + 1);
892 for (int i = 0; i < RTAX_MAX; i++)
893 {
894 if (0 != (rtm->rtm_addrs & (0x01 << i)))
895 {
896 switch (i)
897 {
898 case RTAX_DST:
899 memcpy(addr, &dst.GetSockAddr(), sockaddrLen);
900 rtm->rtm_msglen += sockaddrLen;
901 break;
902 case RTAX_NETMASK:
903 {
904 unsigned char* ptr = (unsigned char*)(&addr->sa_data[2]);
905 if (prefixLen > 0)
906 {
907 unsigned int numBytes = prefixLen >> 3;
908 memset(ptr, 0xff, numBytes);
909 unsigned int remainder = prefixLen & 0x07;
910 if (remainder)
911 {
912 ptr[numBytes] = 0xff << (8 - remainder);
913 addr->sa_len = 5 + numBytes;
914 }
915 else
916 {
917 addr->sa_len = (ptr - (unsigned char*)addr) + numBytes;
918 }
919 rtm->rtm_msglen += ROUNDUP(addr->sa_len, sizeof(u_long));
920 }
921 else
922 {
923 rtm->rtm_msglen += sizeof(u_long);
924 addr->sa_len = 4;
925
926 }
927 break;
928 }
929 default:
930 break;
931 } // end switch(i)
932 NEXT_SA(addr);
933 } // end if (rtm_addrs[i])
934 } // end for(i=0..RTAX_MAX)
935
936 // Send request to netlink socket
937 int result = send(descriptor, rtm, rtm->rtm_msglen, 0);
938 if ((int)rtm->rtm_msglen != result)
939 {
940 PLOG(PL_ERROR, "BsdRouteMgr::GetRoute() send() error: %s\n", strerror(errno));
941 return false;
942 }
943
944 // Recv the result
945 while (1)
946 {
947 int msgLen = recv(descriptor, rtm, 256*sizeof(int), 0);
948 if (msgLen < 0)
949 {
950 if (errno != EINTR)
951 {
952 PLOG(PL_ERROR, "BsdRouteMgr::GetRoute() recv() error: %s\n", strerror(errno));
953 return false;
954 }
955 else
956 {
957 continue;
958 }
959 }
960 if ((RTM_GET == rtm->rtm_type) &&
961 (seq == rtm->rtm_seq) &&
962 (pid == rtm->rtm_pid))
963 {
964 struct sockaddr* addr = (struct sockaddr*)(rtm + 1);
965 ProtoAddress destination;
966 destination.Invalidate();
967 for (int i = 0; i < RTAX_MAX; i++)
968 {
969 if (0 != (rtm->rtm_addrs & (0x01 << i)))
970 {
971 switch (i)
972 {
973 case RTAX_DST:
974 {
975 destination.SetSockAddr(*addr);
976 //TRACE("RTAX_DST: %s\t\t", dst.GetHostString());
977 break;
978 }
979 case RTAX_GATEWAY:
980 {
981 switch (addr->sa_family)
982 {
983 #ifdef HAVE_IPV6
984 case AF_INET6:
985 #endif // HAVE_IPV6
986 case AF_INET:
987 gw.SetSockAddr(*addr);
988 //TRACE("RTAX_GWY: %s\n", gw.GetHostString());
989 break;
990 case AF_LINK:
991 ifIndex = ((struct sockaddr_dl*)((void*)addr))->sdl_index;
992 //TRACE("RTAX_GWY: ifIndex:%d\n", ifIndex);
993 break;
994 default:
995 PLOG(PL_ERROR, "BsdRouteMgr::GetRoute() recvd unknown sa_family\n");
996 break;
997 }
998 break;
999 }
1000 case RTAX_NETMASK:
1001 {
1002 const unsigned char* ptr = (const unsigned char*)(&addr->sa_data[2]);
1003 if (ptr)
1004 {
1005 unsigned int maskSize = addr->sa_len ? (addr->sa_len - (int)(ptr - (unsigned char*)addr)) : 0;
1006 unsigned int prefixLen = 0;
1007 for (unsigned int i = 0; i < maskSize; i++)
1008 {
1009 if (0xff == *ptr)
1010 {
1011 prefixLen += 8;
1012 ptr++;
1013 }
1014 else
1015 {
1016 unsigned char bit = 0x80;
1017 while (0 != (bit & *ptr))
1018 {
1019 bit >>= 1;
1020 prefixLen += 1;
1021 }
1022 }
1023 break;
1024 }
1025 //TRACE("BsdRouteMgr::GetRoute() recvd RTAX_NMSK: %d\n", prefixLen);
1026 }
1027 break;
1028 }
1029 case RTAX_GENMASK:
1030 {
1031 TRACE("BsdRouteMgr::GetRoute() recvd RTA_GENMASK ...\n");
1032 break;
1033 }
1034 default:
1035 {
1036 TRACE("BsdRouteMgr::GetRoute() recvd unhandled RTA: %d\n", i);
1037 break;
1038 }
1039 } // end switch(i)
1040 NEXT_SA(addr);
1041 } // end if (mask[i] is set)
1042 } // end for(i=0..RTAX_MAX)
1043 if (0 != (rtm->rtm_flags & RTF_DONE))
1044 {
1045 if (destination.IsValid())
1046 {
1047 //if (!gw.IsValid()) gw.Reset(destination.GetType());
1048 //if (prefixLen < 0) prefixLen = dst.GetLength() << 3;
1049 // (TBD) get actual metric
1050 metric = -1;
1051 return true;
1052 }
1053 else
1054 {
1055 return false;
1056 }
1057 }
1058 }
1059 else
1060 {
1061 TRACE("BsdRouteMgr::GetRoute() recvd non-matching response\n");
1062 }
1063 } // end while (1)
1064 return false;
1065 } // end BsdRouteMgr::GetRoute()
1066
GetInterfaceAddressList(unsigned int ifIndex,ProtoAddress::Type addrType,ProtoAddressList & addrList)1067 bool BsdRouteMgr::GetInterfaceAddressList(unsigned int ifIndex,
1068 ProtoAddress::Type addrType,
1069 ProtoAddressList& addrList)
1070 {
1071 ProtoAddressList localAddrList; // keep link & site local addrs separate and add at end
1072 // Init return values
1073 int mib[6];
1074 mib[0] = CTL_NET;
1075 mib[1] = AF_ROUTE;
1076 mib[2] = 0;
1077
1078 switch (addrType)
1079 {
1080 case ProtoAddress::IPv4:
1081 mib[3] = AF_INET;
1082 break;
1083 #ifdef HAVE_IPV6
1084 case ProtoAddress::IPv6:
1085 mib[3] = AF_INET6;
1086 break;
1087 #endif // HAVE_IPV6
1088 default:
1089 PLOG(PL_ERROR, "BsdRouteMgr::GetInterfaceAddressList() unsupported addr family\n");
1090 break;
1091 }
1092 mib[4] = NET_RT_IFLIST;
1093 mib[5] = ifIndex;
1094
1095 char* buf;;
1096 size_t len;
1097 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
1098 {
1099 PLOG(PL_ERROR, "BsdRouteMgr::GetInterfaceAddressList() sysctl() error: %s\n",
1100 strerror(errno));
1101 return false;
1102 }
1103
1104 if (!(buf = new char[len]))
1105 {
1106 PLOG(PL_ERROR, "BsdRouteMgr::GetInterfaceAddressList() malloc(%d) error: %s\n",
1107 len, strerror(errno));
1108 return false;
1109 }
1110
1111 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0)
1112 {
1113 delete[] buf;
1114 PLOG(PL_ERROR, "BsdRouteMgr::GetInterfaceAddressList() sysctl() error: %s\n", strerror(errno));
1115 return false;
1116 }
1117
1118 char* end = buf + len;
1119 char* next = buf;
1120 while (next < end)
1121 {
1122 struct if_msghdr* ifm = (struct if_msghdr*)((void*)next);
1123 switch (ifm->ifm_type)
1124 {
1125 case RTM_IFINFO:
1126 {
1127 // TRACE("received RTM_IFINFO message ...\n");
1128 // (this can give us the the link layer addr)
1129 break;
1130 }
1131 case RTM_NEWADDR:
1132 {
1133 //TRACE("received RTM_NEWADDR message ...\n");
1134 struct ifa_msghdr* ifam = (struct ifa_msghdr*)ifm;
1135 struct sockaddr* addr = (struct sockaddr*)(ifam + 1);
1136 for (int i = 0; i < RTAX_MAX; i++)
1137 {
1138 if (0 != (ifam->ifam_addrs & (0x01 << i)))
1139 {
1140 switch (i)
1141 {
1142 case RTAX_IFA:
1143 //TRACE("received RTAX_IFA ...index:%d\n", ifam->ifam_index);
1144 if (ifIndex == ifam->ifam_index)
1145 {
1146 ProtoAddress addrTemp;
1147 addrTemp.SetSockAddr(*addr);
1148 if (addrTemp.IsValid())
1149 {
1150 if (addrTemp.IsLinkLocal() || addrTemp.IsSiteLocal())
1151 {
1152 if (!localAddrList.Insert(addrTemp))
1153 PLOG(PL_ERROR, "BsdRouteMgr::GetInterfaceAddressList() error: unable to add addr to local list\n");
1154 }
1155 else
1156 {
1157 if (!addrList.Insert(addrTemp))
1158 PLOG(PL_ERROR, "BsdRouteMgr::GetInterfaceAddressList() error: unable to add addr to list\n");
1159 }
1160 }
1161 }
1162 break;
1163 case RTAX_BRD:
1164 //TRACE("received RTAX_BRD ...\n");
1165 break;
1166 case RTAX_NETMASK:
1167 //TRACE("received RTAX_NETMASK ...\n");
1168 break;
1169 default:
1170 //TRACE("unhandled RTAX type:%d\n", i);
1171 break;
1172 }
1173 NEXT_SA(addr);
1174 }
1175 } // end for(i=0..RTAX_MAX)
1176 break;
1177 }
1178 default:
1179 PLOG(PL_ERROR, "BsdRouteMgr::GetInterfaceAddressList() warning: unhandled IFM message type:%d\n", ifm->ifm_type);
1180 break;
1181
1182 }
1183 next += ifm->ifm_msglen;
1184 }
1185 delete[] buf;
1186
1187 ProtoAddressList::Iterator iterator(localAddrList);
1188 ProtoAddress localAddr;
1189 while (iterator.GetNextAddress(localAddr))
1190 {
1191 if (!addrList.Insert(localAddr))
1192 PLOG(PL_ERROR, "BsdRouteMgr::GetInterfaceAddressList() error: unable to add local addr to list\n");
1193 }
1194 if (addrList.IsEmpty())
1195 PLOG(PL_WARN, "BsdRouteMgr::GetInterfaceAddressList() warning: no addresses found\n");
1196 return true;
1197 } // end BsdRouteMgr::GetInterfaceAddressList()
1198
1199