|
|
@@ -1,59 +1,99 @@
|
|
|
package top.lvzhiqiang.util;
|
|
|
|
|
|
import com.jcraft.jsch.JSch;
|
|
|
+import com.jcraft.jsch.JSchException;
|
|
|
import com.jcraft.jsch.Session;
|
|
|
-import org.jsoup.Connection;
|
|
|
import org.jsoup.Jsoup;
|
|
|
import org.jsoup.nodes.Document;
|
|
|
+import org.jsoup.select.Elements;
|
|
|
|
|
|
import java.net.InetSocketAddress;
|
|
|
import java.net.Proxy;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Map;
|
|
|
|
|
|
public class SSHDynamicProxy {
|
|
|
private JSch jsch;
|
|
|
private Session session;
|
|
|
- private final int localPort = 1111; // 本地 SOCKS5 端口
|
|
|
+
|
|
|
+ // SSH 服务器信息
|
|
|
+ private static final String SSH_HOST = "204.13.154.148"; // Trojan/SSH 服务器 IP
|
|
|
+ private static final int SSH_PORT = 22;
|
|
|
+ private static final String SSH_USER = "crawler";
|
|
|
+ private static final String SSH_PASSWORD = "xxxxx";
|
|
|
+
|
|
|
+ // 本地 SOCKS 代理端口
|
|
|
+ private static final int LOCAL_SOCKS_PORT = 10808;
|
|
|
|
|
|
/**
|
|
|
* SSH 服务器参数:host/user/password 是 SSH 登录凭据
|
|
|
*/
|
|
|
- public void startDynamicProxy(String sshHost, int sshPort, String sshUser, String sshPassword) throws Exception {
|
|
|
+ public void startDynamicProxy(String sshHost, int sshPort, String sshUser, String sshPassword) throws JSchException {
|
|
|
+ // 1. 创建 SSH 会话
|
|
|
jsch = new JSch();
|
|
|
-
|
|
|
- // 创建 SSH 会话
|
|
|
session = jsch.getSession(sshUser, sshHost, sshPort); // sshPort 默认为 22
|
|
|
session.setPassword(sshPassword); // SSH 登录密码,不是 Trojan 密码
|
|
|
|
|
|
- // 配置:跳过主机密钥检查(生产环境不推荐)
|
|
|
+ // 跳过主机密钥检查 (生产环境不推荐,应使用 known_hosts)
|
|
|
java.util.Properties config = new java.util.Properties();
|
|
|
config.put("StrictHostKeyChecking", "no");
|
|
|
+
|
|
|
+ // 启用客户端发送心跳包 (Client Alive),告诉远程服务器,每隔 5 秒发送一个心跳包
|
|
|
+ config.put("ServerAliveInterval", "5");
|
|
|
+ config.put("ServerAliveCountMax", "3"); // 如果 3 次心跳失败,断开连接
|
|
|
+
|
|
|
+ // 增加隧道稳定性配置:
|
|
|
+ // 降低窗口大小,以适应复杂的网络环境和MTU不匹配
|
|
|
+ config.put("session.connect.timeout", "30000"); // 增加连接超时
|
|
|
+ config.put("fsacp-streamlocal-window-size", "32768"); // 降低窗口大小
|
|
|
+ config.put("fsacp-remote-window-size", "32768"); // 降低窗口大小
|
|
|
+
|
|
|
session.setConfig(config);
|
|
|
|
|
|
// 建立连接
|
|
|
session.connect();
|
|
|
System.out.println("SSH 连接成功: " + sshHost);
|
|
|
|
|
|
- // 建立动态端口转发(SOCKS5 代理)
|
|
|
- int assignedPort = session.setPortForwardingL(localPort, "0.0.0.0", 0);
|
|
|
+ // 2. 启动动态端口转发 (创建本地 SOCKS 代理)
|
|
|
+ // L: Dynamic Forwarding (动态转发)
|
|
|
+ int assignedPort = session.setPortForwardingL(LOCAL_SOCKS_PORT, "127.0.0.1", 0);
|
|
|
+ // 这里的 "127.0.0.1" 和 "0" 是动态转发的标准设置
|
|
|
System.out.println("SOCKS5 代理启动在: 127.0.0.1:" + assignedPort);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 通过 SSH 隧道爬取网页
|
|
|
*/
|
|
|
- public Document fetchViaSSH(String targetUrl) throws Exception {
|
|
|
+ public void fetchViaSSH(String targetUrl) throws Exception {
|
|
|
// 创建 SOCKS5 代理,指向本地端口
|
|
|
- Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", localPort));
|
|
|
+ Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", LOCAL_SOCKS_PORT));
|
|
|
|
|
|
- Connection connection = Jsoup.connect(targetUrl)
|
|
|
- .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
|
|
|
- .proxy(proxy) // 使用本地 SOCKS5 代理
|
|
|
- .timeout(30000)
|
|
|
- .followRedirects(true);
|
|
|
+ Map<String, String> headerMap = new HashMap<>();
|
|
|
+ headerMap.put("referer", targetUrl);
|
|
|
+ Document document = JsoupUtil.requestDocument(targetUrl, JsoupUtil.HTTP_GET, proxy, null, headerMap, null);
|
|
|
+ Elements itembSelects = document.select("div.movie-list").select("div.item");
|
|
|
|
|
|
- Document doc = connection.get();
|
|
|
- System.out.println("页面标题: " + doc.title());
|
|
|
- return doc;
|
|
|
+ System.out.println("页面标题: " + itembSelects.text());
|
|
|
+ }
|
|
|
+
|
|
|
+ public String verifySSH(String targetUrl) throws Exception {
|
|
|
+ // 创建 SOCKS 代理对象
|
|
|
+ Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", LOCAL_SOCKS_PORT));
|
|
|
+
|
|
|
+ System.out.println("Attempting to crawl via SOCKS5 proxy...");
|
|
|
+
|
|
|
+ /* Map<String, String> headerMap = new HashMap<>();
|
|
|
+ Document doc = JsoupUtil.requestDocument(targetUrl, JsoupUtil.HTTP_GET, proxy, null, headerMap, null);*/
|
|
|
+
|
|
|
+ org.jsoup.nodes.Document doc = Jsoup.connect(targetUrl)
|
|
|
+ .proxy(proxy)
|
|
|
+ .timeout(10000)
|
|
|
+ .get();
|
|
|
+
|
|
|
+ String title = doc.title();
|
|
|
+ System.out.println("Crawl successful! Title: " + title);
|
|
|
+
|
|
|
+ return title;
|
|
|
}
|
|
|
|
|
|
public void stop() {
|
|
|
@@ -66,21 +106,21 @@ public class SSHDynamicProxy {
|
|
|
public static void main(String[] args) {
|
|
|
SSHDynamicProxy proxy = new SSHDynamicProxy();
|
|
|
try {
|
|
|
- // SSH 服务器配置(不是 Trojan 配置)
|
|
|
- String sshHost = "144.34.207.84"; // SSH 服务器 IP/域名
|
|
|
- String sshUser = "root"; // SSH 用户名
|
|
|
- String sshPassword = "SnS2fm42wWWc"; // SSH 登录密码
|
|
|
-
|
|
|
// 启动 SSH 动态代理
|
|
|
- proxy.startDynamicProxy(sshHost, 26376, sshUser, sshPassword);
|
|
|
+ proxy.startDynamicProxy(SSH_HOST, SSH_PORT, SSH_USER, SSH_PASSWORD);
|
|
|
|
|
|
// 测试访问(通过 SSH 隧道)
|
|
|
- Document doc = proxy.fetchViaSSH("https://www.google.com");
|
|
|
- System.out.println("IP 检查: " + doc.select("pre").text()); // 应显示 SSH 服务器 IP
|
|
|
+ // proxy.fetchViaSSH("https://javdb.com/lists/Nw7OzB?lst=0");
|
|
|
|
|
|
+ proxy.verifySSH("https://www.google.com");
|
|
|
+ } catch (JSchException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ System.err.println("SSH Error (check host/user/pass or SSH service): " + e.getMessage());
|
|
|
} catch (Exception e) {
|
|
|
e.printStackTrace();
|
|
|
+ System.err.println("Jsoup Error (check connectivity/target site): " + e.getMessage());
|
|
|
} finally {
|
|
|
+ // 4. 关闭 SSH 会话
|
|
|
proxy.stop();
|
|
|
}
|
|
|
}
|