找回密码
 立即注册

手机短信,快捷登录

QQ登录

只需一步,快速开始

查看: 2914|回复: 0

用java编写一个websocket端口转发工具

[复制链接]

4

主题

2

回帖

20

积分

新手上路

积分
20
发表于 2024-1-6 16:43:13 | 显示全部楼层 |阅读模式
编写背景
工作原因,需要使用到内网,项目组的几个同事都要用内网,然后,甲方问上级申请了内网服务器。但是这个内网服务器需要通过堡垒机访问,而堡垒机只能用指定的两个内网ip访问。本来,两个ip是够用的,但是甲方有个领导是技术出身,就让我们在他的电脑上给他配置堡垒机的访问环境。然后,两个ip就被甲方领导占用了一个。然后,就导致内网ip不够用,我和同事经常等对方用完。
而资源池对内网开放了应用服务器的端口来供内网访问应用,堡垒机上只能编辑nginx的配置,虽然nginx支持tcp协议代理,但是需要安装单独的模块,内网显然是无法实现的。
所以,我就在网上搜索,有没有用websocket转发端口的程序,查了一下之后,发现一个go写的,又因为,资源池的服务器是没办法装go环境的,所以,我选择自己用java实现。

实现原理
我先用客户端监听本地的某一个端口,在有连接请求之后,客户端会生成一个随机的密钥,用公钥加密之后发送到服务器端,然后,服务器端和客户端之间的所有信息都会使用密钥加密通讯。socketServer收到的所有信息都加密后通过webSocket发送到服务端,而服务端又将数据解密后发送到目标ip和端口,再将从目标ip端口接收到的数据都加密了之后通过webSocket发送给客户端,客户端解密数据之后将数据反馈到本地的端口,然后就实现了资源池的端口加密映射到本地端口。数据库一类的端口映射出来后,就可以通过工具连接了,网页也可以映射,测试也可以正常访问。常见的应用的网络通讯,基本都是基于tcp协议的,所以,这样映射,基本可以满足日常开放。也就不用和同事争ip了。

核心代码

服务端

  1. @Component
  2. @Slf4j
  3. @ServerEndpoint("/ws")
  4. public class WSTServer {
  5.        
  6.        
  7.         private Session session;
  8.        
  9.         private int step = 0;
  10.        
  11.         private String k;
  12.         private String host;
  13.         private int port;
  14.        
  15.         private Socket socket;
  16.        
  17.         private OutputStream out;
  18.        
  19.         private DES des;
  20.        
  21.         @OnOpen
  22.         public void onOpen(Session session) {
  23.                 this.session = session;
  24.                 this.step = 0;
  25.                 log.info("连接建立");
  26.         }
  27.        
  28.         @OnMessage
  29.         public void strMsg(String msg) {
  30.                
  31.                 switch(step) {
  32.                        
  33.                 case 0:
  34.                         //密钥交换
  35.                         swKey(msg);
  36.                         break;
  37.                 case 1:
  38.                         //建立隧道
  39.                         buildLink(msg);
  40.                         break;
  41.                 }
  42.         }
  43.        
  44.         @OnMessage
  45.         public void byteMsg(byte[] b) {
  46.                 if( this.step == 2 ) {
  47.                         byte[] sendByte = this.des.decrypt(b);
  48.                         try {
  49.                                 this.out.write(sendByte);
  50.                         } catch (IOException e) {
  51.                                 e.printStackTrace();
  52.                         }
  53.                 }
  54.         }
  55.        
  56.         @OnClose
  57.         public void onClose() {
  58.                 if(this.socket != null) {
  59.                         try {
  60.                                 this.session.close();
  61.                         } catch (IOException e) {
  62.                                 e.printStackTrace();
  63.                         }
  64.                 }
  65.         }
  66.        
  67.         private void buildLink(String msg) {
  68.                
  69.                 try {
  70.                        
  71.                         String url = des.decryptStr(msg);
  72.                         List<String> pms = StrUtil.split(url, ":");
  73.                        
  74.                         this.host = pms.get(0);
  75.                         this.port = Integer.valueOf(pms.get(1));
  76.                        
  77.                         this.socket = new Socket(host, this.port);
  78.                        
  79.                         this.out = socket.getOutputStream();
  80.                        
  81.                         new Thread(()->{
  82.                                
  83.                                 try {
  84.                                        
  85.                                        
  86.                                         try(
  87.                                                 InputStream input = socket.getInputStream();
  88.                                         ){
  89.                                                
  90.                                                 while(socket.isConnected()) {
  91.                                                        
  92.                                                         byte[] b = new byte[1024];
  93.                                                         int len = 0;
  94.                                                         while( ( len = input.read(b) ) > 0) {
  95.                                                                 byte[] send = new byte[len];
  96.                                                                 System.arraycopy(b, 0, send, 0, len);
  97.                                                                 this.session.getBasicRemote().sendBinary(ByteBuffer.wrap(des.encrypt(send)));
  98.                                                         }
  99.                                                 }
  100.                                                
  101.                                         }
  102.                                        
  103.                                 }catch (IOException e) {
  104.                                         e.printStackTrace();
  105.                                 }
  106.                                
  107.                         }).start();
  108.                        
  109.                         sendMsg("success");
  110.                         this.step++;
  111.                        
  112.                         log.info("隧道建立成功");
  113.                 }catch (Exception e) {
  114.                         e.printStackTrace();
  115.                         log.info("隧道构建失败");
  116.                         close();
  117.                 }
  118.                
  119.         }
  120.        
  121.         private void swKey(String msg) {
  122.                 try {
  123.                         //获取客户端发来的密钥
  124.                         this.k = RsaUtil.decodeHex(msg);
  125.                         this.des = new DES(HexUtil.decodeHex(this.k));
  126.                         this.step++;
  127.                         sendMsg("success");
  128.                         log.info("密钥获取完毕");
  129.                 }catch (Exception e) {
  130.                         // 密钥获取失败,中断连接
  131.                         e.printStackTrace();
  132.                         log.info("密钥获取失败");
  133.                         close();
  134.                 }
  135.         }
  136.        
  137.         private void sendMsg(String msg) {
  138.                 if(this.des != null) {
  139.                         try {
  140.                                 this.session.getBasicRemote().sendText(this.des.encryptHex(msg));
  141.                         } catch (IOException e) {
  142.                                 e.printStackTrace();
  143.                         }
  144.                 }
  145.         }
  146.        
  147.         private void close() {
  148.                 try {
  149.                         this.session.close();
  150.                 } catch (IOException e1) {}
  151.         }
复制代码

客户端
  1. public class WSClient {

  2.         public static void main(String[] args) {
  3.                
  4.                 String pub = FileUtil.readString("pub", CharsetUtil.CHARSET_GBK);
  5.                 RSA rsa = new RSA(null,pub);
  6.                
  7.                 try (
  8.                                 ServerSocket server = new ServerSocket(Integer.valueOf(args[0]));
  9.                         ){
  10.                        
  11.                         while(true) {
  12.                                
  13.                                 Socket skt = server.accept();
  14.                                
  15.                                 InputStream in = skt.getInputStream();
  16.                                 OutputStream out = skt.getOutputStream();
  17.                                
  18.                                 new Thread( () -> {
  19.                                         buildLink(args[1],args[2],in, out, new DES(), rsa);
  20.                                 } ).start();
  21.                         }
  22.                        
  23.                 } catch (IOException e) {
  24.                         e.printStackTrace();
  25.                 }
  26.                
  27.         }

  28.         public static void buildLink(String tar,String ws,InputStream input, OutputStream out,DES des,RSA rsa) {
  29.                
  30.                 try {
  31.                        
  32.                         AtomicBoolean wconnect = new AtomicBoolean(true);
  33.                        
  34.                         WebSocketClient client = new WebSocketClient(new URI(ws)) {

  35.                                 @Override
  36.                                 public void onOpen(ServerHandshake handshakedata) {
  37.                                        
  38.                                 }

  39.                                 @Override
  40.                                 public void onMessage(String message) {
  41.                                         //接收到回复后,发送需要建立的连接
  42.                                         wconnect.set(false);
  43.                                 }
  44.                                
  45.                                 @Override
  46.                                 public void onMessage(ByteBuffer bytes) {
  47.                                         byte[] b = des.decrypt(bytes.array());
  48.                                         try {
  49.                                                 out.write(b);
  50.                                         } catch (IOException e) {
  51.                                                 e.printStackTrace();
  52.                                         }
  53.                                 }

  54.                                 @Override
  55.                                 public void onError(Exception ex) {

  56.                                 }

  57.                                 @Override
  58.                                 public void onClose(int code, String reason, boolean remote) {

  59.                                 }
  60.                         };
  61.                        
  62.                         client.connectBlocking();
  63.                        
  64.                         //建立连接后,发送信息
  65.                         client.send(rsa.encryptHex(HexUtil.encodeHexStr(des.getSecretKey().getEncoded()), KeyType.PublicKey));
  66.                        
  67.                         while(wconnect.get()) {
  68.                                 Thread.sleep(200);
  69.                         }
  70.                        
  71.                         //收到回复后,发送连接目标
  72.                         client.send(des.encryptHex(tar));
  73.                         wconnect.set(true);
  74.                        
  75.                         while(wconnect.get()) {
  76.                                 Thread.sleep(200);
  77.                         }
  78.                        
  79.                         //发送心跳包,防止会话过期
  80.                         new Thread( () -> {
  81.                                 while(true) {
  82.                                         client.send("123");
  83.                                         ThreadUtil.safeSleep(1000*5);
  84.                                 }
  85.                         }).start();
  86.                        
  87.                         //收到连接建立后,建立本地连接
  88.                         while(true) {
  89.                                
  90.                                 byte[] b = new byte[1024];
  91.                                 int len = 0;
  92.                                
  93.                                 while((len = input.read(b) ) > 0) {
  94.                                        
  95.                                         byte[] send = new byte[len];
  96.                                         System.arraycopy(b, 0, send, 0, len);
  97.                                        
  98.                                         client.send(des.encrypt(send));
  99.                                 }
  100.                         }
  101.                        
  102.                 } catch (URISyntaxException e) {
  103.                         e.printStackTrace();
  104.                 } catch (InterruptedException e) {
  105.                         e.printStackTrace();
  106.                 } catch (IOException e) {
  107.                         e.printStackTrace();
  108.                 }
  109.         }
  110. }
复制代码




回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|老超市 ( 辽ICP备16008076号-2|辽公网安备21140302000151号 )

GMT+8, 2024-5-14 01:35 , Processed in 0.123252 second(s), 21 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表