1 /*
2 * scamper_rtsock: code to deal with a route socket or equivalent
3 *
4 * $Id: scamper_rtsock.c,v 1.87 2020/06/10 09:09:27 mjl Exp $
5 *
6 * Matthew Luckie
7 *
8 * Supported by:
9 * The University of Waikato
10 * NLANR Measurement and Network Analysis
11 * CAIDA
12 * The WIDE Project
13 *
14 * The purpose of this code is to obtain the outgoing interface's index
15 * using whatever mechanisms the operating system supports. A route
16 * socket is created where necessary and is kept open for the lifetime
17 * of scamper.
18 *
19 * scamper_rtsock_getifindex returns the interface index on success.
20 * if an error occurs, it returns -1. as route sockets are unreliable
21 * sockets, if we do not get an expected response, we return -2 to
22 * indicate to the caller to try again.
23 *
24 * Copyright (C) 2003-2006 Matthew Luckie
25 * Copyright (C) 2006-2010 The University of Waikato
26 * Copyright (C) 2014 The Regents of the University of California
27 *
28 * This program is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation, version 2.
31 *
32 * This program is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
36 *
37 * You should have received a copy of the GNU General Public License
38 * along with this program; if not, write to the Free Software
39 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
40 *
41 */
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46 #include "internal.h"
47
48 #if defined(__APPLE__)
49 static int broken = -1;
50 #endif
51
52 /* include support for the netlink socket in linux */
53 #if defined(__linux__)
54
55 struct rtattr
56 {
57 unsigned short rta_len;
58 unsigned short rta_type;
59 };
60
61 struct rtmsg
62 {
63 unsigned char rtm_family;
64 unsigned char rtm_dst_len;
65 unsigned char rtm_src_len;
66 unsigned char rtm_tos;
67 unsigned char rtm_table;
68 unsigned char rtm_protocol;
69 unsigned char rtm_scope;
70 unsigned char rtm_type;
71 unsigned rtm_flags;
72 };
73
74 #define RTA_ALIGNTO 4
75 #define RTA_ALIGN(len) (((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1))
76 #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
77 #define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0)))
78 #define RTA_OK(rta,len) ((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
79 (rta)->rta_len <= (len))
80 #define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
81 (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
82 #define RTA_UNSPEC 0
83 #define RTA_DST 1
84 #define RTA_SRC 2
85 #define RTA_IIF 3
86 #define RTA_OIF 4
87 #define RTA_GATEWAY 5
88 #define RTA_PRIORITY 6
89 #define RTA_PREFSRC 7
90 #define RTA_METRICS 8
91 #define RTA_MULTIPATH 9
92 #define RTA_PROTOINFO 10
93 #define RTA_FLOW 11
94 #define RTA_CACHEINFO 12
95 #define RTA_SESSION 13
96
97 #define RTM_RTA(r) ((struct rtattr*)(((char*)(r)) + \
98 NLMSG_ALIGN(sizeof(struct rtmsg))))
99 #define RTM_BASE 0x10
100 #define RTM_NEWROUTE (RTM_BASE+8)
101 #define RTM_GETROUTE (RTM_BASE+10)
102 #define NETLINK_ROUTE 0
103
104 #endif
105
106 #include "scamper.h"
107 #include "scamper_addr.h"
108 #include "scamper_list.h"
109 #include "scamper_fds.h"
110 #include "scamper_rtsock.h"
111 #include "scamper_privsep.h"
112 #include "scamper_osinfo.h"
113 #include "scamper_debug.h"
114 #include "utils.h"
115 #include "mjl_list.h"
116
117 extern scamper_addrcache_t *addrcache;
118
119 #ifndef _WIN32
120 typedef struct rtsock_pair
121 {
122 scamper_route_t *route; /* query */
123 uint16_t seq; /* sequence number used */
124 dlist_node_t *node; /* pointer to node in pair dlist */
125 } rtsock_pair_t;
126
127 static pid_t pid; /* [unpriviledged] process id */
128 static uint16_t seq = 0; /* next sequence number to use */
129 static dlist_t *pairs = NULL; /* list of addresses queried with their seq */
130
rtsock_pair_alloc(scamper_route_t * route,int seq)131 static rtsock_pair_t *rtsock_pair_alloc(scamper_route_t *route, int seq)
132 {
133 rtsock_pair_t *pair;
134 if((pair = malloc_zero(sizeof(rtsock_pair_t))) == NULL)
135 return NULL;
136 pair->route = route;
137 pair->seq = seq;
138 if((pair->node = dlist_head_push(pairs, pair)) == NULL)
139 {
140 free(pair);
141 return NULL;
142 }
143 route->internal = pair;
144 return pair;
145 }
146
rtsock_pair_free(rtsock_pair_t * pair)147 static void rtsock_pair_free(rtsock_pair_t *pair)
148 {
149 if(pair == NULL)
150 return;
151 pair->route->internal = NULL;
152 if(pair->node != NULL)
153 dlist_node_pop(pairs, pair->node);
154 free(pair);
155 return;
156 }
157
rtsock_pair_get(uint16_t seq)158 static rtsock_pair_t *rtsock_pair_get(uint16_t seq)
159 {
160 rtsock_pair_t *pair;
161 dlist_node_t *node;
162
163 for(node=dlist_head_node(pairs); node != NULL; node=dlist_node_next(node))
164 {
165 pair = dlist_node_item(node);
166 if(pair->seq != seq)
167 continue;
168 dlist_node_pop(pairs, node);
169 pair->node = NULL;
170 return pair;
171 }
172
173 return NULL;
174 }
175
176 #if defined(HAVE_BSD_ROUTE_SOCKET)
177 #if 0
178 static void rtmsg_dump(const uint8_t *buf, size_t len)
179 {
180 char str[80];
181 size_t i, off = 0;
182 int k = 0;
183
184 for(i=0; i<len; i++)
185 {
186 if(k == 20)
187 {
188 printerror_msg(__func__, "%s", str);
189 k = 0;
190 off = 0;
191 }
192
193 if(k != 0 && (k % 4) == 0)
194 string_concat(str, sizeof(str), &off, " ");
195 string_concat(str, sizeof(str), &off, "%02x", buf[i]);
196 k++;
197 }
198
199 if(k != 0)
200 printerror_msg(__func__, "%s", str);
201 return;
202 }
203 #endif
204
scamper_rtsock_roundup(size_t len)205 size_t scamper_rtsock_roundup(size_t len)
206 {
207 #ifdef __APPLE__
208 const scamper_osinfo_t *osinfo;
209
210 if(broken == -1)
211 {
212 osinfo = scamper_osinfo_get();
213 if(osinfo->os_id == SCAMPER_OSINFO_OS_DARWIN &&
214 osinfo->os_rel_dots > 0 && osinfo->os_rel[0] >= 10)
215 broken = 1;
216 else
217 broken = 0;
218 }
219
220 if(broken != 0)
221 {
222 if(len > 0)
223 return (1 + ((len - 1) | (sizeof(uint32_t) - 1)));
224 else
225 return sizeof(uint32_t);
226 }
227 #endif
228
229 return ((len > 0) ? (1 + ((len - 1) | (sizeof(long) - 1))) : sizeof(long));
230 }
231
232 /*
233 * scamper_rtsock_getifindex
234 *
235 * figure out the outgoing interface id / route using route sockets
236 *
237 * route(4) gives an overview of the functions called in here
238 */
scamper_rtsock_getifindex(int fd,scamper_addr_t * dst)239 static int scamper_rtsock_getifindex(int fd, scamper_addr_t *dst)
240 {
241 struct sockaddr_storage sas;
242 struct sockaddr_dl *sdl;
243 struct rt_msghdr *rtm;
244 uint8_t buf[1024];
245 size_t len;
246 ssize_t ss;
247 int slen;
248
249 if(SCAMPER_ADDR_TYPE_IS_IPV4(dst))
250 sockaddr_compose((struct sockaddr *)&sas, AF_INET, dst->addr, 0);
251 else if(SCAMPER_ADDR_TYPE_IS_IPV6(dst))
252 sockaddr_compose((struct sockaddr *)&sas, AF_INET6, dst->addr, 0);
253 else
254 return -1;
255
256 if((slen = sockaddr_len((struct sockaddr *)&sas)) <= 0)
257 return -1;
258
259 len = sizeof(struct rt_msghdr) + scamper_rtsock_roundup(slen) +
260 scamper_rtsock_roundup(sizeof(struct sockaddr_dl));
261 if(len > sizeof(buf))
262 return -1;
263
264 memset(buf, 0, len);
265 rtm = (struct rt_msghdr *)buf;
266 rtm->rtm_msglen = len;
267 rtm->rtm_version = RTM_VERSION;
268 rtm->rtm_type = RTM_GET;
269 rtm->rtm_addrs = RTA_DST | RTA_IFP;
270 rtm->rtm_pid = pid;
271 rtm->rtm_seq = seq;
272 memcpy(buf + sizeof(struct rt_msghdr), &sas, (size_t)slen);
273
274 sdl = (struct sockaddr_dl *)(buf + sizeof(struct rt_msghdr) +
275 scamper_rtsock_roundup(slen));
276 sdl->sdl_family = AF_LINK;
277
278 #if !defined(__sun__)
279 sdl->sdl_len = sizeof(struct sockaddr_dl);
280 #endif
281
282 if((ss = write(fd, buf, len)) < 0 || (size_t)ss != len)
283 {
284 printerror(__func__, "could not write routing socket");
285 return -1;
286 }
287
288 return 0;
289 }
290 #endif /* HAVE_BSD_ROUTE_SOCKET */
291
292 #if defined(__linux__)
293 /*
294 * scamper_rtsock_getifindex
295 *
296 * figure out the outgoing interface id / route using linux netlink
297 *
298 * this works on Linux systems with netlink compiled into the kernel.
299 * i think netlink comes compiled into the kernel with most distributions
300 * these days.
301 *
302 * the man pages netlink(3), netlink(7), rtnetlink(3), and rtnetlink(7)
303 * give an overview of the functions and structures used in here, but the
304 * documentation in those man pages is pretty crap.
305 * you'd be better off studying netlink.h and rtnetlink.h
306 */
scamper_rtsock_getifindex(int fd,scamper_addr_t * dst)307 static int scamper_rtsock_getifindex(int fd, scamper_addr_t *dst)
308 {
309 struct nlmsghdr *nlmsg;
310 struct rtmsg *rtmsg;
311 struct rtattr *rta;
312 int error;
313 int dst_len;
314 uint8_t buf[1024];
315 int af;
316
317 if(SCAMPER_ADDR_TYPE_IS_IPV4(dst))
318 {
319 dst_len = 4;
320 af = AF_INET;
321 }
322 else if(SCAMPER_ADDR_TYPE_IS_IPV6(dst))
323 {
324 dst_len = 16;
325 af = AF_INET6;
326 }
327 else
328 {
329 return -1;
330 }
331
332 /*
333 * fill out a route request.
334 * we use the standard netlink header, with a route msg subheader
335 * to query for the outgoing interface.
336 * the message includes one attribute - the destination address
337 * we are querying the route for.
338 */
339 memset(buf, 0, sizeof(buf));
340 nlmsg = (struct nlmsghdr *)buf;
341 nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
342 nlmsg->nlmsg_type = RTM_GETROUTE;
343 nlmsg->nlmsg_flags = NLM_F_REQUEST;
344 nlmsg->nlmsg_seq = seq;
345 nlmsg->nlmsg_pid = pid;
346
347 /* netlink wants the bit length of each address */
348 rtmsg = NLMSG_DATA(nlmsg);
349 rtmsg->rtm_family = af;
350 rtmsg->rtm_flags = 0;
351 rtmsg->rtm_dst_len = dst_len * 8;
352
353 rta = (struct rtattr *)(buf + NLMSG_ALIGN(nlmsg->nlmsg_len));
354 rta->rta_type = RTA_DST;
355 rta->rta_len = RTA_LENGTH(dst_len);
356 nlmsg->nlmsg_len += RTA_LENGTH(dst_len);
357 memcpy(RTA_DATA(rta), dst->addr, dst_len);
358
359 /* send the request */
360 if((error = send(fd, buf, nlmsg->nlmsg_len, 0)) != nlmsg->nlmsg_len)
361 {
362 printerror(__func__, "could not send");
363 return -1;
364 }
365
366 return 0;
367 }
368 #endif
369
scamper_rtsock_getroute(scamper_fd_t * fdn,scamper_route_t * route)370 int scamper_rtsock_getroute(scamper_fd_t *fdn, scamper_route_t *route)
371 {
372 int fd;
373
374 /* get the route socket fd */
375 if((fd = scamper_fd_fd_get(fdn)) == -1)
376 return -1;
377
378 /* ask the question */
379 if(scamper_rtsock_getifindex(fd, route->dst) != 0)
380 return -1;
381
382 /* keep track of the question */
383 if(rtsock_pair_alloc(route, seq++) == NULL)
384 return -1;
385 return 0;
386 }
387
388 #if defined(__linux__)
389 #if 0
390 static void rtattr_dump(struct rtattr *rta)
391 {
392 char *rta_type;
393 char rta_data[64];
394 int i;
395
396 switch(rta->rta_type)
397 {
398 case RTA_UNSPEC: rta_type = "unspec"; break;
399 case RTA_DST: rta_type = "dst"; break;
400 case RTA_SRC: rta_type = "src"; break;
401 case RTA_IIF: rta_type = "iif"; break;
402 case RTA_OIF: rta_type = "oif"; break;
403 case RTA_GATEWAY: rta_type = "gateway"; break;
404 case RTA_PRIORITY: rta_type = "priority"; break;
405 case RTA_PREFSRC: rta_type = "prefsrc"; break;
406 case RTA_METRICS: rta_type = "metrics"; break;
407 case RTA_MULTIPATH: rta_type = "multipath"; break;
408 case RTA_PROTOINFO: rta_type = "protoinfo"; break;
409 case RTA_FLOW: rta_type = "flow"; break;
410 case RTA_CACHEINFO: rta_type = "cacheinfo"; break;
411 case RTA_SESSION: rta_type = "session"; break;
412 default: rta_type = "<unknown>"; break;
413 }
414
415 for(i=0;i<rta->rta_len-sizeof(struct rtattr)&&i<(sizeof(rta_data)/2)-1;i++)
416 {
417 snprintf(&rta_data[i*2], 3, "%02x",
418 *(uint8_t *)(((char *)rta) + sizeof(struct rtattr) + i));
419 }
420
421 if(i != 0)
422 {
423 scamper_debug(__func__, "type %s len %d data %s",
424 rta_type, rta->rta_len-sizeof(struct rtattr), rta_data);
425 }
426 else
427 {
428 scamper_debug(__func__, "type %s\n", rta_type);
429 }
430
431 return;
432 }
433 #endif
434
rtsock_parsemsg(uint8_t * buf,size_t len)435 static void rtsock_parsemsg(uint8_t *buf, size_t len)
436 {
437 struct nlmsghdr *nlmsg;
438 struct nlmsgerr *nlerr;
439 struct rtmsg *rtmsg;
440 struct rtattr *rta;
441 void *gwa = NULL;
442 int ifindex = -1;
443 scamper_addr_t *gw = NULL;
444 rtsock_pair_t *pair = NULL;
445 scamper_route_t *route = NULL;
446
447 if(len < sizeof(struct nlmsghdr))
448 {
449 scamper_debug(__func__, "len %d != %d", len, sizeof(struct nlmsghdr));
450 return;
451 }
452
453 nlmsg = (struct nlmsghdr *)buf;
454
455 /* if the message isn't addressed to this pid, drop it */
456 if(nlmsg->nlmsg_pid != pid)
457 return;
458
459 if((pair = rtsock_pair_get(nlmsg->nlmsg_seq)) == NULL)
460 return;
461 route = pair->route;
462 rtsock_pair_free(pair);
463
464 if(nlmsg->nlmsg_type == RTM_NEWROUTE)
465 {
466 rtmsg = NLMSG_DATA(nlmsg);
467
468 /* this is the payload length of the response packet */
469 len = nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
470
471 /* hunt through the payload for the RTA_OIF entry */
472 rta = RTM_RTA(rtmsg);
473 while(RTA_OK(rta, len))
474 {
475 switch(rta->rta_type)
476 {
477 case RTA_OIF:
478 ifindex = *(unsigned *)RTA_DATA(rta);
479 break;
480
481 case RTA_GATEWAY:
482 gwa = RTA_DATA(rta);
483 break;
484 }
485 rta = RTA_NEXT(rta, len);
486 }
487
488 if(gwa != NULL)
489 {
490 if(rtmsg->rtm_family == AF_INET)
491 gw = scamper_addrcache_get_ipv4(addrcache, gwa);
492 else if(rtmsg->rtm_family == AF_INET6)
493 gw = scamper_addrcache_get_ipv6(addrcache, gwa);
494 else
495 route->error = EINVAL;
496 }
497 }
498 else if(nlmsg->nlmsg_type == NLMSG_ERROR)
499 {
500 nlerr = NLMSG_DATA(nlmsg);
501 route->error = nlerr->error;
502 }
503 else goto skip;
504
505 route->gw = gw;
506 route->ifindex = ifindex;
507 route->cb(route);
508
509 return;
510
511 skip:
512 if(route != NULL) scamper_route_free(route);
513 return;
514 }
515 #endif
516
517 #if defined(HAVE_BSD_ROUTE_SOCKET)
rtsock_parsemsg(uint8_t * buf,size_t len)518 static void rtsock_parsemsg(uint8_t *buf, size_t len)
519 {
520 struct rt_msghdr *rtm;
521 struct sockaddr *addrs[RTAX_MAX];
522 struct sockaddr_dl *sdl;
523 struct sockaddr *sa;
524 struct in6_addr *ip6;
525 size_t off, x;
526 int i, tmp, ifindex;
527 void *addr;
528 scamper_addr_t *gw;
529 rtsock_pair_t *pair;
530 scamper_route_t *route;
531
532 x = 0;
533 while(x < len)
534 {
535 if(len - x < sizeof(struct rt_msghdr))
536 {
537 scamper_debug(__func__,"len %d != %d",len,sizeof(struct rt_msghdr));
538 return;
539 }
540
541 /*
542 * check if the message is something we want, and that we have
543 * a pair for it
544 */
545 rtm = (struct rt_msghdr *)(buf + x);
546 if(rtm->rtm_pid != pid ||
547 rtm->rtm_msglen > len - x ||
548 rtm->rtm_type != RTM_GET ||
549 (rtm->rtm_flags & RTF_DONE) == 0 ||
550 (pair = rtsock_pair_get(rtm->rtm_seq)) == NULL)
551 {
552 x += rtm->rtm_msglen;
553 continue;
554 }
555
556 route = pair->route;
557 rtsock_pair_free(pair);
558
559 ifindex = -1;
560 addr = NULL;
561 gw = NULL;
562
563 if(rtm->rtm_errno != 0)
564 {
565 route->error = rtm->rtm_errno;
566 goto done;
567 }
568
569 off = sizeof(struct rt_msghdr);
570 memset(addrs, 0, sizeof(addrs));
571 for(i=0; i<RTAX_MAX; i++)
572 {
573 if(rtm->rtm_addrs & (1 << i))
574 {
575 addrs[i] = sa = (struct sockaddr *)(buf + x + off);
576 if((tmp = sockaddr_len(sa)) <= 0)
577 {
578 printerror_msg(__func__, "unhandled af %d", sa->sa_family);
579 route->error = EINVAL;
580 goto done;
581 }
582 off += scamper_rtsock_roundup(tmp);
583 }
584 }
585
586 if((sdl = (struct sockaddr_dl *)addrs[RTAX_IFP]) != NULL)
587 {
588 if(sdl->sdl_family != AF_LINK)
589 {
590 printerror_msg(__func__, "sdl_family %d", sdl->sdl_family);
591 route->error = EINVAL;
592 goto done;
593 }
594 ifindex = sdl->sdl_index;
595 }
596
597 if((sa = addrs[RTAX_GATEWAY]) != NULL)
598 {
599 if(sa->sa_family == AF_INET)
600 {
601 i = SCAMPER_ADDR_TYPE_IPV4;
602 addr = &((struct sockaddr_in *)sa)->sin_addr;
603 }
604 else if(sa->sa_family == AF_INET6)
605 {
606 /*
607 * check to see if the gw address is a link local address. if
608 * it is, then drop the embedded index from the gateway address
609 */
610 ip6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
611 if(IN6_IS_ADDR_LINKLOCAL(ip6))
612 {
613 ip6->s6_addr[2] = 0;
614 ip6->s6_addr[3] = 0;
615 }
616 i = SCAMPER_ADDR_TYPE_IPV6;
617 addr = ip6;
618 }
619 else if(sa->sa_family == AF_LINK)
620 {
621 sdl = (struct sockaddr_dl *)sa;
622 if(sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == ETHER_ADDR_LEN)
623 {
624 i = SCAMPER_ADDR_TYPE_ETHERNET;
625 addr = sdl->sdl_data + sdl->sdl_nlen;
626 }
627 }
628
629 /*
630 * if we have got a gateway address that we know what to do with,
631 * then store it here.
632 */
633 if(addr != NULL &&
634 (gw = scamper_addrcache_get(addrcache, i, addr)) == NULL)
635 {
636 scamper_debug(__func__, "could not get rtsmsg->rr.gw");
637 route->error = EINVAL;
638 goto done;
639 }
640 }
641
642 done:
643 route->gw = gw;
644 route->ifindex = ifindex;
645 route->cb(route);
646 x += rtm->rtm_msglen;
647 }
648
649 return;
650 }
651 #endif
652
653 /*
654 * scamper_rtsock_read_cb
655 *
656 * this callback handles reading a message from the route socket.
657 * we check to see if the message is something that we have sent by parsing
658 * the message out. if we did send the message, then we search for the
659 * address-sequence pair, which matches the sequence number with a route
660 * lookup.
661 * if we get a pair back, then we remove it from the list and look for a
662 * trace matching the address. we then take the result from the route
663 * lookup and apply it to the trace.
664 */
scamper_rtsock_read_cb(const int fd,void * param)665 void scamper_rtsock_read_cb(const int fd, void *param)
666 {
667 uint8_t buf[2048];
668 ssize_t len;
669
670 if((len = recv(fd, buf, sizeof(buf), 0)) < 0)
671 {
672 printerror(__func__, "recv failed");
673 return;
674 }
675
676 if(len > 0)
677 rtsock_parsemsg(buf, len);
678
679 return;
680 }
681
scamper_rtsock_close(int fd)682 void scamper_rtsock_close(int fd)
683 {
684 close(fd);
685 return;
686 }
687
scamper_rtsock_open_fd()688 int scamper_rtsock_open_fd()
689 {
690 #if defined(HAVE_BSD_ROUTE_SOCKET)
691 return socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
692 #elif defined(__linux__)
693 return socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
694 #else
695 #error "route socket support for this system not implemented"
696 #endif
697 }
698
scamper_rtsock_open()699 int scamper_rtsock_open()
700 {
701 int fd;
702
703 #if defined(WITHOUT_PRIVSEP)
704 if((fd = scamper_rtsock_open_fd()) == -1)
705 #else
706 if((fd = scamper_privsep_open_rtsock()) == -1)
707 #endif
708 {
709 printerror(__func__, "could not open route socket");
710 return -1;
711 }
712
713 return fd;
714 }
715 #endif
716
717 #ifdef _WIN32
scamper_rtsock_getroute4(scamper_route_t * route)718 static int scamper_rtsock_getroute4(scamper_route_t *route)
719 {
720 struct in_addr *in = route->dst->addr;
721 MIB_IPFORWARDROW fw;
722 DWORD dw;
723
724 if((dw = GetBestRoute(in->s_addr, 0, &fw)) != NO_ERROR)
725 {
726 route->error = dw;
727 return -1;
728 }
729
730 route->ifindex = fw.dwForwardIfIndex;
731
732 /* determine the gateway address to use, if one is specified */
733 if((dw = fw.dwForwardNextHop) != 0)
734 {
735 if((route->gw = scamper_addrcache_get_ipv4(addrcache, &dw)) == NULL)
736 {
737 route->error = errno;
738 return -1;
739 }
740 }
741
742 return 0;
743 }
744
scamper_rtsock_getroute(scamper_route_t * route)745 int scamper_rtsock_getroute(scamper_route_t *route)
746 {
747 if(SCAMPER_ADDR_TYPE_IS_IPV4(route->dst) &&
748 scamper_rtsock_getroute4(route) == 0)
749 {
750 route->cb(route);
751 return 0;
752 }
753
754 return -1;
755 }
756 #endif
757
scamper_route_free(scamper_route_t * route)758 void scamper_route_free(scamper_route_t *route)
759 {
760 if(route == NULL)
761 return;
762 #ifndef _WIN32
763 if(route->internal != NULL)
764 rtsock_pair_free(route->internal);
765 #endif
766 if(route->dst != NULL)
767 scamper_addr_free(route->dst);
768 if(route->gw != NULL)
769 scamper_addr_free(route->gw);
770 free(route);
771 return;
772 }
773
scamper_route_alloc(scamper_addr_t * dst,void * param,void (* cb)(scamper_route_t * rt))774 scamper_route_t *scamper_route_alloc(scamper_addr_t *dst, void *param,
775 void (*cb)(scamper_route_t *rt))
776 {
777 scamper_route_t *route;
778 if((route = malloc_zero(sizeof(scamper_route_t))) == NULL)
779 return NULL;
780 route->dst = scamper_addr_use(dst);
781 route->param = param;
782 route->cb = cb;
783 return route;
784 }
785
scamper_rtsock_init()786 int scamper_rtsock_init()
787 {
788 #ifndef _WIN32
789 if((pairs = dlist_alloc()) == NULL)
790 {
791 printerror(__func__, "could not allocate pair list");
792 return -1;
793 }
794 pid = getpid();
795 #endif
796
797 return 0;
798 }
799
scamper_rtsock_cleanup()800 void scamper_rtsock_cleanup()
801 {
802 #ifndef _WIN32
803 rtsock_pair_t *pair;
804
805 if(pairs != NULL)
806 {
807 while((pair = dlist_head_pop(pairs)) != NULL)
808 {
809 pair->node = NULL;
810 rtsock_pair_free(pair);
811 }
812
813 dlist_free(pairs);
814 pairs = NULL;
815 }
816 #endif
817
818 return;
819 }
820