Моя текущая реализация выглядит следующим образом:
- Впереди AWS Load Balancer (тип Network TCP/UDP) с двойным стеком, который перенаправляет на группу инстансов EC2.
- Эти экземпляры EC2 используют HaProxy для получения запросов к списку процессов.
- Список процессов — это экземпляры aiosmtpd (из Python).
Поскольку цель состоит в том, чтобы подключиться через SMTP, мне нужно знать IP-адрес клиента, но мне также нужно сначала отправить ответ.
Я заметил, что если
- Я связываю переднюю часть без
принять-прокси
- но перенаправить поддерживаемый сервер, отправив
отправить-прокси
- И отключите Proxy v2 в AWS Load Balancer.
он отлично работает... только для IPv4 (??)!
IPv6 не работает, и вместо этого прокси возвращает мне IP-адрес балансировщика нагрузки AWS.
Итак, я попытался включить Proxy v2 на уровне AWS, установив принять-прокси
на интерфейсе связывать
и отправить-прокси
на сервер
бэкэнд-свойство.
На этот раз он работает как для IPv4/v6, НО он никогда не отправляет начальный ответ: никакие соединения с кодом Python не устанавливаются, пока первая строка не будет отправлена от клиента!
В протоколе SMTP это невозможно: как сервер, я должен быть первым, кто отправит ответ.
Что случилось?
Вот моя конфигурация HaProxy:
Глобальный
журнал /dev/лог локальный0
журнал /dev/log local1 уведомление
chroot /var/lib/haproxy
пользовательский прокси
группа haproxy
демон
максконн 60000
# Шифры по умолчанию для использования в прослушивающих сокетах с поддержкой SSL.
# Для получения дополнительной информации см. ciphers(1SSL). Этот список взят из:
# https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
# Альтернативный список с дополнительными директивами можно получить из
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
ssl-default-bind-ciphers -CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256: TLS_AES_256_GCM_SHA384: TLS_CHACHA20_POLY1305_SHA256
ssl-default-bind-options предпочитаете-клиентские шифры no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
ssl-default-server-ciphers -CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256: TLS_AES_256_GCM_SHA384: TLS_CHACHA20_POLY1305_SHA256
ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
значения по умолчанию
тайм-аут соединения 5s
тайм-аут клиента 30 сек.
тайм-аут сервера 30 секунд
режим TCP
smtp-интерфейс
привязать :25 принять-прокси
привязать :::25 принять-прокси
default_backend smtp_backend
серверная часть smtp_backend
режим TCP
таймаут сервера 1м
тайм-аут соединения 5s
сервер srv1 127.0.0.1:2525 отправка-прокси maxconn 500
Я пытался добавить/удалить один или оба или ни один из принять-прокси
и отправить-прокси
и даже отправить-прокси-v2
. Без всякого везения!
Ближе всего к тому, чтобы это работало, я был без Proxy v2, включенного на стороне AWS, нет. принять-прокси
на фронтенд части и отправить-прокси
на клиенте, но не работает для IPv6.
Я создал базовый скрипт для описания проблемы:
# -*- конфиг:utf-8 -*-
импортировать сокет, argparse
класс TestingServer (объект):
def __init__(я, хост, порт):
self.sock = сокет.сокет (сокет.AF_INET6)
self.sock.setsockopt(сокет.SOL_SOCKET, сокет.SO_REUSEADDR, True)
self.sock.setsockopt(сокет.IPPROTO_IPV6, сокет.IPV6_V6ONLY, False)
self.sock.bind((хост, порт))
print('Настройка слушателя на {}:{}'.format(хост, порт))
деф слушай(я):
print('Ожидание соединений...')
self.sock.listen()
пока верно:
пытаться:
клиент, адрес = self.sock.accept()
print('Соединение есть!', адрес)
client.send(b'250 Отправка исходных данных.\r\n')
данные = клиент.recv(1024)
print('Полученные данные:', данные)
client.send(b'250 Gotcha')
данные = клиент.recv(1024)
print('Полученные данные 2:', данные)
client.send(b'250 Second Gotcha')
клиент.закрыть()
кроме Исключения как e:
print('Есть исключение!', e)
проходят
Ну наконец то:
пытаться:
клиент.закрыть()
кроме исключения:
проходят
если __name__ == '__main__':
parser = argparse.ArgumentParser(description='Запустить демон SMTPD.')
parser.add_argument('--host', nargs='?', default='localhost', type=str)
parser.add_argument('--port', nargs='?', по умолчанию=2552, тип=int)
аргументы = парсер.parse_args()
TestingServer(args.host, args.port).listen()
При включении AWS Proxy v2 с принять-прокси
за связывать
и отправить-прокси
за сервер
, вот что происходит:
Запускаю сервер:
$> python testserver.py --port 2525 --host ::
Настройка слушателя на :::2525
Ожидание подключения...
На моей локальной машине я делаю:
$> telnet {aws-loadbalancer-name}.elb.eu-west-3.amazonaws.com 25
Попытка {ipv6}...
Подключено к {aws-loadbalancer-name}.elb.eu-west-3.amazonaws.com.
Экранирующий символ '^]'.
На сервере пока ничего.
На стороне клиента (телнет) пишу что угодно:
$> а [введите]
Затем, как только я нажимаю Enter, сервер показывает следующее:
Адрес: ('::ffff:127.0.0.1', 42494, 0, 0)
Есть связь! <socket.socket fd=4, family=AddressFamily.AF_INET6, type=SocketKind.SOCK_STREAM, proto=0, laddr=('::ffff:127.0.0.1', 2525, 0, 0), raddr=(':: ffff:127.0.0.1', 42494, 0, 0)> ('::ffff:127.0.0.1', 42494, 0, 0)
Полученные данные: b'PROXY TCP6 {clients_ip} {loadbalancer_ip} 44012 25\r\ns\r\n'
Итак, ясно, что по какой-то причине HaProxy не отправляет соединение с процессом Python, как только оно будет создано, а ожидает поступления первых данных.
Как я могу этого избежать?
Заранее спасибо!