6161import java .lang .reflect .InvocationTargetException ;
6262import java .lang .reflect .Method ;
6363import java .lang .reflect .Modifier ;
64+ import java .net .Inet4Address ;
65+ import java .net .Inet6Address ;
6466import java .net .InetAddress ;
6567import java .net .NetworkInterface ;
6668import java .net .SocketException ;
69+ import java .net .UnknownHostException ;
6770import java .security .AccessController ;
6871import java .security .PrivilegedAction ;
6972import java .security .PrivilegedExceptionAction ;
7073import java .util .Enumeration ;
7174import java .util .HashMap ;
7275import java .util .Iterator ;
7376import java .util .Map ;
77+ import java .util .List ;
78+ import java .util .ArrayList ;
79+ import java .util .Comparator ;
80+ import java .util .function .Function ;
7481
7582public class Utils {
7683 private static final Log log = LogFactory .getLog (Utils .class );
@@ -569,6 +576,93 @@ public static int getMtomThreshold(MessageContext msgCtxt){
569576 }
570577 return threshold ;
571578 }
579+ /**
580+ * Returns all <code>InetAddress</code> objects encapsulating what are most likely the machine's
581+ * LAN IP addresses. This method was copied from apache-commons-jcs HostNameUtil.java.
582+ * <p>
583+ * This method will scan all IP addresses on all network interfaces on the host machine to
584+ * determine the IP addresses most likely to be the machine's LAN addresses.
585+ * <p>
586+ * @return List<InetAddress>
587+ * @throws IllegalStateException If the LAN address of the machine cannot be found.
588+ */
589+ public static List <InetAddress > getLocalHostLANAddresses () throws SocketException
590+ {
591+ final List <InetAddress > addresses = new ArrayList <>();
592+
593+ try
594+ {
595+ InetAddress candidateAddress = null ;
596+ // Iterate all NICs (network interface cards)...
597+ final Enumeration <NetworkInterface > ifaces = NetworkInterface .getNetworkInterfaces ();
598+ while ( ifaces .hasMoreElements () )
599+ {
600+ final NetworkInterface iface = ifaces .nextElement ();
601+
602+ // Skip loopback interfaces
603+ if (iface .isLoopback () || !iface .isUp ())
604+ {
605+ continue ;
606+ }
607+
608+ // Iterate all IP addresses assigned to each card...
609+ for ( final Enumeration <InetAddress > inetAddrs = iface .getInetAddresses (); inetAddrs .hasMoreElements (); )
610+ {
611+ final InetAddress inetAddr = inetAddrs .nextElement ();
612+ if ( !inetAddr .isLoopbackAddress () )
613+ {
614+ if (!inetAddr .isLinkLocalAddress ())
615+ {
616+ if (inetAddr instanceof Inet6Address ) {
617+ // we ignore the site-local attribute for IPv6 because
618+ // it has been deprecated, see https://www.ietf.org/rfc/rfc3879.txt
619+ addresses .add (inetAddr );
620+ } else if (inetAddr instanceof Inet4Address && inetAddr .isSiteLocalAddress ()) {
621+ // check site-local
622+ addresses .add (inetAddr );
623+ }
624+ }
625+
626+ if ( candidateAddress == null )
627+ {
628+ // Found non-loopback address, but not necessarily site-local.
629+ // Store it as a candidate to be returned if site-local address is not subsequently found...
630+ candidateAddress = inetAddr ;
631+ // Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates,
632+ // only the first. For subsequent iterations, candidate will be non-null.
633+ }
634+ }
635+ }
636+ }
637+ if (candidateAddress != null && addresses .isEmpty ())
638+ {
639+ // We did not find a site-local address, but we found some other non-loopback address.
640+ // Server might have a non-site-local address assigned to its NIC (or it might be running
641+ // IPv6 which deprecates the "site-local" concept).
642+ addresses .add (candidateAddress );
643+ }
644+ // At this point, we did not find a non-loopback address.
645+ // Fall back to returning whatever InetAddress.getLocalHost() returns...
646+ if (addresses .isEmpty ())
647+ {
648+ final InetAddress jdkSuppliedAddress = InetAddress .getLocalHost ();
649+ if ( jdkSuppliedAddress == null )
650+ {
651+ throw new IllegalStateException ( "The JDK InetAddress.getLocalHost() method unexpectedly returned null." );
652+ }
653+ addresses .add (jdkSuppliedAddress );
654+ }
655+ }
656+ catch (UnknownHostException e )
657+ {
658+ var throwable = new SocketException ("Failed to determine LAN address" );
659+ throwable .initCause (e );
660+ throw throwable ;
661+ }
662+
663+ return addresses ;
664+ }
665+
572666 /**
573667 * Returns the ip address to be used for the replyto epr
574668 * CAUTION:
@@ -582,25 +676,13 @@ public static int getMtomThreshold(MessageContext msgCtxt){
582676 * - Obtain the ip to be used here from the Call API
583677 *
584678 * @return Returns String.
585- * @throws java.net.SocketException
586679 */
587680 public static String getIpAddress () throws SocketException {
588- Enumeration e = NetworkInterface .getNetworkInterfaces ();
589- String address = "127.0.0.1" ;
590-
591- while (e .hasMoreElements ()) {
592- NetworkInterface netface = (NetworkInterface ) e .nextElement ();
593- Enumeration addresses = netface .getInetAddresses ();
594-
595- while (addresses .hasMoreElements ()) {
596- InetAddress ip = (InetAddress ) addresses .nextElement ();
597- if (!ip .isLoopbackAddress () && isIP (ip .getHostAddress ())) {
598- return ip .getHostAddress ();
599- }
600- }
601- }
602-
603- return address ;
681+ //prefer ipv4 for backwards compatibility, we used to only consider ipv4 addresses
682+ Function <InetAddress ,Integer > preferIpv4 = (i ) -> i instanceof Inet4Address ? 1 : 0 ;
683+ return getLocalHostLANAddresses ().stream ()
684+ .max (Comparator .comparing (preferIpv4 ))
685+ .map (InetAddress ::getHostAddress ).orElse ("127.0.0.1" );
604686 }
605687
606688 /**
@@ -639,10 +721,6 @@ public static String getHostname(AxisConfiguration axisConfiguration) {
639721 return null ;
640722 }
641723
642- private static boolean isIP (String hostAddress ) {
643- return hostAddress .split ("[.]" ).length == 4 ;
644- }
645-
646724 /**
647725 * Get the scheme part from a URI (or URL).
648726 *
0 commit comments