/*************************************************************************
* 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" ) );
}
}