Forum Discussion

Andrea_110925's avatar
Andrea_110925
Icon for Nimbostratus rankNimbostratus
Dec 15, 2016

Two different source nat for one VIP based on HTTP::URI

How can I realize the following case?

I have a vip with an iRule that forward traffic to different pool based on specific uri, easy, done. I need to apply different snat based on different uri, and now the situation is going to complicate: I have a case in which I need to apply two different snat based on specific uri, but clients are the same and the destination pool of real servers is the same, the only difference is the uri. Everything works fine if clients use always one uri, rather than other uri, the issue occurs when clients switch from one uri to the other, in this case the first snat will maintained for the other uri too. Unfortunately I think that is correct, because when the connection is established (and the correct snat is applied) it's not possible change snat in that connection, but only for a new one. Could someone confirm that? I attach the iRule, any suggestion is appreciated. Thanks in advance, Andrea

when HTTP_REQUEST {

switch -glob [HTTP::uri] {

"/uri1/" - "/uri2/" - "/uri3/*" { if { [IP::addr [IP::client_addr]/24 equals 10.1.1.0] } { snat automap } pool pool-www-11 }

"/uri4/*" { if { ( [IP::addr [IP::client_addr] equals 10.1.1.69] ) or ( [IP::addr [IP::client_addr] equals 10.1.1.76] ) } { snat 10.1.1.250 } pool pool-www-11 }

default        {
                if { [IP::addr [IP::client_addr]/23 equals 10.10.10.0] } { snat automap }
                pool pool-www-22
               }
     }

}

4 Replies

  • I'd be curious to know if this even selects the desired pool member if the initial request is for 'uri1', and a subsequent request is received that matches default. Assuming no pool member overlap between pools 'pool-www-11' and 'pool-www-22' I'd expect the actual result to be different than anticipated since, as you noted, the connection table entry has already been established.

     

    This sounds like a situation where OneConnect or the LB::detach method would come into play. Those would allow detachment of the client from the server-side on a per-request basis and may enable the functionality you're looking for. Not posting as an answer since I can't give you a definitive "here's an example that will work" answer. Offering in case you hadn't considered those and I'll fill my knowledge from the next person that expertly answers this question. ;)

     

  • I must confess that this scenario made me cringe a bit.

    But it sounds like a bit of a challenge and I don't mind experimenting on other peoples environments! 🙂

    How about trying to force the LB to detach the connection before doing the SNAT again?

    Please note that I have not checked the syntax in my LB as I'm not at the office. Use in QA first if possible:

    when HTTP_REQUEST {
    
        switch -glob [HTTP::uri] {
            "/uri1/" - "/uri2/" - "/uri3/*" {
                if { [IP::addr [IP::client_addr]/24 equals 10.1.1.0] } {
                    Check if another snat has been chosen in this session
                    Close the server side connection if it has
                    if{ [info exists chosensnat] && $chosensnat != "snat1"
                        LB::detach
                    }
                    snat automap
                    set chosensnat "snat1"
                }
                pool pool-www-11 
            }
            "/uri4/*" { 
                if { ( [IP::addr [IP::client_addr] equals 10.1.1.69] ) or ( [IP::addr [IP::client_addr] equals 10.1.1.76] ) } {
                    Check if another snat has been chosen in this session
                    Close the server side connection if it has
                    if{ [info exists chosensnat] && $chosensnat != "snat2"
                        LB::detach
                    }
                    snat 10.1.1.250 
                    set chosensnat "snat2"
                }
                pool pool-www-11
            }
            default {
                if { [IP::addr [IP::client_addr]/23 equals 10.10.10.0] }{
                    Check if another snat has been chosen in this session
                    Close the server side connection if it has
                    if{ [info exists chosensnat] && $chosensnat != "default"
                        LB::detach
                    }
                    snat automap
                    set chosensnat "default"
                }
                pool pool-www-22
            }
        }
    }
    

    Updated: Thanks Ed

    /Patrik

  • Ok, starting again with the answer, as my original post was not entire correct. I also did some lab tests, so besides the theory, there is a practical part to show the behavior.

    Answering Andrea’s question. I did some tests with 12.1.1 HF1, did not have time yet to install 12.1.2. In my lab this setup worked with no problems. I did not do test the pool command, but try change the order of the snat and pool commands in case you still have problems.

    An important point is the fact that the behavior when using snat command is different than using snatpool.

    https://devcentral.f5.com/wiki/irules.snat.ashx

    “This command will not cause BigIP to answer any ARP requests for the address when the address exists on the egress VLAN. If responding to ARP requests in this situation is desired, SNAT pools may be created and the snatpool may be used instead.” In my setup I just created a self IP with the snat IP.

    LAB configuration:

    when HTTP_REQUEST {
      log local0. "test1 irule"
      if { [HTTP::path] == "/index.php" } {
        snat automap
        log local0. "snat 172.16.0.3"
      }
      if { [HTTP::path] == "/user_login.php" } {
        snat 172.16.0.103
        log local0. "snat 172.16.0.103"
      }
    }
    
    Virtual Server: 10.0.0.102:80
    Pool with only pool member: 172.16.0.14:80
    

    Test 1 – snat command via iRule:

    GET index.php

     tcpdump
    16:28:42.606124 IP 172.16.0.3.24252 > 172.16.0.14.http: Flags [S], seq 1795381369, win 4380, options [mss 1460,sackOK,eol], length 0 out slot1/tmm4 lis=/Common/vs_asm
    16:28:42.606727 IP 172.16.0.14.http > 172.16.0.3.24252: Flags [S.], seq 2191007059, ack 1795381370, win 5840, options [mss 1460,nop,nop,sackOK], length 0 in slot1/tmm4 lis=/Common/vs_asm
    16:28:42.606737 IP 172.16.0.3.24252 > 172.16.0.14.http: Flags [.], ack 1, win 4380, length 0 out slot1/tmm4 lis=/Common/vs_asm
     /var/log/ltm
    Dec 19 16:28:42 LABBIGIP1 info tmm4[16483]: Rule /Common/test1 : test1 irule
    Dec 19 16:28:42 LABBIGIP1 info tmm4[16483]: Rule /Common/test1 : snat 172.16.0.3
     date and tmsh show sys connections (removed unrelated connections) 
    Mon Dec 19 16:28:42 GMT 2016
    Sys::Connections
    10.0.0.30:24252   10.0.0.102:80    172.16.0.3:24252  172.16.0.14:80   tcp  0  (tmm: 4)  none
    10.0.0.30:24253    10.0.0.102:80     10.0.0.30:24253   172.16.0.14:80    tcp  0    (tmm: 5)  none
    Total records returned: 14
    

    GET user_login.php (using same source ip and port)

     tcpdump
    16:28:45.893412 IP 172.16.0.103.24252 > 172.16.0.14.http: Flags [S], seq 1406730911, win 4380, options [mss 1460,sackOK,eol], length 0 out slot1/tmm4 lis=/Common/vs_asm
    16:28:45.894067 IP 172.16.0.14.http > 172.16.0.103.24252: Flags [S.], seq 2196642615, ack 1406730912, win 5840, options [mss 1460,nop,nop,sackOK], length 0 in slot1/tmm4 lis=/Common/vs_asm
    16:28:45.894082 IP 172.16.0.103.24252 > 172.16.0.14.http: Flags [.], ack 1, win 4380, length 0 out slot1/tmm4 lis=/Common/vs_asm
     /var/log/ltm
    Dec 19 16:28:45 LABBIGIP1 info tmm4[16483]: Rule /Common/test1 : test1 irule
    Dec 19 16:28:45 LABBIGIP1 info tmm4[16483]: Rule /Common/test1 : snat 172.16.0.103
     date and tmsh show sys connections (removed unrelated connections)
    Mon Dec 19 16:28:46 GMT 2016
    Sys::Connections
    any6.any          any6.any         172.16.0.3:24252    172.16.0.14:80   tcp  1  (tmm: 4)  none
    10.0.0.30:24252   10.0.0.102:80    172.16.0.103:24252  172.16.0.14:80   tcp  1  (tmm: 4)  none
    10.0.0.30:24253    10.0.0.102:80     10.0.0.30:24253   172.16.0.14:80    tcp  1    (tmm: 5)  none
    Total records returned: 15
    

    As you can see in the above information, the correct snat is applied to the connection. The system just move the client side connection to the new connection, so the previous connection with snat 172.16.0.3 stays without client side connection. There is also a connection that does not use snat, as that is for the other objects the page has, and does not match the criteria for snat.

    Test 2 – LB::detach command via iRule:

    I did some tests but is not easy to show the output, this is the test using another virtual server.

    10.0.0.30:26522  10.0.0.100:80  any6.any  any6.any  tcp  8  (tmm: 2)  none

    Basically, the server side connection will be removed from the connection and be terminated.

    Test 3 – Oneconnect applied to the virtual server:

    After I read Patrik question, I realized that this wouldn’t work in the scenario.

    GET index.php (multiple times)

    00:49:32.155547 172.16.0.3.37012 > 172.16.0.14.http: . ack 37973 win 42352 (DF)
    00:49:32.160821 172.16.0.3.37012 > 172.16.0.14.http: . ack 38265 win 42644 (DF)
    00:49:32.163192 172.16.0.3.37013 > 172.16.0.14.http: P 1398:1865(467) ack 9720 win 14099 (DF)
    00:49:32.163519 172.16.0.14.http > 172.16.0.3.37013: . 9720:11180(1460) ack 1865 win 9648 (DF)
    00:49:32.163557 172.16.0.14.http > 172.16.0.3.37013: . 11180:12640(1460) ack 1865 win 9648 (DF)
    00:49:32.163576 172.16.0.14.http > 172.16.0.3.37013: . 12640:14100(1460) ack 1865 win 9648 (DF)
    00:49:32.163597 172.16.0.14.http > 172.16.0.3.37013: . 14100:15560(1460) ack 1865 win 9648 (DF)
    00:49:32.163618 172.16.0.14.http > 172.16.0.3.37013: P 15560:16226(666) ack 1865 win 9648 (DF)
    00:49:32.174014 172.16.0.3.37013 > 172.16.0.14.http: . ack 11180 win 15559 (DF)
    00:49:32.206002 172.16.0.3.37013 > 172.16.0.14.http: . ack 14100 win 18479 (DF)
    00:49:32.215058 172.16.0.3.37013 > 172.16.0.14.http: . ack 16226 win 20605 (DF)
    

    GET user_login.php (using same source ip and port, and multiple times)

    00:50:22.682430 172.16.0.103.37013 > 172.16.0.14.http: . ack 19000 win 23379 (DF)
    00:50:22.702261 172.16.0.3.37016 > 172.16.0.14.http: . ack 13359 win 17738 (DF)
    

    The goal of oneconnect is to allow the same connection to be used by different clients/networks. In this scenario, while I only have the connection with snat 172.16.0.3, the system only uses this connection. When I start a request that triggers snat 172.16.0.103, because oneconnect, the requests uses 172.16.0.3 or 172.16.0.103, and does not matter that I am only requesting user_login.php that should use 172.16.0.103.

    If you want to read more about this, these links are helpful:

    https://devcentral.f5.com/wiki/irules.lb__detach.ashx

  • Just thought of something.

     

    Shall we what's behind door number 2? Have you tried cloning the pools instead?

     

    Something like this:

     

    • pool-www-11-snat1
    • pool-www-11-snat2
    • pool-www-11-default

    I am not sure how the F5 handles connections in these case you you might have a shot at solving it this way without killing server side connections so you should definitely try it.

     

    Bummer would of course be that you'd have 3 times the monitor traffic hammering the members but that should be a small price to pay if it works.

     

    Please update the thread with your findings, I find this a bit intriguing. :)

     

    /Patrik