如何针对自己的OpenSSL库编译Node.js本机插件?

时间:2018-10-05 19:34:46

标签: c++ node.js linker libcurl node.js-addon

此问题与GitHub上的以下问题有关:

https://github.com/nodejs/node-gyp/issues/155
https://github.com/nodejs/help/issues/1724
https://github.com/JCMais/node-libcurl/issues/164

所以,如果可能的话,也请阅读(如果有的话,也请在此处张贴建议的操作)。

某些背景

我为Node.js编写了一个libcurl绑定,默认情况下使用OpenSSL(node-libcurl)。

在Windows上,我有一个步骤可以使用OpenSSL构建静态链接版本的libcurl,以便在构建插件时将其用作依赖项:

https://github.com/JCMais/node-libcurl/blob/56c2be4/binding.gyp#L49-L51

上面的代码基本上返回一个字符串,该字符串带有指向以下curl.gyp文件的路径(在构建过程中,<(library)static_library替换了): https://github.com/JCMais/curl-for-windows/blob/445e537cb2f5656e3a3ede09e9e4782a6b62c299/curl.gyp

该文件包含OpenSSL依赖项:https://github.com/JCMais/curl-for-windows/blob/445e537cb2f5656e3a3ede09e9e4782a6b62c299/curl.gyp#L33

问题是,在Node.js 10上,运行时使用的OpenSSL实际上是与其一起构建的一个Node.js,而不是上面的那个,这会导致分段错误。因为Node.js 10会导出OpenSSL 1.1.0,而我的插件仍在使用1.0.0。

我很乐意提供一些有关如何将插件正确链接到我提供的OpenSSL版本的想法,而不是使用Node.js的版本。

  

编辑-经过数小时的阅读/调试/弄乱:

这个问题不是Windows特有的,它一直存在于其他平台上,我以前只是没有寻找它。

我刚刚在下面汇总了我的发现。


以下测试是使用以下代码完成的:

const Curl = require('node-libcurl').Curl
curl = new Curl()

console.log(Curl.getVersion())

curl.setOpt('URL', 'https://www.google.com')
curl.setOpt('SSL_VERIFYPEER', false)

curl.on('end', () => {
  console.log('Works')
  curl.close()
})

curl.on('error', error => {
  console.log('err', error)
  curl.close()
})

curl.perform()

然后在项目存储库中运行以下命令:

yarn pregyp rebuild && node ssl.js

请记住,我在以下位置具有针对OpenSSL 1.1.1b(也是静态链接)的libcurl 7.64.1静态链接:

/home/jcm/curl/build/

OpenSSL 1.1.1b位于:

/home/jcm/openssl/build/

场景:

1

Node.js 8.15.1 (with OpenSSL 1.0.2r)
Addon deps:
 static linked only with libcurl 7.64.1, which itself is static linked against OpenSSL 1.1.1b

bindings.gyp

  

输出:

# Bunch of output for rebuild command
node: symbol lookup error: /mnt/e/jc/node-libcurl/lib/binding/node_libcurl.node: undefined symbol: OpenSSL_version_num

可以理解,OpenSSL_version_num是OpenSSL 1.1.x上的新功能,libcurl试图使用它,因为它是使用OpenSSL 1.1.1b标头编译的。

2

Node.js 10.9.0 (with OpenSSL 1.1.0i)
Addon deps:
 static linked only with libcurl 7.64.1, witch itself is static linked against OpenSSL 1.1.1b

bindings.gyp

  

输出:

# Bunch of output for rebuild command
libcurl/7.64.1 OpenSSL/1.1.0i
node: symbol lookup error: /mnt/e/jc/node-libcurl/lib/binding/node_libcurl.node: undefined symbol: SSL_CTX_set_post_handshake_auth

从上面的OpenSSL版本中,我们可以看到libcurl使用了node提供的那个,但是有一个未定义的符号。 此功能仅在OpenSSL 1.1.1上存在,libcurl here上有一个防护装置,称为here。再次期望,我已经使用OpenSSL 1.1.1b标头构建了libcurl。

3

Node.js 10.9.0 (with OpenSSL 1.1.0i)
Addon deps:
 static linked with libcurl 7.64.1 (also static linked against OpenSSL 1.1.1b)
 static linked with OpenSSL 1.1.1b

bindings.gyp

  

输出:

# Bunch of output for rebuild command
libcurl/7.64.1 OpenSSL/1.1.0i
Works

工作正常,看起来像我们与附加组件静态链接的OpenSSL版本用于提供未定义的符号,但是Node.js自己的OpenSSL仍然优先于所有其他符号。之所以可行,是因为两个OpenSSL版本1.1.1b和1.1.0i都兼容。

4

Node.js 8.15.1 (with OpenSSL 1.0.2r)
Addon deps:
 static linked with libcurl 7.64.1 (also static linked against OpenSSL 1.1.1b)
 static linked with OpenSSL 1.1.1b

bindings.gyp

  

输出:

# Bunch of output for rebuild command
libcurl/7.64.1 OpenSSL/1.1.1b
[1]    20063 segmentation fault (core dumped)  node ssl.js

段错误:

(gdb) backtrace
#0  0x0000000002174920 in TLSv1_2_enc_data ()
#1  0x0000000001181dcd in SSL_CTX_new ()
#2  0x00007fffefa7a89b in ossl_connect_step1 (conn=0x22621c8, sockindex=0) at vtls/openssl.c:2380
#3  0x00007fffefa7e495 in ossl_connect_common (conn=0x22621c8, sockindex=0, nonblocking=true, done=0x7ffffffe9ca9) at vtls/openssl.c:3552
#4  0x00007fffefa7e70f in Curl_ossl_connect_nonblocking (conn=0x22621c8, sockindex=0, done=0x7ffffffe9ca9) at vtls/openssl.c:3638
#5  0x00007fffefa2d3f0 in Curl_ssl_connect_nonblocking (conn=0x22621c8, sockindex=0, done=0x7ffffffe9ca9) at vtls/vtls.c:275
# omitted...
#16 0x00000000008d59c0 in node::Start(int, char**) ()
#17 0x00007ffffe091b97 in __libc_start_main (main=0x89f010 <main>, argc=2, argv=0x7ffffffee1b8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffffffee1a8)
    at ../csu/libc-start.c:310
#18 0x000000000089f101 in _start ()


(gdb) info symbol 0x0000000001181dcd
SSL_CTX_new + 189 in section .text of /home/jcm/.nvm/versions/node/v8.15.1/bin/node
(gdb) info symbol 0x0000000002174920
TLSv1_2_enc_data in section .data of /home/jcm/.nvm/versions/node/v8.15.1/bin/node

再次期望,因为1.1.1b1.0.2r不兼容。


由于似乎无法使Node.js停止导出OpenSSL符号,因此唯一可行的解​​决方案是始终为给定的Node.js版本使用相应的OpenSSL版本,以便它们尽可能匹配。

如果有人知道更好的解决方案,请告诉我。


这些问题/答案可能有些相关:

Linking two shared libraries with some of the same symbols
Which function is used when loading two shared libraries with same statically linked functions
Program linked against libraries that share symbol names runs wrong implementation

0 个答案:

没有答案