Forum Discussion
henrik_k
Sep 03, 2024Altostratus
TCP::collect and large TLS v1.3 client hello packets
Is anyone using iRules successfully to parse SNI names from the new TLS 1.3 hybridized Kyber client hello packets? The problem is the these packets are larger than MTU(?) size, around ~1800 bytes. No...
- Sep 04, 2024
Here is working cleaned up example code for everyone. TLS parsing itself is based on some old forum code which I cleaned up, all credits there.
when CLIENT_ACCEPTED { set collect_count 0 set tls_servername "" TCP::collect } when CLIENT_DATA { # Collect max 2 extra packets if { $collect_count > 2 } { reject; event disable all; return } # Parse first packet? if { not $collect_count } { if { [binary scan [TCP::payload] cSSc tls_xacttype tls_version tls_recordlen tls_action] != 4 } { reject; event disable all; return } # Only allow TLSv1.2 = 771, TLSv1.3 = 769 if { $tls_xacttype ne "22" or ($tls_version ne "769" and $tls_version ne "771") or $tls_action ne "1" } { reject; event disable all; return } set record_offset 43 if { not [binary scan [TCP::payload] @${record_offset}c tls_sessidlen] } { reject; event disable all; return } incr record_offset [expr {1 + $tls_sessidlen}] if { not [binary scan [TCP::payload] @${record_offset}S tls_ciphlen] } { reject; event disable all; return } incr record_offset [expr {2 + $tls_ciphlen}] if { not [binary scan [TCP::payload] @${record_offset}c tls_complen] } { reject; event disable all; return } incr record_offset [expr {1 + $tls_complen}] if { not [binary scan [TCP::payload] @${record_offset}S tls_extenlen] } { reject; event disable all; return } incr record_offset 2 } # Collect more if TLS extensions data not fully received if { $tls_extenlen > [TCP::payload length] - $record_offset } { incr collect_count return } if { not [binary scan [TCP::payload] @${record_offset}a* tls_extensions] } { reject; event disable all; return } for { set x 0 } { $x < $tls_extenlen } { incr x 4 } { if { [binary scan $tls_extensions @${x}SS etype elen] != 2 } { reject; event disable all; return } if { $etype == "00" } { if { [binary scan $tls_extensions @[expr {$x + 9}]A[expr {$elen - 5}] tls_servername] } { break } } incr x $elen } # Choose pool, unknown will be rejected switch -- [string tolower $tls_servername] { "host1.example.com" { pool host1.example.com } "host2.example.com" { pool host2.example.com } default { reject; event disable all; return } } TCP::release }
henrik_k
Sep 04, 2024Altostratus
Here is working cleaned up example code for everyone. TLS parsing itself is based on some old forum code which I cleaned up, all credits there.
when CLIENT_ACCEPTED {
set collect_count 0
set tls_servername ""
TCP::collect
}
when CLIENT_DATA {
# Collect max 2 extra packets
if { $collect_count > 2 } {
reject; event disable all; return
}
# Parse first packet?
if { not $collect_count } {
if { [binary scan [TCP::payload] cSSc tls_xacttype tls_version tls_recordlen tls_action] != 4 } {
reject; event disable all; return
}
# Only allow TLSv1.2 = 771, TLSv1.3 = 769
if { $tls_xacttype ne "22" or ($tls_version ne "769" and $tls_version ne "771") or $tls_action ne "1" } {
reject; event disable all; return
}
set record_offset 43
if { not [binary scan [TCP::payload] @${record_offset}c tls_sessidlen] } {
reject; event disable all; return
}
incr record_offset [expr {1 + $tls_sessidlen}]
if { not [binary scan [TCP::payload] @${record_offset}S tls_ciphlen] } {
reject; event disable all; return
}
incr record_offset [expr {2 + $tls_ciphlen}]
if { not [binary scan [TCP::payload] @${record_offset}c tls_complen] } {
reject; event disable all; return
}
incr record_offset [expr {1 + $tls_complen}]
if { not [binary scan [TCP::payload] @${record_offset}S tls_extenlen] } {
reject; event disable all; return
}
incr record_offset 2
}
# Collect more if TLS extensions data not fully received
if { $tls_extenlen > [TCP::payload length] - $record_offset } {
incr collect_count
return
}
if { not [binary scan [TCP::payload] @${record_offset}a* tls_extensions] } {
reject; event disable all; return
}
for { set x 0 } { $x < $tls_extenlen } { incr x 4 } {
if { [binary scan $tls_extensions @${x}SS etype elen] != 2 } {
reject; event disable all; return
}
if { $etype == "00" } {
if { [binary scan $tls_extensions @[expr {$x + 9}]A[expr {$elen - 5}] tls_servername] } {
break
}
}
incr x $elen
}
# Choose pool, unknown will be rejected
switch -- [string tolower $tls_servername] {
"host1.example.com" { pool host1.example.com }
"host2.example.com" { pool host2.example.com }
default { reject; event disable all; return }
}
TCP::release
}
Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects