miniupnpd 1.9 (20160113)
[tomato.git] / release / src / router / miniupnpd / getifaddr.c
blob3febe64b839e685e986fa4215958bd69a3ca43ec
1 /* $Id: getifaddr.c,v 1.24 2015/07/09 12:27:26 nanard Exp $ */
2 /* MiniUPnP project
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 */
8 #include <stdio.h>
9 #include <string.h>
10 #include <syslog.h>
11 #include <unistd.h>
12 #include <sys/ioctl.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <net/if.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18 #if defined(sun)
19 #include <sys/sockio.h>
20 #endif
22 #include "config.h"
23 #include "getifaddr.h"
24 #if defined(USE_GETIFADDRS) || defined(ENABLE_IPV6) || defined(ENABLE_PCP)
25 #include <ifaddrs.h>
26 #endif
28 int
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 * */
35 int s;
36 struct ifreq ifr;
37 int ifrlen;
38 struct sockaddr_in * ifaddr;
39 ifrlen = sizeof(ifr);
41 if(!ifname || ifname[0]=='\0')
42 return -1;
43 s = socket(PF_INET, SOCK_DGRAM, 0);
44 if(s < 0)
46 syslog(LOG_ERR, "socket(PF_INET, SOCK_DGRAM): %m");
47 return -1;
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");
54 close(s);
55 return -1;
57 if ((ifr.ifr_flags & IFF_UP) == 0)
59 syslog(LOG_DEBUG, "network interface %s is down", ifname);
60 close(s);
61 return -1;
63 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
64 if(ioctl(s, SIOCGIFADDR, &ifr, &ifrlen) < 0)
66 syslog(LOG_ERR, "ioctl(s, SIOCGIFADDR, ...): %m");
67 close(s);
68 return -1;
70 ifaddr = (struct sockaddr_in *)&ifr.ifr_addr;
71 if(addr) *addr = ifaddr->sin_addr;
72 if(buf)
74 if(!inet_ntop(AF_INET, &ifaddr->sin_addr, buf, len))
76 syslog(LOG_ERR, "inet_ntop(): %m");
77 close(s);
78 return -1;
81 if(mask)
83 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
84 if(ioctl(s, SIOCGIFNETMASK, &ifr, &ifrlen) < 0)
86 syslog(LOG_ERR, "ioctl(s, SIOCGIFNETMASK, ...): %m");
87 close(s);
88 return -1;
90 #ifdef ifr_netmask
91 *mask = ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr;
92 #else
93 *mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
94 #endif
96 close(s);
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')
103 return -1;
104 if(getifaddrs(&ifap)<0)
106 syslog(LOG_ERR, "getifaddrs: %m");
107 return -1;
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)))
113 continue;
114 if(ife->ifa_addr == NULL)
115 continue;
116 switch(ife->ifa_addr->sa_family)
118 case AF_INET:
119 if(buf)
121 inet_ntop(ife->ifa_addr->sa_family,
122 &((struct sockaddr_in *)ife->ifa_addr)->sin_addr,
123 buf, len);
125 if(addr) *addr = ((struct sockaddr_in *)ife->ifa_addr)->sin_addr;
126 if(mask) *mask = ((struct sockaddr_in *)ife->ifa_netmask)->sin_addr;
127 break;
129 case AF_INET6:
130 inet_ntop(ife->ifa_addr->sa_family,
131 &((struct sockaddr_in6 *)ife->ifa_addr)->sin6_addr,
132 buf, len);
136 freeifaddrs(ifap);
137 #endif
138 return 0;
141 #ifdef ENABLE_PCP
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;
148 #ifdef ENABLE_IPV6
149 const struct sockaddr_in6 * tmpaddr;
150 #endif /* ENABLE_IPV6 */
151 int found = 0;
153 if(!ifname || ifname[0]=='\0')
154 return -1;
155 if(getifaddrs(&ifap)<0)
157 syslog(LOG_ERR, "getifaddrs: %m");
158 return -1;
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)))
164 continue;
165 if(ife->ifa_addr == NULL)
166 continue;
167 if (ife->ifa_addr->sa_family != af)
168 continue;
169 switch(ife->ifa_addr->sa_family)
171 case AF_INET:
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),
179 found = 1;
180 break;
182 #ifdef ENABLE_IPV6
183 case AF_INET6:
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,
189 &tmpaddr->sin6_addr,
190 16);
191 found = 1;
193 break;
194 #endif /* ENABLE_IPV6 */
197 freeifaddrs(ifap);
198 return (found ? 0 : -1);
199 #else /* defined(ENABLE_IPV6) || defined(USE_GETIFADDRS) */
200 /* IPv4 only */
201 struct in_addr addr4;
202 if(af != AF_INET)
203 return -1;
204 if(getifaddr(ifname, NULL, 0, &addr4, NULL) < 0)
205 return -1;
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);
211 return 0;
212 #endif
214 #endif /* ENABLE_PCP */
216 #ifdef ENABLE_IPV6
218 find_ipv6_addr(const char * ifname,
219 char * dst, int n)
221 struct ifaddrs * ifap;
222 struct ifaddrs * ife;
223 const struct sockaddr_in6 * addr;
224 char buf[64];
225 int r = 0;
227 if(!dst)
228 return -1;
230 if(getifaddrs(&ifap)<0)
232 syslog(LOG_ERR, "getifaddrs: %m");
233 return -1;
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)))
239 continue;
240 if(ife->ifa_addr == NULL)
241 continue;
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,
249 &addr->sin6_addr,
250 buf, sizeof(buf));
251 /* add brackets */
252 snprintf(dst, n, "[%s]", buf);
253 r = 1;
257 freeifaddrs(ifap);
258 return r;
260 #endif