Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
Still some bugs to iron for instance being able to rejoin properly.
  • Loading branch information
SupremeMortal committed Dec 8, 2018
0 parents commit 1aee6de
Show file tree
Hide file tree
Showing 12 changed files with 925 additions and 0 deletions.
13 changes: 13 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Address proxy will bind to.
proxy:
host: 0.0.0.0
port: 19122
## Destination server which the client will connect to.
## You are only able to join offline mode servers
destination:
host: 127.0.0.1
port: 19132
## Pass packet buffers through to minimize processing (Disable to test protocol library for bugs)
pass-through: true
## Log packets for each session
log-packets: false
133 changes: 133 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.nukkitx</groupId>
<artifactId>proxypass</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>ProxyPass</name>

<repositories>
<repository>
<id>nukkitx-repo</id>
<url>https://repo.nukkitx.com/snapshot</url>
</repository>
</repositories>

<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.build.timestamp.format>HHmm-ddMMyyyy</maven.build.timestamp.format>
<jackson.version>2.9.6</jackson.version>
</properties>

<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.nukkitx.network</groupId>
<artifactId>raknet</artifactId>
<version>1.2.3-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>1.3.9</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.nukkitx.protocol</groupId>
<artifactId>bedrock-v291</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>${jackson.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.nukkitx</groupId>
<artifactId>common</artifactId>
<version>1.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.fusesource.jansi</groupId>
<artifactId>jansi</artifactId>
<version>1.17.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jline</groupId>
<artifactId>jline-reader</artifactId>
<version>3.7.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>4.41.2</version>
<scope>compile</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<Main-Class>com.nukkitx.proxypass.ProxyPass</Main-Class>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<dependencies>
<dependency>
<groupId>com.github.edwgiz</groupId>
<artifactId>maven-shade-plugin.log4j2-cachefile-transformer</artifactId>
<version>2.8.1</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<transformers>
<transformer
implementation="com.github.edwgiz.mavenShadePlugin.log4j2CacheTransformer.PluginsCacheFileTransformer">
</transformer>
</transformers>
</configuration>
</plugin>
</plugins>
</build>
</project>
54 changes: 54 additions & 0 deletions src/main/java/com/nukkitx/proxypass/Configuration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.nukkitx.proxypass;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.ToString;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

@Getter
@ToString
public class Configuration {

private Address proxy;
private Address destination;

@JsonProperty("pass-through")
private boolean passingThrough = true;
@JsonProperty("log-packets")
private boolean loggingPackets = false;

public static Configuration load(Path path) throws IOException {
try (BufferedReader reader = Files.newBufferedReader(path)) {
return ProxyPass.YAML_MAPPER.readValue(reader, Configuration.class);
}
}

public static Configuration load(InputStream stream) throws IOException {
return ProxyPass.YAML_MAPPER.readValue(stream, Configuration.class);
}

public static void save(Path path, Configuration configuration) throws IOException {
try (BufferedWriter writer = Files.newBufferedWriter(path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
ProxyPass.YAML_MAPPER.writerWithDefaultPrettyPrinter().writeValue(writer, configuration);
}
}

@Getter
@ToString
public static class Address {
private String host;
private int port;

InetSocketAddress getAddress() {
return new InetSocketAddress(host, port);
}
}
}
132 changes: 132 additions & 0 deletions src/main/java/com/nukkitx/proxypass/ProxyPass.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package com.nukkitx.proxypass;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
import com.nukkitx.network.raknet.RakNetClient;
import com.nukkitx.network.raknet.RakNetServer;
import com.nukkitx.protocol.bedrock.session.BedrockSession;
import com.nukkitx.protocol.bedrock.v291.Bedrock_v291;
import com.nukkitx.protocol.bedrock.wrapper.WrappedPacket;
import com.nukkitx.proxypass.network.NukkitSessionManager;
import com.nukkitx.proxypass.network.ProxyRakNetEventListener;
import com.nukkitx.proxypass.network.bedrock.session.DownstreamPacketHandler;
import com.nukkitx.proxypass.network.bedrock.session.ProxyPlayerSession;
import com.nukkitx.proxypass.network.bedrock.session.UpstreamPacketHandler;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Log4j2
@Getter
public class ProxyPass {
public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
public static final YAMLMapper YAML_MAPPER = (YAMLMapper) new YAMLMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
public static final String MINECRAFT_VERSION;
public static final int PROTOCOL_VERSION = 291;

static {
String minecraftVersion;

Package mainPackage = ProxyPass.class.getPackage();
try {
minecraftVersion = mainPackage.getImplementationVersion().split("-")[0];
} catch (NullPointerException e) {
minecraftVersion = "0.0.0";
}
MINECRAFT_VERSION = minecraftVersion;
}

private final AtomicBoolean running = new AtomicBoolean(true);
private NukkitSessionManager sessionManager = new NukkitSessionManager();
private RakNetServer<BedrockSession<ProxyPlayerSession>> rakNetServer;
private RakNetClient<BedrockSession<ProxyPlayerSession>> rakNetClient;
private InetSocketAddress targetAddress;
private InetSocketAddress proxyAddress;
private Configuration configuration;
private Path loggingDir;

public static void main(String[] args) {
ProxyPass proxy = new ProxyPass();
try {
proxy.boot();
} catch (IOException e) {
throw new RuntimeException(e);
}
}

public void boot() throws IOException {
log.info("Loading configuration...");
Path configPath = Paths.get(".").resolve("config.yml");
if (Files.notExists(configPath) || !Files.isRegularFile(configPath)) {
Files.copy(ProxyPass.class.getClassLoader().getResourceAsStream("config.yml"), configPath, StandardCopyOption.REPLACE_EXISTING);
}

configuration = Configuration.load(configPath);

proxyAddress = configuration.getProxy().getAddress();
targetAddress = configuration.getDestination().getAddress();

loggingDir = Paths.get(".").resolve("packet-logs/").toAbsolutePath();
Files.createDirectories(loggingDir);

log.info("Loading server...");
rakNetServer = RakNetServer.<BedrockSession<ProxyPlayerSession>>builder()
.eventListener(new ProxyRakNetEventListener())
.address(proxyAddress)
.packet(WrappedPacket::new, 0xfe)
.sessionManager(sessionManager)
.sessionFactory(rakNetSession -> {
BedrockSession<ProxyPlayerSession> session = new BedrockSession<>(rakNetSession);
session.setHandler(new UpstreamPacketHandler(session, this));
return session;
})
.build();
if (rakNetServer.bind()) {
log.info("RakNet server started on {}", proxyAddress);
} else {
log.fatal("RakNet server was not able to bind to {}", proxyAddress);
}
rakNetClient = new RakNetClient.Builder<BedrockSession<ProxyPlayerSession>>()
.packet(WrappedPacket::new, 0xfe)
.sessionFactory(rakNetSession -> {
BedrockSession<ProxyPlayerSession> session = new BedrockSession<>(rakNetSession, Bedrock_v291.V291_CODEC);
session.setHandler(new DownstreamPacketHandler(session, this));
return session;
})
.sessionManager(sessionManager)
.build();
log.info("RakNet client ready for connections to {}", targetAddress);
loop();
}

public void loop() {
Lock lock = new ReentrantLock();

while (running.get()) {
lock.lock();
try {
lock.newCondition().await(50, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
//Ignore
}
lock.unlock();
}
}

public void shutdown() {
running.compareAndSet(false, true);
rakNetClient.close();
rakNetServer.close();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.nukkitx.proxypass.network;

import com.flowpowered.math.GenericMath;
import com.nukkitx.network.SessionManager;
import com.nukkitx.protocol.bedrock.session.BedrockSession;
import com.nukkitx.proxypass.network.bedrock.session.ProxyPlayerSession;
import lombok.extern.log4j.Log4j2;

import java.util.concurrent.ThreadPoolExecutor;

@Log4j2
public class NukkitSessionManager extends SessionManager<BedrockSession<ProxyPlayerSession>> {
private static final int SESSIONS_PER_THREAD = 50;

/*public NukkitSessionManager() {
super(Executors.newSingleThreadScheduledExecutor());
ScheduledExecutorService service = (ScheduledExecutorService) executor;
service.scheduleAtFixedRate(this::onTick, 50, 50, TimeUnit.MILLISECONDS);
}*/

@Override
protected void onAddSession(BedrockSession<ProxyPlayerSession> session) {
adjustPoolSize();
}

@Override
protected void onRemoveSession(BedrockSession<ProxyPlayerSession> session) {
adjustPoolSize();
}

private void adjustPoolSize() {
if (executor instanceof ThreadPoolExecutor) {
ThreadPoolExecutor sessionTicker = (ThreadPoolExecutor) executor;
int threads = GenericMath.clamp(sessions.size() / SESSIONS_PER_THREAD, 1, Runtime.getRuntime().availableProcessors());
if (sessionTicker.getMaximumPoolSize() != threads) {
sessionTicker.setMaximumPoolSize(threads);
}
}
}

public void onTick() {
for (BedrockSession session : sessions.values()) {
executor.execute(session::onTick);
}
}
}
Loading

0 comments on commit 1aee6de

Please sign in to comment.