yanchang
yanchang
发布于 2025-04-25 / 63 阅读
0
0

(旧)利用ssh隧道实现远程控制实验室的无人机(校园网会拦截特定端口,且本方案有BUG))

闲言

昨天折腾了报告ipv6实现远程控制,也就是我比较想尽可能的实现p2p连接,最终失败了,p2p我目前想到的只有两个方法,一个是ipv4NAT,另一个是ipv6直连,可惜的是校园网好像禁止了ipv6直连,总之连不上,然而实验室的路由器后台又进不去,所以说..p2p这条路算是彻底堵死了。所以说还是要代理。还好我在寝室还是有动态公网ip,寝室进行一个ddns,算是有了域名,然后进行代理就好了

中转服务器端

首先编辑配置文件

/etc/ssh/sshd_config

GatewayPorts yes

被控端

ssh -f -N -T -R 0.0.0.0:2222:localhost:22 -p 9022 yanchang@www.yanchang.xyz \
  -o ServerAliveInterval=60 -o ServerAliveCountMax=3
ssh -f -N -T -R 0.0.0.0:4001:localhost:4000 -p 9022 yanchang@www.yanchang.xyz \
  -o ServerAliveInterval=60 -o ServerAliveCountMax=3

参数解析​​

参数

作用

-f

SSH 连接成功后转入后台运行(无需终端交互)。

-N

不执行远程命令(仅用于端口转发)。

-T

禁用伪终端分配(纯端口转发场景不需要终端)。

-R 0.0.0.0:2222:localhost:22

​远程端口转发​​:将远程服务器(www.yanchang.xyz)的 2222 端口流量转发到本地机器的 22 端口(SSH 服务默认端口)。
- 0.0.0.0 表示远程服务器监听所有 IP 地址(允许外部访问)。
- 若省略 0.0.0.0:,默认仅绑定到 127.0.0.1(仅允许本地访问)。

-p 9022

指定远程服务器 SSH 服务端口为 9022(非默认 22 端口)。

yanchang@www.yanchang.xyz

登录远程服务器的用户名和主机名(或 IP)。

心跳机制导致代理隧道断开

  • ​SSH 心跳配置​

    • 默认情况下,若长时间无数据传输,SSH 连接可能因空闲超时断开(通常几分钟到几小时)。

    • 服务器/客户端的 ClientAliveInterval(服务端主动发送心跳)和 ServerAliveInterval(客户端主动发送心跳)参数决定心跳频率。若未配置,可能快速超时。

观察当前链接是否正常

pgrep -af "2222:localhost:22"
pgrep -af "4001:localhost:4000"

解决方案

  • ​编写配置脚本,若链接断开就自动重连(仅限于ssh)

#!/bin/bash

# 目标服务器信息
REMOTE_USER="yanchang"
REMOTE_HOST="www.yanchang.xyz"
REMOTE_PORT=9022
TUNNEL_SPEC="0.0.0.0:2222:localhost:22"
KEY_PASSWORD="017100"  # 密钥密码

while true; do
    echo "[$(date)] 正在建立带密钥认证的SSH隧道..."

    # 使用sshpass自动输入密钥密码
    sshpass -p "${KEY_PASSWORD}" \
    ssh -N -T -R ${TUNNEL_SPEC} -p ${REMOTE_PORT} ${REMOTE_USER}@${REMOTE_HOST} \
        -o ServerAliveInterval=60 \
        -o ServerAliveCountMax=3 \
        -o ExitOnForwardFailure=yes \
        -o TCPKeepAlive=yes \
        -o BatchMode=yes \
        -o StrictHostKeyChecking=no

    # 断线后处理
    echo "[$(date)] 连接异常断开,10秒后重试..."
    sleep 10
done

添加新功能的(DNS刷新,避免ip更换后无法)

#!/bin/bash

# 目标服务器信息
REMOTE_USER="yanchang"
REMOTE_HOST="www.yanchang.xyz"
REMOTE_PORT=9022
TUNNEL_SPEC="0.0.0.0:2222:localhost:22"
KEY_PASSWORD="017100"
SUDO_PASSWORD="017100"  # 新增sudo密码变量

while true; do
    # 刷新DNS缓存(通过管道传递sudo密码)
    echo "[$(date)] 刷新DNS缓存..."
    echo "$SUDO_PASSWORD" | sudo -S systemd-resolve --flush-caches 2>/dev/null || 
    echo "$SUDO_PASSWORD" | sudo -S /etc/init.d/nscd restart 2>/dev/null || 
    echo "$SUDO_PASSWORD" | sudo -S systemctl restart dnsmasq 2>/dev/null

    # 解析远程主机地址
    REMOTE_IP=$(dig +short "$REMOTE_HOST" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -n1)
    if [ -z "$REMOTE_IP" ]; then
        echo "[$(date)] 警告: DNS解析失败,请检查网络连接或DNS配置"
    else
        echo "[$(date)] 成功解析 $REMOTE_HOST → $REMOTE_IP"
    fi

    echo "[$(date)] 正在建立带密钥认证的SSH隧道..."
    sshpass -p "${KEY_PASSWORD}" \
    ssh -N -T -R ${TUNNEL_SPEC} -p ${REMOTE_PORT} ${REMOTE_USER}@${REMOTE_HOST} \
        -o ServerAliveInterval=60 \
        -o ServerAliveCountMax=3 \
        -o ExitOnForwardFailure=yes \
        -o TCPKeepAlive=yes \
        -o BatchMode=yes \
        -o StrictHostKeyChecking=no

    echo "[$(date)] 连接异常断开,10秒后重试..."
    sleep 10
done


评论