Как скомпилировать родной аддон Node.js для собственной библиотеки OpenSSL? - PullRequest
0 голосов
/ 05 октября 2018

Этот вопрос связан со следующими проблемами на GitHub:

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

Поэтому, если возможно, прочитайтетам тоже (и опубликуйте рекомендованное действие там, если оно у вас есть).

Некоторая справка:

Я написал привязку libcurl для Node.js, котораяпо умолчанию использует OpenSSL ( node-libcurl ).

В Windows у меня есть шаг, который создает статически связанную версию libcurl с OpenSSL, чтобы использовать ее в качестве зависимости при создании дополнения:

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

Имейте в виду, что у меня libcurl 7.64.1 статически связан с OpenSSL 1.1.1b (также статически связан) по адресу:

/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 использовала версию, предоставленную узлом, однако там был неопределенный символ.Эта функция существует только в OpenSSL 1.1.1, здесь есть защита libcurl здесь и она называется здесь .Как и ожидалось, я построил libcurl с использованием заголовков OpenSSL 1.1.1b.

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, которую мы статически связали с надстройкой, использовалась для предоставления неопределенного символа, однако собственный OpenSSL Node.js по-прежнему имеет приоритет для всех других символов.Вероятно, это сработало, потому что обе версии 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.1b и 1.0.2r не совместимы.


Поскольку, похоже, нет способа заставить Node.js прекратить экспорт символов OpenSSL, единственно возможное решение - всегда использовать соответствующую версию OpenSSL для данной версии Node.js, чтобы они соответствовали максимально возможному.

Если кто-нибудь знает лучшее решение, пожалуйста, дайте мне знать.


Эти вопросы / ответы, вероятно, в некоторой степени связаны:

Связывание двух общих библиотек с одними и теми же символами
Какая функция используется при загрузке двух общих библиотек с одинаковыми статически связанными функциями
Программа, связанная с библиотеками, которые имеют общие имена символов, работает некорректно

...