javapingjpcap

Capture ping packets throws exception (too many instances)


I have written a code snippet to cpature ping using JPCAP. the code I have written is given below :

while (true) {
    try {
    PacketCapture m_pcap;
    m_pcap = new PacketCapture();
    m_pcap.open("\\Device\\NPF_{007262BD-....-7EE83D72EBEA}",true);//param 1 is actual device ID
    m_pcap.setFilter("proto ICMP", true);
    pktlistener a = new pktlistener(); //handles the packet
    m_pcap.addPacketListener(a);
    System.out.println("going to sleep");
    Thread.sleep(1 * 1000);// Waiting for 1 second before ending capture
    System.out.println("woken up");
    m_pcap.removePacketListener(a);
    m_pcap.endCapture();
    m_pcap.close();
    a = null;
    m_pcap = null;
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Now the above code starts a new capture after every one second. The problem with the above is that after 10 runs of the loop, it throws the exception :

 Exception in thread "Thread-6" java.lang.Error: Too many instances, exceeds 10
    at net.sourceforge.jpcap.capture.PacketCapture.<init>(PacketCapture.java:51)

Q1. How do i prevent this. I need to start a new PacketCapture every second.

Q2. Is there any other simpler way to capture ping messages recived on a system through java?


Solution

  • You cannot use the constructor of PacketCapture more than ten times. This behavior is hardcoded as the constructor looks like this:

    /**
     * Create a new packet capture instance.
     */
    public PacketCapture() {
        if (nextInstance >= INSTANCE_MAX) {
            throw new Error("Too many instances, exceeds " + INSTANCE_MAX);
        }
    
        instanceNum = nextInstance++;
    }
    

    To capture ping requests, you should try the following code

    public class Main {
    
        public static void main(String[] args) throws CaptureDeviceLookupException {
            Capture cap = new Capture();
            cap.doCapture();
        }
    }
    
    class PingListener implements PacketListener {
    
        @Override
        public void packetArrived(Packet packet) {
            try {
                // only ICMP packages
                if (packet instanceof ICMPPacket) {
                    ICMPPacket tcpPacket = (ICMPPacket) packet;
                    int data = tcpPacket.getMessageCode();
                    // only echo request packages
                    if (data == ICMPMessages.ECHO) {
                        // print source and destination.
                        String srcHost = tcpPacket.getSourceAddress();
                        String dstHost = tcpPacket.getDestinationAddress();
                        System.out.println("Ping from: " + srcHost + " to " + dstHost);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    
    class Capture {
        public void doCapture() {
            // create capture instance
            PacketCapture capture = new PacketCapture();
            // add listener that handles incomming and outgoing packages
            PingListener pingListener = new PingListener();
            capture.addPacketListener(pingListener);
            // m_pcap.setFilter("filter here or in handler", true);
    
            try {
                capture.open("\\Device\\NPF_{...}", true); // connect capture to device
                while (true) {
                    capture.capture(1); // capture one package
                }
            } catch (Exception e) {
                e.printStackTrace(); // exception during capture or handling of
                                     // packages
            } finally {
                // technically never reached as the loop goes on forever.
                // if loop terminates after a while then:
    
                // remove listener
                capture.removePacketListener(pingListener);
                // end capture (only necessary, if PacketCapture still waits for
                // other packages)
                capture.endCapture();
                // close connection to capture device
                capture.close();
            }
        }
    }
    

    I think there is a misunderstanding of the class PacketCapture. It does not actually capture one package and is then discarded. It opens a connection to the device you want to capture packages of and then starts listening for as long as you hold that connection. You then start capturing n packages by calling capture.capture(n). For each package arriving while "capture" blocks your program, the listener is called.

    Alternatively you can drop the while-loop and use capture.capture(-1). This will block your program forever until you close the capture from another device.