Go SSH服务器上次登录消息实现

Go SSH服务器上次登录消息实现,go,ssh,server,Go,Ssh,Server,我使用crypto/SSH库在Go中实现了一个SSH服务器守护进程,我想实现OpenSSH中的“last login message”功能:当用户连接到服务器时,他会收到一条消息,指示其上次连接的IP/时间 为了验证用户,SSH服务器使用PublicKeyCallback,如下所示 &ssh.ServerConfig{ NoClientAuth: false, PublicKeyCallback: func(c ssh.ConnMetadata, pk s

我使用
crypto/SSH
库在Go中实现了一个SSH服务器守护进程,我想实现OpenSSH中的“last login message”功能:当用户连接到服务器时,他会收到一条消息,指示其上次连接的IP/时间

为了验证用户,SSH服务器使用PublicKeyCallback,如下所示

&ssh.ServerConfig{
        NoClientAuth: false,
        PublicKeyCallback: func(c ssh.ConnMetadata, pk ssh.PublicKey) (*ssh.Permissions, error) {
            pkstr := string(pk.Marshal())

            akmu.Lock()
            defer akmu.Unlock()
            if _, ok := authorizedKeys[pkstr]; ok {
                authorizedKeys[pkstr].last = time.Now()
                return nil, nil
            }
            return nil, errors.New("unauthorized public key")
        },
    }
authorizedKeys
变量将封送的公钥映射到一种类型,该类型应存储公钥上次连接的原始ip地址和时间

var authorizedKeys map[string]*keyHistory

type keyHistory struct {
    Origin   net.Addr
    Time     time.Time
}
问题是,用于自动验证用户的公钥唯一可用的地方是在执行
PublicKeyCallback
期间,但在此处注册连接事件并不能保证连接过程以后不会失败

我后面所说的是公钥被授权后发生的不同步骤:

  • 拒绝所有非会话通道
  • 接受会话通道
  • 使用会话通道和conn创建一个新的终端(使用自己的
    terminal.terminal
  • 处理其他请求(
    shell
    pty-req
    窗口更改
  • 使用
    terminal.ReadLine()
理想情况下,连接事件ip/时间将在运行终端循环之前记录,以确保它与成功登录相对应。不幸的是,此时只有终端的底层
ssh.ServerConn
可用,无法将其链接回公钥

var authorizedKeys map[string]*keyHistory

type keyHistory struct {
    Origin   net.Addr
    Time     time.Time
}
是否有实现类似功能的线索?任何例子或链接到一个项目,将实现同样的事情将不胜感激


谢谢

为什么您不能在
PublicKeyCallback
期间缓存该值,然后在登录成功后将其移动
authorizedKeys
?您还需要围绕
authorizedKeys
进行数据竞争,并且需要围绕地图进行某种同步。@JimB既然可以同时运行多个连接,您将如何缓存它并将成功的连接链接到私钥?(publick key/
net.Addr
对的临时缓存。可以工作,因为主机:起始端口应该是唯一的)映射由一个
sync.Mutex
支持。@JimB好的,所以你的想法是好的。我缓存映射到publick密钥的连接attampt详细信息,在我假设连接成功的情况下,我使用缓存中找到的数据更新上次成功的尝试详细信息(匹配是使用
net.Addr
完成的,它应该是唯一的,因为它的格式是host:port),并写入上次连接详细信息(如果有)给客户。不知道为什么我之前没有想到这一点。