以下是一个简单的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客户端。

go语言实现SSH服务器允许端口转发不允许sftp不允许执行任何命令

原文地址: https://www.cveoy.top/t/topic/bwwy 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录