1 /* $Id: getifaddr.c,v 1.23 2014/05/06 14:40:53 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 if(ioctl(s
, SIOCGIFFLAGS
, &ifr
, &ifrlen
) < 0)
52 syslog(LOG_DEBUG
, "ioctl(s, SIOCGIFFLAGS, ...): %m");
56 if ((ifr
.ifr_flags
& IFF_UP
) == 0)
58 syslog(LOG_DEBUG
, "network interface %s is down", ifname
);
62 strncpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
63 if(ioctl(s
, SIOCGIFADDR
, &ifr
, &ifrlen
) < 0)
65 syslog(LOG_ERR
, "ioctl(s, SIOCGIFADDR, ...): %m");
69 ifaddr
= (struct sockaddr_in
*)&ifr
.ifr_addr
;
70 if(addr
) *addr
= ifaddr
->sin_addr
;
73 if(!inet_ntop(AF_INET
, &ifaddr
->sin_addr
, buf
, len
))
75 syslog(LOG_ERR
, "inet_ntop(): %m");
82 strncpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
83 if(ioctl(s
, SIOCGIFNETMASK
, &ifr
, &ifrlen
) < 0)
85 syslog(LOG_ERR
, "ioctl(s, SIOCGIFNETMASK, ...): %m");
90 *mask
= ((struct sockaddr_in
*)&ifr
.ifr_netmask
)->sin_addr
;
92 *mask
= ((struct sockaddr_in
*)&ifr
.ifr_addr
)->sin_addr
;
96 #else /* ifndef USE_GETIFADDRS */
97 /* Works for all address families (both ip v4 and ip v6) */
98 struct ifaddrs
* ifap
;
101 if(!ifname
|| ifname
[0]=='\0')
103 if(getifaddrs(&ifap
)<0)
105 syslog(LOG_ERR
, "getifaddrs: %m");
108 for(ife
= ifap
; ife
; ife
= ife
->ifa_next
)
110 /* skip other interfaces if one was specified */
111 if(ifname
&& (0 != strcmp(ifname
, ife
->ifa_name
)))
113 if(ife
->ifa_addr
== NULL
)
115 switch(ife
->ifa_addr
->sa_family
)
120 inet_ntop(ife
->ifa_addr
->sa_family
,
121 &((struct sockaddr_in
*)ife
->ifa_addr
)->sin_addr
,
124 if(addr
) *addr
= ((struct sockaddr_in
*)ife
->ifa_addr
)->sin_addr
;
125 if(mask
) *mask
= ((struct sockaddr_in
*)ife
->ifa_netmask
)->sin_addr
;
129 inet_ntop(ife->ifa_addr->sa_family,
130 &((struct sockaddr_in6 *)ife->ifa_addr)->sin6_addr,
142 int getifaddr_in6(const char * ifname
, int af
, struct in6_addr
* addr
)
144 #if defined(ENABLE_IPV6) || defined(USE_GETIFADDRS)
145 struct ifaddrs
* ifap
;
146 struct ifaddrs
* ife
;
148 const struct sockaddr_in6
* tmpaddr
;
149 #endif /* ENABLE_IPV6 */
152 if(!ifname
|| ifname
[0]=='\0')
154 if(getifaddrs(&ifap
)<0)
156 syslog(LOG_ERR
, "getifaddrs: %m");
159 for(ife
= ifap
; ife
&& !found
; ife
= ife
->ifa_next
)
161 /* skip other interfaces if one was specified */
162 if(ifname
&& (0 != strcmp(ifname
, ife
->ifa_name
)))
164 if(ife
->ifa_addr
== NULL
)
166 if (ife
->ifa_addr
->sa_family
!= af
)
168 switch(ife
->ifa_addr
->sa_family
)
171 /* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */
172 memset(addr
->s6_addr
, 0, 10);
173 addr
->s6_addr
[10] = 0xff;
174 addr
->s6_addr
[11] = 0xff;
175 memcpy(addr
->s6_addr
+ 12,
176 &(((struct sockaddr_in
*)ife
->ifa_addr
)->sin_addr
.s_addr
),
183 tmpaddr
= (const struct sockaddr_in6
*)ife
->ifa_addr
;
184 if(!IN6_IS_ADDR_LOOPBACK(&tmpaddr
->sin6_addr
)
185 && !IN6_IS_ADDR_LINKLOCAL(&tmpaddr
->sin6_addr
))
187 memcpy(addr
->s6_addr
,
193 #endif /* ENABLE_IPV6 */
197 return (found
? 0 : -1);
198 #else /* defined(ENABLE_IPV6) || defined(USE_GETIFADDRS) */
200 struct in_addr addr4
;
203 if(getifaddr(ifname
, NULL
, 0, &addr4
, NULL
) < 0)
205 /* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */
206 memset(addr
->s6_addr
, 0, 10);
207 addr
->s6_addr
[10] = 0xff;
208 addr
->s6_addr
[11] = 0xff;
209 memcpy(addr
->s6_addr
+ 12, &addr4
.s_addr
, 4);
213 #endif /* ENABLE_PCP */
217 find_ipv6_addr(const char * ifname
,
220 struct ifaddrs
* ifap
;
221 struct ifaddrs
* ife
;
222 const struct sockaddr_in6
* addr
;
229 if(getifaddrs(&ifap
)<0)
231 syslog(LOG_ERR
, "getifaddrs: %m");
234 for(ife
= ifap
; ife
; ife
= ife
->ifa_next
)
236 /* skip other interfaces if one was specified */
237 if(ifname
&& (0 != strcmp(ifname
, ife
->ifa_name
)))
239 if(ife
->ifa_addr
== NULL
)
241 if(ife
->ifa_addr
->sa_family
== AF_INET6
)
243 addr
= (const struct sockaddr_in6
*)ife
->ifa_addr
;
244 if(!IN6_IS_ADDR_LOOPBACK(&addr
->sin6_addr
)
245 && !IN6_IS_ADDR_LINKLOCAL(&addr
->sin6_addr
))
247 inet_ntop(ife
->ifa_addr
->sa_family
,
251 snprintf(dst
, n
, "[%s]", buf
);