三种不同SSH隧道

转自 http://hetaoo.iteye.com/blog/2299123

前言

想通过ssh隧道连接远端机器的VNC服务,对ssh -L命令不太熟悉,man ssh后发现3组与隧道(turnnel)相关的参数:ssh -D,ssh -L,ssh -R,一下子就搞糊涂了,所有下决心仔细研究一番。

何谓SSH隧道

隧道是一种把一种网络协议封装进另外一种网络协议进行传输的技术。这里我们研究ssh隧道,所以所有的网络通讯都是加密的。又被称作端口转发,因为ssh隧道通常会绑定一个本地端口,所有发向这个端口端口的数据包,都会被加密并透明地传输到远端系统。

SSH隧道的类型

ssh隧道有3种类型:

  • 动态端口转发(Socks 代理)
  • 本地端口转发
  • 远端端口转发
动态端口转发

动态端口允许通过配置一个本地端口,把通过隧道到数据转发到远端的所有地址。本地的应用程序需要使用Socks协议与本地端口通讯。此时SSH充当Socks代理服务器的角色。

命令格式

ssh -D [bind_address:]port

参数说明

bind_address 指定绑定的IP地址,默认情况会绑定在本地的回环地址(即127.0.0.1),如果空值或者为*会绑定本地所有的IP地址,如果希望绑定的端口仅供本机使用,可以指定为localhost。
port 指定本地绑定的端口
使用场景

假设X网络(192.168.18.0/24)有主机A(192.168.18.100),Y网络(192.168.2.0/24)有主机B(192.168.2.100)和主机C(192.168.2.101),已知主机A可以连接主机B,但无法连接主机C。 在主机A执行
$ ssh -D localhost:8080 root@192.168.2.100
然后主机A上的应用程序就可以通过
SOCKS5 localhost:8080
访问主机C上的服务。

优点

配置一个代理服务就可以访问远端机器和与其所在子网络的所有服务
缺点

应用程序需要额外配置SOCKS代理,若应用程序不支持代理配置则无法使用

本地端口转发

通过SSH隧道,将一个远端机器能够访问到的地址和端口,映射为一个本地的端口。
命令格式

ssh -L [bind_address:]port:host:hostport
参数说明

bind_address 指定绑定的IP地址,默认情况会绑定在本地的回环地址(即127.0.0.1),如果空值或者为*会绑定本地所有的IP地址,如果希望绑定的端口仅供本机使用,可以指定为localhost。
port 指定本地绑定的端口
host 指定数据包转发目标地址的IP,如果目标主机和ssh server是同一台主机时该参数指定为localhost
host_port 指定数据包转发目标端口
使用场景

假设X网络(192.168.18.0/24)有主机A(192.168.18.100),Y网络(192.168.2.0/24)有主机B(192.168.2.100)和主机C(192.168.2.101),已知主机A可以连接主机B,但无法连接主机C。A主机需要访问C主机的VNC服务(5900端口)
在A主机上建立本地转发端口5901
$ ssh -L 5901:192.168.2.101:5900 root@192.168.2.100
然后本地vnc客户端通过5901端口打开c主机的vnc服务
$ open vnc://localhost:5901

优点
无需设置代理

缺点
每个服务都需要配置不同的端口转发

远端端口转发

远程端口转发用于某些单向阻隔的内网环境,比如说NAT,网络防火墙。在NAT设备之后的内网主机可以直接访问公网主机,但外网主机却无法访问内网主机的服务。如果内网主机向外网主机建立一个远程转发端口,就可以让外网主机通过该端口访问该内网主机的服务。可以把这个内网主机理解为“内应”和“开门者”。

命令格式
ssh -R [bind_address:]port:host:hostport

参数说明
bind_address 指定绑定的IP地址,默认情况会绑定在本地的回环地址(即127.0.0.1),如果空值或者为*会绑定本地所有的IP地址,如果希望绑定的端口仅供本机使用,可以指定为localhost。
port 指定本地绑定的端口
host 指定数据包转发源地址的IP,如果源主机和ssh server是同一台主机时该参数指定为localhost
host_port 指定数据包转发源端口

使用场景

假设X网络(192.168.18.0/24)有主机A(192.168.18.100),Y网络(192.168.2.0/24)有主机B(192.168.2.100)和主机C(192.168.2.101),已知主机A可以通过SSH访问登录B主机,但反向直接连接被禁止,主机B和主机C可以相互访问。若主机C想访问主机A的VNC服务(5900端口)。
$ ssh -R 5900:192.168.2.100:5901 root@192.168.2.100
然后主机C连接主机B的5901端口 $ open vnc://192.168.2.100:5901

优点
可以穿越防火墙和NAT设备

缺点
每个服务都需要配置不同的端口转发

如何禁止端口转发

设置ssh服务配置文件/etc/ssh/sshd_config
AllowTcpForwardingno

在使用 Go 语言创建 SSH 隧道的场景中,开发者可以选择多个开源库来实现这一目标。以下是一些主流的方法和推荐的库。 ### 使用 `sshtunnel` 创建 SSH 隧道 `sshtunnel` 是一个为 Go 程序设计的超简单 SSH 隧道工具,它能够帮助开发者在 Go 应用中轻松实现 SSH 隧道功能,无需复杂的配置和繁琐的代码。无论是连接到远程数据库、API 服务,还是其他需要通过 SSH 隧道访问的资源,`sshtunnel` 都能提供一种简洁、高效的方式来实现这一目标[^1]。 ### 使用 `sshego` 实现 SSH 隧道 `sshego` 是一个使用 Go 语言编写的开源项目,旨在为开发者提供一个简单易用的 SSH 隧道(安全端口转发)库。该库填补了 Go 标准库中 SSH 功能的空白,提供了内嵌的 SSH 服务器功能,使得用户可以方便地为自己的应用添加 3 因素认证的 SSH 服务[^2]。 ### 使用 `go-ssh-tunnel` 进行隧道连接 `go-ssh-tunnel` 是一个用于实现 SSH 隧道的 Go 扩展包,可以通过简单的函数调用来创建 SSH 隧道。以下是一个使用 `go-ssh-tunnel` 的示例代码: ```go package main import ( "github.com/dtapps/dtapps/go-ssh-tunnel/dssh" ) func main() { dssh.Tunnel("root", "", ":22", ":3306", "localhost:13306") } ``` 这段代码展示了如何通过 `dssh.Tunnel` 函数创建一个 SSH 隧道,将本地端口 `13306` 转发到远程主机的 `3306` 端口[^5]。 ### 手动实现 SSH 隧道 如果希望手动实现 SSH 隧道,可以使用 Go 的 `golang.org/x/crypto/ssh` 包来创建 SSH 客户端并建立连接。以下是一个基本的 SSH 客户端连接示例: ```go package main import ( "fmt" "golang.org/x/crypto/ssh" "net" ) func main() { // SSH 客户端配置 config := &ssh.ClientConfig{ User: "username", Auth: []ssh.AuthMethod{ ssh.Password("password"), }, HostKeyCallback: ssh.InsecureIgnoreHostKey(), // 注意:生产环境中应使用更安全的 HostKeyCallback } // 建立 SSH 连接 conn, err := ssh.Dial("tcp", "host:port", config) if err != nil { fmt.Errorf("Failed to dial: %s", err) return } defer conn.Close() // 创建一个本地监听器 listener, err := net.Listen("tcp", "localhost:13306") if err != nil { fmt.Errorf("Failed to listen: %s", err) return } defer listener.Close() for { // 接受本地连接 localConn, err := listener.Accept() if err != nil { fmt.Errorf("Failed to accept: %s", err) continue } // 在远程主机上建立连接 remoteConn, err := conn.Dial("tcp", "localhost:3306") if err != nil { fmt.Errorf("Failed to dial remote: %s", err) localConn.Close() continue } // 转发数据 go func() { defer localConn.Close() defer remoteConn.Close() // 从本地到远程的数据转发 go func() { _, err := io.Copy(remoteConn, localConn) if err != nil { fmt.Errorf("Error copying from local to remote: %s", err) } }() // 从远程到本地的数据转发 _, err = io.Copy(localConn, remoteConn) if err != nil { fmt.Errorf("Error copying from remote to local: %s", err) } }() } } ``` 上述代码展示了如何使用 `golang.org/x/crypto/ssh` 包创建一个 SSH 客户端,并通过 SSH 隧道将本地端口转发到远程主机上的指定端口。这种方式提供了更大的灵活性,但同时也需要更多的代码来实现和维护[^3]。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值