`
liyixing1
  • 浏览: 939527 次
  • 性别: Icon_minigender_1
  • 来自: 江西上饶
社区版块
存档分类
最新评论

jdbc ssh通道

ssh 
阅读更多
java通过ssh链接数据库,需要用到
JSCH是一个纯粹的用java实现SSH功能的java  客户端。

原理则是先通过 jsch链接到真实的ssh目标服务器,建立起链接通道。

然后通过jsch开启一个本地端口,数据库链接,先进入该端口,jsch监控到该端口有数据,把该端口的数据获取,并通过上面的SSH链接通道,发送给目标服务器的SSH,目标的SSH服务器再转发给真是的目标IP(目标地址是相对SSH服务器,而不是相对本地而言的地址)和端口。



package cn.gou23.cgodo.jdbc;

import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import cn.gou23.cgodo.util.UtilLog;
import cn.gou23.cgodo.util.UtilUrl;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

/**
*
*
* 描述:mysqlssh驱动
*
* @author liyixing
* @version 1.0
* @since 2015年9月17日 上午11:02:23
*/
public class MySqlSsh implements Driver {
private static final String PRIEX = "jdbc:mysqlssh:";
/**
* 代理端口
*/
private static final int PROXY_PORT = 3307;
private Proxy proxy;
/**
* 最后一个匹配到的驱动
*/
private Driver lastUnderlyingDriverRequested;

private static final Set<String> SUBDRIVERS_SET = new TreeSet<String>();

static {
// 需要对接的驱动
SUBDRIVERS_SET.add("net.sf.log4jdbc.DriverSpy");
SUBDRIVERS_SET.add("com.mysql.jdbc.Driver");

try {
DriverManager.registerDriver(new MySqlSsh());

for (Iterator<String> i = SUBDRIVERS_SET.iterator(); i.hasNext();) {
String driverClass = (String) i.next();
try {
Class.forName(driverClass);
} catch (Throwable c) {
i.remove();
}
}
} catch (SQLException s) {
throw (RuntimeException) new RuntimeException("无法注册驱动!")
.initCause(s);
}
}

/**
*
* 描述:计算出实际的驱动
*
* @param url
* @return
* @throws SQLException
* @author liyixing 2015年9月17日 上午11:05:40
*/
private Driver getUnderlyingDriver(String url) throws SQLException {
if (url.startsWith(PRIEX)) {
url = url.substring(PRIEX.length());

Enumeration<Driver> e = DriverManager.getDrivers();

Driver d;

while (e.hasMoreElements()) {
d = (Driver) e.nextElement();

if (d.acceptsURL(url)) {
lastUnderlyingDriverRequested = d;
return d;
}
}
}
return null;
}

@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}

@Override
public synchronized Connection connect(String url, Properties info)
throws SQLException {
// 查找实际驱动
Driver d = getUnderlyingDriver(url);

if (d == null) {
return null;
}

url = url.substring(PRIEX.length());

// 解析出实际的MYSQLIP和端口
Pattern pattern = Pattern
.compile("mysql://(\\d{1,}\\.\\d{1,}\\.\\d{1,}\\.\\d{1,}):+(\\d{1,})/");
Matcher matcher = pattern.matcher(url);

matcher.find();

try {
if (proxy == null) {
proxy = new Proxy();

// 真实的mysql地址
String mysqlIp = matcher.group(1);
// 真实的MYSQL端口
String mysqlPort = matcher.group(2);
Map<String, String> params = UtilUrl.urlToMap(url, "utf-8");
String sshIp = params.get("sshIp");
String sshUser = params.get("sshUser");
String sshPassword = params.get("sshPassword");
String sshPort = params.get("sshPort");

proxy.setMysqlIp(mysqlIp);
proxy.setMysqlPort(Integer.valueOf(mysqlPort));
proxy.setSshIp(sshIp);
proxy.setSshUser(sshUser);
proxy.setSshPassword(sshPassword);
proxy.setSshPort(Integer.valueOf(sshPort));
proxy.doPorxy();
}

// sshIp = params
url = url
.replaceFirst(
"mysql://(\\d{1,}\\.\\d{1,}\\.\\d{1,}\\.\\d{1,}):+(\\d{1,})/",
"mysql://127.0.0.1:" + PROXY_PORT + "/");
Connection c = d.connect(url, info);

if (c == null) {
throw new SQLException("无效的URL: " + url);
}

return c;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("url解析出错", e);
}
}

/**
* 是否自己需要处理的链接
*
* @see java.sql.Driver#acceptsURL(java.lang.String)
*/
@Override
public boolean acceptsURL(String url) throws SQLException {
Driver d = getUnderlyingDriver(url);

if (d != null) {
return true;
} else {
return false;
}
}

@Override
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info)
throws SQLException {
Driver d = getUnderlyingDriver(url);
if (d == null) {
return new DriverPropertyInfo[0];
}

return d.getPropertyInfo(url, info);
}

@Override
public int getMajorVersion() {
if (lastUnderlyingDriverRequested == null) {
return 1;
} else {
return lastUnderlyingDriverRequested.getMajorVersion();
}
}

@Override
public int getMinorVersion() {
if (lastUnderlyingDriverRequested == null) {
return 0;
} else {
return lastUnderlyingDriverRequested.getMinorVersion();
}
}

@Override
public boolean jdbcCompliant() {
return lastUnderlyingDriverRequested != null
&& lastUnderlyingDriverRequested.jdbcCompliant();
}

/**
*
* 描述:代理ssh
*
* @author liyixing 2015年9月17日 上午11:18:03
*/
public class Proxy {
public String sshUser;// SSH连接用户名
public String sshPassword;// SSH连接密码
public String sshIp;// SSH服务器
public int sshPort;// SSH访问端口
public String mysqlIp;
public int mysqlPort;

public String getMysqlIp() {
return mysqlIp;
}

public void setMysqlIp(String mysqlIp) {
this.mysqlIp = mysqlIp;
}

public int getMysqlPort() {
return mysqlPort;
}

public void setMysqlPort(int mysqlPort) {
this.mysqlPort = mysqlPort;
}

public String getSshUser() {
return sshUser;
}

public void setSshUser(String sshUser) {
this.sshUser = sshUser;
}

public String getSshPassword() {
return sshPassword;
}

public void setSshPassword(String sshPassword) {
this.sshPassword = sshPassword;
}

public String getSshIp() {
return sshIp;
}

public void setSshIp(String sshIp) {
this.sshIp = sshIp;
}

public int getSshPort() {
return sshPort;
}

public void setSshPort(int sshPort) {
this.sshPort = sshPort;
}

public void doPorxy() {
try {
JSch jsch = new JSch();
// 先链接到ssh,建立通道
Session session = jsch.getSession(sshUser, sshIp, sshPort);
session.setPassword(sshPassword);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
UtilLog.debug("ssh版本信息:{}", session.getServerVersion());// 这里打印SSH服务器版本信息
/**
* Registers the local port forwarding for loop-back interface.
* If lport is 0, the tcp port will be allocated.
*
* 总共有三个参数,第一个参数,jsch会在本地机器开启一个端口,并把该端口,并告知上面session建立的通道,
* 该通道是用来做数据转发的,<br>
* 实际的参数需要发送给目标IP和端口 <br>
* 本地机器看成C,目标SSH服务器看成B,目标数据库看成A <br>
* 那么就是驱动链接到C,C通过通道B,发送给A
*/
int assinged_port = session.setPortForwardingL(PROXY_PORT,
mysqlIp, mysqlPort);
UtilLog.debug("assinged", assinged_port);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics