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.

2 Answers2

36

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();
}
Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
  • 1
    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. – Serenity Stack Holder Apr 28 '12 at 11:45
  • 2
    To recognize the country/city use GeoIP service. For instance check this link: http://www.maxmind.com/app/java –  Apr 28 '12 at 11:47
  • 2
    Geocode an IP address: http://stackoverflow.com/questions/3232516/geocode-an-ip-address – Pavel Veller Apr 28 '12 at 11:47
  • 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?) – Nepoxx Jul 17 '14 at 18:23
  • 1
    @Nepoxx check this: http://serverfault.com/questions/90725/are-ip-addresses-trivial-to-forge –  Jul 18 '14 at 10:27
  • I'm not fully satisfied with this answer as I think it leaves out a few relevant aspects. Nearly four years later I still provided an alternative. – Marcel Stör Jan 19 '16 at 10:20
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;
}
Community
  • 1
  • 1
Marcel Stör
  • 22,695
  • 19
  • 92
  • 198
  • Your Solution is elegant and I am gona use this. UpVote – Mubasher Sep 19 '16 at 11:36
  • 1
    X-Forwarded-For can contain a comma separated list of proxy IP-addresses, so I would split the string first. – Gerardo Cauich Feb 08 '18 at 22:12
  • 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. – Jacques Koorts Sep 23 '20 at 07:58