/************************************************************************* * Copyright 2009-2012 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. * * This file may incorporate work covered under the following copyright * and permission notice: * * Software License Agreement (BSD License) * * Copyright (c) 2008, Regents of the University of California * All rights reserved. * * Redistribution and use of this software in source and binary forms, * with or without modification, are permitted provided that the * following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. USERS OF THIS SOFTWARE ACKNOWLEDGE * THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE LICENSED MATERIAL, * COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS SOFTWARE, * AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING * IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, * SANTA BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, * WHICH IN THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION, * REPLACEMENT OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO * IDENTIFIED, OR WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT * NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS. ************************************************************************/ package com.eucalyptus.util; import java.io.IOException; import java.io.Serializable; import java.net.Inet4Address; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.log4j.Logger; import com.eucalyptus.bootstrap.BootstrapArgs; import com.eucalyptus.records.Logs; import com.eucalyptus.scripting.Groovyness; import com.eucalyptus.scripting.ScriptExecutionFailedException; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.net.InetAddresses; import static com.eucalyptus.util.Parameters.checkParam; import static org.hamcrest.Matchers.notNullValue; public class Internets { private static Logger LOG = Logger.getLogger( Internets.class ); private static final ConcurrentMap<String, InetAddress> localHostAddrList = new ConcurrentHashMap<String, InetAddress>( ); private static final InetAddress localHostAddr = determineLocalAddress( ); private static final String localId = localHostIdentifier( ); // public static List<InetAddress> localInetAddresses( ) { // return localHostAddrList; // } // public static boolean isReachable( InetAddress addr, int timeoutMillis ) throws IOException { // try { // timeoutMillis = timeoutMillis / 1000; // return ( Boolean ) Groovyness.eval( String.format( "ret = \"/bin/ping -W %d -c 1 %s\".execute( ); ret.waitFor(); ret.exitValue() == 0;", // timeoutMillis, // addr.getHostAddress( ) ) ); // } catch ( ScriptExecutionFailedException ex ) { // Logs.extreme( ).error( ex, ex ); return addr.isReachable( timeoutMillis ); // } } private static InetAddress determineLocalAddress( ) { InetAddress laddr = null; LOG.info( "Trying to determine local bind address based on cli (--bind-addr)... " ); if ( !BootstrapArgs.bindAddresses( ).isEmpty( ) ) { laddr = lookupBindAddresses( ); } if ( laddr == null ) { LOG.info( "Trying to determine local bind address based on the default route... " ); laddr = lookupDefaultRoute( ); } if ( laddr == null ) { LOG.info( "Trying to determine local bind address based on a netmask and scope maximizing heuristic... " ); laddr = Internets.getAllInetAddresses( ).get( 0 ); } LOG.info( "==> Decided to use local bind address: " + laddr ); System.setProperty( "bind_addr", laddr.getHostAddress( ) ); System.setProperty( "bind.address", laddr.getHostAddress( ) ); System.setProperty( "jgroups.bind_addr", laddr.getHostAddress( ) ); System.setProperty( "jgroups.udp.bind_addr", laddr.getHostAddress( ) ); return laddr; } private static InetAddress lookupDefaultRoute( ) { InetAddress laddr = null; try { String localAddr = ( String ) Groovyness.eval( "hi=\"/sbin/ip -o route get 4.2.2.1\".execute();hi.waitFor();hi.text" ); String[] parts = localAddr.replaceAll( ".*src *", "" ).split( " " ); if ( parts.length >= 1 ) { laddr = InetAddresses.forString( parts[0] ); } } catch ( ScriptExecutionFailedException ex ) { LOG.error( ex ); Logs.extreme( ).error( ex, ex ); } catch ( Exception ex ) { LOG.error( ex ); Logs.extreme( ).error( ex, ex ); } return laddr; } private static InetAddress lookupBindAddresses( ) { InetAddress laddr = null; List<InetAddress> locallyBoundAddrs = Internets.getAllInetAddresses( ); boolean err = false; for ( String addrStr : BootstrapArgs.bindAddresses( ) ) { try { InetAddress next = InetAddress.getByName( addrStr ); laddr = ( laddr == null ) ? next : laddr; NetworkInterface iface = NetworkInterface.getByInetAddress( next ); if ( locallyBoundAddrs.contains( InetAddress.getByName( addrStr ) ) ) { localHostAddrList.put( next.getHostAddress( ), next ); LOG.info( "Identified local bind address: " + addrStr + " on interface " + iface.toString( ) ); } else { LOG.error( "Failed to find specified --bind-addr=" + addrStr + " as it is not bound to a local interface.\n Known addresses are: " + Joiner.on( ", " ).join( locallyBoundAddrs ) ); } } catch ( UnknownHostException ex ) { LOG.fatal( "Invalid argument given for --bind-addr=" + addrStr + " " + ex.getMessage( ) ); LOG.error( ex, ex ); err = true; } catch ( SocketException ex ) { LOG.fatal( "Invalid argument given for --bind-addr=" + addrStr + " " + ex.getMessage( ) ); LOG.error( ex, ex ); err = true; } if ( err ) { System.exit( 1 );//GRZE: special case, failed to determine bind address } } return laddr; } public static InetAddress loopback( ) { try { return InetAddress.getByName( "127.0.0.1" ); } catch ( UnknownHostException ex ) { for ( InetAddress i : getAllInetAddresses( ) ) { if ( i.isLoopbackAddress( ) ) { return i; } } return localHostInetAddress( ); } } public static InetAddress any( ) { return InetAddresses.fromInteger( 0 ); } public static InetAddress localHostInetAddress( ) { return localHostAddr; } public static String localHostAddress( ) { return localHostInetAddress( ).getHostAddress( ); } public static String localHostIdentifier( ) { return localId != null ? localId : localHostInetAddress( ).getHostAddress( ); } public static List<NetworkInterface> getNetworkInterfaces( ) { try { List<NetworkInterface> ifaces = Collections.list( NetworkInterface.getNetworkInterfaces( ) ); ifaces = Lists.newArrayList( Iterables.filter( ifaces, new Predicate<NetworkInterface>( ) { @Override public boolean apply( NetworkInterface input ) { return !input.getName( ).contains( "virbr0" ) && !input.getDisplayName( ).contains( "virbr0" ); } } ) ); Collections.sort( ifaces, new Comparator<NetworkInterface>( ) { @Override public int compare( NetworkInterface o1, NetworkInterface o2 ) { int min1 = 0; int min2 = 0; for ( InterfaceAddress ifaceAddr : o1.getInterfaceAddresses( ) ) { min1 = ( min1 > ifaceAddr.getNetworkPrefixLength( ) ? ifaceAddr.getNetworkPrefixLength( ) : min1 ); } for ( InterfaceAddress ifaceAddr : o2.getInterfaceAddresses( ) ) { min2 = ( min2 > ifaceAddr.getNetworkPrefixLength( ) ? ifaceAddr.getNetworkPrefixLength( ) : min2 ); } return min2 - min1;//return a positive int when min1 has a shorter routing prefix } } ); return ifaces; } catch ( SocketException ex ) { LOG.error( ex, ex ); throw new RuntimeException( "Getting list of network interfaces failed because of " + ex.getMessage( ), ex ); } } public static List<InetAddress> getAllInetAddresses( ) { List<InetAddress> addrs = Lists.newArrayList( ); for ( NetworkInterface iface : Internets.getNetworkInterfaces( ) ) { try { if ( iface.isPointToPoint( ) ) { continue; } } catch ( SocketException ex ) { LOG.error( ex, ex ); } for ( InterfaceAddress iaddr : iface.getInterfaceAddresses( ) ) { InetAddress addr = iaddr.getAddress( ); if ( addr instanceof Inet4Address ) { if ( !addr.isMulticastAddress( ) && !addr.isLoopbackAddress( ) && !addr.isLinkLocalAddress( ) && !addr.isSiteLocalAddress( ) && !addr.getHostAddress( ).contains( "192.168.122." ) ) { addrs.add( addr ); } } } for ( InterfaceAddress iaddr : iface.getInterfaceAddresses( ) ) { InetAddress addr = iaddr.getAddress( ); if ( addr instanceof Inet4Address ) { if ( !addr.isMulticastAddress( ) && !addr.isLoopbackAddress( ) && !addr.isLinkLocalAddress( ) && !addrs.contains( addr.getHostAddress( ) ) && !addr.getHostAddress( ).contains( "192.168.122." ) ) { addrs.add( addr ); } } } } return addrs; } public static List<String> getAllAddresses( ) { return Lists.transform( Internets.getAllInetAddresses( ), new Function<InetAddress, String>( ) { @Override public String apply( InetAddress arg0 ) { return arg0.getHostAddress( ); } } ); } public static class Inet4AddressComparator implements Comparator<InetAddress>, Serializable { private static final long serialVersionUID = 1L; @Override public int compare( InetAddress o1, InetAddress o2 ) { return o1.getHostAddress( ).compareTo( o2.getHostAddress( ) ); } } public static final Comparator<InetAddress> INET_ADDRESS_COMPARATOR = new Inet4AddressComparator( ); public static boolean testReachability( InetAddress inetAddr ) { checkParam( "BUG: inetAddr is null.", inetAddr, notNullValue() ); try { return inetAddr.isReachable( 10000 ); } catch ( IOException ex ) { LOG.error( ex, ex ); return false; }//TODO:GRZE:make reachability time tuneable } public static boolean testReachability( String addr ) { checkParam( "BUG: addr is null.", addr, notNullValue() ); try { InetAddress inetAddr = Inet4Address.getByName( addr ); return testReachability( inetAddr ); } catch ( UnknownHostException ex ) { LOG.error( ex, ex ); return false; } } public static InetAddress toAddress( URI uri ) { checkParam( "BUG: uri is null.", uri, notNullValue() ); try { return InetAddress.getByName( uri.getHost( ) ); } catch ( UnknownHostException e ) { throw Exceptions.toUndeclared( "Failed to resolve address for host: " + uri.getHost( ), e ); } } public static InetAddress toAddress( String maybeUrlMaybeHostname ) { checkParam( "BUG: maybeUrlMaybeHostname is null.", maybeUrlMaybeHostname, notNullValue() ); if ( maybeUrlMaybeHostname.startsWith( "vm:" ) ) { maybeUrlMaybeHostname = "localhost"; } URI uri = null; String hostAddress = null; try { uri = new URI( maybeUrlMaybeHostname ); hostAddress = uri.getHost( ); } catch ( URISyntaxException e ) { hostAddress = maybeUrlMaybeHostname; } InetAddress ret = null; try { ret = InetAddress.getByName( hostAddress ); } catch ( UnknownHostException e1 ) { Exceptions.error( "Failed to resolve address for host: " + maybeUrlMaybeHostname, e1 ); } return ret; } public static boolean testLocal( final InetAddress addr ) { if ( addr == null ) return true; try { Boolean result = addr.isAnyLocalAddress( ); result |= Iterables.any( Internets.getNetworkInterfaces( ), new Predicate<NetworkInterface>( ) { @Override public boolean apply( NetworkInterface arg0 ) { return Iterables.any( arg0.getInterfaceAddresses( ), new Predicate<InterfaceAddress>( ) { @Override public boolean apply( InterfaceAddress arg0 ) { return arg0.getAddress( ).equals( addr ); } } ); } } ); return result; } catch ( Exception e ) { // Exceptions.eat( e.getMessage( ), e ); return false; } } public static boolean testLocal( String address ) { if ( address == null ) return true; InetAddress addr; try { addr = InetAddress.getByName( address ); return testLocal( addr ); } catch ( UnknownHostException e ) { LOG.error( e.getMessage( ) ); return address.endsWith( "Internal" ); } } public static boolean testGoodAddress( String address ) throws Exception { InetAddress addr = InetAddress.getByName( address ); LOG.debug( addr + " site=" + addr.isSiteLocalAddress( ) ); LOG.debug( addr + " any=" + addr.isAnyLocalAddress( ) ); LOG.debug( addr + " loop=" + addr.isLoopbackAddress( ) ); LOG.debug( addr + " link=" + addr.isLinkLocalAddress( ) ); LOG.debug( addr + " multi=" + addr.isMulticastAddress( ) ); return addr.isSiteLocalAddress( ) || ( !addr.isAnyLocalAddress( ) && !addr.isLoopbackAddress( ) && !addr.isLinkLocalAddress( ) && !addr.isMulticastAddress( ) ); } private static void addAddress(Set<String> out, InetAddress addr) { if (addr instanceof Inet4Address && !addr.isMulticastAddress() && !addr.isLinkLocalAddress() && !addr.isLoopbackAddress()) { out.add(addr.getCanonicalHostName()); out.add(addr.getHostName()); out.add(addr.getHostAddress()); } } private static void addName(Set<String> out, String name) { try { for (InetAddress addr : InetAddress.getAllByName(name)) { addAddress(out, addr); } } catch (UnknownHostException uhe) { LOG.error("Failed to get addresses for name " + name + ": " + uhe, uhe); } } public static Set<String> getAllLocalHostNamesIps() { Set<String> results = new HashSet<String>(); try { InetAddress localHost = InetAddress.getLocalHost(); addAddress(results, localHost); addName(results, localHost.getCanonicalHostName()); addName(results, localHost.getHostName()); } catch (UnknownHostException uhe) { LOG.error("Failed to get localhost: " + uhe, uhe); } try { Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); if (ifaces != null) { while (ifaces.hasMoreElements()) { NetworkInterface iface = ifaces.nextElement(); Enumeration<InetAddress> addrs = iface.getInetAddresses(); if (addrs != null) { while (addrs.hasMoreElements()) { addAddress(results, addrs.nextElement()); } } } } } catch (SocketException se) { LOG.error("Failed to get all network interfaces: " + se); } return results; } public static Optional<Cidr> getInterfaceCidr( final InetAddress address ) { try { final NetworkInterface networkInterface = NetworkInterface.getByInetAddress( address ); if(networkInterface==null) return Optional.absent(); for ( final InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses( ) ) { if ( address.equals( interfaceAddress.getAddress( ) ) ) { final int prefix = interfaceAddress.getNetworkPrefixLength( ); return Optional.of( Cidr.fromAddress( address, prefix ) ); } } } catch ( SocketException e ) { LOG.debug("Error finding interface CIDR for address '"+address+"'", e ); } return Optional.absent( ); } public static Function<InetAddress,Optional<Cidr>> interfaceCidr( ) { return InetAddressToCidr.INSTANCE; } private enum InetAddressToCidr implements Function<InetAddress,Optional<Cidr>> { INSTANCE; @Override public Optional<Cidr> apply( final InetAddress address ) { return getInterfaceCidr( address ); } } public static void main( String[] args ) throws Exception { for ( String addr : Internets.getAllAddresses( ) ) { System.out.println( addr ); } for ( String addr : Internets.getAllLocalHostNamesIps() ) { System.out.println( "Address: " + addr ); } System.out.println( "Testing if 192.168.7.8 is reachable: " + Internets.testReachability( "192.168.7.8" ) ); } }