Get real client IP in a Servlet [duplicate]

2019-01-09 02:46发布

问题:

This question already has an answer here:

  • How do I get the remote address of a client in servlet? 8 answers

I'm having some trouble with a simple problem. I would get the real client IP inside an HTTPServlet.

Since now I used:

request.getRemoteAddr()

But now it returns a false IP. eg: xxx.xxx.xxx.50 but my IP is something like xxx.xxx.xxx.159. (checked at http://whatismyipaddress.com/).

Now I tried to use:

request.getHeader("X-Forwarded-For")

It returns NULL.

I also took a probe with the following class:

public class IpUtils {

public static final String _255 = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
public static final Pattern pattern = Pattern.compile("^(?:" + _255 + "\\.){3}" + _255 + "$");

public static String longToIpV4(long longIp) {
    int octet3 = (int) ((longIp >> 24) % 256);
    int octet2 = (int) ((longIp >> 16) % 256);
    int octet1 = (int) ((longIp >> 8) % 256);
    int octet0 = (int) ((longIp) % 256);

    return octet3 + "." + octet2 + "." + octet1 + "." + octet0;
}

public static long ipV4ToLong(String ip) {
    String[] octets = ip.split("\\.");
    return (Long.parseLong(octets[0]) << 24) + (Integer.parseInt(octets[1]) << 16)
            + (Integer.parseInt(octets[2]) << 8) + Integer.parseInt(octets[3]);
}

public static boolean isIPv4Private(String ip) {
    long longIp = ipV4ToLong(ip);
    return (longIp >= ipV4ToLong("10.0.0.0") && longIp <= ipV4ToLong("10.255.255.255"))
            || (longIp >= ipV4ToLong("172.16.0.0") && longIp <= ipV4ToLong("172.31.255.255"))
            || longIp >= ipV4ToLong("192.168.0.0") && longIp <= ipV4ToLong("192.168.255.255");
}

public static boolean isIPv4Valid(String ip) {
    return pattern.matcher(ip).matches();
}

public static String getIpFromRequest(HttpServletRequest request) {
    String ip;
    boolean found = false;
    if ((ip = request.getHeader("x-forwarded-for")) != null) {
        StringTokenizer tokenizer = new StringTokenizer(ip, ",");
        while (tokenizer.hasMoreTokens()) {
            ip = tokenizer.nextToken().trim();
            if (isIPv4Valid(ip) && !isIPv4Private(ip)) {
                found = true;
                break;
            }
        }
    }

    if (!found) {
        ip = request.getRemoteAddr();
    }

    return ip;
}
}

It also returned the xxx.xxx.xxx.50 IP. :(

Now I don't know how to get the real client IP. If somebody knows the solution please make an answer.

回答1:

I suppose that your problem is that you are running server somewhere in local network, so you get your IP in that network. However when you are trying to use online service that discovers your IP address your IP is the IP of your service provider's router or something like this. Using request.getRemoteAddr() is correct. This is what such services do and they do not have other facilities.



回答2:

When you have NAT (Network Address Translation) device before your servlet container request.getRemoteAddr() returns the address of NAT , since it initiate a new connection.

To solve your problem you should configure you NAT to send in a header the IP of the original client. Then, to take the header from the request. In case you configure in NAT X-Forwarded-For header use this code: request.getHeader("X-Forwarded-For")

You function is correct, you can use it when you configure NAT.



回答3:

Java

String ip = request.getRemoteAddr();
if (ip.equalsIgnoreCase("0:0:0:0:0:0:0:1")) {
    InetAddress inetAddress = InetAddress.getLocalHost();
    String ipAddress = inetAddress.getHostAddress();
    ip = ipAddress;
}
model.addAttribute("IP", ip);

JSP <span><B>IP : <c:out value="${IP}" /></B></span> // Spring MAV

JSP

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%>
<%@ page import="java.net.InetAddress" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Displays Client IP Address</title>
</head>
<body>
<%
    // paste above java code 
out.println("<br><B>Clients IP : </B>"+ip);
%>
<span><br>Local Host  : <%= request.getRemoteAddr() %></span>
<span><br>ServerPort  : <%= request.getServerPort() %></span>
<span><br>Path        : <%= request.getRequestURI()%></span>
</span>
</body>
</html>

If the jsp is deployed in local server and accessing this jsp returns 0:0:0:0:0:0:0:1. If accessing the application locally with ip then it returns IP.

RESTful Web Services with Jersey

@javax.ws.rs.Path("/ip")
public class GetIPInfo {

    @GET    @Produces(MediaType.TEXT_PLAIN) 
    public Response getIP(@Context javax.servlet.http.HttpServletRequest request) throws UnknownHostException { 

        String remoteHost = request.getRemoteHost();
        String remoteAddr = request.getRemoteAddr();
        if (remoteAddr.equals("0:0:0:0:0:0:0:1")) {
            InetAddress localip = java.net.InetAddress.getLocalHost();
            remoteAddr = localip.getHostAddress();
            remoteHost = localip.getHostName();
        }
        int remotePort = request.getRemotePort();

        String msgoutput = remoteHost + " (" + remoteAddr + " : " + remotePort + ")";
        return Response.status(200).entity(msgoutput).build(); 
    }
}

using JavaScript to find IP