суббота, 29 июля 2017 г.

C++ symbol lookup error при запуске приложения

Суть проблемы
 
Недавно, занимаясь одним из своих С++ проектов обнаружил следующее занимательное поведение программы, использующих динамическую библиотеку. На самом деле, неважно какая библиотека вызвала данную проблему, я уверен, что это не имеет никакого значения. Но в моем случае данная проблема возникла с библиотекой libuhd. Я собрал для себя специальную версию ibuhd, успешно скомпилировал и слинковал приложение с либой и бац! при запуске:
linux; GNU C++ version 4.8.5; Boost_105800; UHD_003.010.001.001-0-unknown

/home/michael/Projects/eclipse/C++/wirelessdriver/UhdRadio/Debug/UhdRadio: symbol lookup error: /home/michael/Projects/eclipse/C++/wirelessdriver/UhdRadio/Debug/UhdRadio: undefined symbol: _ZN20radio_ctrl_core_30004makeEbN5boost10shared_ptrIN3uhd9transport12zero_copy_ifEEES5_jRKSs




Причина в отсутствии функции в классе библиотеки или самого класса! Собирал я это чудо cmake, и, как оказалось, в cmake также можно задавать видимость определенных классов, но предварительно я снял все ограничения, экспортировал все, что есть. Сижу недоумеваю, пью кофе и тихо матерюсь ("С++, что же ты со мной делаешь!").

Дьявол скрывается в мельчайших деталях

В первую очередь решил проверить, а есть ли в библиотеке такой символ. Для таких целей в Linux есть утилита nm. Она позволяет вывести список экспортируемых символов, но он оказывается гигантским, поэтому используем ее совместно с grep, получаем:

~/Projects/eclipse/C++/wirelessdriver/UhdRadio/uhd-release_003_010_001_001/host/build/lib> nm -D libuhd.so | grep _ZN20radio_ctrl_core_30004makeEbN5boost10shared_ptrIN3uhd9transport12zero_copy_ifEEES5_jRKSs
00000000004e1ff0 T _ZN20radio_ctrl_core_30004makeEbN5boost10shared_ptrIN3uhd9transport12zero_copy_ifEEES5_jRKSs


Да, что же такое! Нужные символы есть, возможно не все зависимости (библиотеки) есть в системе, но ldd показывает, что все ОК (показывает откуда (путь) подлинковываются либы). И тут меня осенило!!! Я собирал целую массу версий uhd и параллельно ставил ее из пакетов, а что же говорит ldd относительно этой либы в моей утилите???  А говорит он, что либа при запуске приложения берется не из того, же источника откуда проводилась линковка! Понятно, что для запуска либа должна быть в LD_LIBRARY_PATH, но оба пути находятся в этой переменной, а при запуске либа тянется из первого в порядке упоминания пути, а моих изменений там вовсе НЕТ. Правим и наслаждаемся спокойной работой дальше.

Заключение

С++ , GCC люблю я вас! Настолько много в вас неожиданных сюрпризов...

вторник, 11 июля 2017 г.

Бесплатный сыр SSL

SSL, паранойя браузеров и зеленый HTTPS

Собственно ситуация довольно простая: имею собственный сервер, на котором развернут Gitlab + CI в лице Hudson: пишу код, тружусь, собираю автоматически билды проектов и т.п. В один прекрасный момент захотелось, чтобы сервис был развернут на HTTPS ( это не прихоть, просто, иногда люблю зайти на свой сервер из общественных мест с общего wi-fi, а шифрования нет, что может привести к доступу ко всей информации любому, кто способен запустить wireshark или tcpdump и т.п. Примерно около двух с половиной лет назад, по довольно тривиальной схеме я создал самоподписанный сертификат по следующей схеме (из под Linux):

1) Нужно сгенерировать CSR (Certificate Signing Request), который состоит из открытого (public) и закрытого (private) ключа и доп информации. При генерации CSR нужно записать/запомнить пароль!!!!, иначе дешифровать ключ не получится и придется генерировать CSR и ключ заново.

openssl req -newkey rsa:2048 -keyout gitlab.key -out gitlab.csr

2)  Генерируем сертификат:

openssl -key gitlav.key -new -x509 -days 1536 -out gitlab.crt
 
Параметр days задает время действия сертификата - 1536. Теперь самоподписанный сертификат готов, но, современные браузеры начинают жутко параноить и разрывают соединение при наличии на сервере такого сертификата. Использование сервиса, начинает доставлять неудобства.

3) Дешифровать  ключ, который понадобится Nginx для работы по SSL:

openssl rsa -in gitlab.key -out gitlab_dec.key

Немного теории об SSL

Как работает SSL для чего нужны открытые, закрытые ключи и сертификаты? Сама безопасность обеспечивается шифрованием данных, на сервере и у клиента: при установке соединения клиент и сервер договариваются о выборе типа шифрования, сервер передает на клиент сертификат и открытый ключ, закрытый ключ остается на стороне сервера. Далее происходит генерация сеансового ключа на стороне клиента (шифрование случайной последовательности открытым ключом),  и передача их на сервер, расшифровать данные можно только с помощью закрытого ключа (т.к.) шифрование является асимметричным. Закрытый ключ находится на сервере и недоступен никому.

StartSSL и иже с ними

Жадные капиталисты за работу своих центров сертификации, хотят  деньги, поэтому, чтобы стать обладателем сертификата нужно раскошелиться на, сумму от 50 до 200$. Для хостинга своих небольших сайтов и Web-сервисов такая цена является неоправданно высокой, поэтому лучше найти варианты с бесплатным SSL. Из известных мне сервисов это StartSSL и Letsencrypt. Изначально я подсел на первый и, поэтому решил работать с ним дальше.

Полезные команды на заметку

Самым главным вопрос для меня являлось узнать/проверить а соответствует ли мой приватный ключ сертификату, чтобы это сделать наиболее просто нужно получить хэши поля modulus приватного ключа и сертификата:

openssl x509 -noout -modulus -in gitlab.crt | openssl md5
(stdin)= ca2097c19fa0af553533037e290dfb02
openssl rsa -noout -modulus -in gitlab_dec.key | openssl md5
(stdin)= 933b16d478523d8d8f3fbfceb57644e0
openssl rsa -noout -modulus -in gitlab.key | openssl md5
Enter pass phrase for gitlab.key:
(stdin)= ca2097c19fa0af553533037e290dfb02

Как видно из выхлопа консоли у одного ключа совпадает хэш с сертификатом, а у другого нет

Что делать в случае использования StartSSL

Да, я выбрал Start SSL и в 2016-м получил свой первый зеленый сертификат на целый год работы,все было хорошо. Но сертификат буквально неделю назад испарился и возобновить его нет возможности, необходимо создавать новый, что же попробуем создать новый. Сразу скажу, что сертификат выпускается на доменное имя, поэтому для того, чтобы его получить нужно где-то взять имя. Я использую dnsexit, они предоставляют бесплатные доменные имена 2го уровня в зонах типа linkpc.net и т.п.

1) Прежде всего подтверждаем, что являемся владельцами домена. Раньше в StartSSL можно было разместить страничку на сервере и пройти валидацию, теперь все только через e-mail адрес домена, который выдает whois. Я заплатил 12$ за редирект почты в dnsexit на свою почту и получил код валидации домена.

2) После валидации домена необходимо зайти в Certificate Wizard и создать csr на базе приватного ключа:
openssl req -newkey rsa:2048 -keyout um-gitlab.linkpc.net_enc.key -out um-gitlab.linkpc.net.

 3) Скачиваем сертификат из StartSSL ToolBox панели, нам нужен вот этот сертификат:

Нажимаем Retrieve и забираем весь архив. И вот тут-то начинается самое прекрасное. У Start SSL есть инструкция по установке сертификата на NGINX, только по этой инструкции сертификат поставить невозможно. Для того чтобы домучить процесс нужно запросить промежуточный сертификат, который имеет имя BR Intermediate. Из папки OtherServer взять сертификат домена и корневой сертификат (root.crt), теперь эти 3 сетификата нужно объединить в следующем порятке:
          1. Сертификат домена
          2. Промежуточный сертификат
          3. Корневой сертификат

Объединяем все это дело утилитой cat:

cat gitlab.crt BR\ Intermediate.crt root.crt > ssl-unified.crt

Ну а далее стандартная процедура накатывания сертификата на nginx: в качестве ключа берем дешифрованный приватный ключ, а в качестве сертификата ssl-unified. После установки сертификата перезагружаем nginx и теперь все готово к работе.

Проверить правильно ли сгенерировались и объединились сертификаты можно с помощью данного онлайн ресурса: https://www.sslshopper.com/ssl-checker.html Если цепочка является полной, то все ок.

И здоровенная ложка дегтя!!!!

На текущий момент у StartSSL проблемы с Chrome > 57 и Firefox, эти браузеры считают сертификаты не валидными. Поэтому я сижу, грущу и использую Konqueror. В службе поддержки мне сказали, что, вероятно, через 1-2 месяца они решат проблему с этими браузерами. Ресурсы для отслеживания этой темы:
https://blog.mozilla.org/security/2016/10/24/distrusting-new-wosign-and-startcom-certificates/
https://bugzilla.mozilla.org/show_bug.cgi?id=1311832

Насколько сыр оказался бесплатным?

Если не считать 12 баксов на редирект электронной почты (возможно, я смог бы поднять mail-сервер, но не факт, что он стал бы работать в этом домене с нужным адресом эл. почты, поэтому я не стал тратить время на решение этого вопроса) и рабочего дня времени убитого на то, чтобы создать и установить сертификат правильно, то все остальное оказалось бесплатным, на выходе имеем сертификат валидный в течение двух лет. В целом, я считаю, это неплохим результатом и если бы цены на сертификаты были раза в два меньше, то можно было бы купить сертификат более высокого класса.

Распространение Windows-приложений (Chocolatey)

Менеджеры пакетов для ОС Windows В большинстве дистрибутивов Linux есть свои менеджеры пакетов: в Ubuntu/Mint это apt и deb, в OpenSuse э...