I have to create a program that sniff a local network for school. I chose to work with Java and found out that you can capture packets with jpcap.
So I wanted to follow one of the example provided in jpcap's github and it seems like I can only find my own packets.
Like I said, I've looked at the code and chose my wifi interface. The program is capturing packets and I put all the source ip addresses in a text file to run some tests. I have also created a hashmap the ip addresses I've finded when I did a arp -a. From what I've read online, this command shows you ip addresses in your network.I created a boolean set to false and I then proceeded to run a loop that goes through the textfile and looked if the ip address was in the hashMap : if one of the addresses appeared in the hashmap, the boolean would be change to true and it would mean that I've managed to catch something.
After running the test, the boolean came out false.
Here's the example code
``public class PacketCaptor {
private static final int INFINITE = -1;
private static final int PACKET_COUNT = INFINITE;
/*
private static final String HOST = "203.239.110.20";
private static final String FILTER =
"host " + HOST + " and proto TCP and port 23";
*/
private static final String FILTER =
// "port 23";
"";
public static void main(String[] args) {
try {
if(args.length == 1){
PacketCaptor sniffer = new PacketCaptor(args[0]);
} else {
System.out.println("Usage: java Sniffer [device name]");
System.out.println("Available network devices on your machine:");
String[] devs = PacketCapture.lookupDevices();
for(int i = 0; i < devs.length ; i++)
System.out.println("\t" + devs[i]);
}
} catch(Exception e) {
e.printStackTrace();
}
}
public PacketCaptor(String device) throws Exception {
// Initialize jpcap
PacketCapture pcap = new PacketCapture();
System.out.println("Using device '" + device + "'");
pcap.open(device, true);
//pcap.setFilter(FILTER, true);
pcap.addPacketListener(new PacketHandler());
System.out.println("Capturing packets...");
pcap.capture(PACKET_COUNT);
}
}
class PacketHandler implements PacketListener
{
WritingClass writing = new WritingClass();
public void packetArrived(Packet packet) {
try {
// only handle TCP packets
if(packet instanceof TCPPacket) {
TCPPacket tcpPacket = (TCPPacket)packet;
byte[] data = tcpPacket.getTCPData();
String srcHost = tcpPacket.getSourceAddress();
String dstHost = tcpPacket.getDestinationAddress();
String isoData = new String(data, "ISO-8859-1");
System.out.println(srcHost+" -> " + dstHost + ": " + isoData);
String datas = srcHost+"|"+dstHost+"|";
writing.write(datas, this.writing.getFileName());
}
} catch( Exception e ) {
e.printStackTrace();
}
}
Can anyone help me figure out why It doesn't work ?
Thank you so much for your help
The reason why you aren't able to capture more packets is because you need an interface in promisc or raw mode, I advice you to use a proper sniffer like wireshark to check if other packets that aren't addressed to you can be captured. If not, means you need apply a mitm method because you are in a commuted network. For use that code on wifi should be enough an interface in monitor mode (check aircrack-ng suite).
In GNU/Linux Debian based systems may use the command iw dev wlan0 interface add mon0 type monitor (from package wireless-tools)
I'm developing an Android application, I have to discover each hosts in a WiFi network, I have implemented a function that "ping" all IP address between 1 and 255 of a certain network.
This solution it work perfectly, but there is a problem, the execution time.. Every time that i start my application I wait about 256 second, it too long, i can't wait this time.
This is my source code (i found this code on Stack, i modified the code to work in my condition):
public class ScanNetwork {
ArrayList < String > hosts;
int i;
boolean finish = false;
public ArrayList < String > ScanNetwork(String ipAddress) {
hosts = new ArrayList < String > ();
final String subnet = ipAddress.substring(0, ipAddress.lastIndexOf("."));
for (i = 0; i < 256; i++) {
String currentHost = subnet + "." + i;
Process p1 = null;
int returnVal = 0;
try {
p1 = Runtime.getRuntime().exec("ping -w 50 -c 1 " + currentHost);
returnVal = p1.waitFor();
} catch (IOException e) {
System.out.println("Log: " + e.toString());
} catch (InterruptedException e) {
System.out.println("Log: " + e.toString());
}
boolean reachable = (returnVal == 0);
if (reachable) {
if (!hosts.contains(currentHost)) {
hosts.add(currentHost);
System.out.println(currentHost);
}
}
}
return hosts;
}
}
This source code is perfect but the execution time is excessive, there are other way to obtain all the host in the network ?
How i can solve this problem ?
The problem I see is that you are doing all the pings sequentially - the loop is spending most of its time waiting for replies. Try starting up a few AsyncTasks, each of which has an assigned range of addresses to search, and let them work in parallel.
Note that for a typical 192.168.1.x network, ".0" (all 0 bits) ".255" (all 1 bits) will not correspond to a host and doesn't need checking.
Also don't forget that not everybody responds to a ping (this is more likely in a corporate network, less so at home)
I am trying to build a port scanner which not only scans for port numbers but, also list the services running on the respective port .I am new to java-programming and As you can see i have the code for scanning the status of ports on the local machine. I don't know where to start when it comes to list services running on each port. I would appreciate if anyone can suggest me any code/links to list those services. Thanks for the help.....
public class port {
public static void main(String[] args) throws Exception {
String host = "localhost";
InetAddress inetAddress = InetAddress.getByName(host);
String hostName = inetAddress.getHostName();
for (int port = 0; port <= 200; port++) {
try {
Socket socket = new Socket(hostName, port);
String text = hostName + " is listening on port " + port;
System.out.println(text);
socket.close();
}
catch (IOException e)
{
String s = hostName + " is not listening on port " + port;
System.out.println(s);
}
}
}
}
The code seems fine if you want to check for open ports, but identifying services... well, that's tricky.
It's a bit like identifying the type of file by reading the first few bytes. An easy solution is to compare the port number with the list of well known ports. So if port 80 is open, you just assume it's HTTP and move on.
This method assumes that services actually listen on their assigned ports. This is like assuming that a file that ends with "zip" is always a zip file. It's correct most of the time, but only because it's a convention. Not because it has to be this way. If you want to actually fingerprint services - determine the type of service by "talking to it", then it's a serious undertaking, not something that can be explained in a few lines. I suggest you take a look at Nmap, as it's an existing tool that does just that. You might be able to use it instead of writing your own.
So, you are looking for something like Nmap?
Your code seems good to me, although I would do something like
public class PortScanner {
public static void main(String[] args) throws Exception {
final String host = "localhost";
final InetAddress inetAddress = InetAddress.getByName(host);
final String hostName = inetAddress.getHostName();
final List<int> openPorts = new ArrayList();
// we begin at port 1 because port 0 is never used
for (int port = 1; port <= 200; port++) {
try {
Socket socket = new Socket(hostName, port);
openPorts.add(port);
} catch (IOException) {
} finally {
socket.close();
}
}
}
}
You cannot easily know what service is running on the port, you can only simply assume what service is running on that port using this list. But beware, a web server can use custom ports instead of default ones.
If you do have the requirement to know exactly what service is running on what port, I suggest you use Nmap and make a bash script out of it which in turn outputs it's findings in a .txt file. That .txt file can then be read by Java. This approach saves tons of work.
InetAddress byName = InetAddress.getByName("173.39.161.140");
System.out.println(byName);
System.out.println(byName.isReachable(1000));
Why does isReachable return false? I can ping the IP.
The "isReachable" method has not been worthy of using for me in many cases. You can scroll to the bottom to see my alternative for simply testing if you're online and capable of resolving external hosts (i.e. google.com) ... Which generally seems to work on *NIX machines.
The issue
There is alot of chatter about this :
Here are other, similar questions :
Detect internet Connection using Java
How do I test the availability of the internet in Java?
And even a reported bug on this same matter :
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4921816
Part 1 : A reproducible example of the problem
Note that in this case, it fails.
//also, this fails for an invalid address, like "www.sjdosgoogle.com1234sd"
InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
for (InetAddress address : addresses) {
if (address.isReachable(10000))
{
System.out.println("Connected "+ address);
}
else
{
System.out.println("Failed "+address);
}
}
//output:*Failed www.google.com/74.125.227.114*
Part 2 : A Hackish Workaround
As an alternative, you can do this :
// in case of Linux change the 'n' to 'c'
Process p1 = java.lang.Runtime.getRuntime().exec("ping -n 1 www.google.com");
int returnVal = p1.waitFor();
boolean reachable = (returnVal==0);
The -c option of ping will allow ping to simply try to reach the server once(as opposed to the infinite ping which we're used to using at the terminal).
This will return 0 if the host is reachable. Otherwise, you will get "2" as a return value.
Much simpler - but of course it is platform specific.
And there may be certain privilege caveats to using this command - but I find it works on my machines.
PLEASE Note that :
1) This solution is not production quality. Its a bit of a hack. If google is down, or your internet is temporarily slow, or maybe even if there is some funniness in your privileges/system settings, if could return false negatives (i.e. it could fail even though the input address is reachable).
2) The isReachable failure is an outstanding issue. Again - there are several online resources indicating that there is no "perfect" way of doing this at the time of this writing, due to the way the JVM tries to reach hosts - I guess it is an intrinsically platform specific task which, although simple, hasn't yet been abstracted sufficiently by the JVM.
I came here to get an answer for this same question, but I was unsatisfied by any of the answers because I was looking for a platform independent solution. Here is the code which I wrote and is platform independent, but requires information about any open port on the other machine (which we have most of the time).
private static boolean isReachable(String addr, int openPort, int timeOutMillis) {
// Any Open port on other machine
// openPort = 22 - ssh, 80 or 443 - webserver, 25 - mailserver etc.
try {
try (Socket soc = new Socket()) {
soc.connect(new InetSocketAddress(addr, openPort), timeOutMillis);
}
return true;
} catch (IOException ex) {
return false;
}
}
Update: Based on a recent comment to this answer, here is a succinct version of the above code:
private static boolean isReachable(String addr, int openPort, int timeOutMillis) {
// Any Open port on other machine
// openPort = 22 - ssh, 80 or 443 - webserver, 25 - mailserver etc.
try (Socket soc = new Socket()) {
soc.connect(new InetSocketAddress(addr, openPort), timeOutMillis);
return true;
} catch (IOException ex) {
return false;
}
}
If you only want to check if it is connected to internet use this method , It returns true if internet is connected, Its preferable if you use the address of the site you are trying to connect through the program.
public static boolean isInternetReachable()
{
try {
//make a URL to a known source
URL url = new URL("http://www.google.com");
//open a connection to that source
HttpURLConnection urlConnect = (HttpURLConnection)url.openConnection();
//trying to retrieve data from the source. If there
//is no connection, this line will fail
Object objData = urlConnect.getContent();
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
Just mentioning it explicitly since the other answers don't. The ping part of isReachable() requires root access on Unix. And as pointed out by bestsss in 4779367:
And if you ask why ping from bash doesn't, actually it does need as well. Do that ls -l /bin/ping.
Since using root was not an option in my case the solution was to allow access to port 7 in the firewall to the specific server I was interested in.
I am not sure what was the state when the original question was asked back in 2012.
As it stands now, ping will be executed as a root. Through the ping executable's authorization you will see the +s flag, and the process belonging to root, meaning it will run as root. run ls -liat on where the ping is located and you should see it.
So, if you run InetAddress.getByName("www.google.com").isReacheable(5000) as root, it should return true.
you need proper authorizations for the raw socket, which is used by ICMP (the protocol used by ping)
InetAddress.getByName is as reliable as ping, but you need proper permissions on the process to have it running properly.
Since you can ping the computer, your Java process should run with sufficient privileges to perform the check. Probably due to use of ports in the lower range. If you run your java program with sudo/superuser, I'll bet it works.
I would suggest that the ONLY reliable way to test an internet connection is to actually connect AND download a file, OR to parse the output of an OS ping call via exec(). You cannot rely on the exit code for ping and isReachable() is crap.
You cannot rely on a ping exit code as it returns 0 if the ping command executes correctly. Unfortunately, ping executes correctly if it can't reach the target host but gets a "Destination host unreachable" from your home ADSL router. This is kind of a reply that gets treated as a successfull hit, thus exit code = 0. Have to add though that this is on a Windows system. Not checked *nixes.
private boolean isReachable(int nping, int wping, String ipping) throws Exception {
int nReceived = 0;
int nLost = 0;
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("ping -n " + nping + " -w " + wping + " " + ipping);
Scanner scanner = new Scanner(process.getInputStream());
process.waitFor();
ArrayList<String> strings = new ArrayList<>();
String data = "";
//
while (scanner.hasNextLine()) {
String string = scanner.nextLine();
data = data + string + "\n";
strings.add(string);
}
if (data.contains("IP address must be specified.")
|| (data.contains("Ping request could not find host " + ipping + ".")
|| data.contains("Please check the name and try again."))) {
throw new Exception(data);
} else if (nping > strings.size()) {
throw new Exception(data);
}
int index = 2;
for (int i = index; i < nping + index; i++) {
String string = strings.get(i);
if (string.contains("Destination host unreachable.")) {
nLost++;
} else if (string.contains("Request timed out.")) {
nLost++;
} else if (string.contains("bytes") && string.contains("time") && string.contains("TTL")) {
nReceived++;
} else {
}
}
return nReceived > 0;
}
nping is number of try to ping ip(packets), if you have busy network or systems choose biger nping numbers.
wping is time waiting for pong from ip, you can set it 2000ms
for using this method u can write this:
isReachable(5, 2000, "192.168.7.93");
Or using this way:
public static boolean exists(final String host)
{
try
{
InetAddress.getByName(host);
return true;
}
catch (final UnknownHostException exception)
{
exception.printStackTrace();
// Handler
}
return false;
}
InetAddress.isReachable is flappy, and sometimes returns unreachable for addresses which we can ping.
I tried the following:
ping -c 1 <fqdn> and check the exit status.
Works for all the cases i had tried where InetAddress.isReachable doesn't work.
To Check Internet
public boolean isInternetAvailable() {
try {
InetAddress ipAddr = InetAddress.getByName("google.com");
//You can replace it with your name
return !ipAddr.equals("");
} catch (Exception e1) {
try {
Process p1 = java.lang.Runtime.getRuntime().exec("/system/bin/ping -W 1 -c 1 www.google.com");
int returnVal = 0;
returnVal = p1.waitFor();
boolean reachable = (returnVal==0);
return reachable;
} catch (Exception e2) {
e2.printStackTrace();
return false;
}
}
}
To check network connectivity
private boolean isNetworkConnected() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
}
Because isReachable is using the TCP protocol(by WireShark) The Ping command is using ICMP protocol,if you want to return true you need to open the 7 port
I am trying to reach a host and have the following code
if(!InetAddress.getByName(host).isReachable(TIMEOUT)){
throw new Exception("Host does not exist::"+ hostname);
}
The hostname I am able to ping from windows, and also did a tracert on it and it returns all the packets. But java throws out exception "Host does not exist::";
The Timeout value I experimented from giving 2000ms, to 5000ms. I tried 3000 as well. What is the cause of this problem I am not able to understand. I researched on the net and some say that InetAddress.getByName(host).isReachable(time) is not reliable and behaves according to the internal system.
What is the best alternative for this if this is true. Please suggest.
Either open a TCP Socket to a port you think is open (22 for Linux, 139 for Windows, etc.)
public static boolean isReachableByTcp(String host, int port, int timeout) {
try {
Socket socket = new Socket();
SocketAddress socketAddress = new InetSocketAddress(host, port);
socket.connect(socketAddress, timeout);
socket.close();
return true;
} catch (IOException e) {
return false;
}
}
Or use some hack to send an actual ping. (inspired from here: http://www.inprose.com/en/content/icmp-ping-in-java)
public static boolean isReachableByPing(String host) {
try{
String cmd = "";
if(System.getProperty("os.name").startsWith("Windows"))
cmd = "cmd /C ping -n 1 " + host + " | find \"TTL\"";
else
cmd = "ping -c 1 " + host;
Process myProcess = Runtime.getRuntime().exec(cmd);
myProcess.waitFor();
return myProcess.exitValue() == 0;
} catch( Exception e ) {
e.printStackTrace();
return false;
}
}
Same hack for Android can be found here:
I've found that ping -n 1 hostname isn't reliable either. If you get Reply from X.X.X.X: Destination host unreachable. the command actually gives an exit code of 0, thus giving you a lot of false positives.
The solution is to search for the string "TTL" in the result, as it only exists when you get a successful ping. Because the command has a pipe, you also need to use cmd /C.
Here is an example (Windows):
public boolean isReachable(String hostname) throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec(
"cmd /C ping -n 1 "+hostname+" | find \"TTL\""
);
return (p.waitFor() == 0);
}
I'm not sure of the unix equivalent, and don't have a unix machine to test on.
For Android developers: the above method does not work if inet is unavailable (more precisely when DNS cache runs in a timeout); what I found: DSN lookup always takes about 1 minute.
My code is like the following:
TIMEOUT = 5000;
socket.connect(new InetSocketAddress(ServerDomainName, Port), TIMEOUT);
It is expected that connect throws a timeout exception within about 5 seconds, but the time was 65 seconds when inet was unreachable (somebody describes it as fake inet connection: Connectivity says connected, but inet is unreachable).