Forum Discussion

Xiaohui_Chen's avatar
Xiaohui_Chen
Icon for Employee rankEmployee
Jun 22, 2019

SNAT not working between two virtuals

Set up a bigip on aws with three servers at the backend. To preserve source IP, ppv2 support on AWS NLB is enabled. There is an irule on the first virtual to parse out the source address from ppv2 header and does a SNAT. Then the traffic is forwarded to virtual2 with "virtual stage_2". The setup is working without the SNAT. If SNAT is added, the traffic never reach the second virtual. Here is the setting

virtual 1

proxy TCP {
    listen 0.0.0.0 $service(https) prefixlen 0 {
        proto $ipproto(tcp)
        name _vs_https
    }
    profile basic_http
    profile sslc

    clientside TCP SSL HTTP
    serverside TCP HTTP
    rule ppv2_snat_rule
}

virtual 2

# HTTPS Virtual
proxy TCP {
    listen 0.0.0.0 4431 prefixlen 0 {
       proto $ipproto(tcp)
         name "vs_https"
    }
    profile basic_http

    use pool pool_http
    clientside TCP HTTP AVR
    serverside TCP HTTP AVR
    rule http_server_rule
}

irule. It is based on the one posted the Proxy Protocol receiver on devcenter

rule ppv2_snat_rule {
    #PROXY Protocol Receiver iRule
    # c.jenison at f5.com (Chad Jenison)
    # v2.0 - Added support for PROXY Protocol v2, control for v1,v2 or lack of proxy via static:: variables set in RULE_INIT
    when RULE_INIT {
        set static::allowProxyV1 1
        set static::allowProxyV2 1
        set static::allowNoProxy 1
    }

    when CLIENT_ACCEPTED {
        TCP::collect
    }

    when CLIENT_DATA {
        set tcplen [TCP::payload length]
            binary scan [TCP::payload 12] H* v2_protocol_sig
            if {$static::allowProxyV1 && [TCP::payload 0 5] eq "PROXY"} {
                set proxy_string [TCP::payload]
                set proxy_string_length [expr {[string first "\r" [TCP::payload]] + 2}]
                scan $proxy_string {PROXY TCP%s%s%s%s%s} tcpver srcaddr dstaddr srcport dstport
                log "Proxy Protocol v1 conn from [IP::client_addr]:[TCP::client_port] for an IPv$tcpver stream from Src: $srcaddr:$srcport to Dst: $dstaddr:$dstport"
                TCP::payload replace 0 $proxy_string_length ""
            } elseif {$static::allowProxyV2 && $v2_protocol_sig eq "0d0a0d0a000d0a515549540a"}{
                binary scan [TCP::payload] @12H* v2_proxyheaderremainder
                binary scan [TCP::payload] @12H2H* v2_verCommand v2_remainder
                if {$v2_verCommand == 21}{
                    binary scan [TCP::payload] @13H2S v2_addressFamilyTransportProtocol v2_tlv_id
                    set v2_remainderLen "[expr {$v2_tlv_id & 0xffff}]"
                    set v2_payloadindex "[expr $v2_remainderLen + 16]"
                    log "TLV - [expr {$v2_tlv_id & 0xffff}]"
                    if {$v2_addressFamilyTransportProtocol == 11} {
                        binary scan [TCP::payload] @16ccccccccSS v2_sourceAddress1 v2_sourceAddress2 v2_sourceAddress3 v2_sourceAddress4 v2_destAddress1 v2_destAddress2 v2_destAddress3 v2_destAddress4 v2_sourcePort1 v2_destPort1
                        set sourceAddress "[expr {$v2_sourceAddress1 & 0xff}].[expr {$v2_sourceAddress2 & 0xff}].[expr {$v2_sourceAddress3 & 0xff}].[expr {$v2_sourceAddress4 & 0xff}]"
                        set destAddress "[expr {$v2_destAddress1 & 0xff}].[expr {$v2_destAddress2 & 0xff}].[expr {$v2_destAddress3 & 0xff}].[expr {$v2_destAddress4 & 0xff}]"
                        set sourcePort [expr {$v2_sourcePort1 & 0xffff}]
                        set destPort [expr {$v2_destPort1 & 0xffff}]
                        log "Proxy Protocol v2 conn from [IP::client_addr]:[TCP::client_port] for an IPv4 Stream from Src: $sourceAddress:$sourcePort to Dst: $destAddress:$destPort"
                        TCP::payload replace 0 $v2_payloadindex ""
                        set proxy_xff 1
                    } elseif {$v2_addressFamilyTransportProtocol == 21} {
                        binary scan [TCP::payload] @16H4H4H4H4H4H4H4H v2_v6sourceAddress1 v2_v6sourceAddress2 v2_v6sourceAddress3 v2_v6sourceAddress4 v2_v6sourceAddress5 v2_v6sourceAddress6 v2_v6sourceAddress7 v2_v6sourceAddress8
                        binary scan [TCP::payload] @32H4H4H4H4H4H4H4H v2_v6destAddress1 v2_v6destAddress2 v2_v6destAddress3 v2_v6destAddress4 v2_v6destAddress5 v2_v6destAddress6 v2_v6destAddress7 v2_v6destAddress8
                        binary scan [TCP::payload] @48SS v2_v6sourcePort1 v2_v6destPort1
                        set sourcePort [expr {$v2_v6sourcePort1 & 0xffff}]
                        set destPort [expr {$v2_v6destPort1 & 0xffff}]
                        set sourceAddress "$v2_v6sourceAddress1:$v2_v6sourceAddress2:$v2_v6sourceAddress3:$v2_v6sourceAddress4:$v2_v6sourceAddress5:$v2_v6sourceAddress6:$v2_v6sourceAddress7:$v2_v6sourceAddress8"
                        set destAddress "$v2_v6destAddress1:$v2_v6destAddress2:$v2_v6destAddress3:$v2_v6destAddress4:$v2_v6destAddress5:$v2_v6destAddress6:$v2_v6destAddress7:$v2_v6destAddress8"
                        log "Proxy Protocol v2 conn from from [IP::client_addr]:[TCP::client_port] for an IPv6 Stream from Src: $sourceAddress:$sourcePort to Dst: $destAddress:$destPort"
                        TCP::payload replace 0 $v2_payloadindex ""
                        set proxy_xff 1
                    } else {
                        log "v2_proxy conn from [IP::client_addr]:[TCP::client_port] - possible unknown/malformed transportProtocol or addressFamily"
                        reject
                    }
                } elseif {$v2_verCommand == 20}{
                    reject
                } else {
                    log "Proxy Protocol Protocol Signature Detected from [IP::client_addr]:[TCP::client_port] but protocol version and command not legal; connection reset"
                    reject
                }
            } elseif {$static::allowNoProxy} {
                log "Connection from [IP::client_addr]:[TCP::client_port] allowed despite lack of PROXY protocol header"
                set proxy_xff 0
            } else {
                reject
                log "Connection rejected from [IP::client_addr]:[TCP::client_port] due to lack of PROXY protocol header"
            }
            TCP::release
    }

    when HTTP_REQUEST {
        log "http request"
        if { $proxy_xff == 1 } {
            log "snat to $sourceAddress"
            snat $sourceAddress $sourcePort
        }
        set vs_stage2 [string range [virtual name] 1 end]
        log "Set virtual to $vs_stage2"
        virtual $vs_stage2
    }
}

No RepliesBe the first to reply