Fix parent negotiation after sending PROXY protocol header
Some checks are pending
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Waiting to run

After 'parent ha' sends the PROXY v1 header, continue negotiating the
real parent protocol (SOCKS5/CONNECT/etc.) instead of returning early.
'ha' used alone still sends the header and relays plain TCP.
This commit is contained in:
Nirmal Khanal 2026-07-23 10:55:07 +03:00 committed by Vladimir Dubrovin
parent 305f9932ac
commit 01f85cf755
5 changed files with 37 additions and 18 deletions

View File

@ -1472,16 +1472,19 @@ socks -H -p1080
<p> <p>
<b>Sending PROXY protocol header to parent proxy:</b> <b>Sending PROXY protocol header to parent proxy:</b>
<br>Use the <code>ha</code> parent type to send a PROXY protocol v1 header to <br>Use the <code>ha</code> parent type to send a PROXY protocol v1 header to
the parent proxy. This must be the last parent in the chain: the parent proxy. Place <code>ha</code> before the parent that should receive
the header; after the header is sent, parent protocol negotiation continues:
</p><pre> </p><pre>
allow * allow *
parent 1000 ha parent 1000 ha 0.0.0.0 0
parent 1000 socks5 parent.example.com 1080 parent 1000 socks5 parent.example.com 1080
socks proxy
</pre> </pre>
<p> <p>
This configuration sends the client IP information to the SOCKS5 parent proxy This configuration connects to the SOCKS5 parent, sends the PROXY protocol
via the PROXY protocol. header with the original client IP, then performs SOCKS5 negotiation before
relaying the client payload. The parent should use <code>-H</code> to accept
the header (for example <code>socks -H</code>).
</p> </p>
<li><a name="MAXSEG"><i>How to set TCP maximum segment size (MSS)</i></a> <li><a name="MAXSEG"><i>How to set TCP maximum segment size (MSS)</i></a>
<p> <p>

View File

@ -1531,16 +1531,20 @@ socks -H -p1080
<p> <p>
<b>Отправка заголовка PROXY протокола родительскому прокси:</b> <b>Отправка заголовка PROXY протокола родительскому прокси:</b>
<br>Используйте тип родительского прокси <code>ha</code> для отправки заголовка <br>Используйте тип родительского прокси <code>ha</code> для отправки заголовка
PROXY протокола v1 родительскому прокси. Это должен быть последний родитель в цепочке: PROXY протокола v1 родительскому прокси. Укажите <code>ha</code> перед родителем,
который должен получить заголовок; после отправки заголовка продолжается
хендшейк протокола родителя:
</p><pre> </p><pre>
allow * allow *
parent 1000 ha parent 1000 ha 0.0.0.0 0
parent 1000 socks5 parent.example.com 1080 parent 1000 socks5 parent.example.com 1080
socks proxy
</pre> </pre>
<p> <p>
Эта конфигурация отправляет информацию об IP-адресе клиента SOCKS5 родительскому Эта конфигурация подключается к SOCKS5 родителю, отправляет PROXY заголовок
прокси через PROXY протокол. с исходным IP клиента, затем выполняет SOCKS5-хендшейк и только после этого
передаёт полезную нагрузку. Родитель должен использовать <code>-H</code>
(например <code>socks -H</code>).
</p> </p>
<li><a name="MAXSEG"><i>Как установить максимальный размер сегмента TCP (MSS)</i></a> <li><a name="MAXSEG"><i>Как установить максимальный размер сегмента TCP (MSS)</i></a>
<p> <p>

View File

@ -759,10 +759,15 @@ useful). Never use this option unless you know exactly you
need it. <b><br> need it. <b><br>
admin</b> redirect request to local &acute;admin&acute; admin</b> redirect request to local &acute;admin&acute;
service (with -s parameter). <b><br> service (with -s parameter). <b><br>
ha</b> send HAProxy PROXY protocol v1 header to parent ha</b> send HAProxy PROXY protocol v1 header to the next
proxy. Must be the last in the proxy chain. Useful for parent proxy (or to the destination if <b>ha</b> is used
passing client IP information to the parent proxy. Example: alone). Place <b>ha</b> before the parent that should
parent 1000 ha <br> receive the header; after the header is sent, negotiation
of that parent protocol continues (SOCKS, CONNECT, etc.).
Useful for passing client IP information to the parent
proxy. Example: <br>
parent 1000 ha 0.0.0.0 0 <br>
parent 1000 socks5 parent.example.com 1080 <br>
Use &quot;+&quot; proxy only with <b>fakeresolve</b> option Use &quot;+&quot; proxy only with <b>fakeresolve</b> option
<br> <br>
Any parent type above can be suffixed with <b>s</b> (e.g. Any parent type above can be suffixed with <b>s</b> (e.g.

View File

@ -828,9 +828,16 @@ unless you know exactly you need it.
.br .br
\fBadmin\fR redirect request to local \'admin\' service (with -s parameter). \fBadmin\fR redirect request to local \'admin\' service (with -s parameter).
.br .br
\fBha\fR send HAProxy PROXY protocol v1 header to parent proxy. Must be the last \fBha\fR send HAProxy PROXY protocol v1 header to the next parent proxy (or to
in the proxy chain. Useful for passing client IP information to the parent proxy. the destination if \fBha\fR is used alone). Place \fBha\fR before the parent
Example: parent 1000 ha that should receive the header; after the header is sent, negotiation of that
parent protocol continues (SOCKS, CONNECT, etc.). Useful for passing client IP
information to the parent proxy.
Example:
.br
parent 1000 ha 0.0.0.0 0
.br
parent 1000 socks5 parent.example.com 1080
.br .br
Use "+" proxy only with \fBfakeresolve\fR option Use "+" proxy only with \fBfakeresolve\fR option
.br .br

View File

@ -375,7 +375,7 @@ int handleredirect(struct clientparam * param, struct ace * acentry){
ntohs(*SAPORT(&param->sincl)) ntohs(*SAPORT(&param->sincl))
); );
if(socksend(param, param->remsock, (unsigned char *)buf, len, conf.timeouts[CHAIN_TO])!=len) return 39; if(socksend(param, param->remsock, (unsigned char *)buf, len, conf.timeouts[CHAIN_TO])!=len) return 39;
return 0; if(cur->type == R_HA) return 0;
} }
} }
else { else {