Serverside SNI injection iRule

Problem this snippet solves:

Hi Folks,

the iRule below can be used to inject a TLS SNI extension to the server side based on e.g. HOST-Header values. The iRule is usefull if your pool servers depending on valid SNI records and you don't want to configure dedicated Server SSL Profiles for each single web application.

Cheers, Kai

How to use this snippet:

  1. Attach the iRule to the Virtual Server where you need to insert a TLS SNI expension
  2. Tweak the
    $sni_value
    variable within the
    HTTP_REQUEST
    to meet your requirements or move it to a different event as needed.
  3. Make sure you've cleared the "Server Name" option in your Server_SSL_Profile.

Code :

when HTTP_REQUEST {
#Set the SNI value (e.g. HTTP::host)
set sni_value [getfield [HTTP::host] ":" 1]
}
when SERVERSSL_CLIENTHELLO_SEND {

# SNI extension record as defined in RFC 3546/3.1
#
# - TLS Extension Type                =  int16( 0 = SNI ) 
# - TLS Extension Length              =  int16( $sni_length + 5 byte )
#    - SNI Record Length              =  int16( $sni_length + 3 byte)
#       - SNI Record Type             =   int8( 0 = HOST )
#          - SNI Record Value Length  =  int16( $sni_length )
#          - SNI Record Value         =    str( $sni_value )
#

# Calculate the length of the SNI value, Compute the SNI Record / TLS extension fields and add the result to the SERVERSSL_CLIENTHELLO 

SSL::extensions insert [binary format SSScSa* 0 [expr { [set sni_length [string length $sni_value]] + 5 }] [expr { $sni_length + 3 }] 0 $sni_length $sni_value]

}

Tested this on version:

12.0
Updated Jun 06, 2023
Version 2.0
  • kgaigl's avatar
    kgaigl
    Icon for Cirrocumulus rankCirrocumulus

    Hello Kai,

     

    could you please explain, how to tweak the sni_value? I'm to stupid to get this...

     

    we've 2 servernames behind a Portal-Access (different from the FQDN of Client-Side), now only the one works, I insert the servername in the sni-field of the SSL-Profile.

     

    But what would there be the $sni_value ? At the moment I don't get it.

     

    thanks

     

    Karl

     

  • Hi kgaigl,

    the iRule uses the

    HTTP_REQUEST
    event to extract the HOST-header value of the client requested ressource. This value is then used as Server_SSL SNI-Value.

    If the client requests https://www.domain.com/ the Server_SSL SNI-Value will become If the client requests https://ww2.domain.com/ the Server_SSL SNI-Value will become ww2.domain.com

    Note: You may use whatever logic during the

    HTTP_REQUEST
    event you like to decide which SNI-Value should be used to negotiate the Server Side SSL connection.

    Important: To make this iRule work you have to make sure that you dont specify a SNI-Value in your Server_SSL_Profile. This will allow the iRule to simply inject the SNI-Value without clearing existing values (aka. clearing existing values is not supported). If you set the "Server Name" option in your Server_SSL_Profile, the SSL negotiation will most likely fail...

    Cheers, Kai

  • kgaigl's avatar
    kgaigl
    Icon for Cirrocumulus rankCirrocumulus

    Hi Stanislas,

     

    that did it, thanks a lot.

     

    Hi Kai, thanks too for explaining and for the Rule

     

    Karl

     

  • Hi Kay,

    Actually Server Name can be enabled, it just has to be empty. Wonder why not use something like that in SERVERSSL_CLIENTHELLO_SEND:

    clientside {
       set sni_value [getfield [HTTP::host] ":" 1]
       log local0. "SNI should be: \"$sni_value\""
    }
    

    I know that TCL error ("{badEventContext {command is not valid in current event context (SERVER_CONNECTED)} is generated when saving iRule but according to support as long as you are actually processing HTTP at clientside this will work without issue - and indeed it works for me.

    Any comments why not to use?

    Piotr

  •   and we know that it's more advanced now because of CLI only parameter for virtual 🙂