Implementarea mea actuală este următoarea:
- În față, un AWS Load Balancer (tip Network TCP/UDP) pe dual-stack, care redirecționează către o flotă de instanțe EC2
- Aceste instanțe EC2 rulează HaProxy pentru a primi solicitările către o listă de procese
- Lista proceselor sunt instanțe aiosmtpd (din Python).
Deoarece scopul este să mă conectez prin SMTP, trebuie să cunosc IP-ul Clientului, dar trebuie să trimit mai întâi răspunsul.
Ceea ce am observat este că dacă
- Leagă front-end-ul fără
accept-proxy
- dar redirecționează serverul susținut prin trimitere
trimite-proxy
- Și dezactivați Proxy v2 pe AWS Load Balancer
funcționează perfect... numai pentru IPv4 (??) !
IPv6 nu funcționează, iar proxy-ul îmi returnează IP-ul AWS Load balancer.
Așa că am încercat să activez Proxy v2 la nivel AWS, setare accept-proxy
pe front-end lega
și trimite-proxy
pe Server
proprietate backend.
De data aceasta, funcționează atât pentru IPv4/v6, DAR, nu trimite niciodată răspunsul inițial: Nu se fac conexiuni la codul python până când prima linie este trimisă de la client!
În protocolul SMTP, acest lucru nu este posibil: ca server, trebuie să fiu primul care trimite un răspuns.
Ce se întâmplă?
Iată configurația mea HaProxy:
global
log /dev/log local0
log /dev/log local1 notificare
chroot /var/lib/haproxy
utilizator haproxy
haproxy de grup
demonul
maxconn 60000
# Cifruri implicite de utilizat pe prizele de ascultare activate pentru SSL.
# Pentru mai multe informații, consultați ciphers(1SSL). Aceasta lista este de la:
# https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
# O listă alternativă cu directive suplimentare poate fi obținută de la
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AESCMDHE-RSA-AES256-ECDSA-ECDSA: -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 prefer-client-ciphers no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AESCMDHE-RSA-AES256-ECDSA-ECDSA: -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
implicite
timeout conectare 5s
timeout client 30s
timeout server 30s
modul tcp
frontend smtp
bind :25 accept-proxy
bind :::25 accept-proxy
default_backend smtp_backend
backend smtp_backend
modul tcp
server timeout 1m
timeout conectare 5s
server srv1 127.0.0.1:2525 trimite-proxy maxconn 500
Am încercat să adaug/eliminăm unul sau ambele sau niciunul accept-proxy
și trimite-proxy
și chiar trimite-proxy-v2
. Fara noroc!
Cel mai aproape am fost să funcționeze este fără Proxy v2 activat la sfârșitul AWS, nu accept-proxy
pe partea frontală și trimite-proxy
pe client, dar nu funcționează pentru IPv6.
Am creat un script de bază pentru a descrie problema:
# -*- config:utf-8 -*-
import socket, argparse
clasa TestingServer(obiect):
def __init__(self, host, port):
self.sock = socket.socket(socket.AF_INET6)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
self.sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
self.sock.bind((gazdă, port))
print('Se configurează ascultatorul pe {}:{}'.format(gazdă, port))
def ascult (auto):
print('Se așteaptă conexiunile...')
self.sock.listen()
în timp ce este adevărat:
încerca:
client, adresa = self.sock.accept()
print('Am o conexiune!', adresa)
client.send(b'250 Se trimite date inițiale.\r\n')
date = client.recv(1024)
print('Date primite:', date)
client.send(b'250 Gotcha')
date = client.recv(1024)
print('Date primite 2:', date)
client.send(b'250 Second gotcha')
client.close()
cu excepția excepției ca e:
print („Am o excepție!”, e)
trece
in cele din urma:
încerca:
client.close()
cu excepția excepției:
trece
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Porniți un daemon SMTPD.')
parser.add_argument('--host', nargs='?', default='localhost', type=str)
parser.add_argument('--port', nargs='?', default=2552, type=int)
args = parser.parse_args()
TestingServer(args.host, args.port).listen()
Când setați AWS Proxy v2 activat, cu accept-proxy
pentru lega
și trimite-proxy
pentru Server
, iată ce se întâmplă:
pornesc serverul:
$> python testserver.py --port 2525 --host ::
Configurarea ascultătorului pe :::2525
În așteptarea conexiunilor...
Pe mașina mea locală, fac:
$> telnet {aws-loadbalancer-name}.elb.eu-west-3.amazonaws.com 25
Se încearcă {ipv6}...
Conectat la {aws-loadbalancer-name}.elb.eu-west-3.amazonaws.com.
Caracterul de evacuare este „^]”.
Nimic încă pe server.
La capătul clientului (telnet), scriu orice:
$> a [intra]
Apoi, de îndată ce apăs pe Enter, serverul arată următoarele:
Adresa este: ('::ffff:127.0.0.1', 42494, 0, 0)
Am o conexiune! <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)
Date primite: b'PROXY TCP6 {clients_ip} {loadbalancer_ip} 44012 25\r\ns\r\n'
Deci, în mod clar, din anumite motive, HaProxy nu trimite conexiunea la procesul Python de îndată ce este creată una, dar așteaptă să vină primele date.
Cum pot evita asta?
Multumesc anticipat!