Прозрачное проксирование - как передать сокет локальному серверу без модификации?

У меня есть программа, которая слушает на порте 443 и затем перенаправляет или к SSH или к локальному серверу HTTPS в зависимости от обнаруженного протокола.

Программа делает это путем соединения с локальным сервером и проксирования всех данных назад и вперед посредством его собственного процесса.

Однако это заставляет инициирующий хост на локальных серверах быть зарегистрированным как localhost.

Есть ли любой способ передать сокет непосредственно процессу локального сервера (вместо того, чтобы просто делать новое соединение TCP) так, чтобы параметры sockaddr_in (или sockaddr_in6) будет сохранен?

Платформой для этого является Linux.

6
задан Luca Farber 29 April 2010 в 23:45
поделиться

2 ответа

Вот фрагмент кода, взятый из stunnel (из client.c в функции local_bind, если вы хотите просмотреть весь код ).

#ifdef IP_TRANSPARENT
int on=1;
if(c->opt->option.transparent) {
    if(setsockopt(c->fd, SOL_IP, IP_TRANSPARENT, &on, sizeof on))
        sockerror("setsockopt IP_TRANSPARENT");
    /* ignore the error to retain Linux 2.2 compatibility */
    /* the error will be handled by bind(), anyway */
}
#endif /* IP_TRANSPARENT */

memcpy(&addr, &c->bind_addr.addr[0], sizeof addr);
if(ntohs(addr.in.sin_port)>=1024) { /* security check */
    if(!bind(c->fd, &addr.sa, addr_len(addr))) {
        s_log(LOG_INFO, "local_bind succeeded on the original port");
        return; /* success */
    }
    if(get_last_socket_error()!=EADDRINUSE
#ifndef USE_WIN32
            || !c->opt->option.transparent
#endif /* USE_WIN32 */
            ) {
        sockerror("local_bind (original port)");
        longjmp(c->err, 1);
    }
}

Ранее c-> bind_addr был установлен на адрес подключающегося однорангового узла с помощью этого кода:

    else if(c->opt->option.transparent)
    memcpy(&c->bind_addr, &c->peer_addr, sizeof(SOCKADDR_LIST));

Документация stunnel содержит этот совет для последних ядер Linux:

Удаленный режим (либо 2.2.x, либо> = 2.6 .28) требует, чтобы stunnel выполнялся от имени пользователя root. Параметр setuid также нарушит эту функциональность.

Linux> = 2.6.28 требует следующих настроек для iptables и маршрутизации (возможно, в /etc/rc.local или аналогичном файле):

iptables -t mangle -N DIVERT
iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
iptables -t mangle -A DIVERT -j MARK --set-mark 1
iptables -t mangle -A DIVERT -j ACCEPT
ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100
7
ответ дан 8 December 2019 в 17:19
поделиться

Если у вас есть контроль над процессами локального сервера, вы можете это сделать. Создайте постоянное соединение сокета домена UNIX между процессом прокси и серверным процессом, затем используйте sendmsg () в этом сокете домена UNIX, чтобы передать сообщение SCM_RIGHTS , содержащее файл сокета TCP дескриптор. Затем прокси-процесс может закрыть свой дескриптор TCP-сокета.

Когда серверный процесс получает дескриптор файла от прокси в сообщении SCM_RIGHTS , ему просто нужно добавить его в свой обычный набор клиентских сокетов, как если бы он пришел из accept () .

6
ответ дан 8 December 2019 в 17:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: