1 /* $Id: getifaddr.c,v 1.26 2019/05/20 19:54:08 nanard Exp $ */ 2 /* vim: tabstop=4 shiftwidth=4 noexpandtab 3 * MiniUPnP project 4 * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ 5 * (c) 2006-2019 Thomas Bernard 6 * This software is subject to the conditions detailed 7 * in the LICENCE file provided within the distribution */ 8 9 #include <stdio.h> 10 #include <string.h> 11 #include <syslog.h> 12 #include <unistd.h> 13 #include <sys/ioctl.h> 14 #include <sys/types.h> 15 #include <sys/socket.h> 16 #include <net/if.h> 17 #include <netinet/in.h> 18 #include <arpa/inet.h> 19 #if defined(sun) 20 #include <sys/sockio.h> 21 #endif 22 23 #include "config.h" 24 #include "getifaddr.h" 25 #if defined(USE_GETIFADDRS) || defined(ENABLE_IPV6) || defined(ENABLE_PCP) 26 #include <ifaddrs.h> 27 #endif 28 29 int 30 getifaddr(const char * ifname, char * buf, int len, 31 struct in_addr * addr, struct in_addr * mask) 32 { 33 #ifndef USE_GETIFADDRS 34 /* use ioctl SIOCGIFADDR. Works only for ip v4 */ 35 /* SIOCGIFADDR struct ifreq * */ 36 int s; 37 struct ifreq ifr; 38 int ifrlen; 39 struct sockaddr_in * ifaddr; 40 ifrlen = sizeof(ifr); 41 42 if(!ifname || ifname[0]=='\0') 43 return -1; 44 s = socket(PF_INET, SOCK_DGRAM, 0); 45 if(s < 0) 46 { 47 syslog(LOG_ERR, "socket(PF_INET, SOCK_DGRAM): %m"); 48 return -1; 49 } 50 strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1); 51 ifr.ifr_name[IFNAMSIZ-1] = '\0'; 52 if(ioctl(s, SIOCGIFFLAGS, &ifr, &ifrlen) < 0) 53 { 54 syslog(LOG_DEBUG, "ioctl(s, SIOCGIFFLAGS, ...): %m"); 55 close(s); 56 return -1; 57 } 58 if ((ifr.ifr_flags & IFF_UP) == 0) 59 { 60 syslog(LOG_DEBUG, "network interface %s is down", ifname); 61 close(s); 62 return -1; 63 } 64 strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1); 65 ifr.ifr_name[IFNAMSIZ-1] = '\0'; 66 if(ioctl(s, SIOCGIFADDR, &ifr, &ifrlen) < 0) 67 { 68 syslog(LOG_ERR, "ioctl(s, SIOCGIFADDR, ...): %m"); 69 close(s); 70 return -1; 71 } 72 ifaddr = (struct sockaddr_in *)&ifr.ifr_addr; 73 if(addr) *addr = ifaddr->sin_addr; 74 if(buf) 75 { 76 if(!inet_ntop(AF_INET, &ifaddr->sin_addr, buf, len)) 77 { 78 syslog(LOG_ERR, "inet_ntop(): %m"); 79 close(s); 80 return -1; 81 } 82 } 83 if(mask) 84 { 85 strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1); 86 ifr.ifr_name[IFNAMSIZ-1] = '\0'; 87 if(ioctl(s, SIOCGIFNETMASK, &ifr, &ifrlen) < 0) 88 { 89 syslog(LOG_ERR, "ioctl(s, SIOCGIFNETMASK, ...): %m"); 90 close(s); 91 return -1; 92 } 93 #ifdef ifr_netmask 94 *mask = ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr; 95 #else 96 *mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; 97 #endif 98 } 99 close(s); 100 #else /* ifndef USE_GETIFADDRS */ 101 /* Works for all address families (both ip v4 and ip v6) */ 102 struct ifaddrs * ifap; 103 struct ifaddrs * ife; 104 105 if(!ifname || ifname[0]=='\0') 106 return -1; 107 if(getifaddrs(&ifap)<0) 108 { 109 syslog(LOG_ERR, "getifaddrs: %m"); 110 return -1; 111 } 112 for(ife = ifap; ife; ife = ife->ifa_next) 113 { 114 /* skip other interfaces if one was specified */ 115 if(ifname && (0 != strcmp(ifname, ife->ifa_name))) 116 continue; 117 if(ife->ifa_addr == NULL) 118 continue; 119 switch(ife->ifa_addr->sa_family) 120 { 121 case AF_INET: 122 if(buf) 123 { 124 inet_ntop(ife->ifa_addr->sa_family, 125 &((struct sockaddr_in *)ife->ifa_addr)->sin_addr, 126 buf, len); 127 } 128 if(addr) *addr = ((struct sockaddr_in *)ife->ifa_addr)->sin_addr; 129 if(mask) *mask = ((struct sockaddr_in *)ife->ifa_netmask)->sin_addr; 130 break; 131 /* 132 case AF_INET6: 133 inet_ntop(ife->ifa_addr->sa_family, 134 &((struct sockaddr_in6 *)ife->ifa_addr)->sin6_addr, 135 buf, len); 136 */ 137 } 138 } 139 freeifaddrs(ifap); 140 #endif 141 return 0; 142 } 143 144 #ifdef ENABLE_PCP 145 146 int getifaddr_in6(const char * ifname, int af, struct in6_addr * addr) 147 { 148 #if defined(ENABLE_IPV6) || defined(USE_GETIFADDRS) 149 struct ifaddrs * ifap; 150 struct ifaddrs * ife; 151 #ifdef ENABLE_IPV6 152 const struct sockaddr_in6 * tmpaddr; 153 #endif /* ENABLE_IPV6 */ 154 int found = 0; 155 156 if(!ifname || ifname[0]=='\0') 157 return -1; 158 if(getifaddrs(&ifap)<0) 159 { 160 syslog(LOG_ERR, "getifaddrs: %m"); 161 return -1; 162 } 163 for(ife = ifap; ife && !found; ife = ife->ifa_next) 164 { 165 /* skip other interfaces if one was specified */ 166 if(ifname && (0 != strcmp(ifname, ife->ifa_name))) 167 continue; 168 if(ife->ifa_addr == NULL) 169 continue; 170 if (ife->ifa_addr->sa_family != af) 171 continue; 172 switch(ife->ifa_addr->sa_family) 173 { 174 case AF_INET: 175 /* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */ 176 memset(addr->s6_addr, 0, 10); 177 addr->s6_addr[10] = 0xff; 178 addr->s6_addr[11] = 0xff; 179 memcpy(addr->s6_addr + 12, 180 &(((struct sockaddr_in *)ife->ifa_addr)->sin_addr.s_addr), 181 4); 182 found = 1; 183 break; 184 185 #ifdef ENABLE_IPV6 186 case AF_INET6: 187 tmpaddr = (const struct sockaddr_in6 *)ife->ifa_addr; 188 if(!IN6_IS_ADDR_LOOPBACK(&tmpaddr->sin6_addr) 189 && !IN6_IS_ADDR_LINKLOCAL(&tmpaddr->sin6_addr)) 190 { 191 memcpy(addr->s6_addr, 192 &tmpaddr->sin6_addr, 193 16); 194 found = 1; 195 } 196 break; 197 #endif /* ENABLE_IPV6 */ 198 } 199 } 200 freeifaddrs(ifap); 201 return (found ? 0 : -1); 202 #else /* defined(ENABLE_IPV6) || defined(USE_GETIFADDRS) */ 203 /* IPv4 only */ 204 struct in_addr addr4; 205 if(af != AF_INET) 206 return -1; 207 if(getifaddr(ifname, NULL, 0, &addr4, NULL) < 0) 208 return -1; 209 /* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */ 210 memset(addr->s6_addr, 0, 10); 211 addr->s6_addr[10] = 0xff; 212 addr->s6_addr[11] = 0xff; 213 memcpy(addr->s6_addr + 12, &addr4.s_addr, 4); 214 return 0; 215 #endif 216 } 217 #endif /* ENABLE_PCP */ 218 219 #ifdef ENABLE_IPV6 220 int 221 find_ipv6_addr(const char * ifname, 222 char * dst, int n) 223 { 224 struct ifaddrs * ifap; 225 struct ifaddrs * ife; 226 const struct sockaddr_in6 * addr; 227 char buf[64]; 228 int r = 0; 229 230 if(!dst) 231 return -1; 232 233 if(getifaddrs(&ifap)<0) 234 { 235 syslog(LOG_ERR, "getifaddrs: %m"); 236 return -1; 237 } 238 for(ife = ifap; ife; ife = ife->ifa_next) 239 { 240 /* skip other interfaces if one was specified */ 241 if(ifname && (0 != strcmp(ifname, ife->ifa_name))) 242 continue; 243 if(ife->ifa_addr == NULL) 244 continue; 245 if(ife->ifa_addr->sa_family == AF_INET6) 246 { 247 addr = (const struct sockaddr_in6 *)ife->ifa_addr; 248 if(!IN6_IS_ADDR_LOOPBACK(&addr->sin6_addr) 249 && !IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) 250 { 251 inet_ntop(ife->ifa_addr->sa_family, 252 &addr->sin6_addr, 253 buf, sizeof(buf)); 254 /* add brackets */ 255 snprintf(dst, n, "[%s]", buf); 256 r = 1; 257 } 258 } 259 } 260 freeifaddrs(ifap); 261 return r; 262 } 263 #endif 264 265 /* List of IP address blocks which are private / reserved and therefore not suitable for public external IP addresses */ 266 /* If interface has IP address from one of this block, then it is either behind NAT or port forwarding is impossible */ 267 #define IP(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) 268 #define MSK(m) (32-(m)) 269 static const struct { uint32_t address; uint32_t rmask; } reserved[] = { 270 { IP( 0, 0, 0, 0), MSK( 8) }, /* RFC1122 "This host on this network" */ 271 { IP( 10, 0, 0, 0), MSK( 8) }, /* RFC1918 Private-Use */ 272 { IP(100, 64, 0, 0), MSK(10) }, /* RFC6598 Shared Address Space */ 273 { IP(127, 0, 0, 0), MSK( 8) }, /* RFC1122 Loopback */ 274 { IP(169, 254, 0, 0), MSK(16) }, /* RFC3927 Link-Local */ 275 { IP(172, 16, 0, 0), MSK(12) }, /* RFC1918 Private-Use */ 276 { IP(192, 0, 0, 0), MSK(24) }, /* RFC6890 IETF Protocol Assignments */ 277 { IP(192, 0, 2, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-1) */ 278 { IP(192, 31, 196, 0), MSK(24) }, /* RFC7535 AS112-v4 */ 279 { IP(192, 52, 193, 0), MSK(24) }, /* RFC7450 AMT */ 280 { IP(192, 88, 99, 0), MSK(24) }, /* RFC7526 6to4 Relay Anycast */ 281 { IP(192, 168, 0, 0), MSK(16) }, /* RFC1918 Private-Use */ 282 { IP(192, 175, 48, 0), MSK(24) }, /* RFC7534 Direct Delegation AS112 Service */ 283 { IP(198, 18, 0, 0), MSK(15) }, /* RFC2544 Benchmarking */ 284 { IP(198, 51, 100, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-2) */ 285 { IP(203, 0, 113, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-3) */ 286 { IP(224, 0, 0, 0), MSK( 4) }, /* RFC1112 Multicast */ 287 { IP(240, 0, 0, 0), MSK( 4) }, /* RFC1112 Reserved for Future Use + RFC919 Limited Broadcast */ 288 }; 289 #undef IP 290 #undef MSK 291 292 int 293 addr_is_reserved(struct in_addr * addr) 294 { 295 uint32_t address = ntohl(addr->s_addr); 296 size_t i; 297 298 for (i = 0; i < sizeof(reserved)/sizeof(reserved[0]); ++i) { 299 if ((address >> reserved[i].rmask) == (reserved[i].address >> reserved[i].rmask)) 300 return 1; 301 } 302 303 return 0; 304 } 305