1 /* $Id: getifaddr.c,v 1.24 2015/07/09 12:27:26 nanard Exp $ */
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2014 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
12 #include <sys/ioctl.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
19 #include <sys/sockio.h>
23 #include "getifaddr.h"
24 #if defined(USE_GETIFADDRS) || defined(ENABLE_IPV6) || defined(ENABLE_PCP)
29 getifaddr(const char * ifname
, char * buf
, int len
,
30 struct in_addr
* addr
, struct in_addr
* mask
)
32 #ifndef USE_GETIFADDRS
33 /* use ioctl SIOCGIFADDR. Works only for ip v4 */
34 /* SIOCGIFADDR struct ifreq * */
38 struct sockaddr_in
* ifaddr
;
41 if(!ifname
|| ifname
[0]=='\0')
43 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
46 syslog(LOG_ERR
, "socket(PF_INET, SOCK_DGRAM): %m");
49 strncpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
50 ifr
.ifr_name
[IFNAMSIZ
-1] = '\0';
51 if(ioctl(s
, SIOCGIFFLAGS
, &ifr
, &ifrlen
) < 0)
53 syslog(LOG_DEBUG
, "ioctl(s, SIOCGIFFLAGS, ...): %m");
57 if ((ifr
.ifr_flags
& IFF_UP
) == 0)
59 syslog(LOG_DEBUG
, "network interface %s is down", ifname
);
63 strncpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
64 if(ioctl(s
, SIOCGIFADDR
, &ifr
, &ifrlen
) < 0)
66 syslog(LOG_ERR
, "ioctl(s, SIOCGIFADDR, ...): %m");
70 ifaddr
= (struct sockaddr_in
*)&ifr
.ifr_addr
;
71 if(addr
) *addr
= ifaddr
->sin_addr
;
74 if(!inet_ntop(AF_INET
, &ifaddr
->sin_addr
, buf
, len
))
76 syslog(LOG_ERR
, "inet_ntop(): %m");
83 strncpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
84 if(ioctl(s
, SIOCGIFNETMASK
, &ifr
, &ifrlen
) < 0)
86 syslog(LOG_ERR
, "ioctl(s, SIOCGIFNETMASK, ...): %m");
91 *mask
= ((struct sockaddr_in
*)&ifr
.ifr_netmask
)->sin_addr
;
93 *mask
= ((struct sockaddr_in
*)&ifr
.ifr_addr
)->sin_addr
;
97 #else /* ifndef USE_GETIFADDRS */
98 /* Works for all address families (both ip v4 and ip v6) */
99 struct ifaddrs
* ifap
;
100 struct ifaddrs
* ife
;
102 if(!ifname
|| ifname
[0]=='\0')
104 if(getifaddrs(&ifap
)<0)
106 syslog(LOG_ERR
, "getifaddrs: %m");
109 for(ife
= ifap
; ife
; ife
= ife
->ifa_next
)
111 /* skip other interfaces if one was specified */
112 if(ifname
&& (0 != strcmp(ifname
, ife
->ifa_name
)))
114 if(ife
->ifa_addr
== NULL
)
116 switch(ife
->ifa_addr
->sa_family
)
121 inet_ntop(ife
->ifa_addr
->sa_family
,
122 &((struct sockaddr_in
*)ife
->ifa_addr
)->sin_addr
,
125 if(addr
) *addr
= ((struct sockaddr_in
*)ife
->ifa_addr
)->sin_addr
;
126 if(mask
) *mask
= ((struct sockaddr_in
*)ife
->ifa_netmask
)->sin_addr
;
130 inet_ntop(ife->ifa_addr->sa_family,
131 &((struct sockaddr_in6 *)ife->ifa_addr)->sin6_addr,
143 int getifaddr_in6(const char * ifname
, int af
, struct in6_addr
* addr
)
145 #if defined(ENABLE_IPV6) || defined(USE_GETIFADDRS)
146 struct ifaddrs
* ifap
;
147 struct ifaddrs
* ife
;
149 const struct sockaddr_in6
* tmpaddr
;
150 #endif /* ENABLE_IPV6 */
153 if(!ifname
|| ifname
[0]=='\0')
155 if(getifaddrs(&ifap
)<0)
157 syslog(LOG_ERR
, "getifaddrs: %m");
160 for(ife
= ifap
; ife
&& !found
; ife
= ife
->ifa_next
)
162 /* skip other interfaces if one was specified */
163 if(ifname
&& (0 != strcmp(ifname
, ife
->ifa_name
)))
165 if(ife
->ifa_addr
== NULL
)
167 if (ife
->ifa_addr
->sa_family
!= af
)
169 switch(ife
->ifa_addr
->sa_family
)
172 /* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */
173 memset(addr
->s6_addr
, 0, 10);
174 addr
->s6_addr
[10] = 0xff;
175 addr
->s6_addr
[11] = 0xff;
176 memcpy(addr
->s6_addr
+ 12,
177 &(((struct sockaddr_in
*)ife
->ifa_addr
)->sin_addr
.s_addr
),
184 tmpaddr
= (const struct sockaddr_in6
*)ife
->ifa_addr
;
185 if(!IN6_IS_ADDR_LOOPBACK(&tmpaddr
->sin6_addr
)
186 && !IN6_IS_ADDR_LINKLOCAL(&tmpaddr
->sin6_addr
))
188 memcpy(addr
->s6_addr
,
194 #endif /* ENABLE_IPV6 */
198 return (found
? 0 : -1);
199 #else /* defined(ENABLE_IPV6) || defined(USE_GETIFADDRS) */
201 struct in_addr addr4
;
204 if(getifaddr(ifname
, NULL
, 0, &addr4
, NULL
) < 0)
206 /* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */
207 memset(addr
->s6_addr
, 0, 10);
208 addr
->s6_addr
[10] = 0xff;
209 addr
->s6_addr
[11] = 0xff;
210 memcpy(addr
->s6_addr
+ 12, &addr4
.s_addr
, 4);
214 #endif /* ENABLE_PCP */
218 find_ipv6_addr(const char * ifname
,
221 struct ifaddrs
* ifap
;
222 struct ifaddrs
* ife
;
223 const struct sockaddr_in6
* addr
;
230 if(getifaddrs(&ifap
)<0)
232 syslog(LOG_ERR
, "getifaddrs: %m");
235 for(ife
= ifap
; ife
; ife
= ife
->ifa_next
)
237 /* skip other interfaces if one was specified */
238 if(ifname
&& (0 != strcmp(ifname
, ife
->ifa_name
)))
240 if(ife
->ifa_addr
== NULL
)
242 if(ife
->ifa_addr
->sa_family
== AF_INET6
)
244 addr
= (const struct sockaddr_in6
*)ife
->ifa_addr
;
245 if(!IN6_IS_ADDR_LOOPBACK(&addr
->sin6_addr
)
246 && !IN6_IS_ADDR_LINKLOCAL(&addr
->sin6_addr
))
248 inet_ntop(ife
->ifa_addr
->sa_family
,
252 snprintf(dst
, n
, "[%s]", buf
);