Forum Discussion

dragonflymr's avatar
dragonflymr
Icon for Cirrostratus rankCirrostratus
Dec 07, 2015

Parsing IP to extract subnet

Hi,

 

I wonder if there is more elegant and fastest way to extract specific part of IP - like get only part of IP up to second dot, third dot.

 

I know that I can use scan to separate IP in four parts then combine first and second, etc.

 

But maybe there is easier and fastest way?

 

Piotr

 

11 Replies

  • That depends somewhat on what you intend to do with the information. For example, if you want to choose a conditional branch based on subnet, you can do something like this:

    when CLIENT_ACCEPTED {
        if { [IP::addr [IP::client_addr] equals "192.168.0.0/16" } {
            pool pool-internal
        }
    }
    

    If you're simply trying to extract dotted-quad octets, then

    scan
    is probably as good an approach as any.

    • dragonflymr's avatar
      dragonflymr
      Icon for Cirrostratus rankCirrostratus
      Thanks, not exactly what I am looking for - as I wrote below - my fault, I was not precise enough. Piotr
  • Vernon_97235's avatar
    Vernon_97235
    Historic F5 Account

    That depends somewhat on what you intend to do with the information. For example, if you want to choose a conditional branch based on subnet, you can do something like this:

    when CLIENT_ACCEPTED {
        if { [IP::addr [IP::client_addr] equals "192.168.0.0/16" } {
            pool pool-internal
        }
    }
    

    If you're simply trying to extract dotted-quad octets, then

    scan
    is probably as good an approach as any.

    • dragonflymr's avatar
      dragonflymr
      Icon for Cirrostratus rankCirrostratus
      Thanks, not exactly what I am looking for - as I wrote below - my fault, I was not precise enough. Piotr
  • Hi Piotr,

    I hope you are doing well.

    I am using
    getfield
    to access the IP address digits i.e. as follows:
    when CLIENT_ACCEPTED {     
        snat 10.10.10.[expr ( [getfield [IP::client_addr] "." 4] % 32 ) + 1]
         snat 10.10.[getfield [IP::client_addr] "." 3].[getfield [IP::client_addr] "." 4]
    }
    

    The second line would apply a SNAT address based on replacing the first three digits the original IP address by "10.10.10." and calculates the last digit by reading the last digit from the original client IP and applies a modulus of 32 + 1 (i.e. turns a 47 into 16 to vary the SNATs in a range of 10.10.10.1 to 10.10.10.32 and persist to this value as long as client IP doesnt change). (Make sure to use a virtual address space or have "real" SNATs configured to avoid ARP issues.) The third line (commented) is using the original third and fourth digit of the original client IP to define a new SNAT. (Same ARP issues to expect as described above.)

    Thanks, Stephan
  • Perhaps I got your question wrong. Following Vernons solution you can check the following if you already know the relevant networks:

    when CLIENT_ACCEPTED {
        switch [IP::addr [IP::client_addr]] {
            "10.131.131.0/26"   { log local0. "client [IP::client_addr] in 10.131.131.0/25 detected"
            "10.131.131.64/26"  { log local0. "client [IP::client_addr] in 10.131.131.64/25 detected"
            "10.131.131.128/26" { log local0. "client [IP::client_addr] in 10.131.131.128/25 detected"
            "10.131.131.192/26" { log local0. "client [IP::client_addr] in 10.131.131.192/25 detected"
        }
    }  
    

    Thanks, Stephan

    PS: I am pretty sure I wrote a subnet calculator iRule a while ago and will post it if you think it would be helpful to solve your requirements.
  • Hi,

    First of all, thanks for help. Second, it was my fault. I did not describe my goal precise enough. Idea is to create keys (for tables or iStats) using variable mask (depending on some iRule logic). IPs are not know in advance and right now there is no idea of using them for some if or switch operations.

    Below my crude iRule that should shed some light on what I mean - at least I hope so 🙂

    when CLIENT_ACCEPTED {
        set addr [IP::client_addr]
    
        log local0. "Client IP: $addr"
    
        scan $addr {%d.%d.%d.%d} a b c d
    
    }
    
    when HTTP_REQUEST {
    
       switch -glob [string tolower [HTTP::uri]] {
          "*/24" {
            set newaddr "$a.$b.$c.0"
            set uri [string map -nocase {"/24" "/"} [HTTP::uri]]
            HTTP::uri $uri
            }
          "*/16" {
            set newaddr "$a.$b.0.0"
            set uri [string map -nocase {"/16" "/"} [HTTP::uri]]
            HTTP::uri $uri
            }
          "*/8" {
            set newaddr "$a.0.0.0"
            set uri [string map -nocase {"/8" "/"} [HTTP::uri]]
            HTTP::uri $uri
            }
            default {
             set newaddr $addr   
            }
       }
       log local0. "scan result: $newaddr"
       ISTATS::incr "ltm.virtual [virtual name] c $newaddr" 1
    }
    

    Point is if I can perform subnet creation in some more elegant, faster way that the one above (scan cmd).

    Piotr

    • dragonflymr's avatar
      dragonflymr
      Icon for Cirrostratus rankCirrostratus
      Well, probably I found solution - question is if it's the best use something like that: set sub_var [IP::addr [IP::client_addr] mask 255.255.0.0] and adjusting mask parameter as needed - is that right track. I am a bit lost how to use IP:addr Piotr
  • Hi Kai,

     

    Thanks for advice. That is great base to choose the right path depending of use case!

     

    Piotr

     

  • Hi Piotr,

     

    the "best solution" will strongly depend on how often you've to contruct the $newaddr on a single TCP connection.

     

    1.) Using the [scan] command to split an IP into octets will cost more cpu cycles than transforming the IP using the [IP::addr] command. So for a single transformation the [IP::addr] command should be used.

     

    2.) Using a [scan] command once during CLIENT_ACCEPTED and then substitute different subnet variations and/or perform this action on multiple consecutive HTTP_REQUEST would be faster than calling [IP::addr] multiple times.

     

    Cheers, Kai

     

  • Hi Piotr,

     

    the "best solution" will strongly depend on how often you've to contruct the $newaddr on a single TCP connection.

     

    1.) Using the [scan] command to split an IP into octets will cost more cpu cycles than transforming the IP using the [IP::addr] command. So for a single transformation the [IP::addr] command should be used.

     

    2.) Using a [scan] command once during CLIENT_ACCEPTED and then substitute different subnet variation and/or on multiple consecutive HTTP_REQUEST would be faster than calling [IP::addr] multiple times.

     

    Cheers, Kai