Здравствуйте, коллега.
Ищу способ работы с БД MySQL в программе на C# через прокси-сервер SOCKS5. Искать пробовал и даже находил платное проприетарное решение. Однако моя программа не для бизнеса и планируется распрострянять её под GPLv3 лицензией. Другие OpenSource MySQL коннекторы либо не имеют такой возможности, либо я не понял какой параметр отвечает за прокси.
Прошу поделиться опытом и мыслями на этот счёт. Возможно существует возможность не прибегать к таким костылям как Proxifier и глобальный VPN на время использования программы?
с C# знаком не много и писать на нём не буду, но из моего опыта(писал на языке ниже уровнем), я могу описать логику и далее Вы уже и сами разберётесь я думаю (протокол и правда простой, вечера/пары_вечеров должно хватить для простой реализации)
Допустим, нам доступно:
сервер socks5 по сокету 192.168.0.100:1234
сервер sql: 85.154.55.10:5678
Делаем TCPConnection(192.168.0.100, 1234)
Этап 1 - аутентификация. Структура отправляемого пакета:
[SOCKS_VERSION, SOCKS_AUTH_ALLOW_METHODS_LENGTH, SOCKS_AUTH_ALLOW_METHOD_CODE1, SOCKS_AUTH_ALLOW_METHOD_CODE2,SOCKS_AUTH_ALLOW_METHOD_CODE3]
SOCKS_AUTH_ALLOW_METHOD_CODE:
No => 0
GSSAPI => 1
Password => 2
Посылаем, к примеру:
[5, 2, 0, 2] - допустимо авторизоваться открыто или по логин/паролю
В ответ на этот пакет приходит
[ 5, 2 ] - значит версия SOCKS совпадает и сервер предпочел авторизацию по паролю (сервер сам выбирает наилучший метод авторизации, если в вашем запросе допустимых нет - пришлет 255)
Этап 2 - авторизация по логин/паролю
(! этот этап пропускаем если выбран метод без авторизации ) (!! Проще без авторизации работать т.к. защита от дурака - минимум безопасности обеспечит соединеиние threw ssh port forwarding)
[SOCKS_VERSION, LOGIN_LENGTH, LOGIN, PASSWORD_LENGTH, PASSWORD]
[хз что это , длина ,логина, длина , пароля]
Отправляем admin/admin:
[5,5,97, 100, 109, 105, 110,5,97, 100, 109, 105, 110]
Получаем [5,0] - это успех, всё что выше нуля во втором байте - неудача (соединение сбрасывается).
Этап 3 - посылаем команду соксу
[SOCKS_VERSION, SOCKS_COMMAND, RESERVED_BYTE, HOST_ADDR_TYPE,DEST_ADDR, DEST_PORT]
[опять версия , тип комманды ,зарезирвирован, тип хоста , адрес , порт ]
SOCKS_COMMAND:
1: CONNECT - соединиться с удалённым хостом
2: BIND - попросить SOCKS сервер слушать коннекты и переправлять пакеты на локальный хост
3: UDP ASSOCIATE - тоже что выше почти, но UDP
RESERVED_BYTE - на будущее, любое значение можно записать, но как правило это ноль
HOST_ADDR_TYPE:
1: IPv4 уже знает что будет 4 байта
3: FQDN (доменное имя), тут первым байтом нужно указать размер строки
4: IPv6 уже знает что будет 6 байт
далее понятно - адрес / порт (размер для порта - 2 байта )
Отправляем:
[5,1,0,1,85,154,55,10,116,104] - 116, 104 это порт 5678, записанный в big-endian
Получаем ответ в виде
[SOCKS_VERSION, REPLY_CODE, RESERVED_BYTE, BINDED_ADDR_TYPE, BINDED_ADDR, BINDED_PORT]
[версия снова , код ответа, пампам , Тип адреса , адрес , порт
REPLY_CODE:
0 - успех, остальное ошибки... Переводить не буду
коды из RFC
o X'01' general SOCKS server failure
o X'02' connection not allowed by ruleset
o X'03' Network unreachable
o X'04' Host unreachable
o X'05' Connection refused
o X'06' TTL expired
o X'07' Command not supported
o X'08' Address type not supported
o X'09' to X'FF' не назначены
BINDED_ADDR_TYPE, BINDED_ADDR, BINDED_PORT - тут может прийти адрес, отличный от адреса SOCKS сервера - мультикаст адрес Ожидаем такой ответ
[5,0,0,1,192,168,0,100,44,196] - 44,196 это 9012 в little-endian
LOtaku, И вуаля - ниче не работает, зря потратили время т.к. BINDED_ADDR, BINDED_PORT в случае CONNECT это "внешний" сокет, используемый для связи sql сервером. Либа в каментах конечно MIT, только вот это "гирлянда" висящая на ёлке MySql.Data.MySqlClient и прикрутить костыль с прокси в его инициализацию я не знаю как (к счастью)), разве что запушить M к MIT и поднять localhost tcp socket, который будет "зеркалить" трафик на socks прокси (но это аж два с половиной костыля).
Доходил абсурд как то долго до меня, потому извиняюсь..