Hi,

I have a question regarding source port selection when using haproxy in tcp
mode.

We are using haproxy with the following scenario:

| public haproxy with tcpmode | -> | PNAT Fortigate FW | -> | internal Host
|

The Fortigate is reachable via two ISPs (ISP-A, ISP-B) and has port
forwards (NAT) to an internal host.
The haproxy backend configuration contains both public IPs assigned to the
Fortigate FW, enabling a distribution of the connections on both ISP
connections (haproxy config appended).

In this scenario we are getting "session clash" messages on the Fortigate
FW. A session clash message indicates, that the tuple of <source ip, source
port, dest ip, dest port> for tcp connection tracking (sessions in the
Fortigate world) is reused, before the previous session was closed.

>From the Fortigate knowledgebase, the tupel is calculated from
[HAPROXY-IP]:49660
and [INTERNAL-HOST-IP]:443
(Ports used from the example message appended, where 49660 is the haproxy
client ip port)

The message shows, that haproxy created a session / tcp connection using
the ISP-B-IP and then created a new connection using the ISP-A-IP using the
same client-ip-port as in the previous connection.

This leads to unexpected behaviour (e.g. packet drop) and I want to get rid
of these messages (and behaviour).

Therefore it might be necessary to understand how haproxy chooses the
client-ip-port when creating new tcp connections to backend servers.
Especially how haproxy behaves when a connection attempt fails and a retry
is triggered because this retry might change the backend server.
Will the retry use the same client port? If yes, is this intended?


Best regards,
Jack



Additional infos:
===================
- Connection / session creation rate is low at around 3/s with peaks of
25/s.
- connection duration is low
- peak total concurrent connections is around 600


haproxy.cfg:
==============
global
maxconn 10000
log stdout format raw daemon notice

defaults
log global
mode tcp
retries 2
timeout client 120s
timeout connect 4s
timeout server 120s
timeout check 5s
option tcpka
option tcplog
option logasap
balance leastconn


frontend tcp_443_frontend_with_proxy_protocol
mode tcp
bind *:443 accept-proxy
maxconn $MAX_CONN
default_backend tcp_443_backend


backend tcp_443_backend
mode tcp
fullconn $MAX_CONN
option tcp-check
default-server init-addr libc,last,none
server ip1_port1 [ISP-A-IP]:443 send-proxy maxconn $MAX_CONN check inter 1s
server ip2_port1 [ISP-B-IP]:443 send-proxy maxconn $MAX_CONN check inter 1s





Example message (the actual IP addresses have been replaced by
placeholders):
===============================================================================
New Status
[HAPROXY-IP]:49660->[ISP-A-IP]:443([INTERNAL-HOST-IP]:443) dir=0 act=1
hook=4
[HAPROXY-IP]:49660->[INTERNAL-HOST-IP]:443([INTERNAL-FW-IP]:22686) dir=1
act=2 hook=0
[INTERNAL-HOST-IP]:443->[INTERNAL-FW-IP]:22686([HAPROXY-IP]:49660) dir=1
act=1 hook=4
[INTERNAL-HOST-IP]:443->[HAPROXY-IP]:49660([ISP-A-IP]:443)

Old Status
[HAPROXY-IP]:49660->[ISP-B-IP]:443([INTERNAL-HOST-IP]:443) dir=0 act=1
hook=4
[HAPROXY-IP]:49660->[INTERNAL-HOST-IP]:443([INTERNAL-FW-IP]:49660) dir=1
act=2 hook=0
[INTERNAL-HOST-IP]:443->[INTERNAL-FW-IP]:49660([HAPROXY-IP]:49660) dir=1
act=1 hook=4
[INTERNAL-HOST-IP]:443->[HAPROXY-IP]:49660([ISP-B-IP]:443)

Reply via email to