Forum Discussion
TCP::collect and large TLS v1.3 client hello packets
- 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 }
Hi, I've already tried to call TCP::collect second time inside CLIENT_DATA with or without length argument, nothing ever happens. CLIENT_DATA is never called again and TCP::payload never changes. Can you provide simple protocode which you think should achieve reading both L2 packets? I believe I've already tried all variations I can think of.
Oh dear this was an user error. I didn't see I had some leftover other priority CLIENT_DATA code that died, this is why it never got called again...
I now managed to get it to collect more data when needed, I'll post a cleaned up code in a moment for others if interested.
Recent Discussions
Related Content
* 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