15

I am curious if there is any library that handles already this kind of stuff, or I have to do it by myself once again. So, the thing is I want to get IP address field from the visitors HTTP header request on my server, and do the whole thing in Java? Any help would be nice. Thanks in advance.

0

2 Answers 2

37

Use the getHeader(String Name) method of the javax.servlet.http.HttpServletRequest object to retrieve the value of Remote_Addr variable. Here is the sample code:

String ipAddress = request.getHeader("Remote_Addr");

If this code returns empty string, then use this way:

String ipAddress = request.getHeader("HTTP_X_FORWARDED_FOR");

if (ipAddress == null) {
    ipAddress = request.getRemoteAddr();
}
Sign up to request clarification or add additional context in comments.

6 Comments

That's awesome! :) Thank you, is there any method that based on the given IP address can conclude from what country is the visitor? P.S. Will mark it as the best one, 'cause you have already answered on my Q.
To recognize the country/city use GeoIP service. For instance check this link: maxmind.com/app/java
Can anyone comment on how those headers are easily forged (or not)? Is it safe to assume that the request is truly coming from that IP (similar to the ip in a tcp packet?)
|
14

Even though there's an accepted answer that has been highly upvoted I'd like to suggest an alternative and point out shortcomings of the accepted answer.

request.getHeader("Remote_Addr") is specified to return exactly the same as request.getRemoteAddr(). Hence, it makes no sense to check both. Also note that getRemoteAddr is a method of javax.servlet.ServletRequest (i.e. HTTP-agnostic) while getHeader is in javax.servlet.http.HttpServletRequest.

Furthermore, some proxies use Client-IP rather than X-Forwarded-For. For a discussion see https://stackoverflow.com/a/7446010/131929.

I don't know how reliable the use of HTTP_X_FORWARDED_FOR over X-Forwarded-For is. In Java I'd rather use the direct, short form. For a discussion see https://stackoverflow.com/a/3834169/131929. Upper/lower case makes no difference because getHeader is specified to be case insensitive.

Java alternative

public final class ClientIpAddress {

  // CHECKSTYLE:OFF
  // https://stackoverflow.com/a/11327345/131929
  private static Pattern PRIVATE_ADDRESS_PATTERN = Pattern.compile(
      "(^127\\.)|(^192\\.168\\.)|(^10\\.)|(^172\\.1[6-9]\\.)|(^172\\.2[0-9]\\.)|(^172\\.3[0-1]\\.)|(^::1$)|(^[fF][cCdD])",
      Pattern.CANON_EQ);
  // CHECKSTYLE:ON

  private ClientIpAddress() {
  }

  /**
   * Extracts the "real" client IP address from the request. It analyzes request headers
   * {@code REMOTE_ADDR}, {@code X-Forwarded-For} as well as {@code Client-IP}. Optionally
   * private/local addresses can be filtered in which case an empty string is returned.
   *
   * @param request HTTP request
   * @param filterPrivateAddresses true if private/local addresses (see
   * https://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces and
   * https://en.wikipedia.org/wiki/Unique_local_address) should be filtered i.e. omitted
   * @return IP address or empty string
   */
  public static String getFrom(HttpServletRequest request, boolean filterPrivateAddresses) {
    String ip = request.getRemoteAddr();

    String headerClientIp = request.getHeader("Client-IP");
    String headerXForwardedFor = request.getHeader("X-Forwarded-For");
    if (StringUtils.isEmpty(ip) && StringUtils.isNotEmpty(headerClientIp)) {
      ip = headerClientIp;
    } else if (StringUtils.isNotEmpty(headerXForwardedFor)) {
      ip = headerXForwardedFor;
    }
    if (filterPrivateAddresses && isPrivateOrLocalAddress(ip)) {
      return StringUtils.EMPTY;
    } else {
      return ip;
    }
  }

  private static boolean isPrivateOrLocalAddress(String address) {
    Matcher regexMatcher = PRIVATE_ADDRESS_PATTERN.matcher(address);
    return regexMatcher.matches();
  }
}

PHP alternative

function getIp()
{
    $ip = $_SERVER['REMOTE_ADDR'];

    if (empty($ip) && !empty($_SERVER['HTTP_CLIENT_IP'])) {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        // omit private IP addresses which a proxy forwarded
        $tmpIp = $_SERVER['HTTP_X_FORWARDED_FOR'];
        $tmpIp = filter_var(
            $tmpIp,
            FILTER_VALIDATE_IP,
            FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
        );
        if ($tmpIp != false) {
            $ip = $tmpIp;
        }
    }
    return $ip;
}

3 Comments

Your Solution is elegant and I am gona use this. UpVote
X-Forwarded-For can contain a comma separated list of proxy IP-addresses, so I would split the string first.
I would improve this even further and check for a public address. HTTP_X_FORWARDED_FOR can return an array, and coming from a VPN the array can contain a local address as well as the public address. I take we all are after the public address.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.