隧道端口(服务)脱离外部无法访问的网络

隧道端口(服务)脱离外部无法访问的网络

我正在协助管理一个私人网络,我想公开一些服务(例如,带有本地端口转发的 SSH 就很棒)。不幸的是,我可能无权在路由器中安装任何端口转发。不过,我可以做的是安装任意硬件(任何类型的计算机、Raspberry Pi 等)。为了解决这个问题,我想到从封闭网络到我控制的网络实现某种端口转发(例如将端口 22 转发到我的网络,然后从那里通过 SSH 访问“无法访问”的网络并进行一些本地端口转发,为 VPN 提供端口,等等)。然而,这对我来说似乎很容易出错,因为我需要实施一些 cron 作业来检查传出连接或建立一个连接。还有其他方法吗?我想象的情况在任何情况下都是常见的吗?谢谢你的帮助。

编辑

今天我读到了一些有关具有客户端 VPN 功能的路由器的文章 - 这可行吗?我想在某个我可以完全控制的地方实施 VPN,然后强制客户端 VPN 路由器连接,这样我就能够访问我想要远程访问的主机。

答案1

几年前我有过类似的要求。我用以下脚本解决了它。

#!/bin/bash

# This script is designed to be scheduled by cron as often as is required
# If STARTFILE exists, it will start/restart the connection
# If STOPFILE exists, it will stop the connection
# If PORTFILE exist, makes sure the tunnel is started, to survive restarts
#
# PORTFILE will always contain the port number on the remote host that the SSH connection is tunneled to
#
# This utilizes the control socket option of SSH to control the tunnel

# Base name, used by other variables
NAME="ssh_tunnel"

# Create this file to start the server
STARTFILE="/etc/$NAME/$NAME.start"

# This file will contain the port number on the remote server to connect to to access the tunnel
PORTFILE="/etc/$NAME/$NAME.port"

# Create this file to stop the server
STOPFILE="/etc/$NAME/$NAME.stop"

# The user and host to connect the tunnel to
REMOTE="user@hostname"

# The private key of the user on the remote server to create the tunnel to
KEYFILE="/etc/$NAME/.ssh/$NAME"

# The control socket of the SSH connection
SOCKET="/var/run/$NAME.socket"

# First port to try and listen on at remote host
LISTEN=9000

# Last port to try and listen on at remote host
MAXPORT=9999

SSH=$(which ssh)

# We need to run as root, otherwise it will fail
if [ "$(id -u)" != "0" ]; then
    echo "Must be run as root!"
    exit 1
fi

# Make directory if if doesn't exist
if [ ! -d "/etc/$NAME" ]; then
    mkdir "/etc/$NAME"
fi

# Starts the tunnel and updates the control files
start_tunnel() {
    # Remove port file, since it is outdated, if it exists
    if [ -f ${PORTFILE} ]; then
        rm -f ${PORTFILE}
    fi

    # Start tunnel and wait 2 seconds.. It the tunnel isn't up, then the port is busy (or the public key is foobar)
    while true; do
        ${SSH} -M -S ${SOCKET} -2 -4 -C -f -N -i ${KEYFILE} -o CheckHostIP=no -o KeepAlive=yes -o StrictHostKeyChecking=no -o ExitOnForwardFailure=yes -o BatchMode=yes ${REMOTE} -R $LISTEN:localhost:22
        sleep 2
        check_tunnel && break
        set LISTEN=LISTEN+1
        if [ $LISTEN -eq $MAXPORT ]; then
            # No ports available (or more likely, the public key is incorrect)
            exit 1
        fi
    done
    echo ${LISTEN} > ${PORTFILE}

    # Remove startfile, since the process is now started
    if [ -f ${STARTFILE} ]; then
        rm -f ${STARTFILE}
    fi

}

# Stops the tunnel and cleans up the control files
stop_tunnel() {
    # Remove portfile and stopfile if they exist
    if [ -f ${PORTFILE} ]; then
        rm -f ${PORTFILE}
    fi
    if [ -f ${STOPFILE} ]; then
        rm -f ${STOPFILE}
    fi
    ${SSH} -S ${SOCKET} -O exit ${REMOTE} > /dev/null 2>&1
}

# Check if the tunnel is up
check_tunnel() {
    if [ -e ${SOCKET} ]; then
        (${SSH} -S ${SOCKET} -O check ${REMOTE} 2>&1 | grep -q "running") && return 0
    fi
    return 1
}

# Use a lock file so only one instance is running
(
    flock -n 9 || exit 1

    if [ -f ${STARTFILE} ]; then
        # Restart if running, otherwise just start
        check_tunnel && stop_tunnel
        start_tunnel
    elif [ -f ${STOPFILE} ]; then
        # Stop if running
        check_tunnel && stop_tunnel
    elif [ -f ${PORTFILE} ]; then
        # The tunnel should be running, might not be after a reboot, for example
        check_tunnel || start_tunnel
    fi

) 9>/var/run/$NAME.lock

该脚本设计为计划任务(在我的例子中,每分钟一次)。它检查变量中指定的文件是否存在STARTFILE。这是通过 Web 界面创建的,但修改此脚本以满足您的需求应该相当容易。使用 Web 界面控制的原因是客户可能不希望他们的网络中存在永久后门。:) 不幸的是,我无法共享 Web 部件,因为这是一个更大项目的一部分。

无论如何,要使其正常工作,您必须配置REMOTEKEYFILE变量,使其指向有效的用户/主机和私钥。其余的都是可选的。之后,只需创建STARTFILE并运行脚本(或通过 cron 安排它),隧道就会启动。

假设您正在服务器上运行脚本A,并且REMOTE设置为。如果服务器上user@B的内容为,那么您应该能够使用服务器上的任何有效用户通过登录到服务器。PORTFILEA9000AB:9000A

我希望这一切都有意义。

相关内容