你是否有过这样的使用场景,比如有一个数据库或主机,因为安全、网络的关系,在你的电脑上无法直接访问。但是此时你有一个中间的机子,中间机子可以访问上述的数据库或主机,同时你的电脑可以访问该中间机子。
开动歪脑筋,能否在中间的机子上装一个什么软件,可以在你的电脑上直接访问你之前所不能访问的数据库或主机?
答案是肯定的,在中间机子上装一个TCP数据转发软件就可以了。这种现成的软件很多,linux自带的iptable也可以实现该功能。不过因为原理简单、还是自己动手、丰衣足食吧,上代码:
package com.ai.police.portmap;
import java.net.ServerSocket;
import java.net.Socket;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class TranslatePort {
private transient static Log log = LogFactory.getLog(TranslatePort.class);
public static void main(String[] args) {
try {
if(args == null || args.length<3){
log.error("输出参数不能为空,分别是 本地监听端口、远程IP、远程端口");
return;
}
//获取本地监听端口、远程IP和远程端口
int localPort = Integer.parseInt(args[0].trim());
String remoteIp = args[1].trim();
int remotePort = Integer.parseInt(args[2].trim());
//启动本地监听端口
ServerSocket serverSocket = new ServerSocket(localPort);
log.error("localPort="+localPort + ";remoteIp=" + remoteIp +
";remotePort="+remotePort+";启动本地监听端口" + localPort + "成功!");
while(true){
Socket clientSocket = null;
Socket remoteServerSocket = null;
try {
//获取客户端连接
clientSocket = serverSocket.accept();
log.error("accept one client");
//建立远程连接
remoteServerSocket = new Socket(remoteIp ,remotePort);
log.error("create remoteip and port success");
//启动数据转换接口
(new TransPortData(clientSocket ,remoteServerSocket ,"1")).start();
(new TransPortData(remoteServerSocket ,clientSocket,"2")).start();
} catch (Exception ex) {
log.error("",ex);
}
//建立连接远程
}
} catch (Exception e) {
log.error("",e);
}
}
}
package com.ai.police.portmap;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* 用于转发数据
* @author Administrator
*
*/
public class TransPortData extends Thread {
private transient static Log log = LogFactory.getLog(TranslatePort.class);
Socket getDataSocket;
Socket putDataSocket;
String type;
public TransPortData(Socket getDataSocket , Socket putDataSocket ,String type){
this.getDataSocket = getDataSocket;
this.putDataSocket = putDataSocket;
this.type = type;
}
public void run(){
try {
while(true){
InputStream in = getDataSocket.getInputStream() ;
OutputStream out = putDataSocket.getOutputStream() ;
//读入数据
byte[] data = new byte[1024];
int readlen = in.read(data);
//如果没有数据,则暂停
if(readlen<=0){
Thread.sleep(300);
continue;
}
out.write(data ,0,readlen);
out.flush();
}
} catch (Exception e) {
log.error("type:"+type,e);
}
finally{
//关闭socket
try {
if(putDataSocket != null){
putDataSocket.close();
}
} catch (Exception exx) {
}
try {
if(getDataSocket != null){
getDataSocket.close();
}
} catch (Exception exx) {
}
}
}
}
测试结果:
1、可以实现对oracle数据库、ssh 、telnet等转发,客户端只要连到中间机子对应的端口上,实现了直接操作后台数据库或主机的功能;
2、上述代码不支持HTTP转发,不能实现的原因并不是因为数据没有转发过去,HTTP是基于TCP上的一种高层协议,tcp数据肯定是转发给对应的web服务器了。不能实现的原因是http协议本身的原因,http请求报文中的host参数包含了目的web服务器的ip和端口,直接转发因为host数据不正确导致真正的web服务器会丢弃该请求;另外,还有其它http协议本身的原因,回头我会专门撰写一篇HTTP数据转发来描述解决方案