parent
a19fa8f2fa
commit
2ee1ff4ca4
9 changed files with 120 additions and 58 deletions
|
@ -1,5 +1,6 @@
|
|||
package eu.m724.autopeerer.client;
|
||||
|
||||
import eu.m724.autopeerer.client.bird.BirdLive;
|
||||
import eu.m724.autopeerer.client.wireguard.WireGuardLive;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -20,7 +21,9 @@ public class Main {
|
|||
URI serverUri = URI.create(config.getString("remote"));
|
||||
|
||||
var wireGuardLive = new WireGuardLive(new File(config.getString("wireguard.directory")));
|
||||
var packetHandler = new PacketHandler(wireGuardLive);
|
||||
var birdLive = new BirdLive(new File(config.getString("bird.directory")));
|
||||
|
||||
var packetHandler = new PacketHandler(wireGuardLive, birdLive, config.getString("link-local"));
|
||||
var client = new MyWebsocketClient(serverUri, packetHandler);
|
||||
|
||||
client.connect();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
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;
|
||||
|
@ -17,15 +19,20 @@ 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) {
|
||||
public PacketHandler(WireGuardLive wireGuardLive, BirdLive birdLive, String serverLinkLocal) {
|
||||
this.wireGuardLive = wireGuardLive;
|
||||
this.birdLive = birdLive;
|
||||
this.serverLinkLocal = serverLinkLocal;
|
||||
}
|
||||
|
||||
void handle(ByteBuffer bytes) {
|
||||
|
@ -49,7 +56,7 @@ public class PacketHandler {
|
|||
if (p instanceof PingRequestPacket packet) {
|
||||
handlePingRequest(packet);
|
||||
} else if (p instanceof SessionRequestPacket packet) {
|
||||
handleVpnRequest(packet);
|
||||
handleSessionRequest(packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,22 +95,29 @@ public class PacketHandler {
|
|||
});
|
||||
}
|
||||
|
||||
private void handleVpnRequest(SessionRequestPacket packet) {
|
||||
private void handleSessionRequest(SessionRequestPacket packet) {
|
||||
var privateKey = WireGuardKeys.generatePrivateKey();
|
||||
var publicKey = WireGuardKeys.derivePublicKey(privateKey);
|
||||
|
||||
// TODO fill port and link local
|
||||
var session = new WireGuardSession(12345, privateKey, "fefe:fefe::fefe", packet.linkLocal.toCompressedString(), packet.endpointHost + ":" + packet.endpointPort, packet.publicKey);
|
||||
int port = ThreadLocalRandom.current().nextInt() & 0xFFFF;
|
||||
if (packet.asn > 4242420000L) {
|
||||
port = (int) (packet.asn % 10000);
|
||||
}
|
||||
|
||||
var wireGuardSession = new WireGuardSession(port, privateKey, serverLinkLocal, packet.linkLocal.toCompressedString(), packet.endpointHost + ":" + packet.endpointPort, packet.publicKey);
|
||||
var birdSession = new BirdSession(packet.asn, packet.linkLocal.toCompressedString());
|
||||
|
||||
try {
|
||||
wireGuardLive.saveSession(packet.sessionId, session);
|
||||
System.out.printf("Created session #%d to %s\n", packet.sessionId, packet.endpointHost);
|
||||
Packets.send(new SessionResponsePacket(packet.sessionId, SessionResponsePacket.SessionResult.OK, session.listenPort(), publicKey), sender);
|
||||
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: #" + packet.sessionId);
|
||||
Packets.send(new SessionResponsePacket(packet.sessionId, SessionResponsePacket.SessionResult.ERROR, -1, null), sender);
|
||||
System.err.println("Tried to create a session which already exists: AS" + packet.asn);
|
||||
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.DUPLICATE, -1, null), sender);
|
||||
} catch (IOException e) {
|
||||
Packets.send(new SessionResponsePacket(packet.sessionId, SessionResponsePacket.SessionResult.ERROR, -1, null), sender);
|
||||
Packets.send(new SessionResponsePacket(packet.asn, SessionResponsePacket.SessionResult.ERROR, -1, null), sender);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
|
33
src/main/java/eu/m724/autopeerer/client/bird/BirdLive.java
Normal file
33
src/main/java/eu/m724/autopeerer/client/bird/BirdLive.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
package eu.m724.autopeerer.client.bird;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
|
||||
public class BirdLive {
|
||||
private final File configsPath;
|
||||
|
||||
public BirdLive(File configsPath) {
|
||||
System.out.println("Bird config path: " + configsPath.getAbsolutePath());
|
||||
this.configsPath = configsPath;
|
||||
}
|
||||
|
||||
public void saveSession(BirdSession session) throws IOException {
|
||||
File file = new File(configsPath, "ap_" + session.asn() + ".conf");
|
||||
Files.writeString(file.toPath(), session.config(), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
|
||||
}
|
||||
|
||||
public BirdSession getSession(long asn) throws IOException {
|
||||
File file = new File(configsPath, "ap_" + asn + ".conf");
|
||||
|
||||
String s = Files.readString(file.toPath());
|
||||
return BirdSession.fromString(s);
|
||||
}
|
||||
|
||||
public boolean existsSession(long asn) {
|
||||
File file = new File(configsPath, "ap_" + asn + ".conf");
|
||||
return file.exists();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package eu.m724.autopeerer.client.bird;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public record BirdSession(
|
||||
long asn,
|
||||
String linkLocal
|
||||
) {
|
||||
private static Pattern PATTERN = Pattern.compile("protocol bgp as\\d+ from dnpeers \\{\n"
|
||||
+ " neighbor [0-9a-f:]+ % as\\d+ as \\d+;\n"
|
||||
+ "}");
|
||||
|
||||
public String config() {
|
||||
return """
|
||||
protocol bgp %s from dnpeers {
|
||||
neighbor %s %% %s as %d;
|
||||
}"""
|
||||
.formatted("as" + asn, linkLocal, "as" + asn, asn);
|
||||
}
|
||||
|
||||
public static BirdSession fromString(String s) {;
|
||||
var matcher = PATTERN.matcher(s);
|
||||
if (!matcher.matches()) return null;
|
||||
|
||||
var asn = Integer.parseInt(matcher.group(0));
|
||||
var linkLocal = matcher.group(1);
|
||||
|
||||
return new BirdSession(
|
||||
asn, linkLocal
|
||||
);
|
||||
}
|
||||
}
|
|
@ -8,24 +8,24 @@ public class WireGuardLive {
|
|||
private final File configsPath;
|
||||
|
||||
public WireGuardLive(File configsPath) {
|
||||
System.out.println(configsPath.getAbsolutePath());
|
||||
System.out.println("WireGuard config path: " + configsPath.getAbsolutePath());
|
||||
this.configsPath = configsPath;
|
||||
}
|
||||
|
||||
public void saveSession(int sessionId, WireGuardSession session) throws IOException {
|
||||
File file = new File(configsPath, "ap_" + sessionId + ".conf");
|
||||
public void saveSession(long asn, WireGuardSession session) throws IOException {
|
||||
File file = new File(configsPath, "ap_" + asn + ".conf");
|
||||
Files.writeString(file.toPath(), session.config(), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
|
||||
}
|
||||
|
||||
public WireGuardSession getSession(int sessionId) throws IOException {
|
||||
File file = new File(configsPath, "ap_" + sessionId + ".conf");
|
||||
public WireGuardSession getSession(long asn) throws IOException {
|
||||
File file = new File(configsPath, "ap_" + asn + ".conf");
|
||||
|
||||
String s = Files.readString(file.toPath());
|
||||
return WireGuardSession.fromString(s);
|
||||
}
|
||||
|
||||
public boolean existsSession(int sessionId) {
|
||||
File file = new File(configsPath, "ap_" + sessionId + ".conf");
|
||||
public boolean existsSession(long asn) {
|
||||
File file = new File(configsPath, "ap_" + asn + ".conf");
|
||||
return file.exists();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@ import java.nio.ByteBuffer;
|
|||
import java.util.Base64;
|
||||
|
||||
public class SessionResponsePacket implements Packet<SessionResponsePacket> {
|
||||
public final short sessionId;
|
||||
public final long asn;
|
||||
public final SessionResult result;
|
||||
public final int port;
|
||||
public final String publicKey;
|
||||
|
||||
public SessionResponsePacket(short connectionId, SessionResult result, int port, String publicKey) {
|
||||
this.sessionId = connectionId;
|
||||
public SessionResponsePacket(long asn, SessionResult result, int port, String publicKey) {
|
||||
this.asn = asn;
|
||||
this.result = result;
|
||||
this.port = port;
|
||||
this.publicKey = publicKey;
|
||||
|
@ -24,7 +24,7 @@ public class SessionResponsePacket implements Packet<SessionResponsePacket> {
|
|||
}
|
||||
|
||||
public static SessionResponsePacket deserialize(ByteBuffer buffer) throws Exception {
|
||||
var id = buffer.getShort();
|
||||
var asn = Integer.toUnsignedLong(buffer.getInt());
|
||||
var result = SessionResult.values()[buffer.get()];
|
||||
|
||||
int port = -1;
|
||||
|
@ -38,15 +38,14 @@ public class SessionResponsePacket implements Packet<SessionResponsePacket> {
|
|||
publicKey = Base64.getEncoder().encodeToString(pkb);
|
||||
}
|
||||
|
||||
|
||||
return new SessionResponsePacket(id, result, port, publicKey);
|
||||
return new SessionResponsePacket(asn, result, port, publicKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer serialize() {
|
||||
var buffer = ByteBuffer.allocate(result == SessionResult.OK ? 37 : 3);
|
||||
var buffer = ByteBuffer.allocate(result == SessionResult.OK ? 39 : 5);
|
||||
|
||||
buffer.putShort(sessionId);
|
||||
buffer.putInt((int) asn);
|
||||
buffer.put((byte) result.ordinal());
|
||||
|
||||
if (result == SessionResult.OK) {
|
||||
|
@ -54,11 +53,10 @@ public class SessionResponsePacket implements Packet<SessionResponsePacket> {
|
|||
buffer.put(Base64.getDecoder().decode(publicKey));
|
||||
}
|
||||
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public enum SessionResult {
|
||||
OK, ERROR
|
||||
OK, ERROR, DUPLICATE
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,15 +12,15 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.util.Base64;
|
||||
|
||||
public class SessionRequestPacket implements Packet<SessionRequestPacket> {
|
||||
public final short sessionId;
|
||||
public final long asn;
|
||||
public final IPv6Address linkLocal;
|
||||
public final String publicKey;
|
||||
public final String endpointHost;
|
||||
public final int endpointPort;
|
||||
public final long asn;
|
||||
|
||||
public SessionRequestPacket(short sessionId, IPv6Address linkLocal, String publicKey, String endpointHost, int endpointPort, long asn) {
|
||||
this.sessionId = sessionId;
|
||||
public SessionRequestPacket(long asn, IPv6Address linkLocal, String publicKey, String endpointHost, int endpointPort) {
|
||||
this.asn = asn;
|
||||
assert asn < 0xFFFFFFFFL;
|
||||
|
||||
this.linkLocal = linkLocal;
|
||||
assert new IPAddressString("fe80::/10").getAddress().contains(linkLocal);
|
||||
|
@ -37,9 +37,6 @@ public class SessionRequestPacket implements Packet<SessionRequestPacket> {
|
|||
|
||||
this.endpointPort = endpointPort;
|
||||
assert endpointPort > 0 && endpointPort < 65536;
|
||||
|
||||
this.asn = asn;
|
||||
assert asn < 0xFFFFFFFFL;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,7 +45,7 @@ public class SessionRequestPacket implements Packet<SessionRequestPacket> {
|
|||
}
|
||||
|
||||
public static SessionRequestPacket deserialize(ByteBuffer buffer) throws Exception {
|
||||
var id = buffer.getShort();
|
||||
var asn = Integer.toUnsignedLong(buffer.getInt());
|
||||
|
||||
var ll = new byte[16];
|
||||
buffer.get(ll);
|
||||
|
@ -65,22 +62,19 @@ public class SessionRequestPacket implements Packet<SessionRequestPacket> {
|
|||
buffer.get(ep);
|
||||
var endpointHost = new String(ep, StandardCharsets.US_ASCII);
|
||||
|
||||
var asn = Integer.toUnsignedLong(buffer.getInt());
|
||||
|
||||
return new SessionRequestPacket(id, linkLocal, publicKey, endpointHost, endpointPort, asn);
|
||||
return new SessionRequestPacket(asn, linkLocal, publicKey, endpointHost, endpointPort);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer serialize() {
|
||||
var buffer = ByteBuffer.allocate(57 + endpointHost.length());
|
||||
var buffer = ByteBuffer.allocate(55 + endpointHost.length());
|
||||
|
||||
buffer.putShort(sessionId); // 2b
|
||||
buffer.putInt((int) asn);
|
||||
buffer.put(linkLocal.getBytes()); // 16b
|
||||
buffer.put(Base64.getDecoder().decode(publicKey)); // 32b
|
||||
buffer.putShort((short) endpointPort); // 2b
|
||||
buffer.put((byte) endpointHost.length()); // 1b
|
||||
buffer.put(endpointHost.getBytes(StandardCharsets.US_ASCII));
|
||||
buffer.putInt((int) asn);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
|
|
@ -33,20 +33,6 @@ public class MyWebsocketServer extends WebSocketServer {
|
|||
var state = new ClientState(++id, conn);
|
||||
states.put(conn, state);
|
||||
System.out.printf("[%d] Connected: %s\n", id, conn.getRemoteSocketAddress().getHostString());
|
||||
|
||||
// TODO testing
|
||||
/*state.send(new PingRequestPacket((short) 1, InetAddress.getByName("1.1.1.1")));
|
||||
state.send(new PingRequestPacket((short) 2, InetAddress.getByName("1.2.3.4")));
|
||||
state.send(new PingRequestPacket((short) 3, InetAddress.getByName("1.1.1.2")));*/
|
||||
|
||||
state.send(new SessionRequestPacket(
|
||||
(short) 1,
|
||||
new IPAddressString("fe80::dead:fed").getAddress().toIPv6(),
|
||||
"IBusHriGmiJaqbp0IGfClDDHXcei8+JL1MIHjueheUw=",
|
||||
"end.point",
|
||||
51820,
|
||||
4242420000L
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
remote=ws://127.0.0.1:8002
|
||||
wireguard.directory=config/wg
|
||||
bird.directory=config/bird
|
||||
link-local=fe80::129:0
|
Loading…
Reference in a new issue