socks-сервер Dante или как одна буква может «съесть» пару суток времени

от автора

Каждый раз сталкиваясь с таким «рабочим моментом» я задумываюсь надо ли его решение давать миру или он мелочно для других, но на этот раз решил-таки выложить. Эта статья больше из разряда заметки на манжетах и написана лишь из-за скудности информации о настройке Dante в нете и хроманием на обе ноги официальной документации.
В пятницу утром заказчик обратился с просьбой поднять socks-сервер на ~100 пользователей, с авторизацией по логину/паролю, привязкой IP и отправкой запросов с того же IP к которому конектится пользователь. При этом заказчик поинтересовался сроком выполнения работ и, хоть я не люблю делать прогнозы по времени установки/настройки, заверил его, что часа через 3-4 альфа-версия будет готова. Ну правда — погуглив выбрать подходящий socks-сервер, установить, почитать маны, подправить под себя дефолтный конфиг… в 4 часа должен вложиться.
ОС FreeBSD 9.2, но всё нижеописанное справедливо и для 10-ки.

Как ни странно, подходящих под запросы заказчика socks-серверов нашлось всего два: 3proxy 0.6.1 и Dante (в портах 1.3.2). Может я, конечно, что-то упустил, но либо нет авторизации, либо нет режима int_ip -> ext_ip. Возможно этим запросам соответствует squid, но ставить этого монстра ради простой задачи не хотелось.
Я ничего не имею против 3proxy, сам с ним работаю не первый год в режиме портмэппинга, нареканий особых нет, но разработка его стоит с 2009 года, код грязноват и слышал неоднократные отзывы о его прожорливости под большой нагрузкой.
Итак, Dante.
До версии 1.3 поддержки int_ip -> ext_ip Dante не имел, точнее имеется схожая реализация в платной версии по весьма недедемократичной цене в EUR400, однако, Lysenko Konstantin добавил данный функционал в виде патча «same-same» в Dante 1.2.2 и он был включён в релиз 1.3.0.
Не берусь утверждать работала ли данная конструкция в 1.3.0, но в 1.3.2 запросы упорно уходят с первого найдённого в конфиге external-ip. Перелопатив скудный ман я обратился к странице разработчика. Информации там несколько больше, но запустить same-same так как мне требовалось не удалось. Однако, с ноября 2013 года на сайте есть версия 1.4, которая почему-то не включена в порты. Качаем, собираем.
Надо отметить, что конфиг в 1.4 претерпел косметические изменения, хотя в манах по прежнему приводятся примеры с параметрами прежних версий, на которые Dante ругается как deprecated и, иногда, подсказывает верные новые параметры.

Тестовый конфиг:

/usr/local/etc/sockd.conf

# cat /usr/local/etc/sockd.conf logoutput: /var/log/socks/socks.log  debug: 0  internal: 11.12.13.1          port = 1080 internal: 11.12.13.2          port = 1080 internal: 11.12.13.3          port = 1080 external: 11.12.13.1 external: 11.12.13.2 external: 11.12.13.3  external.rotation: same-same  socksmethod: username  user.privileged: root user.unprivileged: nobody user.libwrap: nobody  compatibility: sameport  client pass {         from: 0.0.0.0/0 port 1-65535 to: 0.0.0.0/0 }  client block {         from: 0.0.0.0/0 to: 127.0.0.0/8         log: connect error }  client block {         from: 0.0.0.0/0 to: 0.0.0.0/0         log: connect error }   socks pass {         from: 21.22.23.0/24 to: 0.0.0.0/0         log: connect error         user: chaturanga }  socks block {         from: 0.0.0.0/0 to: 0.0.0.0/0         log: connect error }  

И… вопреки ожиданиям в 1.4 same-same также не заработал. На этот раз в отличии от 1.3 посыпались ошибки типа

warning: getoutaddr(): using external.rotation = same-same, local address 21.22.23.48 was selected for forwarding from our local client 21.22.23.48.45980 to target 77.72.80.15.80, but that local address is not set on our external interface(s).  Configuration error in /usr/local/etc/sockd.conf?  

, где 21.22.23.48 — адрес моей локальной машины в то время как здесь должен быть internal-IP сервера к которому которому подключается клиент. Смутившись фразой «Configuration error in /usr/local/etc/sockd.conf?» курочу конфиг и штудирую маны, но, так как информации в них мало, лезу в лучший ман — исходники. Улыбаясь комментариям в виде

   /*     * Just return the first address of the appropriate type from our internal     * list and hope the best.     */ 

нахожу-таки источник проблем (./sockd/sockd_request.c, line 4173):
/*
* Find address to bind for client. First the ipaddress.
*/
if (getoutaddr(&io->dst.laddr,
&io->src.raddr,
req.command,
target,
emsg,
emsglen) == NULL)
return -1;

Меняю на &io->src.raddr на &io->src.laddr, пересобираю, запускаю и, наконец, вижу желанное:

info: pass(1): tcp/connect [: username%chaturanga@21.22.23.48.46050 11.12.13.3.1080 -> 11.12.13.3.27819 77.72.80.15.80 

Тихо матерясь, оформляю баг-репорт разработчикам.
В итоге вместо заявленных 3-4 часов в чтении, додумывании конфигов, попытке запустить Dante не в jail’e, тестах на Centos вместо FreeBSD и копании в исходниках убил пару дней… Вот и обещай после этого…

UPD1: Пока писалась заметка ответил разработчик:

Hello, thank you for the bug-report. You are correct, there is an
error here. Your proposed solution is basically correct, though
we will probably implement the fix slightly differently.

UPD2: И в ходе дальнейшей переписки:

Depending on the current workload, I doubt I will be able to provide
you with our official patch for at least another month.

Ну и на том спасибо.

ссылка на оригинал статьи http://habrahabr.ru/post/218589/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *