package com.voxeo.moho.common.util; import java.io.IOException; import java.io.OutputStream; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.MulticastSocket; import java.net.NetworkInterface; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.List; import javax.management.ObjectName; import org.apache.log4j.Logger; public class NetworkUtils { private static final Logger log = Logger.getLogger(NetworkUtils.class); public static final String MAGIC_COOKIE = "gdg638463"; public static final byte[] MAGIC_COOKIE_BIN = MAGIC_COOKIE.getBytes(); private static boolean IPV6_SUPPORTED = false; private static boolean IPV4_SUPPORTED = false; private static InetAddress LOCAL_ADDRESS = null; private static InetAddress LOCAL_ADDRESS_V4 = null; private static InetAddress LOCAL_ADDRESS_V6 = null; private static final String LOOPBACK_ADDRESS_V4 = "127.0.0.1"; private static final String LOOPBACK_ADDRESS_V6 = "0:0:0:0:0:0:0:1"; private static final String LOOPBACK_ADDRESS_V6_ABBR = "::1"; private static final String ANY_ADDRESS_V4 = "0.0.0.0"; private static final String ANY_ADDRESS_V6 = "0:0:0:0:0:0:0:0"; private static final String ANY_ADDRESS_V6_ABBR = "::"; private static final InetAddress MOCK_ADDRESS_V4_INET = translateAddress("1.1.1.1"); private static final InetAddress MOCK_ADDRESS_V6_INET = translateAddress("1:1:1:1:1:1:1:1"); private static final InetAddress LOOPBACK_ADDRESS_V4_INET = translateAddress(LOOPBACK_ADDRESS_V4); private static final InetAddress LOOPBACK_ADDRESS_V6_INET = translateAddress(LOOPBACK_ADDRESS_V6); private static final InetAddress ANY_ADDRESS_V4_INET = translateAddress(ANY_ADDRESS_V4); private static final InetAddress ANY_ADDRESS_V6_INET = translateAddress(ANY_ADDRESS_V6); private static final String[] ANY_ADDRESS_LIST = {ANY_ADDRESS_V4, ANY_ADDRESS_V6, ANY_ADDRESS_V6_ABBR, "[" + ANY_ADDRESS_V6 + "]", "[" + ANY_ADDRESS_V6_ABBR + "]"}; private static final String[] LOOPBACK_ADDRESS_LIST = {LOOPBACK_ADDRESS_V4, LOOPBACK_ADDRESS_V6, LOOPBACK_ADDRESS_V6_ABBR, "[" + LOOPBACK_ADDRESS_V6 + "]", "[" + LOOPBACK_ADDRESS_V6_ABBR + "]"}; static { resetAddressCache(); } public static boolean isIPAddress(final String addr) { return isIPv4Address(addr) || isIPv6Address(addr); } public static boolean isIPv4Address(final String addr) { if (addr == null || addr.length() == 0) { return false; } final String[] st = StringUtils.split(addr, "."); if (st.length != 4) { return false; } final int a1 = StringUtils.select(st[0], 256); final int a2 = StringUtils.select(st[1], 256); final int a3 = StringUtils.select(st[2], 256); final int a4 = StringUtils.select(st[3], 256); return a1 != -1 && a2 != -1 && a3 != -1 && a4 != -1; } public static boolean isIPv6Address(final String addr) { return !Checker.isEmpty(addr) && sun.net.util.IPAddressUtil.isIPv6LiteralAddress(addr); } public static boolean isIPv6Possible(final String addr) { if (addr == null || addr.length() == 0) { return false; } // return sun.net.util.IPAddressUtil.isIPv6LiteralAddress(addr); if (addr.charAt(0) == '[') { return true; } final int index = addr.indexOf(':'); return index != -1 && addr.indexOf(':', index + 1) != -1; } public static boolean isIPv6Address(final InetAddress addr) { return addr != null && addr instanceof Inet6Address; } public static boolean isIPv4Address(final InetAddress addr) { return addr != null && addr instanceof Inet4Address; } public static boolean isAnyAddress(final String addr) { for (final String s : ANY_ADDRESS_LIST) { if (s.equals(addr)) { return true; } } return false; } public static boolean isLoopbackAddress(final String addr) { for (final String s : LOOPBACK_ADDRESS_LIST) { if (s.equals(addr)) { return true; } } return false; } public static boolean isMulticastAddress(final String addr) { try { return InetAddress.getByName(addr).isMulticastAddress(); } catch (final UnknownHostException e) { return false; } } public static boolean isAvailableIPAddress(final String addr) { return isAvailableIPAddress(NetworkUtils.translateAddress(addr)); } public static boolean isAvailableIPAddress(final InetAddress addr) { return addr != null && !addr.isLoopbackAddress() && !addr.isAnyLocalAddress() && !addr.isLinkLocalAddress() && !addr.isMulticastAddress(); } public static boolean isSupportIPv6() { return IPV6_SUPPORTED; } public static boolean isSupportIPv4() { return IPV4_SUPPORTED; } public static String getPreferAnyAddress() { String retval; if (isSupportIPv6()) { retval = ANY_ADDRESS_V6; } else { retval = ANY_ADDRESS_V4; } return retval; } public static String getPreferLoopbackAddress() { String retval; if (isSupportIPv4()) { retval = LOOPBACK_ADDRESS_V4; } else { retval = LOOPBACK_ADDRESS_V6; } return retval; } // public static String getPreferLocalAddress(){ // // } public static String getLoopbackAddress(final boolean isIPv6) { return isIPv6 ? LOOPBACK_ADDRESS_V6 : LOOPBACK_ADDRESS_V4; } public static List<InetAddress> getAvailableLocalAddresses() { final List<InetAddress> retval = new ArrayList<InetAddress>(); try { final Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces(); while (networkInterfaces.hasMoreElements()) { final Enumeration<InetAddress> addrs = networkInterfaces.nextElement().getInetAddresses(); while (addrs.hasMoreElements()) { final InetAddress addr = addrs.nextElement(); if (isAvailableIPAddress(addr)) { retval.add(0, addr); } } } } catch (final IOException e) { log.warn("NetworkInterfaces: " + getAllNetworkInterfaces(), e); } return retval; } public static InetAddress getAvailableLocalAddressForRemote(final InetAddress remote) { InetAddress retval = null; try { final DatagramSocket socket = new DatagramSocket(); socket.connect(new InetSocketAddress(remote, 5060)); retval = socket.getLocalAddress(); if (!isAvailableIPAddress(retval)) { retval = null; } socket.close(); } catch (final Exception e) { // ignore } return retval; } public static InetAddress getLocalAddress(final InetAddress baseLocalAddress, final boolean automaticBaseLocalAddress, final InetAddress comparableAddress) { InetAddress retval; if (baseLocalAddress == null || baseLocalAddress.isAnyLocalAddress()) { if (isIPv4Address(baseLocalAddress)) { retval = getLocalAddress(false); } else if (comparableAddress == null) { if (baseLocalAddress == null || automaticBaseLocalAddress) { retval = getLocalAddress(); } else { retval = getLocalAddress(true); } } else { if (isIPv6Address(comparableAddress) && isSupportIPv6()) { retval = getLocalAddress(true); } else if (isIPv4Address(comparableAddress) && isSupportIPv4()) { retval = getLocalAddress(false); } else { retval = getLocalAddress(); } } } else { retval = baseLocalAddress; } return retval; } public static InetAddress getLocalAddress() { if (LOCAL_ADDRESS == null) { LOCAL_ADDRESS = getRealtimeLocalAddress(); } return LOCAL_ADDRESS; } public static InetAddress getLocalAddress(final boolean isIPv6) { if (isIPv6) { if (LOCAL_ADDRESS_V6 == null) { LOCAL_ADDRESS_V6 = getRealtimeV6LocalAddress(true); } return LOCAL_ADDRESS_V6; } else { if (LOCAL_ADDRESS_V4 == null) { LOCAL_ADDRESS_V4 = getRealtimeV4LocalAddress(); } return LOCAL_ADDRESS_V4; } } public static void resetAddressCache() { checkProtocolFamily(); if (LOCAL_ADDRESS_V6 != null) { LOCAL_ADDRESS_V6 = getRealtimeV6LocalAddress(true); } if (LOCAL_ADDRESS_V4 != null) { LOCAL_ADDRESS_V4 = getRealtimeV4LocalAddress(); } if (LOCAL_ADDRESS != null) { LOCAL_ADDRESS = getRealtimeLocalAddress(); } } public static Collection<NetworkInterface> getAllNetworkInterfaces() { final Collection<NetworkInterface> retval = new ArrayList<NetworkInterface>(); try { final Enumeration<NetworkInterface> list = NetworkInterface.getNetworkInterfaces(); while (list.hasMoreElements()) { retval.add(list.nextElement()); } } catch (final Throwable t) { log.warn("", t); } return retval; } public static String translateAddress(final InetAddress addr) { if (addr == null) { return null; } return normalizeAddress(addr.getHostAddress()); } public static InetAddress translateAddress(final String sAddr) { if (sAddr == null) { return null; } try { return InetAddress.getByName(sAddr); } catch (final IOException e) { return null; } } public static LazyInetSocketAddress translateAddress(final String sAddr, final int defaultPort) { if (sAddr == null) { return null; } String host = sAddr; int port = defaultPort; if (isIPv6Possible(sAddr)) { if (sAddr.charAt(0) == '[') { final int index = sAddr.lastIndexOf(']'); host = sAddr.substring(1, index); final int index2 = sAddr.indexOf(':', index); if (index2 != -1) { port = Integer.parseInt(sAddr.substring(index2 + 1)); } } host = normalizeAddress(host); } else { final int index = sAddr.lastIndexOf(':'); if (index != -1) { host = sAddr.substring(0, index); port = Integer.parseInt(sAddr.substring(index + 1)); } } return new LazyInetSocketAddress(host, port); } public static String hostportizeAddress(final InetAddress addr) { if (addr == null) { return null; } return hostportizeAddress(translateAddress(addr)); } public static String hostportizeAddress(final InetSocketAddress addr) { if (addr == null) { return null; } String host; if (addr.isUnresolved()) { host = normalizeAddress(addr.getHostName()); } else { host = NetworkUtils.translateAddress(addr.getAddress()); } return hostportizeAddress(host, addr.getPort()); } public static String hostportizeAddress(final String addr) { if (addr == null) { return null; } String retval = addr; if (retval.indexOf(':') != -1) { if (!retval.startsWith("[")) { retval = "[" + retval + "]"; } } return retval; } public static String hostportizeAddress(final String addr, final int port) { return NetworkUtils.hostportizeAddress(addr) + ":" + port; } public static String normalizeAddress(final String addr) { if (addr == null || addr.length() == 0) { return addr; } String retval = addr; if (retval.charAt(0) == '[') { final int index = retval.lastIndexOf(']'); retval = retval.substring(1, index != -1 ? index : retval.length()); } final int index = retval.lastIndexOf('%'); if (index != -1) { retval = retval.substring(0, index); } return retval; } public static String encodeAddress(final String addr) { if (addr == null) { return null; } String retval = addr; if (retval.indexOf(':') != -1) { if (!retval.startsWith("[")) { retval = "[" + retval + "]"; } retval = retval.replace(":", "-"); } return retval; } public static String decodeAddress(final ObjectName oname) { if (oname == null) { return null; } String addr = oname.getKeyProperty("address"); if (addr == null) { addr = oname.getKeyProperty("host"); } if (addr == null) { return null; } if (addr.startsWith("[")) { return addr.replace("-", ":"); } else { return addr.replace("-", "."); } } public static int getFreePort() { try { final ServerSocket ss = new ServerSocket(0); ss.setReuseAddress(true); final int port = ss.getLocalPort(); ss.close(); return port; } catch (final Throwable t) { throw new RuntimeException(t); } } public static boolean isFreeTCPPort(final int port) { try { final ServerSocket ss = new ServerSocket(port); ss.setReuseAddress(true); ss.close(); return true; } catch (final Throwable t) { t.printStackTrace(); return false; } } public static void sendRawDAS(final Socket s, final String data) { if (data != null) { sendRawDAS(s, data.getBytes()); } } public static void sendPacket(final byte[] buf, final String host, final int port) { try { final DatagramPacket packet = new DatagramPacket(buf, buf.length, InetAddress.getByName(host), port); final DatagramSocket socket = new DatagramSocket(); socket.send(packet); socket.close(); } catch (final Throwable t) { throw new RuntimeException(t); } } public static void sendRawDAS(final Socket s, final byte[] data) { if (data != null && data.length > 0) { try { s.getOutputStream().write(data); s.getOutputStream().flush(); } catch (final Exception e) { // ignore } } } public static void sendRawSAS(final OutputStream out, final String data) { if (data != null) { sendRawSAS(out, data.getBytes()); } } public static void sendRawSAS(final OutputStream out, final byte[] data) { if (data != null && data.length > 0) { try { out.write(data); out.flush(); } catch (final Exception e) { // ignore } } } public static MulticastSocket createSocket(final InetAddress groupAddr, final int groupPort, final InetAddress local, final int ttl, final boolean join) throws IOException { final MulticastSocket socket = new MulticastSocket(groupPort); if (local != null) { socket.setInterface(local); } else { if (isIPv6Address(groupAddr)) { socket.setInterface(getLocalAddress(true)); } else if (isIPv4Address(groupAddr)) { socket.setInterface(getLocalAddress(false)); } } socket.setTimeToLive(ttl); if (join) { socket.joinGroup(groupAddr); } return socket; } private synchronized static void checkProtocolFamily() { if (StringUtils.toBoolean(System.getProperty("java.net.preferIPv6Addresses"))) { IPV6_SUPPORTED = true; IPV4_SUPPORTED = false; } else if (StringUtils.toBoolean(System.getProperty("java.net.preferIPv4Stack"))) { IPV6_SUPPORTED = false; IPV4_SUPPORTED = true; } // else if (OSUtils.isFamilyWindows() && !SystemUtils.isJava17OrAbove()) { // IPV6_SUPPORTED = false; // IPV4_SUPPORTED = true; // } else { ServerSocket ss = null; try { ss = new ServerSocket(0, 1, LOOPBACK_ADDRESS_V6_INET); IPV6_SUPPORTED = true; } catch (final Throwable e) { IPV6_SUPPORTED = false; } try { ss = new ServerSocket(0, 1, LOOPBACK_ADDRESS_V4_INET); IPV4_SUPPORTED = true; } catch (final Throwable e) { IPV4_SUPPORTED = false; } if (ss != null) { try { ss.setReuseAddress(true); } catch (final Throwable e) { // ignore } } try { ss.close(); } catch (IOException e) { // ignore. } } } private static List<InetAddress> getAvailableLocalAddresses(final boolean isIPv6) { final List<InetAddress> retval = new ArrayList<InetAddress>(); for (final InetAddress addr : getAvailableLocalAddresses()) { if (isIPv6 && addr instanceof Inet6Address || !isIPv6 && addr instanceof Inet4Address) { retval.add(addr); } } return retval; } private static InetAddress getAvailableLocalAddress(final boolean isIPv6) { InetAddress retval = null; final List<InetAddress> addrs = getAvailableLocalAddresses(isIPv6); if (addrs != null && addrs.size() > 0) { retval = addrs.get(0); } return retval; } private static InetAddress getRealtimeLocalAddress() { InetAddress retval = null; try { retval = InetAddress.getLocalHost(); } catch (final UnknownHostException e) { log.warn("InetAddress.getLocalHost() error: ", e); } if (!isAvailableIPAddress(retval) && isSupportIPv4()) { retval = getAvailableLocalAddressForRemote(MOCK_ADDRESS_V4_INET); } if (!isAvailableIPAddress(retval) && isSupportIPv6()) { retval = getAvailableLocalAddressForRemote(MOCK_ADDRESS_V6_INET); } if (!isAvailableIPAddress(retval) && isSupportIPv4()) { retval = getAvailableLocalAddress(false); } if (!isAvailableIPAddress(retval) && isSupportIPv6()) { retval = getAvailableLocalAddress(true); } if (!isAvailableIPAddress(retval)) { if (isSupportIPv4()) { retval = LOOPBACK_ADDRESS_V4_INET; } else { retval = LOOPBACK_ADDRESS_V6_INET; } } else { retval = NetworkUtils.translateAddress(NetworkUtils.translateAddress(retval)); } return retval; } private static InetAddress getRealtimeV6LocalAddress(final boolean loose) { InetAddress retval = getAvailableLocalAddressForRemote(MOCK_ADDRESS_V6_INET); if (!isAvailableIPAddress(retval)) { retval = getAvailableLocalAddress(true); } if (!isAvailableIPAddress(retval) && loose && isSupportIPv4()) { retval = getAvailableLocalAddress(false); } if (!isAvailableIPAddress(retval)) { retval = LOOPBACK_ADDRESS_V6_INET; } else { retval = NetworkUtils.translateAddress(NetworkUtils.translateAddress(retval)); } return retval; } private static InetAddress getRealtimeV4LocalAddress() { InetAddress retval = getAvailableLocalAddressForRemote(MOCK_ADDRESS_V4_INET); if (!isAvailableIPAddress(retval)) { retval = getAvailableLocalAddress(false); } if (!isAvailableIPAddress(retval)) { retval = LOOPBACK_ADDRESS_V4_INET; } else { retval = NetworkUtils.translateAddress(NetworkUtils.translateAddress(retval)); } return retval; } }