380 likes | 667 Views
Brocade ADX Openscript. March 2013. Derek Kang ( dkang@brocade.com ), Solutions Architect. Agenda. OpenScript Architecture Quick Start Perl Basics OpenScript Examples Best Practices. OpenScript Architecture. What is OpenScript?. Open-Standard (Perl) Based
E N D
Brocade ADX Openscript March 2013 Derek Kang (dkang@brocade.com), Solutions Architect
Agenda • OpenScript Architecture • Quick Start • Perl Basics • OpenScript Examples • Best Practices
What is OpenScript? Open-Standard (Perl) Based Application Delivery Programming Engine Predictable Scripting Engine with Performance Estimator Learn, Browse, Share Scripts through OpenScript Community www.brocade.com/openscript
OpenScript Architecture MP App Core Compile OpenScript Engine (event, context) • Event Driven Model • Script Attached to Virtual Port • Resource Profile Per Script (result) • Performance estimation • Catching syntax errors Content Switching Engine TCP/UDP/IP Limits the resource consumption of a script Packet In Packet Out • 1 MB memory foot print • Watch-dog timer (200 ms) • 100 KB data collection per event
OpenScript Quick Start ADX SLB Config OpenScript “sorry.pl” 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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); } http://20.1.1.1 Sorry. Get back later. script “sorry.pl” rs1 rs2
OpenScript Quick Start Steps With CLI 3. Upload the script to the ADX 2. Write a script on your choice of editor 1. Configure basic L4 SLB ADX#copytftp usb0 10.120.61.68 sorry.pl sys\dpscript\sorry.pl ADX#show script all index name In Use 1 sorry.pl 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 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); } 4. Compile the script ADX#copytftp usb0 10.120.61.68 sorry.pl sys\dpscript\sorry.pl ADX#show script all index name In Use 1 sorry.pl ADX#config term ADX(config)#script compile sorry.pl This 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 port server virtual v1 20.1.1.1 port http script “sorry.pl”
OpenScript Quick Start Steps With Web GUI 1 2 3 4 0 GUI Version Check
Regex $string =~ m/pattern/ 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”; $string =~ s/pattern1/pattern2 x-abc-abcd my $string = “ab-abc-abcd”; $string =~ s/ab/x/g print “$string”; x-xc-xcd
Hash / List / Array %my_hash_table = ( 1030=>”rs1”, 1031=>”rs2” ) $value = $my_hash_table{1030 } rs1 @my_array = (“url1”, “url2”, “url3”); $value = $my_array[ 0 ]; url1 @my_two_dim_array = ([ “url1”, 10 ], [ “url2”, 20 ], [ “url3”, 30 ]) $value = $my_two_dim_array[ 1 ][ 1 ] $size = scalar ( @my_array) 20 3
Pack, Unpack, Split, Join and Substr 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) unpack (template, scalar) 10.1.0.0 split (‘separator’, scalar) join (‘joiner’, list) $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 substr (data, start, size) 1110
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
Loop for ($i=2; $i<=3; $i++) {print “$i";} for$i (2..3) {print “$i";} 2 3 @url = (url1, url2, url3); foreach $i (@url) {print “$i\n”;} @url = (url1, url2, url3); foreach (@url) { print “$_\n”; } url1 url2 url3 $count = 1; while ($count <= 11 ) { $count++;last; $count++;} print “$count\n”; 2
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 DoSattack? • 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
Drop DNS Dynamic Update (DNS Dynamic Update Message) (ADX CLI Config) 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 (dnsdos.pl) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 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); } }
Blocking Access to Certain URLs based on Client IP addresses • 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”. www.mycompany.com www.mycompany.com/datapublic All PCs www.mycompany.com/data www.mycompany.com/data/ www.mycompany.com/data/* Intranet PCs
Blocking Access to Certain URLs based on Client IP addresses 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 • 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); } } 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 • If an external client tries to access www.mycompany.com/data, return a warning page. Regular Expression to match the URL
SIP VIA Header IP Replacement SIP/2.0 200 OK Via: SIP/2.0/UDP server.foo.com;branch=z9hG4bKnashds8;received=192.0.2.3 Via: SIP/2.0/UDP bigbox.site3.com;branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2 Via: SIP/2.0/UDP pc3.atlanta.com;branch=z9hG4bK776asdhds ;received=192.0.2.1 To: Bob <sip:bob.com>;tag=a6c85cf From: Alice <sip:alice.com>;tag=1928301774 Call-ID: a84b4c76e66710.atlanta.com CSeq: 314159 INVITE Contact: <sip:bob.0.2.4> Content-Type: application/sdp Content-Length: 131 SIP/2.0 200 OK Via: SIP/2.0/UDP server.foo.com;branch=z9hG4bKnashds8;received=10.1.1.100 Via: SIP/2.0/UDP bigbox.site3.com;branch=z9hG4bK77ef4c2312983.1;received=10.1.1.100 Via: SIP/2.0/UDP pc3.atlanta.com;branch=z9hG4bK776asdhds ;received=10.1.1.100 To: Bob <sip:bob.com>;tag=a6c85cf From: Alice <sip:alice.com>;tag=1928301774 Call-ID: a84b4c76e66710.atlanta.com CSeq: 314159 INVITE Contact: <sip:bob.0.2.4> Content-Type: application/sdp Content-Length: 131
SIP VIA Header IP Replacement 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 use 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”); } }
OpenScript Best Practices • Readability • Performance • Trouble Shooting
Variable Names and Spaces Around No CamelCase DO my $variable_that_contains_my_server_name = gather_server_stats (gigantic_apache_web_server); DO NOT my $variableThatContainsMyServerName = gatherServerStats (giganticApacheWebServer) ;
Spaces Around Operators and After Commas DO my %server_list = (1030=>”rs1”, 1031=>”rs2” ); DO NOT my %server_list=(1030=>”rs1”,1031=>”rs2” );
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
Compile with “Strict” use strict; use Sub::StrictDecl; …………………………… ……………………………. script compile <script file name> strict Or include in the OpenScript code 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 utilization ADX(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. * the strict option in the compilation CLI and Sub:StrictDecl require 12.4.00f or later.
SLB Forwarding API Use OS_HTTP_REQUEST () { if ( EXPR ) { OS_SLB::forward(1); } else { OS_SLB::forward(2); } } OS_HTTP_REQUEST () { if ( EXPR ) { OS_SLB::forward(1); } OS_SLB::forward(2); } Wrong
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%
BEGIN Subroutine my %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); } • 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. Do As Many As Operations in the BEGIN 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 }; Main Event Handler
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 purpose • OS_SLB::log: Use to log unexpected and rare eventsin production environment
Use Memory To Save CPU 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(); } } sub 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(); } }
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}; }
Trouble Shooting Where To Start • 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? • show script <script name> program • scriptupdate <script name> • show script <script name> detail <vip name> <port> • script compile <script name> strict • use “print” in the script • url debug 3, debug filter, packet capture
Trouble Shooting What To Gather To Escalate • 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
Trouble Shooting Example ADX#showserver 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) My OpenScript code does not send a sorry page out though all servers are down. ADX(config)#script compile sorry.pl strict This 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 show script sorry.pl program 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); } show run ADX#showscript sorry.pl detail v1 80 ===============================================Virtual Server: v1 Service-Port: http Script State: ACTIVE Last Updated: 00:59:21, GMT+00, Sun Mar 3 2013 Script Restart: 0 Total Connections: 0 Concurrent Connections: 0 Error Counters: exceed max rewrite entry: Hits Per Event: HTTP Request event: 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 ? server l7-dont-reset-on-vip-port-fail