V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
LonnyWong
V2EX  ›  Go 编程语言

go 有办法调用基础库 golang.org/x/crypto 的私有结构和方法吗?

  •  
  •   LonnyWong · 185 天前 · 1952 次点击
    这是一个创建于 185 天前的主题,其中的信息可能已经有所发展或是发生改变。

    开源项目 https://github.com/trzsz/trzsz-ssh 想支持 ssh ControlMaster 的功能。

    go 基础库 golang.org/x/crypto 有个 PR https://go-review.googlesource.com/c/crypto/+/383374 还没合入。

    有办法在不 fork 基础库 golang.org/x/crypto 的情况下,优雅地在自己的项目实现这个 PR 的逻辑吗?

    import "golang.org/x/crypto/ssh"
    
    func NewControlClientConn(c net.Conn) (ssh.Conn, <-chan ssh.NewChannel, <-chan *ssh.Request, error) {
      conn := &ssh.connection{     ■ undefined: ssh.connection
        sshConn: ssh.sshConn{conn: c},     ■ undefined: ssh.sshConn
      }
      var err error
      if conn.transport, err = handshakeControlProxy(c); err != nil {
        return nil, nil, nil, fmt.Errorf("ssh: control proxy handshake failed; %v", err)
      }
      conn.mux = ssh.newMux(conn.transport)     ■ undefined: ssh.newMux
      return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil
    }
    
    

    handshakeControlProxy 这个函数很好办,直接从 PR 中复制出来就行了。

    问题:上面的 ssh.connectionssh.sshConnssh.newMux 依赖很深,发现很难直接 copy 出来。

    25 条回复    2023-10-29 16:27:01 +08:00
    Nazz
        1
    Nazz  
       185 天前 via Android   ❤️ 1
    用 go:linkname 把私有函数链出来; unsafe 读写私有结构
    LonnyWong
        2
    LonnyWong  
    OP
       185 天前
    @Nazz unsafe 能引用私有结构吗?具体怎么做?
    liuidetmks
        3
    liuidetmks  
       185 天前
    chatGPT ?
    LonnyWong
        4
    LonnyWong  
    OP
       185 天前
    @liuidetmks 你问问看?
    ysicing
        5
    ysicing  
       185 天前   ❤️ 1
    @LonnyWong V2EX 不允许 gpt 回答的,会 ban 账号的。
    Junian
        6
    Junian  
       185 天前 via iPhone
    @LonnyWong 可以看 https://github.com/dolthub/maphash 这玩意的实现,其实就是自己整个和私有结构体一模一样的,然后把指针映射到自己的结构体上
    lysS
        7
    lysS  
       185 天前
    @Nazz #1 link 要在 golang.org/x/crypto 里面写

    其实可以用 go 汇编,可以直接根据包名﹒变量名引用(这个不安全)
    kkbblzq
        8
    kkbblzq  
       185 天前   ❤️ 2
    @lysS 不需要的,外面写一个相同定义的函数 link 原函数就行了


    //go:linkname func1 pkg.func1
    func func1(a string) string

    记得 import _ "unsafe"
    LonnyWong
        9
    LonnyWong  
    OP
       185 天前
    @kkbblzq 现在要调用的函数是

    func newMux(p packetConn) *mux

    问题是 packetConn 和 mux 都是私有的,怎么用 go:linkname 定义呢?

    type packetConn interface {
    // Encrypt and send a packet of data to the remote peer.
    writePacket(packet []byte) error

    // Read a packet from the connection. The read is blocking,
    // i.e. if error is nil, then the returned byte slice is
    // always non-empty.
    readPacket() ([]byte, error)

    // Close closes the write-side of the connection.
    Close() error
    }


    type mux struct {
    conn packetConn
    chanList chanList

    incomingChannels chan NewChannel

    globalSentMu sync.Mutex
    globalResponses chan interface{}
    incomingRequests chan *Request

    errCond *sync.Cond
    err error
    }
    lysS
        10
    lysS  
       185 天前
    @kkbblzq #8 你这反了,你看 runtime now

    https://github.com/golang/go/blob/master/src/runtime/timestub.go#L14

    连接到 time now ,linkname 是写在 runtime 而不是 time
    learningman
        11
    learningman  
       185 天前
    最好别拿 linkname 搞,升级 go 版本的时候容易炸。
    还是乖乖开个 fork 吧
    lysS
        12
    lysS  
       185 天前
    LonnyWong
        13
    LonnyWong  
    OP
       185 天前
    @learningman fork golang.org/x/crypto 也不好啊。
    777777
        14
    777777  
       185 天前
    Go 创始人说:最好的方法就是复制
    LonnyWong
        15
    LonnyWong  
    OP
       185 天前   ❤️ 1
    @777777 #14 反对他。我只是要加一点点功能,我可没有能力和精力去维护那么大一个库。
    Nazz
        16
    Nazz  
       185 天前
    @LonnyWong 可以算偏移量直接读写; 或者定义一个相同结构的 struct, unsafe 强转 (我不清楚是否安全)
    wwqgtxx
        17
    wwqgtxx  
       185 天前
    @lysS #10 ,linkname 在哪边写都是可以的
    chimission
        18
    chimission  
       185 天前
    可以复制, 毕竟标准库里为了解决循环引用 也搞了很多复制
    bruce0
        19
    bruce0  
       185 天前
    用 `unsafe.Pointer` + 偏移量 可以做到
    kkbblzq
        20
    kkbblzq  
       185 天前
    @LonnyWong packetConn 是个 interface 吧,直接拷贝出来就是了,
    kkbblzq
        21
    kkbblzq  
       185 天前   ❤️ 1
    @kkbblzq mux ,骚一点就是。。
    //go:linkname newMux golang.org/x/crypto/ssh.newMux
    func newMux(p packetConn) *mux

    type mux struct {
    conn packetConn
    _ [40]byte

    incomingChannels chan ssh.NewChannel
    globalSentMu sync.Mutex
    globalResponses chan interface{}
    incomingRequests chan *ssh.Request

    errCond *sync.Cond
    err error
    }
    kkbblzq
        22
    kkbblzq  
       185 天前   ❤️ 1
    @kkbblzq 接口可以
    //go:linkname SendRequest golang.org/x/crypto/ssh.(*mux).SendRequest
    func SendRequest(mux *mux, name string, wantReply bool, payload []byte) (bool, []byte, error)

    func (c *connection) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) {
    return SendRequest(c.mux, name, wantReply, payload)
    }

    不过整体也不是很优雅就是了,兼容性很差
    matrix1010
        23
    matrix1010  
       185 天前
    我觉得最优雅的办法就是 fork 。fork 完 release 个新版本,等 ssh 真的支持你想要的,再发布个新版本换回原来的
    learningman
        24
    learningman  
       184 天前
    @LonnyWong 但是这样 go 版本更新的时候你可以显式的 review 改了什么,用 linkname 炸的无声无息,stacktrace 都没有那种
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2747 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 15:20 · PVG 23:20 · LAX 08:20 · JFK 11:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.