@@ -208,120 +208,13 @@ func (b *HaproxyConfMgrImpl) newFrontend(vListenerName string, vListener *tree.V
208208 var aclList []* models.ACL
209209 switch {
210210 case vListener .ProtocolCategory == protocols .ProtocolCategoryTLS :
211- // TLS Passthrough
212- tcpRules = []* models.TCPRequestRule {
213- { // tcp-request content reject if !{ req.ssl_hello_type 1 }
214- Type : "content" ,
215- Action : "reject" ,
216- Cond : "if" ,
217- CondTest : "!{ req.ssl_hello_type 1 }" ,
218- },
219- {
220- // tcp-request inspect-delay 50000
221- Type : "inspect-delay" ,
222- Timeout : new (int64 (50000 )),
223- },
224- {
225- // tcp-request content set-var(sess.sni) req.ssl_sni
226- Type : "content" ,
227- Action : "set-var" ,
228- VarName : "sni" ,
229- VarScope : "sess" ,
230- Expr : "req.ssl_sni" ,
231- },
232- {
233- // tcp-request content set-var(sess.snireversed) var(sess.sni),lua.reverse_host
234- Type : "content" ,
235- Action : "set-var" ,
236- VarName : "snireversed" ,
237- VarScope : "sess" ,
238- Expr : "var(sess.sni),lua.reverse_host" ,
239- },
240- // -------------------
241- // Look for listener name: selected_listener_name
242- {
243- // tcp-request content set-var(sess.selected_listener_name) var(sess.sni),map(listener_exact_match)
244- Type : "content" ,
245- Action : "set-var" ,
246- VarName : "selected_listener_name" ,
247- VarScope : "sess" ,
248- Expr : "var(sess.sni),map(" + listenerExactMatchMap .Path .FullPath () + ")" ,
249- Metadata : map [string ]any {"hug" : "listener exact match selection" },
250- },
251- {
252- // tcp-request content set-var(sess.selected_listener_name,ifnotexists) var(sess.snireversed),map_beg(listener_wildcard_match)
253- Type : "content" ,
254- Action : "set-var" ,
255- VarName : "selected_listener_name,ifnotexists" ,
256- VarScope : "sess" ,
257- Expr : "var(sess.snireversed),map_beg(" + listenerWildcardMatchMap .Path .FullPath () + ")" ,
258- Metadata : map [string ]any {"hug" : "listener wildcard match selection" },
259- },
260- // -------------------
261- // Look for route name: selected_listener_route
262- {
263- // tcp-request content set-var(txn.TMP) var(txn.selected_listener_name),concat("/",sess.sni)
264- Type : "content" ,
265- Action : "set-var" ,
266- VarName : "TMP" ,
267- VarScope : "sess" ,
268- Expr : "var(sess.selected_listener_name),concat(\" /\" ,sess.sni)" ,
269- },
270- {
271- Type : "content" ,
272- Action : "set-var" ,
273- VarName : "selected_listener_route" ,
274- VarScope : "sess" ,
275- Expr : "var(sess.TMP),map(" + listenerRouteExactMatchMap .Path .FullPath () + ")" ,
276- Metadata : map [string ]any {"hug" : "listener-route exact match selection" },
277- },
278- {
279- // tcp-request content set-var(txn.TMP) var(txn.selected_listener_name),concat("/",txn.snireversed)
280- Type : "content" ,
281- Action : "set-var" ,
282- VarName : "TMP" ,
283- VarScope : "sess" ,
284- Expr : "var(sess.selected_listener_name),concat(\" /\" ,sess.snireversed)" ,
285- },
286- {
287- Type : "content" ,
288- Action : "set-var" ,
289- VarName : "selected_listener_route,ifnotexists" ,
290- VarScope : "sess" ,
291- Expr : "var(sess.TMP),map_beg(" + listenerRouteWildcardMatchMap .Path .FullPath () + ")" ,
292- Metadata : map [string ]any {"hug" : "listener-route wildcard match selection" },
293- },
294- // -------------------
295- // Look for backend: sni_match
296- {
297- // tcp-request content set-var(txn.sni_match) var(txn.selected_listener_route),map(sni.map)
298- Type : "content" ,
299- Action : "set-var" ,
300- VarName : "sni_match" ,
301- VarScope : "sess" ,
302- Expr : "var(sess.selected_listener_route),map(" + sniMap .Path .FullPath () + ")" ,
303- },
304- }
305- backendSwitchingRules = []* models.BackendSwitchingRule {
306- {
307- Name : "%[var(txn.backend)]" ,
308- Cond : "if" ,
309- CondTest : "route_is_json" ,
310- },
311- {
312- Name : "%[var(sess.sni_match),field(1,.)]" ,
313- },
314- }
315- aclList = []* models.ACL {
316- { // acl route_is_json var(txn.sni_match),bytes(0,1) -m str
317- ACLName : "route_is_json" ,
318- Criterion : "var(txn.sni_match),bytes(0,1)" ,
319- Value : "-m str {" ,
320- Metadata : map [string ]any {
321- "hug" : "for lua routing" ,
322- },
323- },
324- }
211+ tcpRules , backendSwitchingRules , aclList = tlsPassthroughRules (
212+ listenerExactMatchMap .Path .FullPath (),
213+ listenerWildcardMatchMap .Path .FullPath (),
214+ listenerRouteExactMatchMap .Path .FullPath (),
215+ listenerRouteWildcardMatchMap .Path .FullPath (),
216+ sniMap .Path .FullPath (),
217+ )
325218
326219 default :
327220 httpRules = []* models.HTTPRequestRule {
@@ -598,3 +491,123 @@ func (b *HaproxyConfMgrImpl) bindParams(_, bindName string, vListenerName string
598491 }
599492 return params
600493}
494+
495+ // tlsPassthroughRules returns the TCP request rules, backend-switching rules
496+ // and ACLs used by the TLS-passthrough frontend. All variables referenced in
497+ // this rule set live in the sess scope — keep it that way: the route_is_json
498+ // ACL reads var(sess.sni_match), matching the scope in which sni_match is
499+ // written. Mixing sess and txn leaves the ACL branch permanently dead.
500+ func tlsPassthroughRules (
501+ listenerExactMatch , listenerWildcardMatch ,
502+ listenerRouteExactMatch , listenerRouteWildcardMatch ,
503+ sniMapPath string ,
504+ ) ([]* models.TCPRequestRule , []* models.BackendSwitchingRule , []* models.ACL ) {
505+ tcpRules := []* models.TCPRequestRule {
506+ { // tcp-request content reject if !{ req.ssl_hello_type 1 }
507+ Type : "content" ,
508+ Action : "reject" ,
509+ Cond : "if" ,
510+ CondTest : "!{ req.ssl_hello_type 1 }" ,
511+ },
512+ {
513+ // tcp-request inspect-delay 50000
514+ Type : "inspect-delay" ,
515+ Timeout : new (int64 (50000 )),
516+ },
517+ {
518+ // tcp-request content set-var(sess.sni) req.ssl_sni
519+ Type : "content" ,
520+ Action : "set-var" ,
521+ VarName : "sni" ,
522+ VarScope : "sess" ,
523+ Expr : "req.ssl_sni" ,
524+ },
525+ {
526+ // tcp-request content set-var(sess.snireversed) var(sess.sni),lua.reverse_host
527+ Type : "content" ,
528+ Action : "set-var" ,
529+ VarName : "snireversed" ,
530+ VarScope : "sess" ,
531+ Expr : "var(sess.sni),lua.reverse_host" ,
532+ },
533+ {
534+ // tcp-request content set-var(sess.selected_listener_name) var(sess.sni),map(listener_exact_match)
535+ Type : "content" ,
536+ Action : "set-var" ,
537+ VarName : "selected_listener_name" ,
538+ VarScope : "sess" ,
539+ Expr : "var(sess.sni),map(" + listenerExactMatch + ")" ,
540+ Metadata : map [string ]any {"hug" : "listener exact match selection" },
541+ },
542+ {
543+ // tcp-request content set-var(sess.selected_listener_name,ifnotexists) var(sess.snireversed),map_beg(listener_wildcard_match)
544+ Type : "content" ,
545+ Action : "set-var" ,
546+ VarName : "selected_listener_name,ifnotexists" ,
547+ VarScope : "sess" ,
548+ Expr : "var(sess.snireversed),map_beg(" + listenerWildcardMatch + ")" ,
549+ Metadata : map [string ]any {"hug" : "listener wildcard match selection" },
550+ },
551+ {
552+ // tcp-request content set-var(sess.TMP) var(sess.selected_listener_name),concat("/",sess.sni)
553+ Type : "content" ,
554+ Action : "set-var" ,
555+ VarName : "TMP" ,
556+ VarScope : "sess" ,
557+ Expr : "var(sess.selected_listener_name),concat(\" /\" ,sess.sni)" ,
558+ },
559+ {
560+ Type : "content" ,
561+ Action : "set-var" ,
562+ VarName : "selected_listener_route" ,
563+ VarScope : "sess" ,
564+ Expr : "var(sess.TMP),map(" + listenerRouteExactMatch + ")" ,
565+ Metadata : map [string ]any {"hug" : "listener-route exact match selection" },
566+ },
567+ {
568+ // tcp-request content set-var(sess.TMP) var(sess.selected_listener_name),concat("/",sess.snireversed)
569+ Type : "content" ,
570+ Action : "set-var" ,
571+ VarName : "TMP" ,
572+ VarScope : "sess" ,
573+ Expr : "var(sess.selected_listener_name),concat(\" /\" ,sess.snireversed)" ,
574+ },
575+ {
576+ Type : "content" ,
577+ Action : "set-var" ,
578+ VarName : "selected_listener_route,ifnotexists" ,
579+ VarScope : "sess" ,
580+ Expr : "var(sess.TMP),map_beg(" + listenerRouteWildcardMatch + ")" ,
581+ Metadata : map [string ]any {"hug" : "listener-route wildcard match selection" },
582+ },
583+ {
584+ // tcp-request content set-var(sess.sni_match) var(sess.selected_listener_route),map(sni.map)
585+ Type : "content" ,
586+ Action : "set-var" ,
587+ VarName : "sni_match" ,
588+ VarScope : "sess" ,
589+ Expr : "var(sess.selected_listener_route),map(" + sniMapPath + ")" ,
590+ },
591+ }
592+ backendSwitchingRules := []* models.BackendSwitchingRule {
593+ {
594+ Name : "%[var(txn.backend)]" ,
595+ Cond : "if" ,
596+ CondTest : "route_is_json" ,
597+ },
598+ {
599+ Name : "%[var(sess.sni_match),field(1,.)]" ,
600+ },
601+ }
602+ aclList := []* models.ACL {
603+ { // acl route_is_json var(sess.sni_match),bytes(0,1) -m str {
604+ ACLName : "route_is_json" ,
605+ Criterion : "var(sess.sni_match),bytes(0,1)" ,
606+ Value : "-m str {" ,
607+ Metadata : map [string ]any {
608+ "hug" : "for lua routing" ,
609+ },
610+ },
611+ }
612+ return tcpRules , backendSwitchingRules , aclList
613+ }
0 commit comments