go语言实现SSH服务器允许端口转发不允许sftp不允许执行任何命令
以下是一个简单的Go语言实现SSH服务器的示例代码,实现了允许端口转发、禁止SFTP和禁止执行任何命令的功能:
package main
import (
"fmt"
"io/ioutil"
"net"
"os"
"golang.org/x/crypto/ssh"
)
func main() {
// 配置SSH服务器
config := &ssh.ServerConfig{
NoClientAuth: true,
}
// 添加一个允许端口转发的认证方法
config.AddHostKey(readPrivateKey("ssh_host_rsa_key"))
config.AddHostKey(readPrivateKey("ssh_host_ecdsa_key"))
config.PermitListen = true
// 启动SSH服务器
listener, err := net.Listen("tcp", "0.0.0.0:2222")
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to listen on 2222: %v\n", err)
os.Exit(1)
}
fmt.Println("Listening on 0.0.0.0:2222...")
for {
// 接受SSH客户端连接
conn, err := listener.Accept()
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to accept incoming connection: %v\n", err)
continue
}
// 进行SSH握手
sshConn, chans, reqs, err := ssh.NewServerConn(conn, config)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to handshake: %v\n", err)
continue
}
fmt.Printf("New SSH connection from %v (%v)\n", sshConn.RemoteAddr(), sshConn.ClientVersion())
// 处理请求
go handleRequests(reqs)
// 处理通道
go handleChannels(chans)
}
}
func handleRequests(reqs <-chan *ssh.Request) {
for req := range reqs {
// 拒绝SFTP请求
if req.Type == "subsystem" && req.Payload[4:] == "sftp" {
req.Reply(false, nil)
continue
}
// 拒绝执行任何命令
if req.Type == "exec" {
req.Reply(false, nil)
continue
}
// 允许其他请求
req.Reply(true, nil)
}
}
func handleChannels(chans <-chan ssh.NewChannel) {
for newChannel := range chans {
// 拒绝所有通道除了端口转发
if newChannel.ChannelType() != "direct-tcpip" {
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
continue
}
// 打开端口转发通道
channel, _, err := newChannel.Accept()
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to accept channel: %v\n", err)
continue
}
go handleForwardedTCPChannel(channel)
}
}
func handleForwardedTCPChannel(channel ssh.Channel) {
// 关闭通道
defer channel.Close()
// 读取远程地址和端口
var remoteAddr string
var remotePort uint32
_, err := fmt.Fscanf(channel, "%s %d\n", &remoteAddr, &remotePort)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to read remote address and port: %v\n", err)
return
}
// 连接远程地址和端口
destConn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", remoteAddr, remotePort))
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to connect to %s:%d: %v\n", remoteAddr, remotePort, err)
return
}
// 复制数据到远程地址和端口
go func() {
_, err := io.Copy(channel, destConn)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to copy data to remote address and port: %v\n", err)
channel.Close()
destConn.Close()
return
}
}()
// 复制数据到SSH客户端
go func() {
_, err := io.Copy(destConn, channel)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to copy data from remote address and port: %v\n", err)
channel.Close()
destConn.Close()
return
}
}()
}
func readPrivateKey(path string) ssh.Signer {
keyBytes, err := ioutil.ReadFile(path)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to read private key file %s: %v\n", path, err)
os.Exit(1)
}
key, err := ssh.ParsePrivateKey(keyBytes)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to parse private key: %v\n", err)
os.Exit(1)
}
return key
}
这个程序使用ssh.NewServerConn函数进行SSH握手,并使用两个goroutine分别处理请求和通道。在请求处理中,我们拒绝了所有的SFTP请求和执行任何命令的请求,并允许其他请求。在通道处理中,我们拒绝了所有通道除了端口转发,并使用handleForwardedTCPChannel函数处理转发的TCP连接。这个函数使用io.Copy函数将数据从SSH客户端复制到远程地址和端口,并从远程地址和端口复制数据到SSH客户端。
原文地址: https://www.cveoy.top/t/topic/bwwy 著作权归作者所有。请勿转载和采集!