Skip to content

Commit c367618

Browse files
committed
net/haproxy: add support for HTTP/3 over QUIC, closes #4341
1 parent 512a24f commit c367618

File tree

4 files changed

+29
-8
lines changed

4 files changed

+29
-8
lines changed

net/haproxy/pkg-descr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Plugin Changelog
99
4.7
1010

1111
Added:
12+
* add support for HTTP/3 over QUIC to frontends (#4341)
1213
* add new rule: http-request silent-drop
1314
* add new condition: HTTP method
1415
* support custom HTTP status code in "http-request deny" rules

net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogFrontend.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<type>select_multiple</type>
2424
<style>tokenize</style>
2525
<allownew>true</allownew>
26-
<help><![CDATA[Configure listen addresses for this Public Service, i.e. 127.0.0.1:8080 or www.example.com:443 or unix@socket-name. Use TAB key to complete typing a listen address.]]></help>
26+
<help><![CDATA[Configure listen addresses for this Public Service, i.e. 127.0.0.1:8080 or www.example.com:443 or unix@socket-name. Add quic4@ or quic6@ to enable QUIC for IPv4/IPv6, e.g. [email protected]:443. Use TAB key to complete typing a listen address.]]></help>
2727
<hint>Enter address:port here. Finish with TAB.</hint>
2828
</field>
2929
<field>
@@ -203,7 +203,7 @@
203203
<style>tokenize</style>
204204
<allownew>true</allownew>
205205
<sortable>true</sortable>
206-
<help><![CDATA[When using the TLS ALPN extension, HAProxy advertises the specified protocol list as supported on top of ALPN. SSL offloading must be enabled.]]></help>
206+
<help><![CDATA[When using the TLS ALPN extension, HAProxy advertises the specified protocol list as supported on top of ALPN. SSL offloading must be enabled. Note that HTTP/3 will only be added to QUIC-compatible Listening Addresses.]]></help>
207207
</field>
208208
<field>
209209
<id>frontend.forwardFor</id>

net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/HAProxy.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,9 +515,9 @@
515515
<bind type="CSVListField">
516516
<Required>Y</Required>
517517
<Multiple>Y</Multiple>
518-
<Mask>/^((([0-9a-zA-Z._\-\*:\[\]]+:+[0-9]+(-[0-9]+)?|unix@[0-9a-z_\-]+)([,]){0,1}))*/u</Mask>
518+
<Mask>/^((([quic4@|quic6@]*[0-9a-zA-Z._\-\*:\[\]]+:+[0-9]+(-[0-9]+)?|unix@[0-9a-z_\-]+)([,]){0,1}))*/u</Mask>
519519
<ChangeCase>lower</ChangeCase>
520-
<ValidationMessage>Please provide a valid listen address, i.e. 127.0.0.1:8080, [::1]:8080, www.example.com:443 or unix@socket-name. Port range as start-end, i.e. 127.0.0.1:1220-1240.</ValidationMessage>
520+
<ValidationMessage>Please provide a valid listen address, i.e. 127.0.0.1:8080, [::1]:8080, www.example.com:443, [email protected] or unix@socket-name. Port range as start-end, i.e. 127.0.0.1:1220-1240.</ValidationMessage>
521521
</bind>
522522
<bindOptions type="TextField">
523523
<Required>N</Required>
@@ -853,6 +853,7 @@
853853
<Sorted>Y</Sorted>
854854
<Multiple>Y</Multiple>
855855
<OptionValues>
856+
<h3>HTTP/3</h3>
856857
<h2>HTTP/2</h2>
857858
<http11>HTTP/1.1</http11>
858859
<http10>HTTP/1.0</http10>

net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,8 @@ global
10131013
{% if helpers.exists('OPNsense.HAProxy.general.tuning.maxConnections') %}
10141014
maxconn {{OPNsense.HAProxy.general.tuning.maxConnections}}
10151015
{% endif %}
1016+
{# # TODO: remove this option when OpenSSL 3.5 is available on OPNsense #}
1017+
limited-quic
10161018
{# # check if OCSP is enabled #}
10171019
{% if OPNsense.HAProxy.general.tuning.ocspUpdateEnabled|default('') == '1' %}
10181020
{% if helpers.exists('OPNsense.HAProxy.general.tuning.ocspUpdateMinDelay') %}
@@ -1420,9 +1422,8 @@ frontend {{frontend.name}}
14201422
{% endif %}
14211423
{# # HTTP/2 with TLS enabled #}
14221424
{% if frontend.http2Enabled|default("") == '1' and frontend.advertised_protocols|default("") != "" %}
1423-
{# # convert protocols to HAProxy-compatible format #}
1424-
{% set alpn_options = frontend.advertised_protocols|replace('http10', 'http/1.0')|replace('http11', 'http/1.1') %}
1425-
{% do ssl_options.append('alpn ' ~ alpn_options) %}
1425+
{# # To ensure proper handling of each HTTP protocol, these #}
1426+
{# # entries will be processed when parsing individual bind lines. #}
14261427
{% else %}
14271428
{# # disable ALPN to enforce the GUI settings #}
14281429
{% do ssl_options.append('no-alpn') %}
@@ -1448,6 +1449,8 @@ frontend {{frontend.name}}
14481449
{# # bind/listen configuration #}
14491450
{% if frontend.bind|default("") != "" %}
14501451
{% for bind in frontend.bind.split(",") %}
1452+
{# # alpn advertisements are specific to each bind line #}
1453+
{% set alpn_options = [] %}
14511454
{# # check if this is a unix socket #}
14521455
{% set unix_bind = bind | regex_replace ("^unix@.*","TRUE") %}
14531456
{% if unix_bind == "TRUE" %}
@@ -1459,7 +1462,23 @@ frontend {{frontend.name}}
14591462
{% set bind_address = bind %}
14601463
{% set bind_name = bind %}
14611464
{% endif %}
1462-
bind {{bind_address}} name {{bind_name}} {% if frontend.bindOptions|default("") != "" %}{{ frontend.bindOptions }} {% endif %}{% if frontend.ssl_enabled == '1' and ssl_certs|default("") != "" %}ssl {{ ssl_options|join(' ') }} {{ ssl_certs|join(' ') }} {% endif %}{% if adv_options|length > 0 %} {{ adv_options|join(' ') }} {% endif %}
1465+
{# # handle incompatible alpn advertisements #}
1466+
{% if bind.startswith('quic4@') or bind.startswith('quic6@') %}
1467+
{# # strip incompatible advertisement for QUIC bind lines #}
1468+
{% set alpn_incompatible = ['h2', 'http11', 'http10'] %}
1469+
{% set alpn_filtered = frontend.advertised_protocols.split(',') | reject('in', alpn_incompatible) | join(',') %}
1470+
{% else %}
1471+
{# # strip incompatible advertisement for non-QUIC bind lines #}
1472+
{% set alpn_incompatible = ['h3'] %}
1473+
{% set alpn_filtered = frontend.advertised_protocols.split(',') | reject('in', alpn_incompatible) | join(',') %}
1474+
{% endif %}
1475+
{# # add alpn advertisements #}
1476+
{% if alpn_filtered|default("") != "" %}
1477+
{# # convert alpn protocols to HAProxy-compatible format #}
1478+
{% set alpn_conv = alpn_filtered|replace('http10', 'http/1.0')|replace('http11', 'http/1.1') %}
1479+
{% do alpn_options.append('alpn ' ~ alpn_conv) %}
1480+
{% endif %}
1481+
bind {{bind_address}} name {{bind_name}} {% if frontend.bindOptions|default("") != "" %}{{ frontend.bindOptions }} {% endif %}{% if frontend.ssl_enabled == '1' and ssl_certs|default("") != "" %}ssl {{ ssl_options|join(' ') }} {{ alpn_options|join(' ') }} {{ ssl_certs|join(' ') }} {% endif %}{% if adv_options|length > 0 %} {{ adv_options|join(' ') }} {% endif %}
14631482

14641483
{% endfor %}
14651484
{% endif %}

0 commit comments

Comments
 (0)