流量转发模式修改Minecraft服务器列表MOTD的方法
本文介绍一种部署在边缘节点的修改Minecraft服务器列表MOTD信息的方法,Demo如下:

图中MikeWu597,即软件实现的基于IP地址实时判定游戏ID的方法。
感谢bangbang93于2021年提供的思路: GitHub Repo minecraft-proxy
本文代码仓库: GitHub Repo AgEdge
程序启动时创建监听器流程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| int localPort = <本地监听端口>; String remoteIp = <远程IP>; int remotePort = <远程端口>; Refresher ref = new Refresher(); ref.start();
ServerSocket serverSocket = new ServerSocket(localPort); log.info("localPort="+localPort + ";remoteIp=" + remoteIp + ";remotePort="+remotePort+";启动本地监听端口" + localPort + "成功!");
while(true){ Socket clientSocket = null; Socket remoteServerSocket = null; try { clientSocket = serverSocket.accept(); remoteServerSocket = new Socket(remoteIp ,remotePort); String clientIP = clientSocket.getLocalAddress().toString(); clientIP = clientIP.substring(clientIP.lastIndexOf("/")+1); log.info("客户端IP:"+clientIP); (new TransPortData(clientSocket ,remoteServerSocket ,"1")).start(); (new TransPortData(remoteServerSocket ,clientSocket,"2")).start(); } catch (Exception ex) { log.info("",ex); } }
|
TransPortData库对数据进行处理,流程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| try { while(true){
InputStream in = getDataSocket.getInputStream() ; OutputStream out = putDataSocket.getOutputStream() ; byte[] data = new byte[2048]; int readlen = in.read(data);
if(readlen<=0){ Thread.sleep(100); continue; } System.out.println(data[7]); if(data[7]==118 && data[8]==101 && data[9]==114 && data[10]==115 && data[11]==105 && data[12]==111 && data[13]==110){ for(int i=0;i<data.length-2;i++){ if (data[i]==110 && data[i+1]==118 && data[i+2]==118){ int offset=i-2; String ip = putDataSocket.getInetAddress().toString(); String editStr=("❌不支持自动登录\",\"color\":\"gray\"},{\"text\":\""); for (HashMap.Entry<String, String> entry : criteria.entrySet()) { System.out.println(entry.getValue()); if(("/"+entry.getKey()).equalsIgnoreCase(ip))editStr=("✔ "+entry.getValue()+"\",\"color\":\"green\",\"bold\":true},{\"text\":\""); } byte[] editBytes=editStr.getBytes(); for(int j=offset;j<offset+editBytes.length;j++)data[j]=editBytes[j-offset]; } } System.out.println(new String(data)); out.write(data ,0,readlen); } else out.write(data ,0,readlen);
out.flush(); } } catch (Exception e) { log.error("type:"+type,e); } finally{ try { if(putDataSocket != null){ putDataSocket.close(); } } catch (Exception exx) { }
try { if(getDataSocket != null){ getDataSocket.close(); } } catch (Exception exx) { } }
|
其中通过一个if语句快速执行对MOTD数据包的判定(即头文字”version”),检测到MOTD信息发送时立即劫持修改数据。修改时,通过服务端预设的关键字(此处为”nvv”)确定修改起始位置,预留足够多的空格避免超长。如需彻底解决此问题,需要像上述bangbang93仓库中代码一样完全重新构建一个MOTD数据包。这里为了降低复杂度、便于劫持,仅做了简单的修改功能。
检测到MOTD后,用putSocket取客户端IP,与预存的键值表HashMap比对,确认是否有预先注册过的用户IP,如有,则注入相应绿色标识,否则注入灰色标识。
程序通过一个单独线程定期从授权服务器拉取完整HashMap,更新授权库。