emanuele-f / PCAPReceiver

A sample app to show how to receive packets via PCAPdroid
13 stars 4 forks source link

Doesn't appear to work with pcapdroid_trailer #1

Closed TeamB1-GP closed 3 months ago

TeamB1-GP commented 2 years ago

If I set the pcapdroid_trailer property to true in the intent, the CaptureThread always sees an exception thrown when trying to parse the IPv4 packet. If I set the property to false or remove it, I see lots of happy packets.

The actual exception is "org.pcap4j.packet.IllegalRawDataException: The ihl must be equal or more than5but it is: 0". The error happens in the ipV4Packet parsing code, but that was called from line 62 in CaptureThread.

I speculate that when the trailer packet is appended, the packet parsing or the size difference might be getting confused? Maybe it just doesn't see it as the trailer and thinks it must be another IP header/packet? Maybe the "len - 16" needs some adjusting if the trailer is in place? Something else?

emanuele-f commented 2 years ago

When the trailer option is enabled, PCAPdroid will add a fake ethernet header to the packet. So in this case you need to parse the packet as Ethernet, try to replace IpV4Packet with EthernetPacket

slhck commented 3 months ago

This is as simple as changing the parsing function in CaptureThread.java to make an Ethernet packet:

EthernetPacket pkt = EthernetPacket.newPacket(buf, 16, len - 16);

Then, in the callback (here I made a new one onEthPacketReceived):

void onPacketReceived(EthernetPacket pkt) {
    if (pkt.getPayload() instanceof IpV4Packet) {
        IpV4Packet ipV4Packet = (IpV4Packet) pkt.getPayload();
        IpV4Packet.IpV4Header hdr = ipV4Packet.getHeader();
        mLog.append(String.format("[%s] %s -> %s [%d B]\n",
                hdr.getProtocol(),
                hdr.getSrcAddr().getHostAddress(), hdr.getDstAddr().getHostAddress(),
                ipV4Packet.length()));
    } else {
        Log.w(TAG, "Received non-IPv4 packet");
    }
}

To actually handle the trailer contents, you can add a bit of code:

private static final int PCAPDROID_TRAILER_SIZE = 32;
private static final int PCAPDROID_MAGIC = 0x01072021;
private static final int FCS_SIZE = 4;

void onPacketReceived(EthernetPacket pkt) {
    int ethPayloadLength = pkt.length();
    if (ethPayloadLength < PCAPDROID_TRAILER_SIZE) {
        Log.w(TAG, "Packet too short to contain trailer");
        return;
    }

    byte[] trailer = Arrays.copyOfRange(pkt.getRawData(), ethPayloadLength - PCAPDROID_TRAILER_SIZE, ethPayloadLength - FCS_SIZE);

    ByteBuffer trailerBuffer = ByteBuffer.wrap(trailer);

    int magic = trailerBuffer.getInt(0);
    int uid = trailerBuffer.getInt(4);
    byte[] appNameBytes = new byte[20];
    trailerBuffer.position(8);
    trailerBuffer.get(appNameBytes, 0, 20);
    String appName = new String(appNameBytes, StandardCharsets.UTF_8).trim();

    if (magic != PCAPDROID_MAGIC) {
        Log.w(TAG, "Invalid magic number: " + Integer.toHexString(magic));
        return;
    }

    if (pkt.getPayload() instanceof IpV4Packet) {
        IpV4Packet ipV4Packet = (IpV4Packet) pkt.getPayload();
        // Handle the IPv4 packet (similar to the previous example)
        IpV4Packet.IpV4Header hdr = ipV4Packet.getHeader();
        mLog.append(String.format("[%s] %s -> %s [%d B] (App: %s, UID: %d)\n",
                hdr.getProtocol(),
                hdr.getSrcAddr().getHostAddress(), hdr.getDstAddr().getHostAddress(),
                ipV4Packet.length(), appName, uid));
    } else {
        Log.w(TAG, "Received non-IPv4 packet");
    }
}

This prints the app and UID:

image
emanuele-f commented 3 months ago

@slhck this would be a great addition for a pull request 😉

emanuele-f commented 3 months ago

Merged: https://github.com/emanuele-f/PCAPReceiver/pull/3