2
Agenda
• OpenScript Architecture
• Quick Start
• Perl Basics
• OpenScript Examples
• Best Practices
3
OpenScript Architecture
4
What is OpenScript?
Open-Standard (Perl) Based Application Delivery Programming
Engine
Predictable Scripting Engine with Performance Estimator
Learn, Browse, Share Scripts through OpenScript Communitywww.brocade.com/openscript
5
OpenScript Architecture
Content Switching Engine
OpenScript Engine
TCP/UDP/IP
Pack
et
In
Packe
t Out
(event, context)
(result)
App Core
• Event Driven Model
• Script Attached to Virtual Port
• Resource Profile Per Script
Limits the resource consumption of a script• 1 MB memory foot print• Watch-dog timer (200 ms)• 100 KB data collection per event
MP
Compile
• Performance estimation• Catching syntax errors
6
OpenScript Quick Start
7
OpenScript Quick Start
Sorry.Get back later.
use OS_SLB;use OS_HTTP_REQUEST;
my $page;
sub BEGIN { $page = "HTTP/1.1 200 OK\r\nContent- Length:21\r\nConnection:close\r\nContent- Type: text/html; charset=UTF-8\r\n\r\n. Sorry .Get. back later.”;}
sub HTTP_REQUEST { OS_SLB::forward (10);}
sub SERVER_SELECTION_FAILURE { OS_SLB::reply($page);}
server l7-dont-reset-on-vip-port-fail
server real rs1 10.1.1.10 port 80 group-id 10 10
server real rs2 10.1.1.11 port 80 group-id 10 10
server virtual v1 20.1.1.1 port 80 bind 80 rs1 80 rs2 80
http://20.1.1.1
rs1 rs2
OpenScript “sorry.pl”ADX SLB Config
script “sorry.pl”
123456789
10111213141516171819
8
OpenScript Quick StartSteps With CLI
use OS_SLB;use OS_HTTP_REQUEST;
sub BEGIN { $page = "HTTP/1.1 200 OK\r\nContent- Length:21\r\nConnection:close\r\nContent- Type: text/html; charset=UTF-8\r\n\r\n. Sorry .Get. back later.”;}
sub HTTP_REQUEST { OS_SLB::forward (10);}
sub SERVER_SELECTION_FAILURE { OS_SLB::reply($page);}
server l7-dont-reset-on-vip-port-fail
server real rs1 10.1.1.10 port 80 group-id 10 10
server real rs2 10.1.1.11 port 80 group-id 10 10
server virtual v1 20.1.1.1 port 80 bind 80 rs1 80 rs2 80
1. Configure basic L4 SLB
2. Write a script on your choice of editor
3. Upload the script to the ADX
4. Compile the script
ADX#copy tftp usb0 10.120.61.68 sorry.pl sys\dpscript\sorry.plADX#show script allindex name In Use 1 sorry.pl
ADX#copy tftp usb0 10.120.61.68 sorry.pl sys\dpscript\sorry.plADX#show script allindex name In Use 1 sorry.pl ADX#config termADX(config)#script compile sorry.plThis script is compiled successfully.Performance for this script: - Approximately 9548 connections/second at 10% CPU utilization - Approximately 47744 connections/second at 50% CPU utilization - Approximately 95488 connections/second at 100% CPU utilization
5. Attach the script to the VIP portserver virtual v1 20.1.1.1
port http script “sorry.pl”
9
OpenScript Quick StartSteps With Web GUI
1
2
3
4
0GUI Version Check
10
Perl Basics
11
Regex
$string =~ m/pattern/
$string =~ s/pattern1/pattern2
my $string = “ab-abc-abcd”;$string =~ m/(.*)-/;print “$1\n”;
ab-abc
my $string = “ab-abc-abcd”;$string =~ m/(.*?)-/print “$1\n”;
ab
my $string = “ab-abc-abcd”;$string =~ s/ab/x/print “$string”;
my $string = “ab-abc-abcd”;$string =~ s/ab/x/gprint “$string”;
x-xc-xcd
x-abc-abcd
12
Hash / List / Array
rs1
url1
20
3
@my_array = (“url1”, “url2”, “url3”);$value = $my_array [ 0 ];
@my_two_dim_array = ( [ “url1”, 10 ], [ “url2”, 20 ], [ “url3”, 30 ] )
$value = $my_two_dim_array [ 1 ] [ 1 ]$size = scalar ( @my_array )
%my_hash_table = ( 1030=>”rs1”, 1031=>”rs2” )
$value = $my_hash_table { 1030 }
13
Pack, Unpack, Split, Join and Substr
unpack (template, scalar)
$hex_string = "\x7e\xf1";
my $bin_string = unpack("b*", $hex_string);print "$bin_string\n";
my $field = substr ($bin_string, 4, 4);print "$field\n";
0111111010001111
1110substr (data, start, size)
my @ip = split('\.', "10.1.2.3");my @net_mask = split('\.', "255.255.0.0");
my $net_ip = pack("C4", @ip) & pack("C4", @net_mask);my $net = join( '.', unpack("C4", $net_ip) );
print "$net\n";
pack (template, list)
10.1.0.0
split (‘separator’, scalar)
join (‘joiner’, list)
14
Conditional Statements
if ( $string == “birthday” ) {
print "Happy Birthday!\n";
} elsif ($string == “christmas”) {
print "Happy Christmas!\n";
} else {
print "Happy Whatever!\n";
}
if (EXPR) BLOCK
if (EXPR) BLOCK else BLOCK
if (EXPR) BLOCK elsif (EXPR) BLOCK
if (EXPR) BLOCK elsif (EXPR) BLOCK else BLOCK
15
Loop
2 3for $i (2..3) {
print “$i";}
url1 url2 url3@url = (url1, url2, url3);foreach $i (@url) {
print “$i\n”;}
$count = 1;while ($count <= 11 ) {
$count++;last;$count++;
}print “$count\n”;
for ($i=2; $i<=3; $i++) {
print “$i";}
2
@url = (url1, url2, url3);foreach (@url) {
print “$_\n”;}
16
OpenScript Examples
17
Mitigate DNS Dynamic Update Attack
• What is DNS dynamic update?• To update a DNS record on the DNS server dynamically, e.g., IP
address change.
• What is DNS dynamic DoS attack?• The attack sends a DNS server a crafted DNS dynamic update
message to cause a server crash.
• Some DNS Server S/Ws based on BIND 9 software are vulnerable to the attack.
• Solution−Drop DNS dynamic update messages using OpenScript
18
Drop DNS Dynamic Update(ADX CLI Config)
(DNS Dynamic Update Message)
use OS_UDP;use OS_SLB;
sub UDP_CLIENT_DATA{ $payload = OS_UDP::payload; $mydata = unpack( "b*", $payload); $mystring = substr ($mydata, 17, 4);
if ($mystring == "0101" ) { OS_SLB::drop; } else { OS_SLB::forward(10); }}
(dnsdos.pl)
server real rs1 10.1.1.2 port 53 group-id 10 10!server real rs2 10.1.1.3 port 53 group-id 10 10
server virtual v1 10.1.1.100 port 53 port 53 script dnsdos.pl bind 53 rs1 53 rs2 1
234567891011121314
19
• You want to allow only Intranet clients to access an URL www.mycompany.com/data/, on your company web server.
• Your Intranet clients belong to IP subnet 10.x.x.x/8
• If someone outside tries to access, return a page with a message “You are not allowed to access the content”.
Blocking Access to Certain URLs based on Client IP addresses
www.mycompany.com/datawww.mycompany.com/data/www.mycompany.com/data/*
www.mycompany.comwww.mycompany.com/datapublic
All PCs
Intranet PCs
20
Blocking Access to Certain URLs based on Client IP addresses
use OS_IP;use OS_SLB;use OS_HTTP_REQUEST;
my $local_subnet;my $page;
sub BEGIN {$local_subnet = “10.”;$page = "HTTP/1.1 200 OK\r\nContent-Length: 43\r\nConnection:
close\r\nContent-Type: text/html; charset=UTF-8\r\n\r\nYou are not allowed to access the content.";}
sub HTTP_REQUEST {my $client_ip = OS_IP::src;my $url = OS_HTTP_REQUEST::url;
if (!($client_ip =~ m/^$local_subnet/) && $url =~ m/www.mycompany.com\/data($|\/.*)/) {
OS_SLB::reply($page);} else {
OS_SLB::forward(1);}
}
• If an external client tries to access www.mycompany.com/data, return a warning page.
List OpenScript API modules to use
Initialization sub routine• Define 10.x.x.x as an internal
network• Prepare a web page to return for
warning to external clients
Main routine
Regular Expression to match the URL
123456789
10111213141516171819202122
21
SIP VIA Header IP ReplacementSIP/2.0 200 OKVia: SIP/2.0/UDP server.foo.com;branch=z9hG4bKnashds8;received=192.0.2.3Via: SIP/2.0/UDP bigbox.site3.com;branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2Via: SIP/2.0/UDP pc3.atlanta.com;branch=z9hG4bK776asdhds ;received=192.0.2.1To: Bob <sip:bob.com>;tag=a6c85cfFrom: Alice <sip:alice.com>;tag=1928301774Call-ID: a84b4c76e66710.atlanta.comCSeq: 314159 INVITEContact: <sip:bob.0.2.4>Content-Type: application/sdpContent-Length: 131 SIP/2.0 200 OK
Via: SIP/2.0/UDP server.foo.com;branch=z9hG4bKnashds8;received=10.1.1.100Via: SIP/2.0/UDP bigbox.site3.com;branch=z9hG4bK77ef4c2312983.1;received=10.1.1.100Via: SIP/2.0/UDP pc3.atlanta.com;branch=z9hG4bK776asdhds ;received=10.1.1.100To: Bob <sip:bob.com>;tag=a6c85cfFrom: Alice <sip:alice.com>;tag=1928301774Call-ID: a84b4c76e66710.atlanta.comCSeq: 314159 INVITEContact: <sip:bob.0.2.4>Content-Type: application/sdpContent-Length: 131
22
SIP VIA Header IP Replacementuse OS_IP;use OS_UDP;
my $vip;
sub BEGIN { $vip = 10.1.1.100; # VIP you want to put in the Via header}
sub UDP_CLIENT_DATA{ my $client_ip = OS_IP::src; my $sip_msg = OS_UDP::payload; if ($sip_msg =~ s/ (.*?Via:) (.*?;) (.*?;) (received=) (\d{1,3}\. \d{1,3}\. \d{1,3}\. \d{1,3}) / $1 $2 $3 $4 $vip /xig) { OS_UDP::payload($sip_msg); } else {
OS_SLB::log (“Warning : SIP client $client_ip : VIA header was not found”); }}
123456789
10111213141516171819
23
OpenScript Best Practices
24
OpenScript Best Practices
• Readability
• Performance
• Trouble Shooting
25
Variable Names and Spaces AroundNo CamelCase
DO my $variable_that_contains_my_server_name = gather_server_stats (gigantic_apache_web_server);
DO NOTmy $variableThatContainsMyServerName = gatherServerStats (giganticApacheWebServer) ;
26
Spaces Around Operators and After Commas
DOmy %server_list = (1030=>”rs1”, 1031=>”rs2” );
DO NOTmy %server_list=(1030=>”rs1”,1031=>”rs2” );
27
Regular Expression
DO/ ( [a-fA-F0-9] ) - [a-fA-F0-9]{4} - [a-fA-F0-9]{4} - [a-fA-F0-9]{4} - [a-fA-F0-9]{12} /x
DO NOT/([a-fA-F0-9])-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}/
Also, Don’t Overdo Regex
28
Compile with “Strict”
script compile <script file name> strictOr include in the OpenScript code
use strict;use Sub::StrictDecl;………………………………………………………….
* the strict option in the compilation CLI and Sub:StrictDecl require 12.4.00f or later.
ADX(config)#script compile hello.pl This script is compiled successfully.Performance for this script: - Approximately 5200 connections/second at 10% CPU utilization - Approximately 26200 connections/second at 50% CPU utilization - Approximately 52400 connections/second at 100% CPU utilizationADX(config)#script compile hello.pl strict S_my_exit_jump being called Compile Errors found : Undeclared subroutine &OS_SLB::Forward at -e line 11.BEGIN not safe after errors--compilation aborted at -e line 17.
29
SLB Forwarding API Use
OS_HTTP_REQUEST () { if ( EXPR ) { OS_SLB::forward(1); } OS_SLB::forward(2);}
OS_HTTP_REQUEST () { if ( EXPR ) { OS_SLB::forward(1); } else { OS_SLB::forward(2); }}
Wrong
30
No Object Oriented Convention
DO$url = OS_HTTP_REQUEST::url;
DO NOT$req_obj = OS_HTTP_REQUEST::get;$url = $req_obj->url
Not Supported, starting in 12.4.00e for increased performance by 30%
31
BEGIN Subroutinemy %network_group;my $net_mask_hex;
sub BEGIN {my $net_mask = "255.255.0.0";%network_group = (
"10.1.0.0“ => "GROUP_A“, "10.2.0.0“ => "GROUP_B”, “10.3.0.0“ => "GROUP_C"
);my @net_mask = split ('\.', $net_mask);$net_mask_hex = pack(C4, @netmask);
}
my $ip = OS_IP::src;my @ip = split ('\.', $ip);
my $net_hex = pack ("C4", @ip) & $net_mask_hex;
$net = join (‘.', unpack("C4", $net_hex) );$group_name = $network_group { $net };
Do As Many As Operations in the BEGIN
Main Event Handler
• Do not assign a value to a variable outside a sub routine
• Just declare the variable with the scope“my” outside a sub routine as lexical scoping is required.
32
Print Statement and Log
script-profile production print-output none!server virtual v1 10.24.142.86 port http port http script "hello.pl" script-profile "production”
print: Do not use in production except for debugging purposeOS_SLB::log: Use to log unexpected and rare events in production environment
33
Use Memory To Save CPUsub HTTP_REQUEST { my $host = OS_HTTP_REQUEST::host;
if ( $host =~ m/www.host1.com/) { OS_SLB::forward (rs1);
} elsif ( $host =~ m/www.host2.com ) { OS_SLB::forward (rs2);
} elsif { $host =~ m/www.host3.com ) { OS_SLB::forward (rs3);
} else { OS_SLB:reset_client(); }}
my %host_server_mapping;
sub BEGIN { %host_server_mapping = { “www.host1.com”=>”rs1”, “www.host2.com”=>”rs2”, “www.host3.com”=>”rs3”};}
sub HTTP_REQUEST { my $host = OS_HTTP_REQUEST::host;
my $server = $host_server_mapping {$host};
if ( $server ) { OS_SLB::forward($server); } else { OS_SLB:reset_client(); }}
34
Release Memory After Use
my %url_hash = ();
sub HTTP_REQUEST () {my $req_id = OS_CONN::client_connection;$url_hash {$req_id} = OS_HTTP_REQUEST::url;
}
sub HTTP_RESPONSE () {my $req_id = OS_CONN::client_connection;print “url from the corresponding request is
$url_hash{$req_id} \n”;delete $url_hash{$req_id};
}
35
Trouble Shooting
• Is my script attached to a VIP?
• Did the script modification take into effect?
• Do event counters increase?
• Does my script reset?
• Is there any typo in OpenScript APIs?
• Is the cause of a problem not identified?
Where To Start
show script <script name> program
show script <script name> detail <vip name> <port>script compile <script name> strict
use “print” in the scripturl debug 3, debug filter, packet capture
script update <script name>
36
Trouble Shooting
• Problem description
• show run
• show script <script name> program
• show script <script name> detail <vip name> <port>• Gather 2~3 times after issuing “script update” to reset counters.
• url debug 3 <client ip>
• packet trace from your client PC
What To Gather To Escalate
37
Trouble Shooting ExampleMy OpenScript code does not send a sorry page out though all servers are down.
server real rs1 10.1.1.10 port 80 group-id 10 10
server real rs2 10.1.1.11 port 80 group-id 10 10
server virtual v1 20.1.1.1 port 80 script “sorry.pl” bind 80 rs1 80 rs2 80
use OS_SLB;use OS_HTTP_REQUEST;
my $page;
sub BEGIN { $page = "HTTP/1.1 200 OK\r\nContent- Length:21\r\nConnection:close\r\nContent- Type: text/html; charset=UTF-8\r\n\r\n. Sorry .Get. back later.”;}
sub HTTP_REQUEST { OS_SLB::forward (10);}
sub SERVER_SELECTION_FAILURE { OS_SLB::reply($page);}
ADX(config)#script compile sorry.pl strictThis script is compiled successfully.Performance for this script: - Approximately 4100 connections/second at 10% CPU utilization - Approximately 20600 connections/second at 50% CPU utilization - Approximately 41200 connections/second at 100% CPU utilization
ADX#show script sorry.pl detail v1 80===============================================Virtual Server: v1Service-Port: httpScript State: ACTIVELast Updated: 00:59:21, GMT+00, Sun Mar 3 2013
Script Restart: 0
Total Connections: 0Concurrent Connections: 0
Error Counters: exceed max rewrite entry:
Hits Per Event: HTTP Request event:
show run
show script sorry.pl program
ADX#show server bind
Bind info
Virtual server: test Status: enabled IP: 20.1.1.1 http -------> rs1: 10.10.1.10, http (Failed) rs2: 10.10.1.1, http (Failed)
?server l7-dont-reset-on-vip-port-fail
38
THANK YOU