package com.intrbiz.bergamot.net.raw; import java.net.InetAddress; import java.security.SecureRandom; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import com.intrbiz.bergamot.net.raw.jna.SockAddrIn; import com.intrbiz.bergamot.net.raw.model.IPPacket; import com.intrbiz.bergamot.net.raw.model.IPPayload; import com.intrbiz.bergamot.net.raw.model.payload.ICMPPacket; public class PingTest { private RawEngine<Target> engine; private Timer timer; /* Targets to ping */ private Map<InetAddress, Target> targets = new HashMap<InetAddress, Target>(); /* Messages on the wire */ private Map<MessageKey,MessageState> messages = new HashMap<MessageKey, MessageState>(); private final SecureRandom random = new SecureRandom(); public PingTest() { super(); this.engine = new RawEngine<Target>(this::recvPing); this.timer = new Timer(); } private void sendPing(final Target target) { ICMPPacket payload = new ICMPPacket(ICMPPacket.ICMP_TYPE_ECHO, target.id, target.seq++); this.engine.send(target, payload, target.dest, 8, this::onSent); } private void onSent(Target target, IPPayload payload, InetAddress to, int port, SockAddrIn.ByReference addr) { ICMPPacket icmp = (ICMPPacket) payload; MessageKey key = new MessageKey(to, icmp.getId(), icmp.getSequence()); MessageState state = new MessageState(target, key, System.nanoTime()); this.messages.put(key, state); this.timer.schedule(state, target.interval / 2); } private void recvPing(IPPacket packet) { long gotAt = System.nanoTime(); ICMPPacket icmp = (ICMPPacket) packet.getPayload(); MessageState state = this.messages.remove(new MessageKey(packet.getSource(), icmp.getId(), icmp.getSequence())); if (state != null) { state.cancel(); System.out.println("ICMP Reply from " + state.target.dest + " seq " + ((ICMPPacket) packet.getPayload()).getSequence() + " in " + (((double)((gotAt - state.sentAt) / 1000L)) / 1000D) + "ms"); } else { // System.out.println("Duplicate or bad ICMP Reply from " + packet.getSource() + " seq " + ((ICMPPacket) packet.getPayload()).getSequence()); } } /** * Start the ICMP engine */ public void start() { this.engine.start(); } /** * Stop pinging stuff */ public void stop() { for (Target target : this.targets.values()) { target.cancel(); } this.engine.shutdown(); } /** * Add something to ping */ public void ping(final InetAddress dest, final int interval) { final Target target = new Target(dest, (short) this.random.nextInt(), interval); this.targets.put(dest, target); this.timer.scheduleAtFixedRate(target, this.random.nextInt(interval) , interval); } /** * Stop pinging something */ public void cancel(final InetAddress dest) { TimerTask task = this.targets.get(dest); if (task != null) task.cancel(); } public static final class MessageKey { public byte[] address; public short id; public short seq; public MessageKey(InetAddress address, short id, short seq) { this.address = address.getAddress(); this.id = id; this.seq = seq; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(address); result = prime * result + id; result = prime * result + seq; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; MessageKey other = (MessageKey) obj; if (!Arrays.equals(address, other.address)) return false; if (id != other.id) return false; if (seq != other.seq) return false; return true; } } public final class Target extends TimerTask { public final InetAddress dest; public final short id; public short seq = 0; public long interval; public Target(InetAddress dest, short id, long interval) { this.dest = dest; this.id = id; this.interval = interval; } public void run() { PingTest.this.sendPing(this); } } public static final class MessageState extends TimerTask { public final Target target; public final MessageKey key; public final long sentAt; public MessageState(Target target, MessageKey key, long sentAt) { this.target = target; this.key = key; this.sentAt = sentAt; } @Override public void run() { System.out.println("Timeout for " + this.target.dest + " seq " + this.key.seq); } } public static void main(String[] args) throws Exception { PingTest test = new PingTest(); test.start(); // start pinging things test.ping(InetAddress.getByName("google.com"), 10_000); test.ping(InetAddress.getByName("bbc.co.uk"), 10_000); test.ping(InetAddress.getByName("172.30.12.2"), 10_000); test.ping(InetAddress.getByName("172.30.12.1"), 10_000); test.ping(InetAddress.getByName("172.30.13.1"), 10_000); test.ping(InetAddress.getByName("172.30.13.42"), 10_000); test.ping(InetAddress.getByName("172.28.12.254"), 10_000); test.ping(InetAddress.getByName("172.28.12.253"), 10_000); test.ping(InetAddress.getByName("172.28.12.254"), 10_000); test.ping(InetAddress.getByName("10.250.100.122"), 10_000); test.ping(InetAddress.getByName("10.250.100.133"), 10_000); test.ping(InetAddress.getByName("10.250.100.144"), 10_000); test.ping(InetAddress.getByName("10.250.100.1"), 10_000); test.ping(InetAddress.getByName("172.30.13.10"), 10_000); test.ping(InetAddress.getByName("172.30.13.11"), 10_000); test.ping(InetAddress.getByName("172.30.13.12"), 10_000); test.ping(InetAddress.getByName("172.30.13.13"), 10_000); // /* int t = 0; for (int g = 176; g < 180; g ++) { for (int i = 122; i < 132; i ++) { for (int j = 100; j < 200; j++) { test.ping(InetAddress.getByName(g + ".35." + i + "." + j), 10_000); t++; } } } System.out.println("Added: " + t); */ } }