< prev index next >

src/java.base/unix/native/libnet/NetworkInterface.c

Print this page
rev 14637 : Fix for incorrectly reported network mask and broadcast address on Linux,
when there are more then on IP address on an interface.
Fix is implemented using getifaddrs.

*** 47,56 **** --- 47,57 ---- #if defined(__linux__) #include <sys/ioctl.h> #include <bits/ioctls.h> #include <sys/utsname.h> #include <stdio.h> + #include <ifaddrs.h> #endif #if defined(_AIX) #include <sys/ioctl.h> #include <netinet/in6_var.h>
*** 134,152 **** --- 135,157 ---- static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs); #endif static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs, struct sockaddr *ifr_addrP, int family, short prefix); + static netif *addif2(JNIEnv *env, int sock, const char *if_name, netif *ifs, + struct sockaddr *ifr_addrP, int family, short prefix, + struct sockaddr *brdcast); static void freeif(netif *ifs); static int openSocket(JNIEnv *env, int proto); static int openSocketWithFallback(JNIEnv *env, const char *ifname); static struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *name, struct sockaddr *brdcast_store); static short getSubnet(JNIEnv *env, int sock, const char *ifname); + static short getSubnetFromMaskAddr(const struct sockaddr_in * netmask_addrP); static int getIndex(int sock, const char *ifname); static int getFlags(int sock, const char *ifname, int *flags); static int getMacAddress(JNIEnv *env, int sock, const char *ifname, const struct in_addr *addr, unsigned char *buf);
*** 861,872 **** free(currif); currif = ifs; } } ! netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs, ! struct sockaddr *ifr_addrP, int family, short prefix) { netif *currif = ifs, *parent; netaddr *addrP; #ifdef LIFNAMSIZ --- 866,878 ---- free(currif); currif = ifs; } } ! netif *addif2(JNIEnv *env, int sock, const char *if_name, netif *ifs, ! struct sockaddr *ifr_addrP, int family, short prefix, ! struct sockaddr *brdcast) { netif *currif = ifs, *parent; netaddr *addrP; #ifdef LIFNAMSIZ
*** 913,931 **** --- 919,943 ---- addrP->next = 0; if (family == AF_INET) { // Deal with broadcast addr & subnet mask struct sockaddr *brdcast_to = (struct sockaddr *) ((char *)addrP + sizeof(netaddr) + addr_size); + #if defined(__linux__) + if (brdcast != NULL) { + addrP->brdcast = memcpy(brdcast_to, brdcast, addr_size); + } + #else addrP->brdcast = getBroadcast(env, sock, name, brdcast_to); if ((*env)->ExceptionCheck(env) == JNI_TRUE) { return ifs; } if ((mask = getSubnet(env, sock, name)) != -1) { addrP->mask = mask; } else if((*env)->ExceptionCheck(env)) { return ifs; } + #endif } // Deal with virtual interface with colon notation e.g. eth0:1 name_colonP = strchr(name, ':'); if (name_colonP != NULL) {
*** 1021,1030 **** --- 1033,1048 ---- } return ifs; } + netif *addif(JNIEnv *env, int sock, const char * if_name, + netif *ifs, struct sockaddr* ifr_addrP, int family, + short prefix) { + return addif2(env, sock, if_name, ifs, ifr_addrP, family, prefix, NULL); + } + /* * Opens a socket for further ioct calls. proto is one of AF_INET or AF_INET6. */ static int openSocket(JNIEnv *env, int proto) { int sock;
*** 1040,1049 **** --- 1058,1126 ---- } return sock; } + /* + * Count the number of non-zero bits + */ + static inline short mask2subnet(uint32_t mask) { + short ret = 0; + + for (; mask; mask <<= 1) { + ++ret; + } + + return ret; + } + + static inline short getSubnetFromMaskAddr(const struct sockaddr_in * netmask_addrP) { + return (netmask_addrP != NULL) ? mask2subnet(ntohl(netmask_addrP->sin_addr.s_addr)) : 0; + } + + #if defined(__linux__) || defined(_ALLBSD_SOURCE) + /* + * Enumerates and returns all IPv4 interfaces + */ + static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { + struct ifaddrs *ifa, *origifa; + struct sockaddr *ba = NULL; + short subnet = 0; + + if (getifaddrs(&origifa) != 0) { + NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", + "getifaddrs() function failed"); + return ifs; + } + + for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) { + /* Skip non-AF_INET entries */ + if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET) { + continue; + } + + #if defined(__linux__) + ba = (ifa->ifa_flags & IFF_BROADCAST) ? ifa->ifa_broadaddr : NULL; + subnet = getSubnetFromMaskAddr(((const struct sockaddr_in *)ifa->ifa_netmask)); + #endif + + /* Add to the list */ + ifs = addif2(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, AF_INET, subnet, ba); + + /* If an exception occurred then free the list */ + if ((*env)->ExceptionOccurred(env)) { + freeifaddrs(origifa); + freeif(ifs); + return NULL; + } + } + + /* Free socket and buffer */ + freeifaddrs(origifa); + return ifs; + } + #endif /* __linux__ || _ALLBSD_SOURCE */ /** Linux, AIX **/ #if defined(__linux__) || defined(_AIX) #ifdef AF_INET6
*** 1079,1133 **** static int openSocketWithFallback(JNIEnv *env, const char *ifname) { return openSocket(env,AF_INET); } #endif static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { struct ifconf ifc; struct ifreq *ifreqP; char *buf = NULL; int numifs; unsigned i; int siocgifconfRequest = SIOCGIFCONF; - #if defined(__linux__) - // need to do a dummy SIOCGIFCONF to determine the buffer size. - // SIOCGIFCOUNT doesn't work - ifc.ifc_buf = NULL; - if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "ioctl SIOCGIFCONF failed"); - return ifs; - } - #elif defined(_AIX) ifc.ifc_buf = NULL; if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) { NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "ioctl SIOCGSIZIFCONF failed"); return ifs; } - #endif /* __linux__ */ CHECKED_MALLOC3(buf, char *, ifc.ifc_len); ifc.ifc_buf = buf; - #if defined(_AIX) siocgifconfRequest = CSIOCGIFCONF; ! #endif if (ioctl(sock, siocgifconfRequest, (char *)&ifc) < 0) { NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "ioctl SIOCGIFCONF failed"); free(buf); return ifs; } // Iterate through each interface ifreqP = ifc.ifc_req; for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) { - #if defined(_AIX) if (ifreqP->ifr_addr.sa_family != AF_INET) continue; - #endif // Add to the list ifs = addif(env, sock, ifreqP->ifr_name, ifs, (struct sockaddr *)&(ifreqP->ifr_addr), AF_INET, 0); // If an exception occurred then free the list --- 1156,1197 ---- static int openSocketWithFallback(JNIEnv *env, const char *ifname) { return openSocket(env,AF_INET); } #endif + #if defined(_AIX) static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { struct ifconf ifc; struct ifreq *ifreqP; char *buf = NULL; int numifs; unsigned i; int siocgifconfRequest = SIOCGIFCONF; ifc.ifc_buf = NULL; if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) { NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "ioctl SIOCGSIZIFCONF failed"); return ifs; } CHECKED_MALLOC3(buf, char *, ifc.ifc_len); ifc.ifc_buf = buf; siocgifconfRequest = CSIOCGIFCONF; ! if (ioctl(sock, siocgifconfRequest, (char *)&ifc) < 0) { NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "ioctl SIOCGIFCONF failed"); free(buf); return ifs; } // Iterate through each interface ifreqP = ifc.ifc_req; for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) { if (ifreqP->ifr_addr.sa_family != AF_INET) continue; // Add to the list ifs = addif(env, sock, ifreqP->ifr_name, ifs, (struct sockaddr *)&(ifreqP->ifr_addr), AF_INET, 0); // If an exception occurred then free the list
*** 1140,1149 **** --- 1204,1214 ---- // Free socket and buffer free(buf); return ifs; } + #endif /* _AIX */ #if defined(AF_INET6) && defined(__linux__) /*
*** 1877,1916 **** #endif /* * Enumerates and returns all IPv4 interfaces. */ - static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { - struct ifaddrs *ifa, *origifa; - - if (getifaddrs(&origifa) != 0) { - NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", - "getifaddrs() function failed"); - return ifs; - } - - for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) { - - // Skip non-AF_INET entries. - if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET) - continue; - - // Add to the list. - ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, AF_INET, 0); - - // If an exception occurred then free the list. - if ((*env)->ExceptionOccurred(env)) { - freeifaddrs(origifa); - freeif(ifs); - return NULL; - } - } - - // Free socket and buffer - freeifaddrs(origifa); - return ifs; - } #ifdef AF_INET6 /* * Determines the prefix on BSD for IPv6 interfaces. */ --- 1942,1951 ----
< prev index next >