获取客户端IP、获取公网IP、验证IP是否内网
来源:互联网 发布:艺妓和舞女的区别知乎 编辑:程序博客网 时间:2024/06/05 06:12
获取客户端IP、获取公网IP、验证IP是否内网
1、获取客户端IP
在开发工作中,我们常常需要获取客户端的IP。一般获取客户端的IP地址的方法是:request.getRemoteAddr();但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。
原因:由于在客户端和服务之间增加了中间代理,因此服务器无法直接拿到客户端的IP,服务器端应用也无法直接通过转发请求的地址返回给客户端。
现在图示代理上网和IP的关系:
第一种情况:不通过代理上网,服务器端拿到真实IP
第二种情况:通过代理服务器如:Nginx,Squid等一层代理或多层代理上网,如下图:
需要注意的是X-Forwarded-For和X-Real-IP都不是http的正式协议头,而是squid等反向代理软件最早引入的,之所以resin能拿到,是因为NGINX里一般缺省都会这么配置转发的http请求:
location / { proxy_pass http://yourdomain.com; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
从X-Forwarded-For的定义来看,ips[0]才是原始客户端ip,如果这个都不是,那拿第二个就更不靠谱了,我们平时检验的时候,可能是直接在内网挂代理去访问的,跟外面网友访问经过的网络路径不一样,后面不停添加的是经过的每一层代理ip才对,下面举例说明;
request.getRemoteAddr() 192.168.239.196request.getHeader("X-Forwarded-For") 58.63.227.162, 192.168.237.178,192.168.238.218request.getHeader("X-Real-IP") 192.168.238.218
所以访问的流程应该是这样,客户端58.63.227.162发出请求,经过192.168.237.178, 192.168.238.218两层转发,到了192.168.239.196这台NGINX上,NGINX就把X-Real-IP头设成了自己看到的remote_addr,也就是直接发给到他的192.168.238.218,这时候resin收到这个包,对resin来说直接发给他的remote_addr就是NGINX的ip,也就是192.168.239.196,那么resin里面的request.getRemoteAddr()就是192.168.239.196,那么在resin里拿最原始的ip逻辑(也就是拿能够知道的最外层的ip)应该是这样:
如果XFF不为空,拿XFF的左边第一个如果XFF为空,拿XRI如果XRI为空,只能拿request.getRemoteAddr(),也就是只能拿到最直接发给他的机器ip了
其他都不可考究,参考代码如下:
第一种代码:
/** * 从Request对象中获得客户端IP,处理了HTTP代理服务器和Nginx的反向代理截取了ip * * @param request * @return ip */ public static String getRealIp1(HttpServletRequest request) { String remoteAddr = request.getRemoteAddr(); String forwarded = request.getHeader("X-Forwarded-For"); String realIp = request.getHeader("X-Real-IP"); String ip = null; if (realIp == null) { if (forwarded == null) { ip = remoteAddr; } else { ip = remoteAddr + "/" + forwarded.split(",")[0]; } } else { if (realIp.equals(forwarded)) { ip = realIp; } else { if (forwarded != null) { forwarded = forwarded.split(",")[0]; } ip = realIp + "/" + forwarded; } } return ip; }
第二种代码:
/** * 从Request对象中获得客户端IP,处理了HTTP代理服务器和Nginx的反向代理截取了ip * @param request * @return ip */ public static String getRealIp2(HttpServletRequest request) { String remoteAddr = request.getRemoteAddr(); String forwarded = request.getHeader("X-Forwarded-For"); String realIp = request.getHeader("X-Real-IP"); String ip = null; if (realIp == null) { if (forwarded == null) { ip = remoteAddr; } else { ip = remoteAddr + "/" + forwarded; } } else { if (realIp.equals(forwarded)) { ip = realIp; } else { ip = realIp + "/" + forwarded.replaceAll(", " + realIp, ""); } } return ip; }
第三种代码:
/** * 从Request对象中获得客户端IP,处理了HTTP代理服务器和Nginx的反向代理截取了ip * @param request * @return ip */ public static String getRealIp3(HttpServletRequest request) { String ip = request.getHeader("X-Forwarded-For"); if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){ //多次反向代理后会有多个ip值,第一个ip才是真实ip int index = ip.indexOf(","); if(index != -1){ return ip.substring(0,index); }else{ return ip; } } ip = request.getHeader("X-Real-IP"); if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){ return ip; } return request.getRemoteAddr(); }
第三种是最合适的,最清晰理解的
2、获取公网IP
/** * Java获取本机公网ip * @return ip * @throws SocketException */ public static String getRealIp() throws SocketException { String localip = null;// 本地IP,如果没有配置外网IP则返回它 String netip = null;// 外网IP Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces(); InetAddress ip = null; boolean finded = false;// 是否找到外网IP while (netInterfaces.hasMoreElements() && !finded) { NetworkInterface ni = netInterfaces.nextElement(); Enumeration<InetAddress> address = ni.getInetAddresses(); while (address.hasMoreElements()) { ip = address.nextElement(); if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 外网IP netip = ip.getHostAddress(); finded = true; break; } else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 内网IP localip = ip.getHostAddress(); } } } if (netip != null && !"".equals(netip)) { return netip; } else { return localip; } }
3、验证IP是否内网
tcp/ip协议中,专门保留了三个IP地址区域作为私有地址,其地址范围如下:
10.0.0.0/8:10.0.0.0~10.255.255.255
172.16.0.0/12:172.16.0.0~172.31.255.255
192.168.0.0/16:192.168.0.0~192.168.255.255
那么,直接上代码吧:
/** * Java判断IP地址为内网IP还是公网IP * @param ip * @return boolean */ public static boolean internalIp(String ip) { byte[] addr = IPAddressUtil.textToNumericFormatV4(ip); final byte b0 = addr[0]; final byte b1 = addr[1]; //10.x.x.x/8 final byte SECTION_1 = (byte) 0x0A; //172.16.x.x/12 final byte SECTION_2 = (byte) 0xAC; final byte SECTION_3 = (byte) 0x10; final byte SECTION_4 = (byte) 0x1F; //192.168.x.x/16 final byte SECTION_5 = (byte) 0xC0; final byte SECTION_6 = (byte) 0xA8; switch (b0) { case SECTION_1: return true; case SECTION_2: if (b1 >= SECTION_3 && b1 <= SECTION_4) { return true; } case SECTION_5: switch (b1) { case SECTION_6: return true; } default: return false; } }
- 获取客户端IP、获取公网IP、验证IP是否内网
- android 获取公网ip 内网ip
- 内网linux获取出口公网ip
- java获取客户端请求IP地址 获取公网ip
- java获取客户端请求IP地址 获取公网ip
- java获取客户端请求IP地址 获取公网ip
- 关于获取客户端公网IP问题
- java获取公网ip
- Java获取公网ip
- 获取公网IP
- win32获取公网ip
- 获取公网IP
- 获取公网的ip
- 获取公网ip地址
- c#获取公网IP
- 获取公网IP
- 获取公网IP地址
- 获取公网IP地址
- JNI DETECTED ERROR IN APPLICATION: can't call void XXX on instance of java.lang.Class <XXX>解决方案
- epoll多路复用
- SIteMesh介绍
- Unity 3D官方教程——Tanks!学习记录
- “从我们能够预知未来的那一刻起,好事就会不断发生”
- 获取客户端IP、获取公网IP、验证IP是否内网
- Vue学习(1.1)
- shell script学习需要几天?
- B. Maximize Sum of Digits
- 60. Permutation Sequence
- ubantu16.04的更新源
- 排序算法总结(持续更新中)
- TCP vs UDP
- redis 编辑配置