NetworkInterface.c revision d5476be7c8108697ac20d19ffba3955d392a39fe
1/* 2 * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27#include <errno.h> 28#include <strings.h> 29#if defined(_ALLBSD_SOURCE) && defined(__OpenBSD__) 30#include <sys/types.h> 31#endif 32#include <netinet/in.h> 33#include <stdlib.h> 34#include <string.h> 35#include <sys/types.h> 36#include <sys/socket.h> 37#include <arpa/inet.h> 38#include <net/if.h> 39#include <net/if_arp.h> 40#include <linux/if_packet.h> 41 42#include <sys/ioctl.h> 43//#include <bits/ioctls.h> 44#include <sys/utsname.h> 45#include <stdio.h> 46#include <ifaddrs.h> 47 48#include "jvm.h" 49#include "jni_util.h" 50#include "net_util.h" 51#include "JNIHelp.h" 52 53#define NATIVE_METHOD(className, functionName, signature) \ 54{ #functionName, signature, (void*)(className ## _ ## functionName) } 55 56typedef struct _netaddr { 57 struct sockaddr *addr; 58 struct sockaddr *brdcast; 59 short mask; 60 int family; /* to make searches simple */ 61 struct _netaddr *next; 62} netaddr; 63 64typedef struct _netif { 65 char *name; 66 int index; 67 char virtual; 68 69 uint8_t hwAddrLen; 70 uint8_t *hwAddr; 71 netaddr *addr; 72 struct _netif *childs; 73 struct _netif *next; 74} netif; 75 76/************************************************************************ 77 * NetworkInterface 78 */ 79 80 81/************************************************************************ 82 * NetworkInterface 83 */ 84jclass ni_class; 85jfieldID ni_nameID; 86jfieldID ni_indexID; 87jfieldID ni_descID; 88jfieldID ni_addrsID; 89jfieldID ni_bindsID; 90jfieldID ni_virutalID; 91jfieldID ni_childsID; 92jfieldID ni_parentID; 93jfieldID ni_defaultIndexID; 94jfieldID ni_hardwareAddrID; 95jmethodID ni_ctrID; 96 97static jclass ni_iacls; 98static jclass ni_ia4cls; 99static jclass ni_ia6cls; 100static jclass ni_ibcls; 101static jmethodID ni_ia4ctrID; 102static jmethodID ni_ia6ctrID; 103static jmethodID ni_ibctrID; 104static jfieldID ni_ia6ipaddressID; 105static jfieldID ni_ibaddressID; 106static jfieldID ni_ib4broadcastID; 107static jfieldID ni_ib4maskID; 108 109/** Private methods declarations **/ 110static jobject createNetworkInterface(JNIEnv *env, netif *ifs); 111static int getFlags0(JNIEnv *env, jstring ifname); 112 113static netif *enumInterfaces(JNIEnv *env); 114 115static netif *addif(JNIEnv *env, int sock, struct ifaddrs *ifa, netif *ifs); 116static void freeif(netif *ifs); 117 118static int openSocket(JNIEnv *env, int proto); 119static int openSocketWithFallback(JNIEnv *env, const char *ifname); 120 121static int getIndex(int sock, const char *ifname); 122 123static int getFlags(int sock, const char *ifname, int *flags); 124static int getMTU(JNIEnv *env, int sock, const char *ifname); 125 126/******************* Java entry points *****************************/ 127 128/* 129 * Class: java_net_NetworkInterface 130 * Method: init 131 * Signature: ()V 132 */ 133JNIEXPORT void JNICALL 134NetworkInterface_init(JNIEnv *env, jclass cls) { 135 ni_class = (*env)->FindClass(env,"java/net/NetworkInterface"); 136 ni_class = (*env)->NewGlobalRef(env, ni_class); 137 ni_nameID = (*env)->GetFieldID(env, ni_class,"name", "Ljava/lang/String;"); 138 ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I"); 139 ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs", "[Ljava/net/InetAddress;"); 140 ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings", "[Ljava/net/InterfaceAddress;"); 141 ni_descID = (*env)->GetFieldID(env, ni_class, "displayName", "Ljava/lang/String;"); 142 ni_virutalID = (*env)->GetFieldID(env, ni_class, "virtual", "Z"); 143 ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;"); 144 ni_parentID = (*env)->GetFieldID(env, ni_class, "parent", "Ljava/net/NetworkInterface;"); 145 ni_hardwareAddrID = (*env)->GetFieldID(env, ni_class, "hardwareAddr", "[B"); 146 ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V"); 147 148 ni_iacls = (*env)->FindClass(env, "java/net/InetAddress"); 149 ni_iacls = (*env)->NewGlobalRef(env, ni_iacls); 150 ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address"); 151 ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls); 152 ni_ia6cls = (*env)->FindClass(env, "java/net/Inet6Address"); 153 ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls); 154 ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress"); 155 ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls); 156 ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V"); 157 ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V"); 158 ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V"); 159 ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B"); 160 ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;"); 161 ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;"); 162 ni_ib4maskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S"); 163 ni_defaultIndexID = (*env)->GetStaticFieldID(env, ni_class, "defaultIndex", "I"); 164} 165 166 167/* 168 * Class: java_net_NetworkInterface 169 * Method: getByName0 170 * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface; 171 */ 172JNIEXPORT jobject JNICALL NetworkInterface_getByName0 173 (JNIEnv *env, jclass cls, jstring name) { 174 175 netif *ifs, *curr; 176 jboolean isCopy; 177 const char* name_utf; 178 jobject obj = NULL; 179 180 ifs = enumInterfaces(env); 181 if (ifs == NULL) { 182 return NULL; 183 } 184 185 name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); 186 187 /* 188 * Search the list of interface based on name 189 */ 190 curr = ifs; 191 while (curr != NULL) { 192 if (strcmp(name_utf, curr->name) == 0) { 193 break; 194 } 195 curr = curr->next; 196 } 197 198 /* if found create a NetworkInterface */ 199 if (curr != NULL) {; 200 obj = createNetworkInterface(env, curr); 201 } 202 203 /* release the UTF string and interface list */ 204 (*env)->ReleaseStringUTFChars(env, name, name_utf); 205 freeif(ifs); 206 207 return obj; 208} 209 210 211/* 212 * Class: java_net_NetworkInterface 213 * Method: getByIndex0 214 * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface; 215 */ 216JNIEXPORT jobject JNICALL NetworkInterface_getByIndex0 217 (JNIEnv *env, jclass cls, jint index) { 218 219 netif *ifs, *curr; 220 jobject obj = NULL; 221 222 if (index <= 0) { 223 return NULL; 224 } 225 226 ifs = enumInterfaces(env); 227 if (ifs == NULL) { 228 return NULL; 229 } 230 231 /* 232 * Search the list of interface based on index 233 */ 234 curr = ifs; 235 while (curr != NULL) { 236 if (index == curr->index) { 237 break; 238 } 239 curr = curr->next; 240 } 241 242 /* if found create a NetworkInterface */ 243 if (curr != NULL) {; 244 obj = createNetworkInterface(env, curr); 245 } 246 247 freeif(ifs); 248 return obj; 249} 250 251/* 252 * Class: java_net_NetworkInterface 253 * Method: getByInetAddress0 254 * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface; 255 */ 256JNIEXPORT jobject JNICALL NetworkInterface_getByInetAddress0 257 (JNIEnv *env, jclass cls, jobject iaObj) { 258 259 netif *ifs, *curr; 260 261 int family = (getInetAddress_family(env, iaObj) == IPv4) ? AF_INET : AF_INET6; 262 263 jobject obj = NULL; 264 jboolean match = JNI_FALSE; 265 266 ifs = enumInterfaces(env); 267 if (ifs == NULL) { 268 return NULL; 269 } 270 271 curr = ifs; 272 while (curr != NULL) { 273 netaddr *addrP = curr->addr; 274 275 /* 276 * Iterate through each address on the interface 277 */ 278 while (addrP != NULL) { 279 280 if (family == addrP->family) { 281 if (family == AF_INET) { 282 int address1 = htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr); 283 int address2 = getInetAddress_addr(env, iaObj); 284 285 if (address1 == address2) { 286 match = JNI_TRUE; 287 break; 288 } 289 } 290 291 if (family == AF_INET6) { 292 jbyte *bytes = (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr); 293 jbyteArray ipaddress = (*env)->GetObjectField(env, iaObj, ni_ia6ipaddressID); 294 jbyte caddr[16]; 295 int i; 296 297 (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddr); 298 i = 0; 299 while (i < 16) { 300 if (caddr[i] != bytes[i]) { 301 break; 302 } 303 i++; 304 } 305 if (i >= 16) { 306 match = JNI_TRUE; 307 break; 308 } 309 } 310 } 311 312 if (match) { 313 break; 314 } 315 addrP = addrP->next; 316 } 317 318 if (match) { 319 break; 320 } 321 curr = curr->next; 322 } 323 324 /* if found create a NetworkInterface */ 325 if (match) {; 326 obj = createNetworkInterface(env, curr); 327 } 328 329 freeif(ifs); 330 return obj; 331} 332 333 334/* 335 * Class: java_net_NetworkInterface 336 * Method: getAll 337 * Signature: ()[Ljava/net/NetworkInterface; 338 */ 339JNIEXPORT jobjectArray JNICALL NetworkInterface_getAll 340 (JNIEnv *env, jclass cls) { 341 342 netif *ifs, *curr; 343 jobjectArray netIFArr; 344 jint arr_index, ifCount; 345 346 ifs = enumInterfaces(env); 347 if (ifs == NULL) { 348 return NULL; 349 } 350 351 /* count the interface */ 352 ifCount = 0; 353 curr = ifs; 354 while (curr != NULL) { 355 ifCount++; 356 curr = curr->next; 357 } 358 359 /* allocate a NetworkInterface array */ 360 netIFArr = (*env)->NewObjectArray(env, ifCount, cls, NULL); 361 if (netIFArr == NULL) { 362 freeif(ifs); 363 return NULL; 364 } 365 366 /* 367 * Iterate through the interfaces, create a NetworkInterface instance 368 * for each array element and populate the object. 369 */ 370 curr = ifs; 371 arr_index = 0; 372 while (curr != NULL) { 373 jobject netifObj; 374 375 netifObj = createNetworkInterface(env, curr); 376 if (netifObj == NULL) { 377 freeif(ifs); 378 return NULL; 379 } 380 381 /* put the NetworkInterface into the array */ 382 (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj); 383 384 curr = curr->next; 385 } 386 387 freeif(ifs); 388 return netIFArr; 389} 390 391 392/* 393 * Class: java_net_NetworkInterface 394 * Method: isUp0 395 * Signature: (Ljava/lang/String;I)Z 396 */ 397JNIEXPORT jboolean JNICALL NetworkInterface_isUp0(JNIEnv *env, jclass cls, jstring name, jint index) { 398 int ret = getFlags0(env, name); 399 return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE : JNI_FALSE; 400} 401 402/* 403 * Class: java_net_NetworkInterface 404 * Method: isP2P0 405 * Signature: (Ljava/lang/String;I)Z 406 */ 407JNIEXPORT jboolean JNICALL NetworkInterface_isP2P0(JNIEnv *env, jclass cls, jstring name, jint index) { 408 int ret = getFlags0(env, name); 409 return (ret & IFF_POINTOPOINT) ? JNI_TRUE : JNI_FALSE; 410} 411 412/* 413 * Class: java_net_NetworkInterface 414 * Method: isLoopback0 415 * Signature: (Ljava/lang/String;I)Z 416 */ 417JNIEXPORT jboolean JNICALL NetworkInterface_isLoopback0(JNIEnv *env, jclass cls, jstring name, jint index) { 418 int ret = getFlags0(env, name); 419 return (ret & IFF_LOOPBACK) ? JNI_TRUE : JNI_FALSE; 420} 421 422/* 423 * Class: java_net_NetworkInterface 424 * Method: supportsMulticast0 425 * Signature: (Ljava/lang/String;I)Z 426 */ 427JNIEXPORT jboolean JNICALL NetworkInterface_supportsMulticast0(JNIEnv *env, jclass cls, jstring name, jint index) { 428 int ret = getFlags0(env, name); 429 return (ret & IFF_MULTICAST) ? JNI_TRUE : JNI_FALSE; 430} 431 432/* 433 * Class: java_net_NetworkInterface 434 * Method: getMTU0 435 * Signature: ([bLjava/lang/String;I)I 436 */ 437 438JNIEXPORT jint JNICALL NetworkInterface_getMTU0(JNIEnv *env, jclass class, jstring name, jint index) { 439 jboolean isCopy; 440 int ret = -1; 441 int sock; 442 const char* name_utf; 443 444 name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); 445 446 if ((sock =openSocketWithFallback(env, name_utf)) < 0) { 447 (*env)->ReleaseStringUTFChars(env, name, name_utf); 448 return JNI_FALSE; 449 } 450 451 ret = getMTU(env, sock, name_utf); 452 453 (*env)->ReleaseStringUTFChars(env, name, name_utf); 454 455 close(sock); 456 return ret; 457} 458 459/*** Private methods definitions ****/ 460 461static int getFlags0(JNIEnv *env, jstring name) { 462 jboolean isCopy; 463 int ret, sock; 464 const char* name_utf; 465 int flags = 0; 466 467 name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); 468 469 if ((sock = openSocketWithFallback(env, name_utf)) < 0) { 470 (*env)->ReleaseStringUTFChars(env, name, name_utf); 471 return -1; 472 } 473 474 name_utf = (*env)->GetStringUTFChars(env, name, &isCopy); 475 476 ret = getFlags(sock, name_utf, &flags); 477 478 close(sock); 479 (*env)->ReleaseStringUTFChars(env, name, name_utf); 480 481 if (ret < 0) { 482 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFFLAGS failed"); 483 return -1; 484 } 485 486 return flags; 487} 488 489 490 491 492/* 493 * Create a NetworkInterface object, populate the name and index, and 494 * populate the InetAddress array based on the IP addresses for this 495 * interface. 496 */ 497jobject createNetworkInterface(JNIEnv *env, netif *ifs) { 498 jobject netifObj; 499 jobject name; 500 jobjectArray addrArr; 501 jobjectArray bindArr; 502 jobjectArray childArr; 503 netaddr *addrs; 504 jint addr_index, addr_count, bind_index; 505 jint child_count, child_index; 506 netaddr *addrP; 507 netif *childP; 508 jobject tmp; 509 510 /* 511 * Create a NetworkInterface object and populate it 512 */ 513 netifObj = (*env)->NewObject(env, ni_class, ni_ctrID); 514 name = (*env)->NewStringUTF(env, ifs->name); 515 if (netifObj == NULL || name == NULL) { 516 return NULL; 517 } 518 (*env)->SetObjectField(env, netifObj, ni_nameID, name); 519 (*env)->SetObjectField(env, netifObj, ni_descID, name); 520 (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index); 521 (*env)->SetBooleanField(env, netifObj, ni_virutalID, ifs->virtual ? JNI_TRUE : JNI_FALSE); 522 523 /* 524 * Set the hardware address 525 */ 526 if (ifs->hwAddrLen > 0 && ifs->hwAddr != NULL) { 527 jbyteArray hardwareAddr = (*env)->NewByteArray(env, ifs->hwAddrLen); 528 if (hardwareAddr == NULL) { 529 return NULL; 530 } 531 (*env)->SetByteArrayRegion(env, hardwareAddr, 0, ifs->hwAddrLen, (jbyte *)ifs->hwAddr); 532 (*env)->SetObjectField(env, netifObj, ni_hardwareAddrID, hardwareAddr); 533 } 534 535 /* 536 * Count the number of address on this interface 537 */ 538 addr_count = 0; 539 addrP = ifs->addr; 540 while (addrP != NULL) { 541 addr_count++; 542 addrP = addrP->next; 543 } 544 545 /* 546 * Create the array of InetAddresses 547 */ 548 addrArr = (*env)->NewObjectArray(env, addr_count, ni_iacls, NULL); 549 if (addrArr == NULL) { 550 return NULL; 551 } 552 553 bindArr = (*env)->NewObjectArray(env, addr_count, ni_ibcls, NULL); 554 if (bindArr == NULL) { 555 return NULL; 556 } 557 addrP = ifs->addr; 558 addr_index = 0; 559 bind_index = 0; 560 while (addrP != NULL) { 561 jobject iaObj = NULL; 562 jobject ibObj = NULL; 563 564 if (addrP->family == AF_INET) { 565 iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID); 566 if (iaObj) { 567 setInetAddress_addr(env, iaObj, htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr)); 568 } 569 ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); 570 if (ibObj) { 571 (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj); 572 if (addrP->brdcast) { 573 jobject ia2Obj = NULL; 574 ia2Obj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID); 575 if (ia2Obj) { 576 setInetAddress_addr(env, ia2Obj, htonl(((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr)); 577 (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj); 578 } 579 } 580 (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask); 581 (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj); 582 } 583 } 584 585 if (addrP->family == AF_INET6) { 586 int scope=0; 587 iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID); 588 if (iaObj) { 589 jbyteArray ipaddress = (*env)->NewByteArray(env, 16); 590 if (ipaddress == NULL) { 591 return NULL; 592 } 593 (*env)->SetByteArrayRegion(env, ipaddress, 0, 16, 594 (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr)); 595 596 scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id; 597 598 if (scope != 0) { /* zero is default value, no need to set */ 599 (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope); 600 (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE); 601 (*env)->SetObjectField(env, iaObj, ia6_scopeifnameID, netifObj); 602 } 603 (*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress); 604 } 605 ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID); 606 if (ibObj) { 607 (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj); 608 (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask); 609 (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj); 610 } 611 } 612 613 if (iaObj == NULL) { 614 return NULL; 615 } 616 617 (*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj); 618 addrP = addrP->next; 619 } 620 621 /* 622 * See if there is any virtual interface attached to this one. 623 */ 624 child_count = 0; 625 childP = ifs->childs; 626 while (childP) { 627 child_count++; 628 childP = childP->next; 629 } 630 631 childArr = (*env)->NewObjectArray(env, child_count, ni_class, NULL); 632 if (childArr == NULL) { 633 return NULL; 634 } 635 636 /* 637 * Create the NetworkInterface instances for the sub-interfaces as 638 * well. 639 */ 640 child_index = 0; 641 childP = ifs->childs; 642 while(childP) { 643 tmp = createNetworkInterface(env, childP); 644 if (tmp == NULL) { 645 return NULL; 646 } 647 (*env)->SetObjectField(env, tmp, ni_parentID, netifObj); 648 (*env)->SetObjectArrayElement(env, childArr, child_index++, tmp); 649 childP = childP->next; 650 } 651 (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr); 652 (*env)->SetObjectField(env, netifObj, ni_bindsID, bindArr); 653 (*env)->SetObjectField(env, netifObj, ni_childsID, childArr); 654 655 /* return the NetworkInterface */ 656 return netifObj; 657} 658 659/* 660 * Determines the mask length for IPV4/v6 addresses. 661 */ 662static 663int mask_address_to_mask_length(uint8_t *val, int size) { 664 int byte, bit, plen = 0; 665 666 for (byte = 0; byte < size && val[byte] == 0xff; byte++) { 667 plen += 8; 668 } 669 if (byte < size) { 670 for (bit = 7; bit > 0; bit--) { 671 if (val[byte] & (1 << bit)) plen++; 672 } 673 } 674 return plen; 675} 676 677/* 678 * Enumerates all interfaces 679 */ 680static netif *enumInterfaces(JNIEnv *env) { 681 netif *ifs = NULL; 682 struct ifaddrs *ifa, *origifa; 683 684 int sock = openSocket(env, AF_INET); 685 if (sock < 0 && (*env)->ExceptionOccurred(env)) { 686 return NULL; 687 } 688 689 if (getifaddrs(&origifa) != 0) { 690 NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", 691 "getifaddrs() function failed"); 692 return NULL; 693 } 694 695 for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) { 696 if (ifa->ifa_addr != NULL) { 697 switch (ifa->ifa_addr->sa_family) { 698 case AF_PACKET: 699 case AF_INET: 700 case AF_INET6: 701 ifs = addif(env, sock, ifa, ifs); 702 break; 703 } 704 } 705 } 706 707 freeifaddrs(origifa); 708 close(sock); 709 710 return ifs; 711} 712 713#define CHECKED_MALLOC3(_pointer,_type,_size) \ 714 do{ \ 715 _pointer = (_type)malloc( _size ); \ 716 if (_pointer == NULL) { \ 717 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \ 718 return ifs; /* return untouched list */ \ 719 } \ 720 } while(0) 721 722 723/* 724 * Free an interface list (including any attached addresses) 725 */ 726void freeif(netif *ifs) { 727 netif *currif = ifs; 728 netif *child = NULL; 729 730 while (currif != NULL) { 731 netaddr *addrP = currif->addr; 732 while (addrP != NULL) { 733 netaddr *next = addrP->next; 734 free(addrP); 735 addrP = next; 736 } 737 738 /* 739 * Don't forget to free the sub-interfaces. 740 */ 741 if (currif->childs != NULL) { 742 freeif(currif->childs); 743 } 744 745 /* 746 * Remove mac address 747 */ 748 if (currif->hwAddr != NULL) { 749 free(currif->hwAddr); 750 } 751 752 ifs = currif->next; 753 free(currif); 754 currif = ifs; 755 } 756} 757 758netif *addif(JNIEnv *env, int sock, struct ifaddrs *ifa, netif *ifs) 759{ 760 netif *currif = ifs, *parent; 761 netaddr *addrP = NULL; 762 763 char name[IFNAMSIZ], vname[IFNAMSIZ]; 764 765 char *name_colonP; 766 int mask; 767 int isVirtual = 0; 768 int addr_size; 769 int flags = 0; 770 771 /* 772 * If the interface name is a logical interface then we 773 * remove the unit number so that we have the physical 774 * interface (eg: hme0:1 -> hme0). NetworkInterface 775 * currently doesn't have any concept of physical vs. 776 * logical interfaces. 777 */ 778 strncpy(name, ifa->ifa_name, sizeof(name)); 779 name[sizeof(name) - 1] = '\0'; 780 *vname = 0; 781 782 /* 783 * Create and populate the netaddr node. If allocation fails 784 * return an un-updated list. 785 */ 786 switch(ifa->ifa_addr->sa_family) { 787 case AF_INET: 788 addr_size = sizeof(struct sockaddr_in); 789 break; 790 case AF_INET6: 791 addr_size = sizeof(struct sockaddr_in6); 792 break; 793 case AF_PACKET: 794 // Don't add an address entry, will extract data to netif struct 795 addr_size = 0; 796 break; 797 default: 798 return NULL; 799 } 800 801 if (addr_size > 0) { 802 /*Allocate for addr and brdcast at once*/ 803 CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr)+2*addr_size); 804 addrP->addr = (struct sockaddr *)( (char *) addrP+sizeof(netaddr) ); 805 memcpy(addrP->addr, ifa->ifa_addr, addr_size); 806 807 addrP->family = ifa->ifa_addr->sa_family; 808 addrP->next = 0; 809 810 if (ifa->ifa_broadaddr && (ifa->ifa_flags & IFF_BROADCAST)) { 811 struct sockaddr * brdcast_to = (struct sockaddr *) ((char *) addrP + sizeof(netaddr) + addr_size); 812 addrP->brdcast = brdcast_to; 813 memcpy(brdcast_to, ifa->ifa_broadaddr, sizeof(struct sockaddr)); 814 } else { 815 addrP->brdcast = NULL; 816 } 817 818 if (ifa->ifa_netmask) { 819 if (ifa->ifa_netmask->sa_family == AF_INET) { 820 addrP->mask = mask_address_to_mask_length( 821 (uint8_t*)&(((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr), 822 sizeof(struct in_addr)); 823 } else if (ifa->ifa_netmask->sa_family == AF_INET6) { 824 addrP->mask = mask_address_to_mask_length( 825 (uint8_t*)&((struct sockaddr_in6*)ifa->ifa_netmask)->sin6_addr, 826 sizeof(struct in6_addr)); 827 } 828 } else { 829 addrP->mask = 0; 830 } 831 } 832 833 /** 834 * Deal with virtual interface with colon notaion e.g. eth0:1 835 */ 836 name_colonP = strchr(name, ':'); 837 if (name_colonP != NULL) { 838 /** 839 * This is a virtual interface. If we are able to access the parent 840 * we need to create a new entry if it doesn't exist yet *and* update 841 * the 'parent' interface with the new records. 842 */ 843 *name_colonP = 0; 844 if (getFlags(sock, name, &flags) < 0 || flags < 0) { 845 // failed to access parent interface do not create parent. 846 // We are a virtual interface with no parent. 847 isVirtual = 1; 848 *name_colonP = ':'; 849 } 850 else{ 851 // Got access to parent, so create it if necessary. 852 // Save original name to vname and truncate name by ':' 853 memcpy(vname, name, sizeof(vname) ); 854 vname[name_colonP - name] = ':'; 855 } 856 } 857 858 /* 859 * Check if this is a "new" interface. Use the interface 860 * name for matching because index isn't supported on 861 * Solaris 2.6 & 7. 862 */ 863 while (currif != NULL) { 864 if (strcmp(name, currif->name) == 0) { 865 break; 866 } 867 currif = currif->next; 868 } 869 870 /* 871 * If "new" then create an netif structure and 872 * insert it onto the list. 873 */ 874 if (currif == NULL) { 875 CHECKED_MALLOC3(currif, netif *, sizeof(netif) + sizeof(name)); 876 currif->name = (char *) currif+sizeof(netif); 877 strncpy(currif->name, name, sizeof(name)); 878 currif->name[sizeof(name) - 1] = '\0'; 879 currif->index = getIndex(sock, name); 880 currif->addr = NULL; 881 currif->childs = NULL; 882 currif->virtual = isVirtual; 883 currif->hwAddrLen = 0; 884 currif->hwAddr = NULL; 885 currif->next = ifs; 886 ifs = currif; 887 } 888 889 /* 890 * Insert the mac address on the interface 891 */ 892 if (ifa->ifa_addr->sa_family == AF_PACKET) { 893 struct sockaddr_ll *s = (struct sockaddr_ll*)ifa->ifa_addr; 894 895 if (s->sll_halen > 0) { 896 /* 897 * All bytes to 0 means no hardware address. 898 */ 899 int i; 900 for (i = 0;i < s->sll_halen; ++i) { 901 if (s->sll_addr[i] != 0) { 902 break; 903 } 904 } 905 if (i != s->sll_halen && currif->hwAddr == NULL) { 906 CHECKED_MALLOC3(currif->hwAddr, uint8_t *, s->sll_halen); 907 memcpy(currif->hwAddr, s->sll_addr, s->sll_halen); 908 currif->hwAddrLen = s->sll_halen; 909 } 910 } 911 } 912 913 /* 914 * Finally insert the address on the interface 915 */ 916 if (addrP != NULL) { 917 addrP->next = currif->addr; 918 currif->addr = addrP; 919 } 920 921 parent = currif; 922 923 /** 924 * Let's deal with the virtual interface now. 925 */ 926 if (vname[0]) { 927 netaddr *tmpaddr; 928 929 currif = parent->childs; 930 931 while (currif != NULL) { 932 if (strcmp(vname, currif->name) == 0) { 933 break; 934 } 935 currif = currif->next; 936 } 937 938 if (currif == NULL) { 939 CHECKED_MALLOC3(currif, netif *, sizeof(netif) + sizeof(name)); 940 currif->name = (char *) currif + sizeof(netif); 941 strncpy(currif->name, vname, sizeof(name)); 942 currif->name[sizeof(name) - 1] = '\0'; 943 currif->index = getIndex(sock, vname); 944 currif->addr = NULL; 945 /* Need to duplicate the addr entry? */ 946 currif->virtual = 1; 947 currif->childs = NULL; 948 currif->next = parent->childs; 949 parent->childs = currif; 950 } 951 952 CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr)+2*addr_size); 953 memcpy(tmpaddr, addrP, sizeof(netaddr)); 954 if (addrP->addr != NULL) { 955 tmpaddr->addr = (struct sockaddr *) ( (char*)tmpaddr + sizeof(netaddr) ) ; 956 memcpy(tmpaddr->addr, addrP->addr, addr_size); 957 } 958 959 if (addrP->brdcast != NULL) { 960 tmpaddr->brdcast = (struct sockaddr *) ((char *) tmpaddr + sizeof(netaddr)+addr_size); 961 memcpy(tmpaddr->brdcast, addrP->brdcast, addr_size); 962 } 963 964 tmpaddr->next = currif->addr; 965 currif->addr = tmpaddr; 966 } 967 968 return ifs; 969} 970 971/* Open socket for further ioct calls 972 * proto is AF_INET/AF_INET6 973 */ 974static int openSocket(JNIEnv *env, int proto){ 975 int sock; 976 977 if ((sock = JVM_Socket(proto, SOCK_DGRAM, 0)) < 0) { 978 /* 979 * If EPROTONOSUPPORT is returned it means we don't have 980 * support for this proto so don't throw an exception. 981 */ 982 if (errno != EPROTONOSUPPORT) { 983 NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "Socket creation failed"); 984 } 985 return -1; 986 } 987 988 return sock; 989} 990 991 992/** Linux **/ 993 994/* Open socket for further ioct calls, try v4 socket first and 995 * if it falls return v6 socket 996 */ 997 998static int openSocketWithFallback(JNIEnv *env, const char *ifname){ 999 int sock; 1000 struct ifreq if2; 1001 1002 if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 1003 if (errno == EPROTONOSUPPORT){ 1004 if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){ 1005 NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); 1006 return -1; 1007 } 1008 } 1009 else{ // errno is not NOSUPPORT 1010 NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed"); 1011 return -1; 1012 } 1013 } 1014 1015 /* Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or IPv6 socket regardless of type 1016 of address of an interface */ 1017 1018 return sock; 1019} 1020 1021static int getIndex(int sock, const char *name){ 1022 /* 1023 * Try to get the interface index 1024 * (Not supported on Solaris 2.6 or 7) 1025 */ 1026 struct ifreq if2; 1027 strcpy(if2.ifr_name, name); 1028 1029 if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) { 1030 return -1; 1031 } 1032 1033 return if2.ifr_ifindex; 1034} 1035 1036static int getMTU(JNIEnv *env, int sock, const char *ifname) { 1037 struct ifreq if2; 1038 1039 memset((char *) &if2, 0, sizeof(if2)); 1040 strcpy(if2.ifr_name, ifname); 1041 1042 if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) { 1043 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFMTU failed"); 1044 return -1; 1045 } 1046 1047 return if2.ifr_mtu; 1048} 1049 1050static int getFlags(int sock, const char *ifname, int *flags) { 1051 struct ifreq if2; 1052 1053 memset((char *) &if2, 0, sizeof(if2)); 1054 strcpy(if2.ifr_name, ifname); 1055 1056 if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0){ 1057 return -1; 1058 } 1059 1060 if (sizeof(if2.ifr_flags) == sizeof(short)) { 1061 *flags = (if2.ifr_flags & 0xffff); 1062 } else { 1063 *flags = if2.ifr_flags; 1064 } 1065 return 0; 1066} 1067 1068static JNINativeMethod gMethods[] = { 1069 NATIVE_METHOD(NetworkInterface, getMTU0, "(Ljava/lang/String;I)I"), 1070 NATIVE_METHOD(NetworkInterface, supportsMulticast0, "(Ljava/lang/String;I)Z"), 1071 NATIVE_METHOD(NetworkInterface, isLoopback0, "(Ljava/lang/String;I)Z"), 1072 NATIVE_METHOD(NetworkInterface, isP2P0, "(Ljava/lang/String;I)Z"), 1073 NATIVE_METHOD(NetworkInterface, isUp0, "(Ljava/lang/String;I)Z"), 1074 NATIVE_METHOD(NetworkInterface, getAll, "()[Ljava/net/NetworkInterface;"), 1075 NATIVE_METHOD(NetworkInterface, getByInetAddress0, "(Ljava/net/InetAddress;)Ljava/net/NetworkInterface;"), 1076 NATIVE_METHOD(NetworkInterface, getByIndex0, "(I)Ljava/net/NetworkInterface;"), 1077 NATIVE_METHOD(NetworkInterface, getByName0, "(Ljava/lang/String;)Ljava/net/NetworkInterface;"), 1078 NATIVE_METHOD(NetworkInterface, init, "()V"), 1079 1080}; 1081 1082void register_java_net_NetworkInterface(JNIEnv* env) { 1083 jniRegisterNativeMethods(env, "java/net/NetworkInterface", gMethods, NELEM(gMethods)); 1084} 1085