hofund icon indicating copy to clipboard operation
hofund copied to clipboard

Monitor outgoing traffic of UDP and TCP protocols to monitor if all connections are monitored and inform about it in logs

Open marwin1991 opened this issue 1 year ago • 8 comments

@witx98 what do you think about something like this?

marwin1991 avatar Nov 18 '24 18:11 marwin1991

I found some relevant information regarding TCP and UDP support in Spring Integration that might be useful for this issue https://docs.spring.io/spring-integration/reference/ip.html Could you please clarify what exactly we want to know about these connections? @marwin1991

witx98 avatar Nov 21 '24 16:11 witx98

@witx98 I was thinking about something more like this https://stackoverflow.com/a/63197003

The idea is that, application can do some connections, but we don't know about it and this should capture it and print to logs (if it's not monitored by hofund)

marwin1991 avatar Nov 21 '24 16:11 marwin1991

The approach mentioned in the Stack Overflow is based on SecurityManager which is deprecated and planned for removal in future Java versions. @marwin1991

witx98 avatar Nov 21 '24 17:11 witx98

@witx98 yes, but maybe we can find something inside JVM or lib that will allow us to do it :)

marwin1991 avatar Nov 21 '24 18:11 marwin1991

@marwin1991 maybe this way is the way XD ? https://github.com/slytechs-repos/jnetpcap-wrapper?tab=readme-ov-file

Athi avatar Nov 21 '24 18:11 Athi

@Athi @witx98

I have made some simple research and jnetpcap-wrapper but it requires Java23.

package abc;

import org.jnetpcap.Pcap;
import org.jnetpcap.PcapException;
import org.jnetpcap.PcapHeader;
import org.jnetpcap.PcapIf;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;

public class Test {

    void main() throws PcapException {
        List<PcapIf> devices = Pcap.findAllDevs();
        for(PcapIf device: devices) {
            try (Pcap pcap = Pcap.create(device)) {
                pcap.activate();
                pcap.loop(0, (String msg, PcapHeader header, byte[] packet) -> {
                    System.out.println(msg + " " + header.toString() + " " + new String(packet));
                }, "[" + device.name() + " - Capture Example]");
            }
        }
    }

    public static void main(String[] args) throws PcapException {
        System.out.println("Przed inicjalizacji");
        new Thread(() -> {
            try {
                new Test().main();
            } catch (PcapException e) {
                throw new RuntimeException(e);
            }
        }).start();
        System.out.println("Po inicjalizacji");

        try {
            // Create HttpClient
            HttpClient client = HttpClient.newHttpClient();

            // Create HttpRequest
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(new URI("https://www.google.com"))
                    .GET() // Optional, as GET is the default method
                    .build();

            // Send request and receive HttpResponse
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

            // Print the response
            System.out.println("Status Code: " + response.statusCode());
//            System.out.println("Response Body: ");
//            System.out.println(response.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

I don't now yet how to properly capture traffic, because it looks like it capute with delay (i dont see this call, but I see traffic I made from browser).

The second thing to do is to verify how to get url from raw network package

marwin1991 avatar Nov 24 '24 12:11 marwin1991

this looks nice and simple:

package pl.com.softnet.jbramka;

import java.net.*;
import java.io.*;
import java.util.*;

public class MonitorOutgoingTraffic {

    public static void main(String[] args) {
        ProxySelector.setDefault(new LoggingProxySelector(ProxySelector.getDefault()));

        // Example outgoing request
        try {
            URL url = new URL("https://example.com");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();
            System.out.println("Response Code: " + connection.getResponseCode());
            connection.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class LoggingProxySelector extends ProxySelector {
    private final ProxySelector defaultProxySelector;

    public LoggingProxySelector(ProxySelector defaultProxySelector) {
        this.defaultProxySelector = defaultProxySelector;
    }

    @Override
    public List<Proxy> select(URI uri) {
        System.out.println("Outgoing connection detected: " + uri);
        return defaultProxySelector.select(uri);
    }

    @Override
    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
        System.err.println("Connection failed to URI: " + uri);
        ioe.printStackTrace();
    }
}

output:

Outgoing connection detected: socket://127.0.0.1:40563
Outgoing connection detected: https://example.com/
Outgoing connection detected: socket://example.com:443
Response Code: 200

Process finished with exit code 0

marwin1991 avatar Nov 24 '24 12:11 marwin1991

Other option is to use AgentBuddy

package abc;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;


import static net.bytebuddy.matcher.ElementMatchers.named;

public class MonitorSocketTraffic {


    public static void main(String[] args) {
        // Install ByteBuddyAgent dynamically
        ByteBuddyAgent.install();

        // Redefine the Socket class using ByteBuddy with reloading strategy
        new ByteBuddy()
                .redefine(Socket.class)
                .visit(Advice.to(SocketAdvice.class).on(named("connect")))
                .make()
                .load(Socket.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());


        // Example outgoing request
        try {
            URL url = new URL("https://example.com");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();
            System.out.println("Response Code: " + connection.getResponseCode());
            connection.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static class SocketAdvice {
        @Advice.OnMethodEnter
        public static void onEnter(@Advice.Argument(0) Object address) {
            System.out.println("Outgoing connection: " + address);
        }
    }
}

output:

WARNING: A Java agent has been loaded dynamically (/home/pz2/.m2/repository/net/bytebuddy/byte-buddy-agent/1.15.10/byte-buddy-agent-1.15.10.jar)
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
WARNING: Dynamic loading of agents will be disallowed by default in a future release
Outgoing connection: example.com/93.184.215.14:443
Response Code: 200

Process finished with exit code 0
		<dependency>
			<groupId>net.bytebuddy</groupId>
			<artifactId>byte-buddy</artifactId>
			<version>1.15.10</version>
		</dependency>
		<dependency>
			<groupId>net.bytebuddy</groupId>
			<artifactId>byte-buddy-agent</artifactId>
			<version>1.15.10</version>
		</dependency>

marwin1991 avatar Nov 24 '24 13:11 marwin1991