Forum Discussion

Ian_Johnson_382's avatar
Ian_Johnson_382
Icon for Nimbostratus rankNimbostratus
Jan 06, 2012

Seaching for string in tcp payload

Hi All,

I am looking at creating an iRule to perform persistence based on a 32bit value in the tcp payload. I have create a iRule which is using the findstr to perform this and it is working, but I would like to have the iRule just gather 32bit of data.

The information I am looking for is always after the hex be ef here is an example

0000 00 02 a5 75 66 21 00 07 0e 47 77 3f 08 00 45 00 ...uf!...Gw?..E. 
0010 00 78 a3 57 40 00 3e 06 89 22 0a af c9 8b 0a af .x.W@.>.."...... 
0020 31 1d 23 40 07 b1 e9 b8 b3 80 df 38 76 16 50 18 1.@.......8v.P. 
0030 ff c8 87 6f 00 00 24 00 00 00 00 00 00 00 00 00 ...o..$......... 
0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
0060 00 00 00 00 06 06 be ef 20 00 0a 00 00 01 38 50 ........ .....8P 
0070 6f 46 00 00 00 00 4f 53 52 56 5f 4f 50 56 41 4c oF....OSRV_OPVAL 
0080 5f 41 4e 59 00 00                               _ANY..

I have create an iRule using the findstr but I would like to just find be ef and take 32bits after that. Is this possible?

Here is the current iRule

when CLIENT_ACCEPTED { 
   if {$::debug != 0}{log local0. "Client connection [IP::client_addr]"} 
   if {$::debug != 0}{log local0. "Collecting TCP Payload"} 
    Collect tcp packets coming from client 
   TCP::collect 
} 

when CLIENT_DATA { 
   if {$::debug != 0}{log local0. "Save payload"} 
    Save tcp payload to variable payload 
   set payload [TCP::payload] 

   if {$::debug != 0}{log local0. "Convert payload to HEX"} 
    Convert payload to HEX so we can search for the string beef 
   binary scan $payload H* h_payload 

   if {$::debug != 0}{log local0. "Find the BEEF"} 
    Look for the strings beef and get everything between beef and 0001 
   set g_id [findstr $h_payload beef 4 0001] 

   if {$::debug != 0}{log local0. "Looking for matching persistence record"} 
    Persist using the session id 
   persist universal $g_id 
   if {$::debug != 0}{log local0. "BEEF is $g_id"} 

   if {$::debug != 0}{log local0. "TCP release"}   
    Release the tcp connection TCP::release 
} 

Thanks

Ian
  • Hey Ian,

     

     

    You could try using TCP::collect 32, but I think you'll still get whatever is in the first TCP packet when you call TCP::payload.

     

     

    Can you clarify why you want just 32 bytes if you can parse the value out of the full payload?

     

     

    Aaron
  • Also, can you post the iRule and binary snippet in [ code ] [/ code ] blocks to preserve the spacing?

     

     

    Thanks, Aaron
  • if 32 bits data location is fixed, i think you just need to put skip_bytes argument when running TCP::collect.

     

     

    TCP::collect wiki

     

    http://devcentral.f5.com/wiki/iRules.TCP__collect.ashx
  • Aaron,

     

     

     

    Here is the tcp payload again

     

     

    
    000 00 02 a5 75 66 21 00 07 0e 47 77 3f 08 00 45 00 ...uf!...Gw?..E. 
    0010 00 78 a3 57 40 00 3e 06 89 22 0a af c9 8b 0a af .x.W@.>.."...... 
    0020 31 1d 23 40 07 b1 e9 b8 b3 80 df 38 76 16 50 18 1.@.......8v.P. 
    0030 ff c8 87 6f 00 00 24 00 00 00 00 00 00 00 00 00 ...o..$......... 
    0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
    0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 
    0060 00 00 00 00 06 06 be ef 20 00 0a 00 00 01 38 50 ........ .....8P 
    0070 6f 46 00 00 00 00 4f 53 52 56 5f 4f 50 56 41 4c oF....OSRV_OPVAL 
    0080 5f 41 4e 59 00 00                               _ANY.. 
    

     

     

     

    The reason I just need the 32bit is because this is the lenght session id the appilcation creates. The format of the id is

     

    
    be ef                     <- 16 bit magic number
    20                          <- 8 bit gateway id 
    00 0a 00                <- 24 bit session id
    

     

     

    In the iRule I was using the findstr with look for beef and ending in 0001, which worked fine in the test but I have since found out that not all session id will end in 0001. So I want to find the string beef and then get the next 32bit only.

     

     

     

    
    when CLIENT_ACCEPTED {
    if {$::debug != 0}{log local0. "Client connection [IP::client_addr]"}
    if {$::debug != 0}{log local0. "Collecting TCP Payload"}
     Collect tcp packets coming from client
    TCP::collect 
    }
    when CLIENT_DATA {
    if {$::debug != 0}{log local0. "Save payload"}
     Save tcp payload to variable payload
    set payload [TCP::payload]
    
    if {$::debug != 0}{log local0. "Convert payload to HEX"}
     Convert payload to HEX so we can search for the string beef
    binary scan $payload H* h_payload
    
    if {$::debug != 0}{log local0. "Find the BEEF"}
     Look for the strings beef and get everything between beef and 0001
    set g_id [findstr $h_payload beef 4 0001]
    
    if {$::debug != 0}{log local0. "Looking for matching persistence record"}
     Persist using the session id
    persist universal $g_id
    if {$::debug != 0}{log local0. "BEEF is $g_id"}
    
    if {$::debug != 0}{log local0. "TCP release"}
     Release the tcp connection
    TCP::release
    }
    

     

     

    Thanks

     

    Ian

     

     

    PS> Hope this code is easier to read now.
  • Nitass,

     

     

    From the tcp dumps I have taken the location in the payload differs everytime.

     

     

    Ian
  • Not sure why the session id information didn't display correcly

     

     

    be ef 20 00 0a 00

     

     

    be ef <- 16 bit magic number

     

    20 <- 8 bit gateway id (will be the same for a gateway process)

     

    00 0a 00 <- 24 bit session id
  • can you try this?

     

     

    set g_id [findstr $h_payload beef 4 8]
  • [root@ve1023:Active] config  b virtual bar list
    virtual bar {
       snat automap
       pool foo
       destination 172.28.19.79:80
       ip protocol 6
       rules myrule
    }
    [root@ve1023:Active] config  b rule myrule list
    rule myrule {
       when CLIENT_ACCEPTED {
            TCP::collect
    }
    
    when CLIENT_DATA {
            set payload [TCP::payload]
            binary scan $payload H* h_payload
    
            log local0. "\$h_payload: $h_payload"
            log local0. "32 bits data after 486f73743a: [findstr $h_payload 486f73743a 10 8]"
    
            TCP::release
    }
    }
    
    [root@ve1023:Active] config  cat /var/log/ltm
    Jan  6 09:08:10 local/tmm info tmm[26866]: Rule myrule : $h_payload: 474554202f20485454502f312e310d0a557365722d4167656e743a206375726c2f372e31352e352028693638362d7265646861742d6c696e75782d676e7529206c69626375726c2f372e31352e35204f70656e53534c2f302e392e3872207a6c69622f312e322e33206c696269646e2f302e362e350d0a486f73743a203137322e32382e31392e37390d0a4163636570743a202a2f2a0d0a0d0a
    Jan  6 09:08:10 local/tmm info tmm[26866]: Rule myrule : 32 bits data after 486f73743a: 20313732
    
  • I think you should be able to use binary scan to do this without converting to hex first:

     

    http://www.tcl.tk/man/tcl8.4/TclCmd/binary.htmM24

     

     

    I'll try to play around with this later today if no one else does.

     

     

    Aaron