Capture Traffic

Sniffy allows you to record traffic sent or received via network and exposes it via Java API.

Example

    @Test
    public void testCaptureTraffic() throws Exception {

        try (Spy<?> spy = Sniffy.spy(
                SpyConfiguration.builder().captureNetworkTraffic(true).build()) // (1)
        ) {

            performSocketOperation(); // (2)

            Map<SocketMetaData, List<NetworkPacket>> networkTraffic = spy.getNetworkTraffic( // (3)
                    Threads.ANY, // (4)
                    AddressMatchers.anyAddressMatcher(), // (5)
                    GroupingOptions.builder().
                            groupByThread(false). // (6)
                            groupByStackTrace(false). // (7)
                            groupByConnection(false). // (8)
                            build()
            );

            assertEquals(1, networkTraffic.size());

            for (Map.Entry<SocketMetaData, List<NetworkPacket>> entry : networkTraffic.entrySet()) {

                SocketMetaData socketMetaData = entry.getKey(); // (9)

                Protocol protocol = socketMetaData.getProtocol(); // say TCP
                String hostName = socketMetaData.getAddress().getHostName(); // say "hostname.acme.com"
                int port = socketMetaData.getAddress().getPort(); // say 443

                List<NetworkPacket> networkPackets = entry.getValue(); // (10)

                assertArrayEquals(REQUEST, networkPackets.get(0).getBytes());
                assertTrue(networkPackets.get(0).isSent());

                assertArrayEquals(RESPONSE, networkPackets.get(1).getBytes());
                assertFalse(networkPackets.get(1).isSent());

            }

        }

    }
  1. Use captureNetworkTraffic(true) when creating a Spy instance to enable traffic capturing

  2. Invoke socket operation. Can be either in current or another thread. Plain socket API or NIO - doesn’t matter.

  3. Retrieve network packets filtered and grouped as defined in parameters

  4. Allows you to filter traffic by thread

  5. Allows you to filter traffic by target address and/or port

  6. Group traffic by thread

  7. Group traffic by stack trace

  8. Group traffic by connection id - surrogate identifier of network connection

  9. SocketMetaData describes the target host and port and other parameters as described above for GroupingOptions

  10. NetworkPacket contains data in bytes, timestamp, direction and optional stacktrace and thread information

Configuration

packetMergeThreshold allows you to specify threshold for combining similar network packets when capturing traffic. For example if your application calls SocketInputStream.read() 8 times in a row to read a 64-bit value, Sniffy will merge these calls into a single packet given that they were done within specified threshold and of course given that no write/sent operation was done between them.

SSL/TLS Traffic Decryption

Sniffy can decrypt capture traffic but you need to enable this feature explicitly using -D`io.sniffy.decryptTls` system property or IO_SNIFFY_DECRYPT_TLS environment variable. It’s also possible to enable it programmatically using io.sniffy.configuration.SniffyConfiguration.INSTANCE.setDecryptTls() method.

Decrypted traffic is available along with original traffic using dedicated getDecryptedNetworkTraffic method in Spy class.

Map<SocketMetaData, List<NetworkPacket>> decryptedNetworkTraffic = spy.getDecryptedNetworkTraffic(
        Threads.CURRENT,
        AddressMatchers.exactAddressMatcher("www.google.com:443"),
        GroupingOptions.builder().
                groupByConnection(false).
                groupByStackTrace(false).
                groupByThread(false).
                build()
);

Caveats

Some libraries like Apache APR and Netty (only when native transport is enabled explicitly) use native code for network operations. Currently Sniffy doesn’t capture this kind of traffic.