03-Dec-2009
08:00
- last edited on
22-Nov-2022
16:00
by
JimmyPackets
How random is the tcl rand function?
We're currently using it to generate a unique(ish) value for each request we process - using a code bloc like this
set rnum [format "%08X" [expr { int(1000000000 * rand() ) } ] ]
set cthash [format "%08X" [clock clicks -milliseconds] ]
set tracker "$cthash$rnum
The tracker value then get inserted into a database. We would like to be comfortable in making it the primary key of the table (ie. no duplicates).
Is there a cryptogrpahically safe equivalent of rand() available from with iRules?
If I don't seed rand in a RULE_INIT event, will it be reseeded each time it's called?
Alternatively, does anyone have a method to generate a unique request identifier?
Cheers,
Rob
04-Dec-2009
00:42
- last edited on
22-Nov-2022
16:00
by
JimmyPackets
Then for every connection (on every vhost) we can increment a counter. The code snippet then becomes
set iruleversion [format "%04X" 1]
set F5id "[format "%02X" 1]"
STATS::incr Booking_stats request_count
set rnum [format "%08X" [STATS::get Booking_stats request_count] ]
set cthash [format "%08X" [clock seconds] ]
set tracker "$F5id$iruleversion$cthash$rnum"
This allows us to identify the BigIP pair (F5id) the request was processed by, and gives us a version number (iruleversion) for the iRule, which together with the clock should ensure we don't get duplicate values if/when the Booking_stats profile is reset.
Unfortunately the F5id and iruleversion need manual control, but as I don't think we'll be updating either frequently this isn't a problem.
Rob
04-Dec-2009
08:30
- last edited on
15-Dec-2022
09:55
by
JRahm
Hi Rob,
Here is a method we used for a customer to generate a unique ID per HTTP request:
when RULE_INIT {
Initialize 10 variables to track the distribution of first digits
for {set i 0} {$i < 10} {incr i} {
set $i 0
}
Loop through and generate X number of random numbers
for {set i 0} {$i < 1000} {incr i} {
Save a new random number
set random_number [expr {rand()}]
set random_number_float [format %0.10f $random_number]
Log the random number, the formatted string and the first digit
log local0. "$random_number, [format %010s [string range $random_number 2 12]],\
[string range [format %010s [string range $random_number 2 12]] 0 0], $random_number_float"
incr [string range [format %010.f [string range $random_number_float 2 12]] end end]
}
log local0. "Summary: "
for {set i 0} {$i < 10} {incr i} {
log local0. "$i: [set $i]"
}
}
For a run of 100,000 iterations, the distribution is fairly even:
Rule : Summary:
Rule : 0: 10114
Rule : 1: 9981
Rule : 2: 9781
Rule : 3: 9980
Rule : 4: 10104
Rule : 5: 9993
Rule : 6: 10074
Rule : 7: 10067
Rule : 8: 10013
Rule : 9: 9893
I got the basics from this TCL wiki page (http://wiki.tcl.tk/17696). I didn't seed rand as there were a few people stating:
as specifying our own seed for every call to roll is more likely to reduce randomness than improve it, I've left it out altogether.
Aaron
27-Jan-2017
03:55
- last edited on
15-Dec-2022
09:53
by
JRahm
For several purposes (i.e. creating safe passphrases, cookies etc.) I´m using the rand function of TCL quite often.
But for peace of mind I had to prove two aspects of the random numbers:
* Will the random numbers be evenly distributed or will they follow a bell-shaped curve?
* Will rand return numbers less than 1 typically?
Indeed I made a (very short) attempt to have a look at the source code and quickly decided to follow an empiric approach. Instead of opening a new post I will add my 2 cents to this old thread.
Here is the iRule code returning i.e. 10,000 random numbers over a range of 0-20 upon request. A table is used to count the hits for each number in range.
when HTTP_REQUEST {
remove existing table
table delete -subtable randomtest -all
find x random values in range of 0-y
set x 10000
set y 20
for {set i 0} {${i} < ${x}} {incr i} {
table incr -subtable randomtest key[format %03d [expr {int(rand()*${y})}]]
}
build output and prove number of results
set j 0
set page ""
for {set i 0} {${i} <= ${y}} {incr i} {
if { [table lookup -subtable randomtest key[format %03d ${i}]] ne "" } {
incr j [table lookup -subtable randomtest key[format %03d ${i}]]
}
append page "key[format %03d $i]: [table lookup -subtable randomtest key[format %03d $i]]\r\n"
}
append page "calculations: $j\r\n"
return results
HTTP::respond 200 content ${page} Connection Close Content-Type "text/plain; charset=us-ascii"
return
}
The iRule will be bound to a virtual server having an http-profile.
Send a request via browser or cURL as shown below.
A table is used to count the hits for each number in range.
The result shows an even distribution.
The number 20 (representing a random value of 1) doesnt show up.
$ curl http://10.1.1.61/
key000: 537
key001: 557
key002: 464
key003: 518
key004: 487
key005: 482
key006: 482
key007: 520
key008: 502
key009: 502
key010: 516
key011: 479
key012: 525
key013: 470
key014: 554
key015: 439
key016: 471
key017: 477
key018: 541
key019: 477
key020:
calculations: 10000
Thanks, Stephan
27-Jan-2017
04:50
- last edited on
15-Dec-2022
09:53
by
JRahm
Hi Folks,
I'm using a combination of the TMM_ID and a Timestamp to create unique request IDs that will never colide.
set uniqueID [TMM::cmp_unit][clock clicks]
Cheers, Kai