Get outbound IP address - Android Network

Android examples for Network:IP Address

Description

Get outbound IP address

Demo Code

/*****************************************************************************
 *  Project: Android IPv6Config//from w  ww .  ja  va2  s .  c  o  m
 *  Description: Android application to change IPv6 kernel configuration
 *  Author: Ren? Mayrhofer
 *  Copyright: Ren? Mayrhofer, 2011-2014
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 
 * as published by the Free Software Foundation.
 *****************************************************************************/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.Enumeration;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import android.annotation.SuppressLint;
import android.util.Log;

public class Main {
  /** Our logger for this class. */
  private final static Logger logger = null;
  /**
   * This is the host queried for the externally visible IPv6 address of the
   * client when connecting to Internet services. The host name is resolved to
   * IPv6 addresses (AAAA DNS entries) to make sure that we connect via IPv6.
   */
  public final static String GET_OUTBOUND_IP_SERVER = "doc.to";
  public final static String GET_OUTBOUND_IP_SERVER_ADDRESSv6 = "2002:1fc1:a27a:1::1";
  public final static String GET_OUTBOUND_IP_SERVER_ADDRESSv4 = "31.193.162.123";
  public final static int GET_OUTBOUND_IP_PORT = 443;
  public final static String GET_OUTBOUND_IP_URL_PROTOCOL = "https://";
  public final static String GET_OUTBOUND_IP_URL_PATH = "/getip/";
  /**
   * This is the URL queried for the externally visible IPv6 address of the client
   * when connecting to Internet services.
   */
  public final static String GET_OUTBOUND_IP_URL = GET_OUTBOUND_IP_URL_PROTOCOL + GET_OUTBOUND_IP_SERVER + ":"
      + GET_OUTBOUND_IP_PORT + GET_OUTBOUND_IP_URL_PATH;

  /**
   * This method tries to retrieve the IPv6/IPv4 address visible to servers by
   * querying https://doc.to/getip/.
   * 
   * Attention: this may take a few seconds - don't do it in the foreground!
   * 
   * @param queryIPv6
   *          If true, connects via IPv6. If false, connects via IPv4.
   * @return the IPv6/IPv4 address of this host that is used to connect to other
   *         hosts or null if IPv6/IPv4 connections to https://doc.to are not
   *         possible.
   */
  public static String getOutboundIPAddress(boolean queryIPv6) {
    try {
      // first resolve the host's AAAA entries to make sure to connect to the host via
      // IPv6
      InetAddress[] serverAddrs = InetAddress.getAllByName(GET_OUTBOUND_IP_SERVER);
      InetAddress server = null;
      for (InetAddress addr : serverAddrs) {
        if (queryIPv6 && addr instanceof Inet6Address) {
          logger.log(Level.FINE, "Resolved   " + GET_OUTBOUND_IP_SERVER + " to IPv6 address " + addr.getHostAddress());
          if (server == null)
            server = (Inet6Address) addr;
          else
            logger.log(Level.WARNING,
                "Found multiple IPv6 addresses for host " + GET_OUTBOUND_IP_SERVER
                    + ", but expected only one. Will use the one found first " + server.getHostAddress()
                    + " and ignore the one found now " + addr.getHostAddress());
        } else if (!queryIPv6 && addr instanceof Inet4Address) {
          logger.log(Level.FINE, "Resolved " + GET_OUTBOUND_IP_SERVER + " to IPv4 address " + addr.getHostAddress());
          if (server == null)
            server = (Inet4Address) addr;
          else
            logger.log(Level.WARNING,
                "Found multiple IPv4 addresses for host " + GET_OUTBOUND_IP_SERVER
                    + ", but expected only one. Will use the one found first " + server.getHostAddress()
                    + " and ignore the one found now " + addr.getHostAddress());
        }
      }
      if (server == null) {
        if (queryIPv6)
          server = InetAddress.getByName(GET_OUTBOUND_IP_SERVER_ADDRESSv6);
        else
          server = InetAddress.getByName(GET_OUTBOUND_IP_SERVER_ADDRESSv4);
        logger.log(Level.WARNING,
            "Could not resolve host " + GET_OUTBOUND_IP_SERVER + " to " + (queryIPv6 ? "IPv6" : "IPv4")
                + " address, assuming DNS resolver/server to be broken. " + "Will now try with hard-coded address "
                + server + " although it may have changed.");
      }

      // now that we have the IPv6 address to connect to, query the URL
      String url = GET_OUTBOUND_IP_URL_PROTOCOL
          + (queryIPv6 ? ("[" + server.getHostAddress() + "]") : server.getHostAddress()) + ":" + GET_OUTBOUND_IP_PORT
          + GET_OUTBOUND_IP_URL_PATH;
      logger.log(Level.FINER, "Querying URL " + url + " for outbound " + (queryIPv6 ? "IPv6" : "IPv4") + " address");
      return queryServerForOutboundAddress(url);
    } catch (UnknownHostException e) {
      logger.log(Level.WARNING, "Unable to resolve host " + GET_OUTBOUND_IP_SERVER, e);
      return null;
    }
  }

  /**
   * This method queries the passed customURL or "https://doc.to/getip/" if null
   * is given and expects to read the outbound IP address of this client in
   * return.
   * 
   * The only reason to use HTTPS instead of plain HTTP is that the latter is
   * often subject to tampering by deep packet inspection and other potentially
   * unsafe Internet practices. Therefore, we don't care about validating the
   * particular HTTPS URL and disable all certificate validation on purpose. If a
   * man-in-the-middle attack is being performed on this particular connection,
   * then it is highly unlikely that we will be able to establish an IPv6 tunnel
   * anyways.
   * 
   * @param customURL
   *          The URL to query. If null, GET_OUTBOUND_IP_URL will be used.
   * @return the outbound IP address of this host as seen be the server.
   */
  @SuppressLint("TrulyRandom")
  public static String queryServerForOutboundAddress(String customURL) {
    String url = customURL != null ? customURL : GET_OUTBOUND_IP_URL;

    try {
      // setup 1 before querying the URL: enable following HTTP redirects
      HttpURLConnection.setFollowRedirects(true);

      // setup 2 before querying the URL: disable certificate checks
      // create a trust manager that does not validate certificate chains
      TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
          return null;
        }

        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
        }

        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
        }
      } };
      // install the all-trusting trust manager
      SSLContext sc = SSLContext.getInstance("TLS");
      sc.init(null, trustAllCerts, new java.security.SecureRandom());
      HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

      // and also disable hostname verification
      HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
        @Override
        public boolean verify(String arg0, SSLSession arg1) {
          return true;
        }
      });

      // finally query the HTTPS URL
      // URLConnection conn = new URL("https", "[2002:5078:37d:1::19]", 443,
      // GET_OUTBOUND_IP_URL_PATH).openConnection();
      URLConnection conn = new URL(url).openConnection();
      conn.setUseCaches(false);
      // doesn't seem to be required
      /*
       * conn.setRequestProperty("User-Agent","Mozilla/5.0 ( compatible ) ");
       * conn.setRequestProperty("Accept","[star]/[star]");
       */
      logger.log(Level.FINE, "Connecting to URL " + url);
      conn.connect();

      if (conn instanceof HttpURLConnection) {
        int statusCode = ((HttpURLConnection) conn).getResponseCode();
        logger.log(Level.FINE,
            "URL " + url + " returned content type " + conn.getContentType() + " and status code " + statusCode);

        if (statusCode < 200 || statusCode >= 300) {
          logger.warning("Querying for server-resolved IP address resulted in status code " + statusCode
              + ", can not parse response");
          return ((HttpURLConnection) conn).getResponseMessage();
        }

        InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
        BufferedReader buff = new BufferedReader(in, 2048);
        StringBuffer reply = new StringBuffer();
        String line = null;
        do {
          line = buff.readLine();
          if (line != null) {
            if (reply.length() > 0)
              reply.append("\n");
            reply.append(line);
          }
        } while (line != null);

        return reply.toString();
      }
      return null;
    } catch (MalformedURLException e) {
      logger.log(Level.SEVERE, "Internal error: URL deemed invalid " + url, e);
      return null;
    } catch (IOException e) {
      logger.log(Level.WARNING, "Unable to connect to URL " + url + " and/or host " + GET_OUTBOUND_IP_SERVER, e);
      return null;
    } catch (NoSuchAlgorithmException e) {
      logger.log(Level.WARNING, "Unable to install custom TrustManager/SSLContext without certificate validation", e);
      return null;
    } catch (KeyManagementException e) {
      logger.log(Level.WARNING, "Unable to install custom TrustManager/SSLContext without certificate validation", e);
      return null;
    }
  }
}

Related Tutorials