Skip to content

Commit

Permalink
feat(inject): Finished injectors
Browse files Browse the repository at this point in the history
  • Loading branch information
CarmJos committed Jan 3, 2024
1 parent 3d9eb04 commit 5df277f
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 279 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@
import com.artformgames.injector.bungeeauthproxy.handler.ProxiedAuthHandler;
import com.artformgames.injector.bungeeauthproxy.transformer.ProxyHandlerTransformer;
import io.netty.channel.EventLoop;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import net.md_5.bungee.api.Callback;
import net.md_5.bungee.connection.InitialHandler;

import java.lang.instrument.Instrumentation;

Expand All @@ -25,35 +21,19 @@ private BungeeAuthProxyInjector() {
public static void premain(String args, Instrumentation instrumentation) {
BungeeAuthProxyInjector.instance = instrumentation;
log(Logging.Level.INFO, "Loading auth configurations...");
EasyConfiguration.from("auth.yml").initialize(Config.class);
String configFileName = args == null || args.isBlank() ? "auth.yml" : args;
EasyConfiguration.from(configFileName).initialize(Config.class);

log(Logging.Level.INFO, "Initializing auth handler...");
handler = new ProxiedAuthHandler();

log(Logging.Level.INFO, "Injecting InitialHandler...");
instrumentation.addTransformer(new ProxyHandlerTransformer());


try {
ClassPool pool = ClassPool.getDefault();
pool.importPackage("com.artformgames.injector.bungeeauthproxy");

CtClass handlerClass = pool.getCtClass("net.md_5.bungee.connection.InitialHandler");
CtClass responseClass = pool.getCtClass("net.md_5.bungee.protocol.packet.EncryptionResponse");

CtMethod handleMethod = handlerClass.getDeclaredMethod("handle", new CtClass[]{responseClass});
log(Logging.Level.DEBUG, "Found target method: " + handleMethod.getLongName());
} catch (Exception ex) {
log(Logging.Level.ERROR, "Failed to inject handlers, are you really using BungeeCord?");
ex.printStackTrace();
}

instrumentation.addTransformer(new ProxyHandlerTransformer(), true);
}

public static void submitRequest(InitialHandler handler, String encodedHash,
EventLoop loop, Callback<String> callback) throws Exception {
log(Logging.Level.DEBUG, "Submitting request [" + handler.getName() + "] " + encodedHash);
getHandler().submit(handler, encodedHash, loop, callback);
public static void submitRequest(String url, EventLoop loop, Callback<String> callback) throws Exception {
log(Logging.Level.DEBUG, "Submitting request [" + url + "]");
getHandler().submit(url, loop, callback);
}

public static Instrumentation getInstance() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ public interface Config extends Configuration {
@HeaderComment("MineCraft service settings")
interface SERVICE extends Configuration {

@HeaderComment("The authentication url for minecraft.net")
ConfiguredValue<String> MOJANG_AUTH_URL = ConfiguredValue.of(
"https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s%s"
);

@HeaderComment("Timeout duration for single request in milliseconds.")
ConfiguredValue<Long> TIME_OUT = ConfiguredValue.of(5000L);

Expand All @@ -34,10 +29,7 @@ interface SERVICE extends Configuration {
@HeaderComment("Proxy server settings")
interface PROXY extends Configuration {

@HeaderComment("Whether to enable proxy to access the authentication services")
ConfiguredValue<Boolean> ENABLE = ConfiguredValue.of(true);

@HeaderComment("Proxy protocol, 0 = HTTP/HTTPS, 1 = SOCKS4, 2 = SOCKS5")
@HeaderComment("Proxy protocol, -1 = NO_PROXY ,0 = HTTP/HTTPS, 1 = SOCKS4, 2 = SOCKS5")
ConfiguredValue<Integer> PROTOCOL = ConfiguredValue.of(1);

@HeaderComment("Proxy host")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@ public static void log(Level level, String message) {
log(level, message, null);
}

public static void debug(String message) {
log(Level.DEBUG, message);
}

public static void error(String message) {
log(Level.ERROR, message);
}

public static void error(String message, Throwable e) {
log(Level.ERROR, message, e);
}

public static void warning(String message) {
log(Level.WARNING, message);
}

public static void log(Level level, String message, Throwable e) {
if (level == Level.DEBUG && !Config.DEBUG.getNotNull()) return;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@
import io.netty.channel.EventLoop;
import io.netty.handler.codec.http.*;
import jline.internal.Nullable;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.Callback;
import net.md_5.bungee.connection.InitialHandler;
import net.md_5.bungee.http.HttpClient;
import net.md_5.bungee.http.HttpInitializer;
import net.md_5.bungee.netty.PipelineUtils;

import java.net.*;
import java.nio.charset.StandardCharsets;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;

import static com.artformgames.injector.bungeeauthproxy.Logging.debug;

public class ProxiedAuthHandler {

protected Cache<String, InetAddress> addressCache;
Expand All @@ -32,52 +33,39 @@ public ProxiedAuthHandler() {
}
}

public void submit(InitialHandler handler, String encodedHash, EventLoop loop, Callback<String> callback) throws Exception {
submit(encodeName(handler.getName()), encodedHash, getPreventProxyParams(handler.getAddress()), loop, callback);
}

public void submit(String encodedName, String encodedHash, String preventProxy,
EventLoop loop, Callback<String> callback)
throws Exception {
submit(getAuthURL(encodedName, encodedHash, preventProxy), loop, callback);
}

public void submit(String authURL, EventLoop loop, Callback<String> callback) throws Exception {
if (!Config.PROXY.ENABLE.getNotNull()) { // Proxy disabled
HttpClient.get(authURL, loop, callback);
return;
}

URI uri = new URI(authURL);
Preconditions.checkNotNull((Object) uri.getScheme(), "scheme");
Preconditions.checkNotNull((Object) uri.getHost(), "host");
boolean ssl = uri.getScheme().equals("https");
int port = getPort(uri);

ProxyProtocolType proxyProtocol = getProxyProtocol();
InetAddress address = resolveAddress(proxyProtocol, uri.getHost());

ChannelFutureListener listener = channel -> {
if (channel.isSuccess()) {
String path = uri.getRawPath() + (uri.getRawQuery() == null ? "" : "?" + uri.getRawQuery());
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
request.headers().set(HttpHeaderNames.HOST, uri.getHost());
channel.channel().writeAndFlush(request);
} else {
addressCache.invalidate(uri.getHost());
callback.done(null, channel.cause());
}
};
Bootstrap bootstrap = new Bootstrap().channel(PipelineUtils.getChannel(null)).group(loop);

new Bootstrap().channel(PipelineUtils.getChannel(null)).group(loop)
.handler(new ProxiedHttpInitializer(proxyProtocol, callback, ssl, uri.getHost(), port))
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, Math.max(Config.SERVICE.TIME_OUT.getNotNull().intValue(), 100))
.remoteAddress(address, port)
.connect().addListener(listener);
InetAddress address = resolveAddress(uri.getHost());
ProxyProtocolType proxyProtocol = getProxyProtocol();
if (proxyProtocol != null) {
debug("Using proxy protocol [" + proxyProtocol.name() + "] for " + uri.getHost() + ":" + port);
bootstrap.handler(new ProxiedHttpInitializer(proxyProtocol, callback, ssl, uri.getHost(), port));
} else {
bootstrap.handler(new HttpInitializer(callback, ssl, uri.getHost(), port));
}
bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, Math.max(Config.SERVICE.TIME_OUT.getNotNull().intValue(), 100))
.remoteAddress(address, port).connect().addListener((ChannelFutureListener) channel -> {
if (channel.isSuccess()) {
String path = uri.getRawPath() + (uri.getRawQuery() == null ? "" : "?" + uri.getRawQuery());
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
request.headers().set(HttpHeaderNames.HOST, uri.getHost());
channel.channel().writeAndFlush(request);
} else {
addressCache.invalidate(uri.getHost());
callback.done(null, channel.cause());
}
});
}

private InetAddress resolveAddress(@Nullable ProxyProtocolType protocol, String host) throws UnknownHostException {
if (protocol == null || this.addressCache == null) return InetAddress.getByName(host);
private InetAddress resolveAddress(String host) throws UnknownHostException {
if (this.addressCache == null) return InetAddress.getByName(host);

InetAddress inetHost = addressCache.getIfPresent(host);
if (inetHost == null) {
Expand All @@ -91,15 +79,6 @@ private InetAddress resolveAddress(@Nullable ProxyProtocolType protocol, String
return ProxyProtocolType.parse(Config.PROXY.PROTOCOL.getNotNull());
}

public String getAuthURL(String encodedName, String encodedHash, String preventProxy) {
try {
return String.format(Config.SERVICE.MOJANG_AUTH_URL.getNotNull(), encodedName, encodedHash, preventProxy);
} catch (Exception e) {
e.printStackTrace();
return "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" + encodedName + "&serverId=" + encodedHash + preventProxy;
}
}

private static int getPort(URI uri) {
int port = uri.getPort();
if (port != -1) return port;
Expand All @@ -116,15 +95,4 @@ private static int getPort(URI uri) {
}
}

protected static String encodeName(String name) {
return URLEncoder.encode(name, StandardCharsets.UTF_8);
}

protected static String getPreventProxyParams(SocketAddress address) {
if (!BungeeCord.getInstance().config.isPreventProxyConnections() || !(address instanceof InetSocketAddress)) {
return "";
}
return URLEncoder.encode(((InetSocketAddress) address).getAddress().getHostAddress(), StandardCharsets.UTF_8);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,39 @@
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.LoaderClassPath;

import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

import static com.artformgames.injector.bungeeauthproxy.Logging.debug;
import static com.artformgames.injector.bungeeauthproxy.Logging.error;

public class ProxyHandlerTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classFileBuffer) throws IllegalClassFormatException {
if (!className.equals("net/md_5/bungee/connection/InitialHandler")) return classFileBuffer;

System.out.println("Handling: " + className);

byte[] transformed = null;
ClassPool pool = ClassPool.getDefault();
CtClass cl = null;

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classFileBuffer) throws IllegalClassFormatException {
if (!className.equals("net/md_5/bungee/http/HttpClient")) return classFileBuffer;
try {
cl = pool.makeClass(new ByteArrayInputStream(classFileBuffer));
CtClass responseClass = pool.getCtClass("net.md_5.bungee.protocol.packet.EncryptionResponse");

CtMethod handleMethod = cl.getDeclaredMethod("handle", new CtClass[]{responseClass});
handleMethod.insertBefore("System.out.println(\"Successfully loaded!!!!!\");");

transformed = cl.toBytecode();

ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new LoaderClassPath(loader));
CtClass clazz = pool.makeClass(new ByteArrayInputStream(classFileBuffer));
CtClass callbackClass = pool.getCtClass("net.md_5.bungee.api.Callback");
CtClass eventLoopClass = pool.getCtClass("io.netty.channel.EventLoop");
CtClass stringClass = pool.getCtClass("java.lang.String");

CtMethod handleMethod = clazz.getDeclaredMethod("get", new CtClass[]{stringClass, eventLoopClass, callbackClass});
debug("Injecting into " + handleMethod.getLongName());

handleMethod.setBody("{com.artformgames.injector.bungeeauthproxy.BungeeAuthProxyInjector.submitRequest($1, $2, $3);}");
return clazz.toBytecode();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cl != null) {
cl.detach();
}
error("Failed to inject handlers into [" + className + "], are you really using BungeeCord?", e);
return classFileBuffer;
}

return transformed;
}

}
Loading

0 comments on commit 5df277f

Please sign in to comment.