450 } |
450 } |
451 free(buf); |
451 free(buf); |
452 } |
452 } |
453 } |
453 } |
454 |
454 |
455 #if defined(__linux__) |
455 #if defined(_AIX) |
456 |
|
457 /* following code creates a list of addresses from the kernel |
|
458 * routing table that are routed via the loopback address. |
|
459 * We check all destination addresses against this table |
|
460 * and override the scope_id field to use the relevant value for "lo" |
|
461 * in order to work-around the Linux bug that prevents packets destined |
|
462 * for certain local addresses from being sent via a physical interface. |
|
463 */ |
|
464 |
|
465 struct loopback_route { |
|
466 struct in6_addr addr; /* destination address */ |
|
467 int plen; /* prefix length */ |
|
468 }; |
|
469 |
|
470 static struct loopback_route *loRoutes = 0; |
|
471 static int nRoutes = 0; /* number of routes */ |
|
472 static int loRoutes_size = 16; /* initial size */ |
|
473 static int lo_scope_id = 0; |
|
474 |
|
475 static void initLoopbackRoutes(); |
|
476 |
|
477 void printAddr (struct in6_addr *addr) { |
|
478 int i; |
|
479 for (i=0; i<16; i++) { |
|
480 printf ("%02x", addr->s6_addr[i]); |
|
481 } |
|
482 printf ("\n"); |
|
483 } |
|
484 |
|
485 static jboolean needsLoopbackRoute (struct in6_addr* dest_addr) { |
|
486 int byte_count; |
|
487 int extra_bits, i; |
|
488 struct loopback_route *ptr; |
|
489 |
|
490 if (loRoutes == 0) { |
|
491 initLoopbackRoutes(); |
|
492 } |
|
493 |
|
494 for (ptr = loRoutes, i=0; i<nRoutes; i++, ptr++) { |
|
495 struct in6_addr *target_addr=&ptr->addr; |
|
496 int dest_plen = ptr->plen; |
|
497 byte_count = dest_plen >> 3; |
|
498 extra_bits = dest_plen & 0x3; |
|
499 |
|
500 if (byte_count > 0) { |
|
501 if (memcmp(target_addr, dest_addr, byte_count)) { |
|
502 continue; /* no match */ |
|
503 } |
|
504 } |
|
505 |
|
506 if (extra_bits > 0) { |
|
507 unsigned char c1 = ((unsigned char *)target_addr)[byte_count]; |
|
508 unsigned char c2 = ((unsigned char *)&dest_addr)[byte_count]; |
|
509 unsigned char mask = 0xff << (8 - extra_bits); |
|
510 if ((c1 & mask) != (c2 & mask)) { |
|
511 continue; |
|
512 } |
|
513 } |
|
514 return JNI_TRUE; |
|
515 } |
|
516 return JNI_FALSE; |
|
517 } |
|
518 |
|
519 |
|
520 static void initLoopbackRoutes() { |
|
521 FILE *f; |
|
522 char srcp[8][5]; |
|
523 char hopp[8][5]; |
|
524 int dest_plen, src_plen, use, refcnt, metric; |
|
525 unsigned long flags; |
|
526 char dest_str[40]; |
|
527 struct in6_addr dest_addr; |
|
528 char device[16]; |
|
529 struct loopback_route *loRoutesTemp; |
|
530 |
|
531 if (loRoutes != 0) { |
|
532 free (loRoutes); |
|
533 } |
|
534 loRoutes = calloc (loRoutes_size, sizeof(struct loopback_route)); |
|
535 if (loRoutes == 0) { |
|
536 return; |
|
537 } |
|
538 /* |
|
539 * Scan /proc/net/ipv6_route looking for a matching |
|
540 * route. |
|
541 */ |
|
542 if ((f = fopen("/proc/net/ipv6_route", "r")) == NULL) { |
|
543 return ; |
|
544 } |
|
545 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x " |
|
546 "%4s%4s%4s%4s%4s%4s%4s%4s %02x " |
|
547 "%4s%4s%4s%4s%4s%4s%4s%4s " |
|
548 "%08x %08x %08x %08lx %8s", |
|
549 dest_str, &dest_str[5], &dest_str[10], &dest_str[15], |
|
550 &dest_str[20], &dest_str[25], &dest_str[30], &dest_str[35], |
|
551 &dest_plen, |
|
552 srcp[0], srcp[1], srcp[2], srcp[3], |
|
553 srcp[4], srcp[5], srcp[6], srcp[7], |
|
554 &src_plen, |
|
555 hopp[0], hopp[1], hopp[2], hopp[3], |
|
556 hopp[4], hopp[5], hopp[6], hopp[7], |
|
557 &metric, &use, &refcnt, &flags, device) == 31) { |
|
558 |
|
559 /* |
|
560 * Some routes should be ignored |
|
561 */ |
|
562 if ( (dest_plen < 0 || dest_plen > 128) || |
|
563 (src_plen != 0) || |
|
564 (flags & (RTF_POLICY | RTF_FLOW)) || |
|
565 ((flags & RTF_REJECT) && dest_plen == 0) ) { |
|
566 continue; |
|
567 } |
|
568 |
|
569 /* |
|
570 * Convert the destination address |
|
571 */ |
|
572 dest_str[4] = ':'; |
|
573 dest_str[9] = ':'; |
|
574 dest_str[14] = ':'; |
|
575 dest_str[19] = ':'; |
|
576 dest_str[24] = ':'; |
|
577 dest_str[29] = ':'; |
|
578 dest_str[34] = ':'; |
|
579 dest_str[39] = '\0'; |
|
580 |
|
581 if (inet_pton(AF_INET6, dest_str, &dest_addr) < 0) { |
|
582 /* not an Ipv6 address */ |
|
583 continue; |
|
584 } |
|
585 if (strcmp(device, "lo") != 0) { |
|
586 /* Not a loopback route */ |
|
587 continue; |
|
588 } else { |
|
589 if (nRoutes == loRoutes_size) { |
|
590 loRoutesTemp = realloc (loRoutes, loRoutes_size * |
|
591 sizeof (struct loopback_route) * 2); |
|
592 |
|
593 if (loRoutesTemp == 0) { |
|
594 free(loRoutes); |
|
595 loRoutes = NULL; |
|
596 nRoutes = 0; |
|
597 fclose (f); |
|
598 return; |
|
599 } |
|
600 loRoutes=loRoutesTemp; |
|
601 loRoutes_size *= 2; |
|
602 } |
|
603 memcpy (&loRoutes[nRoutes].addr,&dest_addr,sizeof(struct in6_addr)); |
|
604 loRoutes[nRoutes].plen = dest_plen; |
|
605 nRoutes ++; |
|
606 } |
|
607 } |
|
608 |
|
609 fclose (f); |
|
610 { |
|
611 /* now find the scope_id for "lo" */ |
|
612 |
|
613 char devname[21]; |
|
614 char addr6p[8][5]; |
|
615 int plen, scope, dad_status, if_idx; |
|
616 |
|
617 if ((f = fopen("/proc/net/if_inet6", "r")) != NULL) { |
|
618 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n", |
|
619 addr6p[0], addr6p[1], addr6p[2], addr6p[3], |
|
620 addr6p[4], addr6p[5], addr6p[6], addr6p[7], |
|
621 &if_idx, &plen, &scope, &dad_status, devname) == 13) { |
|
622 |
|
623 if (strcmp(devname, "lo") == 0) { |
|
624 /* |
|
625 * Found - so just return the index |
|
626 */ |
|
627 fclose(f); |
|
628 lo_scope_id = if_idx; |
|
629 return; |
|
630 } |
|
631 } |
|
632 fclose(f); |
|
633 } |
|
634 } |
|
635 } |
|
636 |
|
637 /* |
|
638 * Following is used for binding to local addresses. Equivalent |
|
639 * to code above, for bind(). |
|
640 */ |
|
641 |
|
642 struct localinterface { |
|
643 int index; |
|
644 char localaddr [16]; |
|
645 }; |
|
646 |
|
647 static struct localinterface *localifs = 0; |
|
648 static int localifsSize = 0; /* size of array */ |
|
649 static int nifs = 0; /* number of entries used in array */ |
|
650 |
|
651 /* not thread safe: make sure called once from one thread */ |
|
652 |
|
653 static void initLocalIfs () { |
|
654 FILE *f; |
|
655 unsigned char staddr [16]; |
|
656 char ifname [33]; |
|
657 struct localinterface *lif=0; |
|
658 struct localinterface *localifsTemp; |
|
659 int index, x1, x2, x3; |
|
660 unsigned int u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,ua,ub,uc,ud,ue,uf; |
|
661 |
|
662 if ((f = fopen("/proc/net/if_inet6", "r")) == NULL) { |
|
663 return ; |
|
664 } |
|
665 while (fscanf (f, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x " |
|
666 "%d %x %x %x %32s",&u0,&u1,&u2,&u3,&u4,&u5,&u6,&u7, |
|
667 &u8,&u9,&ua,&ub,&uc,&ud,&ue,&uf, |
|
668 &index, &x1, &x2, &x3, ifname) == 21) { |
|
669 staddr[0] = (unsigned char)u0; |
|
670 staddr[1] = (unsigned char)u1; |
|
671 staddr[2] = (unsigned char)u2; |
|
672 staddr[3] = (unsigned char)u3; |
|
673 staddr[4] = (unsigned char)u4; |
|
674 staddr[5] = (unsigned char)u5; |
|
675 staddr[6] = (unsigned char)u6; |
|
676 staddr[7] = (unsigned char)u7; |
|
677 staddr[8] = (unsigned char)u8; |
|
678 staddr[9] = (unsigned char)u9; |
|
679 staddr[10] = (unsigned char)ua; |
|
680 staddr[11] = (unsigned char)ub; |
|
681 staddr[12] = (unsigned char)uc; |
|
682 staddr[13] = (unsigned char)ud; |
|
683 staddr[14] = (unsigned char)ue; |
|
684 staddr[15] = (unsigned char)uf; |
|
685 nifs ++; |
|
686 if (nifs > localifsSize) { |
|
687 localifsTemp = (struct localinterface *) realloc( |
|
688 localifs, sizeof (struct localinterface)* (localifsSize+5)); |
|
689 if (localifsTemp == 0) { |
|
690 free(localifs); |
|
691 localifs = 0; |
|
692 localifsSize = 0; |
|
693 nifs = 0; |
|
694 fclose(f); |
|
695 return; |
|
696 } |
|
697 localifs = localifsTemp; |
|
698 lif = localifs + localifsSize; |
|
699 localifsSize += 5; |
|
700 } else { |
|
701 lif ++; |
|
702 } |
|
703 memcpy (lif->localaddr, staddr, 16); |
|
704 lif->index = index; |
|
705 } |
|
706 fclose (f); |
|
707 } |
|
708 |
|
709 /* return the scope_id (interface index) of the |
|
710 * interface corresponding to the given address |
|
711 * returns 0 if no match found |
|
712 */ |
|
713 |
|
714 static int getLocalScopeID (char *addr) { |
|
715 struct localinterface *lif; |
|
716 int i; |
|
717 if (localifs == 0) { |
|
718 initLocalIfs(); |
|
719 } |
|
720 for (i=0, lif=localifs; i<nifs; i++, lif++) { |
|
721 if (memcmp (addr, lif->localaddr, 16) == 0) { |
|
722 return lif->index; |
|
723 } |
|
724 } |
|
725 return 0; |
|
726 } |
|
727 |
|
728 void platformInit () { |
|
729 initLoopbackRoutes(); |
|
730 initLocalIfs(); |
|
731 } |
|
732 |
|
733 #elif defined(_AIX) |
|
734 |
456 |
735 /* Initialize stubs for blocking I/O workarounds (see src/solaris/native/java/net/linux_close.c) */ |
457 /* Initialize stubs for blocking I/O workarounds (see src/solaris/native/java/net/linux_close.c) */ |
736 extern void aix_close_init(); |
458 extern void aix_close_init(); |
737 |
459 |
738 void platformInit () { |
460 void platformInit () { |
814 sa->sa6.sin6_family = AF_INET6; |
536 sa->sa6.sin6_family = AF_INET6; |
815 if (len != NULL) { |
537 if (len != NULL) { |
816 *len = sizeof(struct sockaddr_in6); |
538 *len = sizeof(struct sockaddr_in6); |
817 } |
539 } |
818 |
540 |
819 #ifdef __linux__ |
|
820 /* |
|
821 * On Linux if we are connecting to a link-local address |
|
822 * we need to specify the interface in the scope_id (2.4 kernel only) |
|
823 * |
|
824 * If the scope was cached then we use the cached value. If not cached but |
|
825 * specified in the Inet6Address we use that, but we first check if the |
|
826 * address needs to be routed via the loopback interface. In this case, |
|
827 * we override the specified value with that of the loopback interface. |
|
828 * If no cached value exists and no value was specified by user, then |
|
829 * we try to determine a value from the routing table. In all these |
|
830 * cases the used value is cached for further use. |
|
831 */ |
|
832 if (IN6_IS_ADDR_LINKLOCAL(&sa->sa6.sin6_addr)) { |
|
833 unsigned int cached_scope_id = 0, scope_id = 0; |
|
834 |
|
835 if (ia6_cachedscopeidID) { |
|
836 cached_scope_id = (int)(*env)->GetIntField(env, iaObj, ia6_cachedscopeidID); |
|
837 /* if cached value exists then use it. Otherwise, check |
|
838 * if scope is set in the address. |
|
839 */ |
|
840 if (!cached_scope_id) { |
|
841 if (ia6_scopeidID) { |
|
842 scope_id = getInet6Address_scopeid(env, iaObj); |
|
843 } |
|
844 if (scope_id != 0) { |
|
845 /* check user-specified value for loopback case |
|
846 * that needs to be overridden |
|
847 */ |
|
848 if (kernelIsV24() && needsLoopbackRoute(&sa->sa6.sin6_addr)) { |
|
849 cached_scope_id = lo_scope_id; |
|
850 (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id); |
|
851 } |
|
852 } else { |
|
853 /* |
|
854 * Otherwise consult the IPv6 routing tables to |
|
855 * try determine the appropriate interface. |
|
856 */ |
|
857 if (kernelIsV24()) { |
|
858 cached_scope_id = getDefaultIPv6Interface(&sa->sa6.sin6_addr); |
|
859 } else { |
|
860 cached_scope_id = getLocalScopeID((char *)&(sa->sa6.sin6_addr)); |
|
861 if (cached_scope_id == 0) { |
|
862 cached_scope_id = getDefaultIPv6Interface(&sa->sa6.sin6_addr); |
|
863 } |
|
864 } |
|
865 (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id); |
|
866 } |
|
867 } |
|
868 } |
|
869 |
|
870 /* |
|
871 * If we have a scope_id use the extended form |
|
872 * of sockaddr_in6. |
|
873 */ |
|
874 sa->sa6.sin6_scope_id = cached_scope_id == 0 ? scope_id : cached_scope_id; |
|
875 } |
|
876 #else |
|
877 /* handle scope_id */ |
541 /* handle scope_id */ |
878 if (family != java_net_InetAddress_IPv4) { |
542 if (family != java_net_InetAddress_IPv4) { |
879 if (ia6_scopeidID) { |
543 if (ia6_scopeidID) { |
880 sa->sa6.sin6_scope_id = getInet6Address_scopeid(env, iaObj); |
544 sa->sa6.sin6_scope_id = getInet6Address_scopeid(env, iaObj); |
881 } |
545 } |
882 } |
546 } |
883 #endif |
|
884 } else { |
547 } else { |
885 jint address; |
548 jint address; |
886 if (family != java_net_InetAddress_IPv4) { |
549 if (family != java_net_InetAddress_IPv4) { |
887 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable"); |
550 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable"); |
888 return -1; |
551 return -1; |
1013 /* not found */ |
676 /* not found */ |
1014 return -1; |
677 return -1; |
1015 } |
678 } |
1016 |
679 |
1017 /* |
680 /* |
1018 * Determine the default interface for an IPv6 address. |
|
1019 * |
|
1020 * 1. Scans /proc/net/ipv6_route for a matching route |
|
1021 * (eg: fe80::/10 or a route for the specific address). |
|
1022 * This will tell us the interface to use (eg: "eth0"). |
|
1023 * |
|
1024 * 2. Lookup /proc/net/if_inet6 to map the interface |
|
1025 * name to an interface index. |
|
1026 * |
|
1027 * Returns :- |
|
1028 * -1 if error |
|
1029 * 0 if no matching interface |
|
1030 * >1 interface index to use for the link-local address. |
|
1031 */ |
|
1032 #if defined(__linux__) |
|
1033 int getDefaultIPv6Interface(struct in6_addr *target_addr) { |
|
1034 FILE *f; |
|
1035 char srcp[8][5]; |
|
1036 char hopp[8][5]; |
|
1037 int dest_plen, src_plen, use, refcnt, metric; |
|
1038 unsigned long flags; |
|
1039 char dest_str[40]; |
|
1040 struct in6_addr dest_addr; |
|
1041 char device[16]; |
|
1042 jboolean match = JNI_FALSE; |
|
1043 |
|
1044 /* |
|
1045 * Scan /proc/net/ipv6_route looking for a matching |
|
1046 * route. |
|
1047 */ |
|
1048 if ((f = fopen("/proc/net/ipv6_route", "r")) == NULL) { |
|
1049 return -1; |
|
1050 } |
|
1051 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x " |
|
1052 "%4s%4s%4s%4s%4s%4s%4s%4s %02x " |
|
1053 "%4s%4s%4s%4s%4s%4s%4s%4s " |
|
1054 "%08x %08x %08x %08lx %8s", |
|
1055 dest_str, &dest_str[5], &dest_str[10], &dest_str[15], |
|
1056 &dest_str[20], &dest_str[25], &dest_str[30], &dest_str[35], |
|
1057 &dest_plen, |
|
1058 srcp[0], srcp[1], srcp[2], srcp[3], |
|
1059 srcp[4], srcp[5], srcp[6], srcp[7], |
|
1060 &src_plen, |
|
1061 hopp[0], hopp[1], hopp[2], hopp[3], |
|
1062 hopp[4], hopp[5], hopp[6], hopp[7], |
|
1063 &metric, &use, &refcnt, &flags, device) == 31) { |
|
1064 |
|
1065 /* |
|
1066 * Some routes should be ignored |
|
1067 */ |
|
1068 if ( (dest_plen < 0 || dest_plen > 128) || |
|
1069 (src_plen != 0) || |
|
1070 (flags & (RTF_POLICY | RTF_FLOW)) || |
|
1071 ((flags & RTF_REJECT) && dest_plen == 0) ) { |
|
1072 continue; |
|
1073 } |
|
1074 |
|
1075 /* |
|
1076 * Convert the destination address |
|
1077 */ |
|
1078 dest_str[4] = ':'; |
|
1079 dest_str[9] = ':'; |
|
1080 dest_str[14] = ':'; |
|
1081 dest_str[19] = ':'; |
|
1082 dest_str[24] = ':'; |
|
1083 dest_str[29] = ':'; |
|
1084 dest_str[34] = ':'; |
|
1085 dest_str[39] = '\0'; |
|
1086 |
|
1087 if (inet_pton(AF_INET6, dest_str, &dest_addr) < 0) { |
|
1088 /* not an Ipv6 address */ |
|
1089 continue; |
|
1090 } else { |
|
1091 /* |
|
1092 * The prefix len (dest_plen) indicates the number of bits we |
|
1093 * need to match on. |
|
1094 * |
|
1095 * dest_plen / 8 => number of bytes to match |
|
1096 * dest_plen % 8 => number of additional bits to match |
|
1097 * |
|
1098 * eg: fe80::/10 => match 1 byte + 2 additional bits in the |
|
1099 * next byte. |
|
1100 */ |
|
1101 int byte_count = dest_plen >> 3; |
|
1102 int extra_bits = dest_plen & 0x3; |
|
1103 |
|
1104 if (byte_count > 0) { |
|
1105 if (memcmp(target_addr, &dest_addr, byte_count)) { |
|
1106 continue; /* no match */ |
|
1107 } |
|
1108 } |
|
1109 |
|
1110 if (extra_bits > 0) { |
|
1111 unsigned char c1 = ((unsigned char *)target_addr)[byte_count]; |
|
1112 unsigned char c2 = ((unsigned char *)&dest_addr)[byte_count]; |
|
1113 unsigned char mask = 0xff << (8 - extra_bits); |
|
1114 if ((c1 & mask) != (c2 & mask)) { |
|
1115 continue; |
|
1116 } |
|
1117 } |
|
1118 |
|
1119 /* |
|
1120 * We have a match |
|
1121 */ |
|
1122 match = JNI_TRUE; |
|
1123 break; |
|
1124 } |
|
1125 } |
|
1126 fclose(f); |
|
1127 |
|
1128 /* |
|
1129 * If there's a match then we lookup the interface |
|
1130 * index. |
|
1131 */ |
|
1132 if (match) { |
|
1133 char devname[21]; |
|
1134 char addr6p[8][5]; |
|
1135 int plen, scope, dad_status, if_idx; |
|
1136 |
|
1137 if ((f = fopen("/proc/net/if_inet6", "r")) != NULL) { |
|
1138 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n", |
|
1139 addr6p[0], addr6p[1], addr6p[2], addr6p[3], |
|
1140 addr6p[4], addr6p[5], addr6p[6], addr6p[7], |
|
1141 &if_idx, &plen, &scope, &dad_status, devname) == 13) { |
|
1142 |
|
1143 if (strcmp(devname, device) == 0) { |
|
1144 /* |
|
1145 * Found - so just return the index |
|
1146 */ |
|
1147 fclose(f); |
|
1148 return if_idx; |
|
1149 } |
|
1150 } |
|
1151 fclose(f); |
|
1152 } else { |
|
1153 /* |
|
1154 * Couldn't open /proc/net/if_inet6 |
|
1155 */ |
|
1156 return -1; |
|
1157 } |
|
1158 } |
|
1159 |
|
1160 /* |
|
1161 * If we get here it means we didn't there wasn't any |
|
1162 * route or we couldn't get the index of the interface. |
|
1163 */ |
|
1164 return 0; |
|
1165 } |
|
1166 #endif |
|
1167 |
|
1168 |
|
1169 /* |
|
1170 * Wrapper for getsockopt system routine - does any necessary |
681 * Wrapper for getsockopt system routine - does any necessary |
1171 * pre/post processing to deal with OS specific oddities :- |
682 * pre/post processing to deal with OS specific oddities :- |
1172 * |
683 * |
1173 * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed |
684 * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed |
1174 * to compensate for an incorrect value returned by the kernel. |
685 * to compensate for an incorrect value returned by the kernel. |