1 /* $Id: getroute.c,v 1.3 2013/02/06 13:11:45 nanard Exp $ */
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2013 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
12 #include <sys/socket.h>
14 #include <net/route.h>
15 #include <netinet/in.h>
17 #include <net/if_dl.h>
20 #include "../config.h"
21 #include "../upnputils.h"
25 get_src_for_route_to(const struct sockaddr
* dst
,
26 void * src
, size_t * src_len
,
35 struct rt_msghdr m_rtm
;
38 #define rtm m_rtmsg.m_rtm
43 if(dst
->sa_family
== AF_INET6
) {
44 syslog(LOG_ERR
, "Sorry, get_src_for_route_to() is known to fail with IPV6 on OS X...");
48 s
= socket(PF_ROUTE
, SOCK_RAW
, dst
->sa_family
);
50 syslog(LOG_ERR
, "socket(PF_ROUTE) failed : %m");
53 memset(&rtm
, 0, sizeof(rtm
));
54 rtm
.rtm_type
= RTM_GET
;
55 rtm
.rtm_flags
= RTF_UP
;
56 rtm
.rtm_version
= RTM_VERSION
;
58 rtm
.rtm_addrs
= RTA_DST
; /* destination address */
59 memcpy(m_rtmsg
.m_space
, dst
, sizeof(struct sockaddr
));
60 rtm
.rtm_msglen
= sizeof(struct rt_msghdr
) + sizeof(struct sockaddr
);
61 if(write(s
, &m_rtmsg
, rtm
.rtm_msglen
) < 0) {
62 syslog(LOG_ERR
, "write: %m");
68 l
= read(s
, &m_rtmsg
, sizeof(m_rtmsg
));
70 syslog(LOG_ERR
, "read: %m");
74 syslog(LOG_DEBUG
, "read l=%d seq=%d pid=%d",
75 l
, rtm
.rtm_seq
, rtm
.rtm_pid
);
76 } while(l
> 0 && (rtm
.rtm_pid
!= getpid() || rtm
.rtm_seq
!= 1));
80 for(i
=1; i
<0x8000; i
<<= 1) {
81 if(i
& rtm
.rtm_addrs
) {
82 char tmp
[256] = { 0 };
83 sa
= (struct sockaddr
*)p
;
84 sockaddr_to_string(sa
, tmp
, sizeof(tmp
));
85 syslog(LOG_DEBUG
, "type=%d sa_len=%d sa_family=%d %s",
86 i
, sa
->sa_len
, sa
->sa_family
, tmp
);
87 if((i
== RTA_DST
|| i
== RTA_GATEWAY
) &&
91 if(sa
->sa_family
== AF_INET
) {
92 paddr
= &((struct sockaddr_in
*)sa
)->sin_addr
;
93 len
= sizeof(struct in_addr
);
94 } else if(sa
->sa_family
== AF_INET6
) {
95 paddr
= &((struct sockaddr_in6
*)sa
)->sin6_addr
;
96 len
= sizeof(struct in6_addr
);
100 syslog(LOG_WARNING
, "cannot copy src. %u<%u",
101 (unsigned)*src_len
, (unsigned)len
);
104 memcpy(src
, paddr
, len
);
110 if(sa
->sa_family
== AF_LINK
) {
111 struct sockaddr_dl
* sdl
= (struct sockaddr_dl
*)sa
;
113 *index
= sdl
->sdl_index
;
120 return found
? 0 : -1;