您的位置:首页 > 理论基础 > 计算机网络

Investigation of Why InetAddress.isReachable() Returning false

2011-08-25 16:55 267 查看
public class TestPing {

public static void main(String[] args) {

InetAddress address = null;
String ipStr="135.198.181.205";

try {
address = InetAddress.getByName(ipStr);
} catch (UnknownHostException e) {
e.printStackTrace();
}
System.out.println(address.getHostName());
System.out.println(address.getHostAddress());

final InetAddress tmpAddress = address;

try {
if (!tmpAddress.isReachable(10000)) {
System.out.println(address.getHostAddress()+" is not reachable");
}else{
System.out.println(address.getHostAddress()+" is  reachable");
}

} catch (Exception e) {
e.printStackTrace();
}
}
}


The InetAddress.isReachable()  return false in some servers, but if use the Ping command 'ping -n 1 -w 10000 135.198.181.205' in windows or 'ping -c 1 -w 10000 135.198.181.205' in linux,  the ping result is true.

It is strange!

some one says that 

http://stackoverflow.com/questions/2777226/isreachable-in-java-doesnt-appear-to-be-working-quite-the-way-its-supposed-to

Linux/Unix, instead, supports an ICMP "ping" system call. So the implementation of java.net.InetAddress.isReachable() first tries to perform the "ping" system call**; if this fails, itfalls back trying to open a TCP socket on [sic -
to] port 7
, as in Windows.

It turns out that in Linux/Unix the ping system call requires root privileges, so most of the times java.net.InetAddress.isReachable() will fail, because many Java programs are not run as root,
and because the target address unlikely has the echo service up and running. Too bad.
Yes, when the program was executed in root privileges, it did return true. but the regular program is not executed in root.  actually this is a bug, only the root privilege could send the ICMP packets, so while the program running on not root privilege and
 the port 7 is not available  then the isReachable method would return false. To validate this thought, i run the TestPing program in the Windows,  and the result still is false, while i run the TestPing program in the linux with the root privilege, the result
is true. and this test proves that the Sending ICMP packets could be used by root, and the tcp sockets at port 7 failed, then the TestPing could be failed both on windows and linux.

so the next step is to find the cause while the tcp connection to port 7 in the remote server is failed.

then use the command 'netstat -tn |grep 7' to see whether the port 7 is occupied or not, and find none program is used.

And the isReachable method attempts Tcp-3 way handshake with Port 7(Echo) which is completely different from the ICMP Ping which sends ICMP Type 8 (ECHO)  to the host and await an ICMP Type 0 (ECHO Reply).  and if the server is not listening on port 7, so
it returns false where as normal ping command receive reply as network link is up.

using /etc/init.d/iptables status to check whether the firewalls is stopped. if it is closed then it would print  "FireWall is stopped".

command '/etc/init.d/iptables start' to start the firewalls, and command '/etc/init.d/iptables stop' to stop the firewalls.
But if i close the firewalls on the remote server using the command '/etc/init.d/iptables stop', then isReachable method return true. so the problem is the Port 7 is closed. if open the port 7, then this method could return true.  and Why port 7 is closed?
Because the destination is a ESX Server Vmware,  and its default configuration is to close all the ports smaller than 3000 after the version vmware 3.0. so 

IF not to close the firewall, should use the command "/sbin/iptables -A INPUT -p tcp --dport 7 -j ACCEPT" to open the Port 7, then the method isReachable() could return true;

and /sbin/iptables -L  command could print the content of rules:

iptables -L

Chain INPUT (policy DROP)

target     prot opt source               destination         

ACCEPT     all  --  anywhere             anywhere            

valid-tcp-flags  tcp  --  anywhere             anywhere            

valid-source-address !udp  --  anywhere             anywhere            

valid-source-address-udp  udp  --  anywhere             anywhere            

valid-source-address  tcp  --  anywhere             anywhere            tcp flags:FIN,SYN,RST,ACK/SYN 

icmp-in    icmp --  anywhere             anywhere            

ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED 

ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:ideafarm-chat state NEW 

ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:http state NEW 

ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:https state NEW 

ACCEPT     udp  --  anywhere             anywhere            udp spts:bootps:bootpc dpts:bootps:bootpc 

ACCEPT     udp  --  anywhere             anywhere            udp dpt:svrloc 

ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:svrloc state NEW 

ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:wbem-https state NEW 

ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:wbem-http state NEW 

ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:ssh state NEW 

ACCEPT     tcp  --  anywhere             anywhere            tcp dpts:av-emb-config:remote-collab state NEW 

ACCEPT     udp  --  anywhere             anywhere            udp dpts:av-emb-config:remote-collab state NEW 

ACCEPT     tcp  --  anywhere             anywhere            tcp dpts:8042:8045 state NEW 

ACCEPT     udp  --  anywhere             anywhere            udp dpts:8042:8045 state NEW 

ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:echo   <-端口已经添加

some tips:

netstat命令是一个监控TCP/IP网络的非常有用的工具,它可以显示路由表、实际的网络连接以及每一个网络接口设备的状态信息,这里我只用到其中的部分功能.

netstat 的常用参数: - t、- u、- w和- x分别表示TCP、UDP、RAW和UNIX套接字连接。-a标记,还会显示出等待连接(也就是说处于监听模式)的套接字。-l 显示正在被监听(listen)的端口, -n表示直接显示端口数字而不是通过察看/etc/service来转换为端口名,-p选项表示列出监听的程序

1) netstat -tl

查看当前tcp监听端口

Active Internet connections (only servers)

Proto Recv-Q Send-Q Local Address           Foreign Address         State      

tcp        0      0 *:rrac                  *:*                     LISTEN      

tcp        0      0 *:34006                 *:*                     LISTEN      

......

2) netstat -tlp

查看当前tcp监听端口, 需要显示监听的程序名,当不清楚mysql的监听端口时比较好用

Active Internet connections (only servers)

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name   

tcp        0      0 *:rrac                  *:*                     LISTEN      -                          

tcp        0      0 *:34006                 *:*                     LISTEN      23425/mysqld   

......

3) netstat -tl | grep 34006

只查看mysql的监听端口,当前启动的mysql端口为34006,明确知道mysql监听端口时使用

4) netstat -ta | grep 34006

tcp        0      0 *:34006                 *:*                     LISTEN      

tcp        0      0 linux.local:34006       linux.local:41485       ESTABLISHED 

tcp        0      0 linux.local:34006       linux.local:41486       ESTABLISHED 

...

tcp        0      0 10.3.2.35:41488         10.3.2.35:34006         ESTABLISHED 

tcp        0      0 10.3.2.35:41489         10.3.2.35:34006         ESTABLISHED 

tcp        0      0 10.3.2.35:41490         10.3.2.35:34006         ESTABLISHED 

由于数据库和运用程序都放在同一台机器了,因此这里连接被显示了两次. 可以使用-p参数来显示PID,然后grep PID.

5) netstat -tap | grep 34006 | grep 23425

23425是当前mysql的PID

tcp        0      0 *:34006                 *:*                     LISTEN      23425/mysqld        

tcp        0      0 linux.local:34006       linux.local:41510       ESTABLISHED 23425/mysqld        

tcp        0      0 linux.local:34006       linux.local:41511       ESTABLISHED 23425/mysqld        

tcp        0      0 linux.local:34006       linux.local:41516       ESTABLISHED 23425/mysqld  

iptables:

using /etc/init.d/iptables status to check whether the firewalls is stopped. if it is closed then it would print  "FireWall is stopped".

command '/etc/init.d/iptables start' to start the firewalls, and command '/etc/init.d/iptables stop' to stop the firewalls.

 1)      重启后永久性生效:        开启: chkconfig iptables on    关闭: chkconfig iptables off

 2)      即时生效,重启后失效:开启: service iptables start   关闭: service iptables stop

 需要说明的是对于Linux下的其它服务都可以用以上命令执行开启和关闭操作。

  在开启了防火墙时,做如下设置,开启相关端口,

  修改/etc/sysconfig/iptables 文件,添加以下内容:

  -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT

  -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息