首页 > 其他分享 >SSH 协议 和 Go SSH 库 转载

SSH 协议 和 Go SSH 库 转载

时间:2024-01-05 21:45:54浏览次数:39  
标签:协议 string MSG SSH Go byte 转载 uint32

导读 

SSH, The Secure Shell Protocol (安全 Shell 协议),是一个使用广泛的网络协议。

在中文互联网世界,关于 SSH 协议的介绍,往往都把重点放到了安全(Secure)方面的细节。这样的文章对于开发者来说,意义并不大,原因在于:

  • 此类文章是以密码学为基础的。而密码学专业程度较高,对于开发者来说理解成本高。
  • 其次,SSH 安全算法部分是 SSH 协议中最不可变的部分。即使完全理解了这部分,对于对 SSH 协议的二次开发,也没有什么帮助。

因此,本文不会仔细介绍 SSH 中 Secure 的细节。而是从整体和分层的角度尝试理解协议作者的设计考量。

和 HTTP 协议一样,SSH 协议是一个标准化的协议,由 IETF 制定,主要的 RFC 有:

还有一些其他 RFC 在实际场景中应用较窄,在此就不列举了。

RFC 文档是网络协议的完整定义,追求的是无歧义和准确性,这导致 RFC 文档对于初学者不够友好,比较晦涩。因此,本文对 SSH 协议的介绍不会按照 RFC 的顺序和结构来进行,而是按照更符合人类认知的方式来进行。对于一些重要的部分,本文会给出对应的 RFC 章节的引用,以方便定位。

本文假设读者使用过 SSH 客户端进行过远程登录。行文上,本文会以:从整体到局部,从低层到顶层,介绍 SSH 协议的包结构。然后以 SSH 登录一台主机执行一条命令的场景为例,通过追踪 Google 维护的 Go SSH 库 x/crypto/ssh 的源码,来实际感受 SSH 协议的整个流程。本文希望读者可以:真正理解 SSH 的整体流程,理解 SSH 协议的设计考量,初步具备对 SSH 协议进行二次开发的能力。

SSH 协议 

SSH 协议架构 

本部分主要来自于: rfc4251

high level
             +-------------------------+---------------------+
             | Authentication Protocol | Connection Protocol |
             +-------------------------+---------------------+
             |           Transport Layer Protocol            |
             +-----------------------------------------------+
             |              Underlying Connection            |
             +-----------------------------------------------+
low  level

SSH 协议由 3 个子协议构成。从底层到顶层分别是:

  • 传输层协议(rfc4253),定义了 SSH 协议数据包的格式以及 Key 交换算法。
  • 认证协议(rfc4252),定义了 SSH 协议支持的用户身份认证算法。
  • 连接协议(rfc4254),定义了 SSH 支持功能特性:交互式登录会话、TCP/IP 端口转发、X11 Forwarding。

需要特别说明的是:

  • 传输层协议底层连接默认是 TCP 协议。但是,这并不是强制的,在现实中,SSH 可以运行在任意提供可靠性保证的底层连接之上。
  • 从层次再看认证协议和连接协议可以认为处于同一层。从时序上来看,认证协议是连接协议的前置条件。

SSH 传输层协议 

数据包 (Packet) 结构 

  • 字节序:大端(网络字节序)
  • SSH 最小传输单元为数据包 (Packet),两个方向的数据包格式是一致的。
  • 数据包格式如下:
    • uint32 packet_length = len(payload) + len(padding) + 1。
    • byte padding_length = len(padding)。
    • []byte payload。有效负载,消息 Message。
    • []byte padding,随机字节数组。
    • []byte mac (Message Authentication Code - MAC)
  • 数据包字段加密方式如下所示:
    • packet_length 和 packet_length 作为整体加密:crypto/cipher.Stream.XORKeyStream(byte[0:5], byte[0:5])
    • payload 加密:crypto/cipher.Stream.XORKeyStream(payload, payload)
    • padding 加密:crypto/cipher.Stream.XORKeyStream(padding, padding)
    • mac 不需要加密

(更多参见:rfc4253#section-6

消息结构 

Packet 定义的是 SSH 协议的最小传输单元,SSH 协议真正的业务数据是放在 payload 部分中的。在 SSH 协议中,payload 部分被称为消息 Message。

消息的格式各不相同,总的来说是由消息的类型来决定的,因此从整体看消息的结构为:

  • byte 消息类型编号。
  • []byte 消息数据,具体定义由消息类型决定。

消息数据部分,可能包含多个字段,不同的字段的序列化方式参见:rfc4251#section-5

SSH 协议对消息编号按照子协议类型进行了划分(rfc4251#section-7):

  • 传输层协议:
    • 1~19 传输层通用消息,如 disconnect, ignore, debug 等等。
    • 20~29 Key 交换算法协商(参见下文:传输层协议流程)。
    • 30~49 Key 交换(同一个编号,在不同的 Key 交换算法中定义是不同的)。
  • 认证协议:
    • 50~59 用户认证通用消息。
    • 60~79 给特定的用户认证方法使用(同一个编号,在不同的认证方法中定义是不同的)。
  • 连接协议:
    • 80~89 连接协议通用消息。
    • 90~127 Channel 相关消息。
  • 为客户端协议保留:128~191。
  • 本地扩展:192~255。

传输层协议流程 

  1. 建立底层连接(以 TCP 协议为例):
    • Client 请求建立 TCP连接。
    • Server Accept 完成 TCP 连接建立。
  2. 协议版本交换(rfc4253#section-4.2):。
    • Client 发送字符串,必须以 SSH-2.0- 开头,以 \r\n 结尾。这部分可以是任意 ASCII 码 > 32 的字符。如 SSH-2.0-Go\r\n,。
    • Server 发送字符串,格式要求和 Client 一致。如 SSH-2.0-dropbear_2022.83\r\n
  3. Key 交换算法协商,参见:rfc4253#section-7.1,也可以参考下文具体编码示例。
  4. Key 交换算法执行,比如 Diffie-Hellman Key Exchange 参见:rfc4253#section-8,也可以参考下文具体编码示例。

解释:

  • 上述第 2、3、4 步,是 SSH 协议中的仅有的明文传输的部分。
  • 上述第 2 步,是 SSH 协议中唯一一个消息格式不符合上文包格式定义的流程。本文介绍的 SSH 协议实际上是 SSH 协议的第 2 版。和其他网络协议类似,SSH 协议也是先有了实现,再进行标准化。因此在这一步,使用了文本格式,以实现对历史上旧版本的识别和兼容。
  • 上述第 2 步,Client 和 Server 发送的字符串,没有前后依赖关系,一般情况下,在建立底层连接后,Client、Server 会立即向对方发送版本信息。
  • 上述第 3、4 步,是 SSH 协议号称安全的关键步骤。SSH 的核心目标就是在不安全的底层连接(如 TCP)之上,建立一个安全的连接,以实现远程登录,端口转发等特性。因此,自然而然的想法就是对传输的数据进行加密。但是,加密必然需要 Client 和 Server 拥有配对的特定秘钥(key),这就是秘钥分发问题。非对称加密算法天然不存在秘钥分发问题,一种办法是所有数据均使用非对称加密算法加密,但是非对称加密算法性能太差,加解密成本难以接受。因此实际上 SSH 协议采用了如下思路:真正的数据加密仍然使用对称加密算法,而对称加密算法的秘钥,由非对称的加密算法进行保护,此类算法在 SSH 协议中有很多种,被称为 Key 交换算法。因为 Key 交换算法是 SSH 安全性的基石。没人可以 100% 保证某个 Key 交换算法一定是安全的。因此 SSH 协议在执行 Key 交换算法之前,需先进行 Key 交换算法协商,来确定要使用哪种 Key 交换算法。
  • 上述第 3、4 步,不仅仅只在第一次连接执行一次,在整个 SSH 连接期间,会根据一些策略,重新执行以生成新的 Key,以保证安全性。

SSH 认证协议 

SSH 支持如下几种身份认证协议:

具体细节本部分就不多赘述了,想了解更多,可以参考上文 RFC 文档,也可以参见下文示例代码。

SSH 连接协议 

Channel 

SSH 连接协议定义的交互式登录终端会话、TCP/IP 端口转发、X11 Forwarding 的这些功能,都工作在自己的通道 (Channel) 之上的。

在 SSH 协议中,Channel 实现了对底层连接的多路复用,就是一个虚拟连接,这就是该子协议叫做连接协议的原因。具体而言 Channel:

  • 通过一个数字来进行标识和区分这些 Channel。
  • 实现流控 (窗口)。

因此,SSH 连接协议实现的这些功能,都需先建立 Channel,流程如下:

  • 服务端和客户端任意一方,发送类型为 SSH_MSG_CHANNEL_OPEN (90) 的消息,通知对方需要建立 Channel。

    byte      SSH_MSG_CHANNEL_OPEN (90)
    string    channel type, 可选值为: 'session', 'x11', 'forwarded-tcpip', 'direct-tcpip' 参见 https://www.rfc-editor.org/rfc/rfc4250#section-4.9.1
    uint32    sender channel 编号
    uint32    初始化窗口大小
    uint32    最大包大小
    ....      下面是 channel type 特定数据
  • 另一方接收到消息后,回复类型为 SSH_MSG_CHANNEL_OPEN_CONFIRMATION (91) 或 SSH_MSG_CHANNEL_OPEN_FAILURE (92) 的消息来告知打开成功或者失败。 成功定义如下:

    byte      SSH_MSG_CHANNEL_OPEN_CONFIRMATION (91)
    uint32    recipient channel 编号,这个是 SSH_MSG_CHANNEL_OPEN 中 sender channel 的值
    uint32    sender channel 编号
    uint32    初始化窗口大小
    uint32    最大包大小
    ....      下面是 channel type 特定数据

    失败定义如下:

    byte      SSH_MSG_CHANNEL_OPEN_FAILURE (92)
    uint32    recipient channel
    uint32    错误码 reason code
    string    描述,格式为 ISO-10646 UTF-8 encoding [RFC3629]
    string    language tag [RFC3066]

    预定义的错误码定义如下:

        Symbolic name                           reason code
        -------------                           -----------
    SSH_OPEN_ADMINISTRATIVELY_PROHIBITED          1
    SSH_OPEN_CONNECT_FAILED                       2
    SSH_OPEN_UNKNOWN_CHANNEL_TYPE                 3
    SSH_OPEN_RESOURCE_SHORTAGE                    4

上文介绍了 Channel 建立的过程,细节参见 rfc4254#section-5.1

Channel 建立完成后,在 Channel 中进行数据传输,主要有:

  • 流量控制类消息,调节窗口大小。

    byte      SSH_MSG_CHANNEL_WINDOW_ADJUST
    uint32    recipient channel
    uint32    bytes to add
  • 数据消息,消息的长度为 min(数据长度, 窗口大小, 传输层协议的限制)

    • 普通数据,如交互式会话的标准输入、标准输出。

      byte      SSH_MSG_CHANNEL_DATA
      uint32    recipient channel
      string    data
    • 扩展数据,如交互式会话的标准出错,标准出错对应 data_type_code 为 1,是 data_type_code 唯一的预定义的值。

      byte      SSH_MSG_CHANNEL_EXTENDED_DATA
      uint32    recipient channel
      uint32    data_type_code
      string    data

Channel 关闭(rfc4254#section-5.3),在此不多赘述了。

最后,在打开一个特定类型的 Channel 后,需要对这个 Channel 进行 Channel 粒度的配置。如,建立了一个 session 类型的 Channel 后,请求对方创建一个伪终端 (pty、pseudo terminal)。这类的请求叫做 Channel 特定请求(Channel-Specific Requests),这类场景使用相同的数据格式:

byte      SSH_MSG_CHANNEL_REQUEST (98)
uint32    recipient channel,对方的 sender channel 编号
string    request type in US-ASCII characters only 请求类型,参见:https://www.rfc-editor.org/rfc/rfc4250#section-4.9.3
boolean   want reply 是否需要对方回复
....      下面是 request type 特定数据

类似的,对于 SSH_MSG_CHANNEL_REQUEST 消息,如果 want reply 为 true,对方应使用 SSH_MSG_CHANNEL_SUCCESS (98)、SSH_MSG_CHANNEL_FAILURE (100) 进行回复。

交互式会话 

在 SSH 语境下,会话(Session)代表远程执行一个程序。这个程序可能是 Shell、应用。同时,它可能有也可能没有一个 tty、可能涉及也可能不涉及 x11 forward。

  • 客户端打开一个类型为 session 的 Channel(为了安全 ssh 客户端应该拒绝创建 session 的请求)。

    byte      SSH_MSG_CHANNEL_OPEN (90)
    string    "session"
    uint32    sender channel
    uint32    initial window size
    uint32    maximum packet size
  • 服务端回复一个类型为 SSH_MSG_CHANNEL_OPEN_CONFIRMATION 的消息。至此 Session 类型的 Channel 创建完成。

  • 客户端可以请求创建一个伪终端(pty、Pseudo-Terminal)。

    byte      SSH_MSG_CHANNEL_REQUEST
    uint32    recipient channel
    string    "pty-req"
    boolean   want_reply
    string    TERM environment variable value (e.g., vt100)
    uint32    terminal width, characters (e.g., 80)
    uint32    terminal height, rows (e.g., 24)
    uint32    terminal width, pixels (e.g., 640)
    uint32    terminal height, pixels (e.g., 480)
    string    encoded terminal modes
  • 关于 x11 forward 参见 rfc4254#section-6.3

  • 客户端可以请求设置环境变量。

    byte      SSH_MSG_CHANNEL_REQUEST
    uint32    recipient channel
    string    "env"
    boolean   want reply
    string    variable name
    string    variable value
  • 客户端启动一个 Shell、执行一个命令、调用一个子系统,如下三种情况同一个 Channel 三选一。

    • 启动一个 Shell

      byte      SSH_MSG_CHANNEL_REQUEST
      uint32    recipient channel
      string    "shell"
      boolean   want reply
    • 执行一个命令

      byte      SSH_MSG_CHANNEL_REQUEST
      uint32    recipient channel
      string    "exec"
      boolean   want reply
      string    command
    • 调用其他子系统(如 sftp)

      byte      SSH_MSG_CHANNEL_REQUEST
      uint32    recipient channel
      string    "subsystem"
      boolean   want reply
      string    subsystem name
  • 上述的启动的程序的输入输出通过如下类型的消息传输:

    • 标准输入、标准输出: SSH_MSG_CHANNEL_DATA,具体参见上文。
    • 标准出错:SSH_MSG_CHANNEL_EXTENDED_DATA,扩展类型为 SSH_EXTENDED_DATA_STDERR,具体参见上文。
    • 伪终端设置终端窗口大小指令(详见:rfc4254#section-6.7):

      byte      SSH_MSG_CHANNEL_REQUEST
      uint32    recipient channel
      string    "window-change"
      boolean   FALSE
      uint32    terminal width, columns
      uint32    terminal height, rows
      uint32    terminal width, pixels
      uint32    terminal height, pixels
    • 信号(详见:rfc4254#section-6.9):

      byte      SSH_MSG_CHANNEL_REQUEST
      uint32    recipient channel
      string    "signal"
      boolean   FALSE
      string    signal name (without the "SIG" prefix)
    • 退出码(详见:rfc4254#section-6.10):

      byte      SSH_MSG_CHANNEL_REQUEST
      uint32    recipient channel
      string    "exit-status"
      boolean   FALSE
      uint32    exit_status
    • 退出信号(详见:rfc4254#section-6.10):

      ` byte SSH_MSG_CHANNEL_REQUEST uint32 recipient channel string "exit-signal" boolean FALSE string signal name (without the "SIG" prefix) boolean core dumped string error message in ISO-10646 UTF-8 encoding string language tag [RFC3066]

TCP/IP 端口转发 

SSH 协议本质上,是建立了在 client 到 server 端这两个设备之间建立了一条加密通讯链路。SSH 基于此实现了两个方向的端口转发:

  • 本地转发(direct-tcpip): 将 client 监听的 tcp 端口连接转发到 server 上。
  • 远端转发(forwarded-tcpip):将 server 监听的 tcp 端口连接转发到 client 上。

如上两者,在协议层面上,最大的区别在于(forwarded-tcpip vs. direct-tcpip):

  • 对于远端转发:流量入口端口位于 server 端,因此 SSH 协议需要提供一种机制,可以让 client 告知 server 监听的 tcp 端口。
  • 而对于本地转发:流量入口位于 client,因此 client 程序自身就可以自助的监听 tcp 端口,而不涉及 client 和 server 端的通讯,因此 client 监听端口不是 SSH 协议需要关心的内容。

direct-tcpip 流程

  • client 监听一个 tcp 端口,并 accept 连接(该步骤不属于 ssh 协议,属于 ssh 的实现部分)。
  • client accept 返回后, client 发起建立一个类型为 direct-tcpip 的 Channel。

    byte      SSH_MSG_CHANNEL_OPEN
    string    "direct-tcpip"
    uint32    sender channel
    uint32    initial window size
    uint32    maximum packet size
    string    host to connect
    uint32    port to connect
    string    originator IP address
    uint32    originator port
  • server 接收到消息后,和 host to connect:port to connect TCP 端口建立 TCP 连接。

  • 至此,转发 Channel 建立完成,后续通过 SSH_MSG_CHANNEL_DATA 进行双向数据的转发。

  • 该流程对应的 openssh client 命令为:

    ssh -L [LOCAL_IP:]LOCAL_PORT:DESTINATION:DESTINATION_PORT [USER@]SSH_SERVER

forwarded-tcpip 流程

  • 准备阶段(具体参见: rfc4254#section-7.1):

    • client 请求 server 监听 tcp 端口,作为流量入口。

      byte      SSH_MSG_GLOBAL_REQUEST
      string    "tcpip-forward"
      boolean   want reply
      string    address to bind (e.g., "0.0.0.0")
      uint32    port number to bind
    • server 根据请求信息,监听对应端口,并回复:

      byte     SSH_MSG_REQUEST_SUCCESS
      uint32   port that was bound on the server
  • server accept 返回后, server 发起建立一个类型为 direct-tcpip 的 Channel。

    byte      SSH_MSG_CHANNEL_OPEN
    string    "forwarded-tcpip"
    uint32    sender channel
    uint32    initial window size
    uint32    maximum packet size
    string    address that was connected
    uint32    port that was connected
    string    originator IP address
    uint32    originator port
  • client 接收到消息后,和 address that was connected:port that was connected TCP 端口建立 TCP 连接。

  • 至此,转发 Channel 建立完成,后续通过 SSH_MSG_CHANNEL_DATA 进行双向数据的转发。

  • 该流程对应的 openssh client 命令为:

    ssh -R [REMOTE:]REMOTE_PORT:DESTINATION:DESTINATION_PORT [USER@]SSH_SERVER

特别说明:

  • 每个 TCP 连接,都会创建一个 Channel。
  • 关于端口转发部分,参见:rfc4254#section-7

Go SSH 库 

主要介绍的是 golang/x/crypto 模块中的 SSH 库。

准备 

fork golang/x/crypto,并 clone 下来。

git clone https://github.com/rectcircle/crypto.git

使用 IDE (VSCode) 打开。

code crypto

核心 API 

该库实现了 SSH 协议,全部 API 参见:godoc

API 可以分为两个部分,分别是 Client 和 Server。下面将分别介绍。

Client 

该库客户端能力通过 ssh.Client 结构体提供。

该结构体的构造函数为: func ssh.Dial(network, addr string, config *ClientConfig) (*Client, error) 该函数流程如下:

  • 使用 func net.Dail 建立底层链接,获得 net.Conn
  • 调用 func ssh.NewClientConn 完成 SSH 传输层协议和认证协议(具体参见上文)部分。
  • 调用 func ssh.NewClient 返回 ssh.Client

注意:如果想使用自定义的底层连接,可以自己构造一个实现了 net.Conn 的对象,然后参考上述的 ssh.Dial 的实现构造一个 ssh.Client

上述构造函数第三个参数 ssh.ClientConfig 结构体,用来配置 SSH Client。部分字段说明如下:

获取到 *ssh.Client 对象后,即可通过如下 API 使用 SSH 连接协议(具体参见上文)提供的能力。

Server 

该库 server 能力通过 func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) 函数提供。,该函数,完成了 SSH 传输层协议和认证协议(具体参见上文)部分。该函数的返回值说明如下:

  • *ssh.ServerConn 对 net.Conn 的封装,主要用于远端转发,具体参见下文。
  • <-chan NewChannel 获取由 ssh client 创建的 Channel,用来实现交互式会话、本地转发。
  • <-chan *Request 主要用于远端转发,对应 SSH_MSG_GLOBAL_REQUEST 消息,具体参见下文。
  • error 处理 SSH 传输层协议和认证协议出现错误,如认证失败。

ssh.NewChannel 接口对应一个 client 创建的 Channel 的消息(SSH_MSG_CHANNEL_OPEN 具体参见上文:Channel 部分),方法有如下几个:

  • ChannelType() string channel 的类型,可选值为:’session’, ‘x11’, ‘forwarded-tcpip’, ‘direct-tcpip’ 详见: rfc4250#section-4.9.1
  • Accept() (Channel, <-chan *Request, error) 同意建立该 Channel。
    • ssh.Channel 接口对应一个已经建立 Channel,在 server 端,该接口方法解释如下:
      • Read(data []byte) (int, error) 从 Channel 中读取数据,对应 client -> server 的 SSH_MSG_CHANNEL_DATA 消息(参见上文 channel),在 session 场景对应 stdin。
      • Write(data []byte) (int, error) 向 Channel 中写入数据,对应 server -> client 的 SSH_MSG_CHANNEL_DATA 消息(参见上文 channel),在 session 场景对应 stdout。
      • Close() error 关闭该 channel,对应 SSH_MSG_CHANNEL_CLOSE 消息 (参见上文 channel)。
      • CloseWrite() error
      • SendRequest(name string, wantReply bool, payload []byte) (bool, error) 对应 server -> client 在该 Channel 上的 SSH_MSG_CHANNEL_REQUEST(参见上文 SSH 连接协议),主要在 session channel 场景有如下几个类型:
        • "window-change",发送 pty 的 window-change 信息。
        • "exit-status",发送 cmd 的退出码消息。
    • ssh.Request 结构体对应 client -> server 在该 Channel 上的 SSH_MSG_CHANNEL_REQUEST(参见上文 SSH 连接协议)该结构体有如下几个字段和方法:
      • Type string 字段,在 session channel 场景有用,有如下几个类型:
        • "pty-req"
        • "shell"
        • "subsystem"
        • "env"
        • "exec"
      • WantReply bool 字段,是否需要回复。
      • Payload []byte 字段,type 特定数据,可以使用 ssh.Unmarshal() 方法进行反序列化。
      • func (r *Request) Reply(ok bool, payload []byte) error 方法,对 WantReply = true 的方法,必须调用该函数进行回复。
  • Stderr() io.ReadWriter server -> client,对应 SSH_MSG_CHANNEL_EXTENDED_DATA,参见上文 交互式会话,在 session 场景对应 stderr。
  • Reject(reason RejectionReason, message string) error 拒绝建立该 Channel。
  • ExtraData() []byte 类型特定数据。

从 API 上来看,Go SSH 库 Server API 比 Client API 更加的底层,需要开发者理解 SSH 连接协议 消息相关细节才能很好的进行开发。而 Go SSH 库的 Client API 在比较高的层次,使用起来比较容易。

因此,如果想使用 Go 语言开发 SSH Server 相关需求,建议直接使用或者参考:github.com/gliderlabs/ssh 库,该库提供了类似于 http.Server 的,更高层次的 API。如:

  • 远端转发的示例实现,主要逻辑是对上文 NewServerConn 返回的:
    • <-chan *Request,接收到 "tcpip-forward" 监听端口,接收到 "cancel-tcpip-forward" 取消监听。
    • *ssh.ServerConn,用户请求上面监听的端口时,调用 OpenChannel 建立一个 server -> client 的 channel,并进行数据拷贝。

本文主要是探索 SSH 协议的相关结构,因此下文的示例的 server 仍然使用 Go SSH 库来实现。

通用 API 

标签:协议,string,MSG,SSH,Go,byte,转载,uint32
From: https://www.cnblogs.com/codestack/p/17948145

相关文章

  • 2016 2019 李世石 人机大战 谷歌人工智能AlphaGo 韩国人工智能"韩豆"
    2016年3月,谷歌围棋人工智能机器人“阿尔法狗”与韩国棋手李世石进行较量,“阿尔法狗”获得比赛胜利,最终双方总比分定格在4:1。首场人机大战结束后,“阿尔法狗”之父、德米斯·哈萨比斯表示,人工智能的下一步目标是让计算机自己学棋。也就是说,下个版本的“阿尔法狗”将从零开始,不接受......
  • go SSH远程终端及WebSocket
      目前chisel基于tcphttpwebsocket的ssh代理!!所以这个东西不就是可以直接远程登录了吗?就行jumpserver一样和chisel一样使用ssh goget"github.com/gorilla/websocket"goget"golang.org/x/crypto/ssh"//等库基于Web的Terminal终端控制台完成这样一个WebTermi......
  • 使用Ventoy制作Win to Go和Fedora to Go双系统
    这是一次简短的记录整体的思路实际上是通过虚拟机制作安装好系统的虚拟磁盘文件,然后加载到Ventoy中,从Ventoy启动Ventoy官方网站在实现的过程中,首先需要对存储介质(U盘等等,我是用的是固态硬盘盒)进行初始化并安装Ventoy随后使用虚拟机来安装系统,装在物理机的硬盘上就可以了,......
  • 敏捷研发管理流程及示例-Leangoo领歌|永久免费的敏捷开发工具
    ​ Leangoo领歌是一款永久免费的专业的敏捷开发管理工具,提供端到端敏捷研发管理解决方案,涵盖敏捷需求管理、任务协同、进展跟踪、统计度量等。Leangoo领歌上手快、实施成本低,可帮助企业快速落地敏捷,提质增效、缩短周期、加速创新。Leangoo领歌区别于传统项目管理软件,项目的需求......
  • Golang如何进行数据库查询
    Golang是一门高效、快速、强大的编程语言,可用于构建各种应用程序,尤其是在Web开发中表现突出。当与数据库结合使用时,Golang提供了一些强大的工具,帮助开发人员操作数据库。在本篇文章中,我们将重点介绍Golang如何进行数据库查询。一、Golang数据库查询Golang中的数据库查询主要有两......
  • openEuler欧拉使用sshpass不输入密码远程登录其他服务器
    ​​ssh登陆不能在命令行中指定密码,sshpass的出现则解决了这一问题。用-p参数指定明文密码,然后直接登录远程服务器,它支持密码从命令行、文件、环境变量中读取。操作步骤:一、关闭防火墙systemctlstopfirewalldsystemctldisablefirewalld二、安装sshpassdnf-yinstall......
  • 如何使用Go语言进行数据库操作
    如何使用Go语言进行数据库操作 https://www.php.cn/faq/587088.html引言:Go语言是一种高效且简洁的编程语言,拥有强大的并发能力和优秀的性能表现。在开发过程中,与数据库的交互是一个非常重要的环节。本文将介绍如何使用Go语言进行数据库操作,包括连接数据库、CRUD操作以及事务处理......
  • UI测试平台RunnerGo一键安装教程
    现在安装RunnerGo仅需要一条命令!目前支持系统:Centos、Debian、Ubuntu三种。下面给大家介绍一下RunnerGo安装使用流程:Step1:复制以下命令wgethttps://img.cdn.apipost.cn/running_go/img/wiki/runnergo.tar&&tarxfrunnergo.tar&&bashinstall.shStep2:选择安装系统输入命令......
  • UI测试平台RunnerGo一键安装教程
    现在安装RunnerGo仅需要一条命令!目前支持系统:Centos、Debian、Ubuntu三种。下面给大家介绍一下RunnerGo安装使用流程:Step1:复制以下命令wget https://img.cdn.apipost.cn/running_go/img/wiki/runnergo.tar&&tarxf runnergo.tar  &&bashinstall.shStep2:选择安装系统......
  • ArgoCD用户管理
    1.创建用户alicekubectlapply-fargocd-cm.yamlapiVersion:v1kind:ConfigMapmetadata:name:argocd-cmnamespace:argocdlabels:app.kubernetes.io/name:argocd-cmapp.kubernetes.io/part-of:argocddata:#addanadditionallocaluserwitha......