projetc3/src/main/java/eu/m724/autopeerer/client/PacketHandler.java
Minecon724 1b3da520e7
Some checks failed
/ deploy (push) Failing after 24s
com
2024-12-26 15:13:31 +01:00

145 lines
6.2 KiB
Java

package eu.m724.autopeerer.client;
import eu.m724.autopeerer.client.bird.BirdLive;
import eu.m724.autopeerer.client.bird.BirdSession;
import eu.m724.autopeerer.client.wireguard.WireGuardKeys;
import eu.m724.autopeerer.client.wireguard.WireGuardLive;
import eu.m724.autopeerer.client.wireguard.WireGuardSession;
import eu.m724.autopeerer.common.AddressTools;
import eu.m724.autopeerer.common.packet.Packet;
import eu.m724.autopeerer.common.packet.Packets;
import eu.m724.autopeerer.common.packet.s2c.PingRequestPacket;
import eu.m724.autopeerer.common.packet.s2c.SessionRequestPacket;
import eu.m724.autopeerer.common.packet.c2s.PingResponsePacket;
import eu.m724.autopeerer.common.packet.c2s.SessionResponsePacket;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.UnknownHostException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.file.FileAlreadyExistsException;
import java.util.Base64;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Consumer;
public class PacketHandler {
Consumer<ByteBuffer> sender;
private final WireGuardLive wireGuardLive;
private final BirdLive birdLive;
private final String serverLinkLocal;
public PacketHandler(WireGuardLive wireGuardLive, BirdLive birdLive, String serverLinkLocal) {
this.wireGuardLive = wireGuardLive;
this.birdLive = birdLive;
this.serverLinkLocal = serverLinkLocal;
}
void handle(ByteBuffer bytes) {
Packet<?> p;
try {
p = Packets.parseClient(bytes);
} catch (BufferUnderflowException e) {
bytes.rewind();
byte[] bytez = new byte[bytes.remaining()];
bytes.get(bytez);
System.err.println("Received too short packet");
System.err.println("> Length: " + bytez.length);
System.err.println("> Packet: " + Base64.getEncoder().encodeToString(bytez));
return;
} catch (Exception e) {
throw new RuntimeException(e);
}
if (p instanceof PingRequestPacket packet) {
handlePingRequest(packet);
} else if (p instanceof SessionRequestPacket packet) {
handleSessionRequest(packet);
}
}
private void handlePingRequest(PingRequestPacket packet) {
System.out.printf("Ping request #%d to %s\n", packet.requestId, packet.target.getHostAddress());
CompletableFuture.runAsync(() -> {
float average = -1, meanDeviation = -1;
var status = PingResponsePacket.PingResponseStatus.ERROR;
try {
Process process = Runtime.getRuntime().exec(new String[] { "ping", "-3Ac", "10", "-W", "1", packet.target.getHostAddress() });
try (BufferedReader reader = process.inputReader()) {
for (String l : reader.lines().toList()) {
boolean end = l.startsWith("rtt");
if (l.startsWith("PING")) {
status = PingResponsePacket.PingResponseStatus.UNREACHABLE;
}
if (end) {
String[] results = l.split(" ")[3].split("/");
average = Float.parseFloat(results[1]);
meanDeviation = Float.parseFloat(results[3]);
status = PingResponsePacket.PingResponseStatus.OK;
}
}
}
} catch (IOException e) {
System.err.println("Error pinging");
e.printStackTrace();
}
System.out.printf("Ping request #%d to %s - %s avg %.3f / mdev %.3f ms\n", packet.requestId, packet.target.getHostAddress(), status, average, meanDeviation);
Packets.send(new PingResponsePacket(packet.requestId, status, average, meanDeviation), sender);
});
}
private void handleSessionRequest(SessionRequestPacket packet) {
// validate endpoint
var resolved = false;
try {
if (ClientPrefs.ipv6Supported()) {
var res = AddressTools.resolve(packet.endpointHost, true);
resolved = res != null;
}
if (!resolved && ClientPrefs.ipv4Supported()) {
var res = AddressTools.resolve(packet.endpointHost, true);
resolved = res != null;
}
} catch (UnknownHostException | AddressTools.MultipleRecordsException ignored) { }
if (!resolved) {
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.ERROR_RESOLVE, -1, null), sender);
return;
}
var privateKey = WireGuardKeys.generatePrivateKey();
var publicKey = WireGuardKeys.derivePublicKey(privateKey);
int port = ThreadLocalRandom.current().nextInt() & 0xFFFF;
if (packet.asn > 4242420000L) {
port = (int) (packet.asn % 10000);
}
var wireGuardSession = new WireGuardSession(port, privateKey, serverLinkLocal, packet.linkLocal.getHostAddress(), packet.endpointHost + ":" + packet.endpointPort, packet.publicKey);
var birdSession = new BirdSession(packet.asn, packet.linkLocal.getHostAddress());
try {
wireGuardLive.saveSession(packet.asn, wireGuardSession);
birdLive.saveSession(birdSession);
System.out.printf("Created session AS%d to %s\n", packet.asn, packet.endpointHost);
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.OK, wireGuardSession.listenPort(), publicKey), sender);
} catch (FileAlreadyExistsException e) {
System.err.println("Tried to create a session which already exists: AS" + packet.asn);
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.ERROR_DUPLICATE, -1, null), sender);
} catch (IOException e) {
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.ERROR_OTHER, -1, null), sender);
System.err.println("Failed to save session");
throw new RuntimeException(e);
}
}
}