Hello, We encounter a nasty bug when htx is enabled. Under certain conditions, the incoming client data can overwrite part of the buffer with data prepared for backend servers. I was able to reproduce the issue by using the attached script ('request.py') to generate http requests. I did a wireshark capture of the traffic originating from haproxy toward the backend server. In random cases, I observe a corrupted x-forwarded-for header in the requests sent to the backend server.
For example : ================================== POST / HTTP/1.1 content-length: 14700 accept-encoding: gzip, deflate accept: */* user-agent: python-requests/2.6.0 CPython/2.7.5 Linux host: a.exemple.com 222222222233333: 3333333344444 abcdefgh<.... the rest of the request body....> ================================== I wasn't able to reproduce the issue by doing requests to a haproxy located on localhost. I believe there are timing requirements to reproduce it: - Haproxy should start processing part of the HTTP request before receiving the rest of the body. - Moreover, the rest of the request body should arrive after this partial processing (but before sending the first request to backend servers). Having some network latency between the client and haproxy helps reproduce the issue. In my case: ~7ms. The issue only occurs for requests with content-length>1448. Moreover, If content-length == 1450, only the first 2 byte of the x-forwarded-for header name will be corrupted with the last 2 bytes of the request. I was able to reproduce the issue with all haproxy 1.9.* release versions, and a fairly minimal haproxy.cfg (see attached). The bug still persists with a freshly compiled git version (head commit: 0b4b27efde653a4b7bbafb56df3796bffa4722ae). Please tell me if you need more details. Sincerely, Radu
#!/usr/bin/env python import requests import time import string data = b'' for i in range(1,50): for j in list(string.ascii_letters) + [str(x) for x in range(0,10)]: data+=bytes(j*i, encoding='ascii') data = data[:14700] print(data) for i in range(0, 200): try: requests.post("http://10.236.100.19", data=data, headers={'host': 'a.exemple.com'}) except Exception as e: print(e) print(i)
global user haproxy group haproxy nbproc 1 nbthread 1 defaults mode http option forwardfor option http-use-htx frontend fe_main bind *:80 name http use_backend be_main backend be_main server srv0 10.236.72.23:31044 weight 10