iRules 設定ガイド(V11.5.1 対応) 初級&中級編 F5 Networks Japan V1.0 目次 1. iRules とは ............................................................................... 4 1.1. iRules の構成 ......................................................................... 4 2. TCL 動作確認の準備 (tclsh の利用) ......................................................... 5 2.1. BIG-IP への SSH アクセス ................................................................ 5 2.2. tclsh を使う ........................................................................... 6 3. TCL の基礎 ................................................................................ 7 3.1. 基本のコマンド行 ....................................................................... 7 3.2. コマンド行の終わり ..................................................................... 7 3.3. expr (計算) .......................................................................... 8 単純な計算........................................................................ 8 計算式を()でまとめる ............................................................... 8 真偽の計算 ....................................................................... 8 [参考] TCL の演算子の一覧 ......................................................... 9 3.4. ドル記号 $ (変数置換) [その 1] ....................................................... 10 3.5. ブレス記号:{ } (無効化) .............................................................. 11 3.6. ドル記号 $ (変数置換) [その 2] ....................................................... 12 3.7. ブラケット記号 [ ] (コマンド置換) ....................................................... 13 3.8. ダブルクォーテーション記号 " " ......................................................... 14 3.9. ブレス{ }の中身をコマンド内部で評価するもの ............................................. 15 expr ............................................................................ 15 if .............................................................................. 16 while ........................................................................... 17 for ............................................................................. 18 3.10. if, else, elseif .................................................................... 19 3.11. switch .............................................................................. 20 switch の基本サンプル ............................................................ 20 switch のオプション ............................................................... 20 switch の glob オプションの例....................................................... 21 3.12. 配列変数 ............................................................................ 22 3.13. 文字列操作 .......................................................................... 24 string .......................................................................... 24 split ........................................................................... 25 join ............................................................................ 25 append .......................................................................... 25 concat .......................................................................... 25 3.14. リスト操作 ............................................................................ 26 list ............................................................................ 26 lindex .......................................................................... 26 llength ......................................................................... 26 lappend ......................................................................... 26 linsert ......................................................................... 27 lrange .......................................................................... 27 lreplace ........................................................................ 27 lsearch ......................................................................... 27 lsort ........................................................................... 28 3.15. foreach ............................................................................. 29 3.16. TCL のマニュアル ...................................................................... 29 4. iRules の概要 ............................................................................ 30 4.1. イベント .............................................................................. 30 4.2. 変数 (variables) について ............................................................ 31 ローカル変数 (Local variables) ................................................... 31 グローバル変数 (Global variables) ................................................ 32 iRules 間で読み書き可能な変数:Table コマンド ........................................ 33 iRules の変数一覧 ................................................................ 34 4.3. 演算子 ( Operators ) ................................................................ 35 Ⅹ 4.4. 4.5. 4.6. ファンクション ......................................................................... ステートメント ......................................................................... コマンド .............................................................................. 出現頻度の高いコマンド ............................................................ コマンドの注意点 .................................................................. 5. iRules 動作確認用のネットワーク構成サンプル ................................................ 6. LTM の設定 ............................................................................... 6.1. Platform 設定 ........................................................................ 6.2. VLAN 設定 ............................................................................ 6.3. Self IP 設定 ......................................................................... 6.4. Routing 設定 ......................................................................... 6.5. Pool の設定 .......................................................................... http-pool ....................................................................... A-pool .......................................................................... B-pool .......................................................................... 6.6. Virtual Server の設定 ................................................................ Web-vs (Port:80) ................................................................ Secure-vs (Port:443) ............................................................ 7. iRules の使い方 .......................................................................... 7.1. [パターン 1] iRule Editor を使う ....................................................... 7.2. [パターン 2] BIG-IP の Web GUI を使う ................................................... iRule の適用 ..................................................................... 出力されるログの確認 .............................................................. 8. iRules の具体例 .......................................................................... 8.1. よく使う EVENT の例 .................................................................... CLIENT_ACCEPTED ................................................................. CLIENT_DATA ..................................................................... HTTP_REQUEST .................................................................... HTTP_RESPONSE ................................................................... RULE_INIT ....................................................................... LB_FAILED ....................................................................... 9. Class / Data-Group の使い方 .............................................................. Data-Group のデータの Type ........................................................ Internal Data-Group ............................................................. External Data-Group (その 1:String 形式) .......................................... External Data-Group (その 2:Address 形式) ......................................... 9.2. table の使い方 ....................................................................... 10. iRule 作成のテクニック ..................................................................... 10.1. デバッグのやり方 ...................................................................... 本番環境でのロギング有効化/無効化 ................................................ 10.2. iRule による CPU 使用率の測定 .......................................................... 2 つの iRule で CPU 使用率を比較 .................................................... iRule の CPU 使用率の計算 ......................................................... 10.3. iRule を最適化する ................................................................... 11. おわりに ................................................................................. 12. Appendix ................................................................................ 12.1. EVENT 発動のタイミング ................................................................. EVENT のフロー .................................................................... EVENT 発動を確認するためだけの iRule ............................................... 出力されたログ ................................................................... 12.2. コマンド一覧 (2015/6 現在) ............................................................ Ⅹ 36 37 38 38 40 41 42 42 42 43 43 44 44 45 45 46 46 47 48 48 50 51 52 53 53 53 54 55 56 57 59 61 62 63 66 68 71 74 74 74 76 76 78 79 84 85 85 85 86 87 89 1. iRules とは iRule は、BIG-IP 上で動作する、パワフルでフレキシブルな機能です。 iRule は、VirtualServer(以下 VS)に関連付けられるオブジェクトの 1 つで、VS に到着、または VS から出力される IP アプリケーショントラフィックに対して、記述されたスクリプトの内容をもとに、インターセプト(割込)、インスペクト(調 査)、トランスフォーム(変換)などの様々な処理を行うことが可能です。 処理されたパケットは VS に設定される Default pool だけではなく、iRule で書かれた pool や node へ送ること もできます。 また、iRule はパーシステンスでも使用でき、更に認証にも使用されます。 iRule は TCL(Tool Command Language)を用いており、汎用性の高い実装を行っているので、様々な用途に使用で きます。 1.1. iRules の構成 iRule は、1 つ以上の event と、その event が発動した際に実行される、TCL コードから構成されます。 <基本的なシンタックス> when EVENT { if { 条件式 (比較演算など) コマンド } } } { 「EVENT」が iRule 発動のトリガーとなり、「条件式」が True なら、「コマンド」を実行します。 例えば、「http://www.foobar.com/test.txt のような、"txt"で終わる URI は"Pool1"に振り分け、それ以外の HTTP リクエストは"Pool2"に振り分けたい」という要件があったとします。 以下が、この要件を実現する iRule です。 when HTTP_REQUEST { if { [HTTP::uri] ends_with "txt"} { pool pool1 } else { pool pool2 } ① ② ③ ④ ⑤ } ① ② ③ ④ ⑤ HTTP リクエストを受信したとき、 その HTTP リクエストの URI が txt で終わるのならば、 Pool1 へ送る。 それ以外は、 Pool2 へ送る。 以降、詳細解説に入ります。 4 2. TCL 動作確認の準備 (tclsh の利用) 以降で、TCL コマンドの動きを確かめることを目的として、BIG-IP へ SSH でログインし、CLI 画面の bash で"tclsh"を実行します。 tclsh は、TCL インタプリタのためのシンプルなシェルで、BIG-IP に限らず多くの Linux ディストリビュー ションで標準搭載またはインストールして利用することができます。 例)CentOS の場合のインストール方法: # yum -y install tcl 2.1. BIG-IP への SSH アクセス SSH クライアント(例:TeraTerm)を使って、BIG-IP へ SSH でアクセスします。 (1) SSH でログインします。 BIG-IP のマネージメント IP アドレス (2) User name に「root」を入力し、Use challenge/response to log in をチェックします。 5 (3) パスワードを入力します。(デフォルト状態のパスワードは「default」です) (4) 以下のようなコマンドプロンプトが表示されます。 [root@big208:Active:In Sync] config # 2.2. tclsh を使う この bash で、tclsh を実行します。 [root@big208:Active:In Sync] config #tclsh % 以降で出てくる TCL コマンド(%が先頭についているものが目印です)を、この tclsh で実行してその結果を 確認してみてください。 tclsh を終了する際は、「% exit」を入力、または 「Ctrl + D」キーを押してください。 6 3. TCL の基礎 TCL(Tool Command Language)はスクリプト言語で、ティクルと読みます。 インタプリタ言語、リスト処理、連想配列などの特長を持ち、アプリケーション開発のためのスクリプト言 語として設計・拡張されてきた言語です。 iRules は TCL で記述されるので、iRules を作成するには、まず TCL の基本を理解する必要があります。 TCL の基本を理解することで、iRule サンプルスクリプトもグッと読み取りやすくなります。 本セクションでは、TCL について解説します。 3.1. 基本のコマンド行 TCL は以下のようなリスト構造(=要素をブランクで区切って並べたもの)になっています。 リストの先頭要素が「コマンド」で、残りの要素は「アーギュメント(引数)」です。 コマンド␣アーギュメント 1␣アーギュメント 2 上記のような形で、コマンドの後にブランクで区切られたアーギュメントが続きます。 TCL はこのようなリスト構造をとっているため、ブランクやタブは、リストを構成する要素の区切り文字として、 重要な意味を持つ、という点に注意が必要です。 3.2. コマンド行の終わり コマンド行の終わりは、「改行」によって示されます。 もうひとつは、「;」 (セミコロン) です。 「;」を使うと、複数のコマンド行を続けて 1 行に書くことができます。 コマンド␣アーギュメント 1␣アーギュメント 2; コマンド␣アーギュメント 3␣アーギュメント 4 7 3.3. expr (計算) まず、TCL で計算を行う際に使う expr コマンドにについて触れておきます。 expr は、数式を解釈して計算した結果を返します。 計算式は、オペランド※と演算子(+ - * / < > == 等)の組み合わせで構成されます。 ※オペランドとは演算の対象となる値や文字列のこと。 尚、TCL でのブランクやタブは、リストを構成する要素の区切り文字として重要な意味を持つ、とお伝えしましたが、 式のなかのブランクに関しては無視されます。 単純な計算 % expr 1 + 2 + 3 + 4 + 5 →「15」 が返されます。 計算式を()でまとめる ( 丸カッコ )は、計算と論理変数をまとめるときに使います。 % expr 2 * 3 / 3 + 3 → 「5」 が返されます。 % expr 2 * 3 / (3 + 3) →「1」 が返されます。 真偽の計算 expr コマンドで、対象比較演算子(< > <= >=)や等値比較演算子(== !=)などを利用することで、真偽の計算が できます。 % expr 1 > 1 → 「0」 = "偽"という値が返されます。 % expr 1 == 1 → 「1」 = "真"という値が返されます。 8 [参考] TCL の演算子の一覧 TCL では、以下のような演算子を使うことができます。 演算子 説明 - + ~ ! 単項のマイナス、プラス、ビット毎の否定、論理否定。いずれも文字列に対しては使えない。 ビット毎の否定は整数に対してのみ適用可能。 * / % 乗算、除算、剰余の 2 項演算子。いずれも文字列に対しては使えない。 剰余演算子(%)は整数に対してのみ適用可能。 + - 加算および減算(2 項演算子)。オペランドが数値ならば使用可能。 << >> 左シフトおよび右シフト演算子。オペランドは整数のみ可能。 < > <= >= 大小比較演算子。比較結果が真なら 1 を、偽なら 0 を返す。オペランドは数値だけではなく、文字列で もよい。 == != 等値比較演算子。結果が真なら 1 を、偽なら 0 を返す。オペランドは数値だけではなく、文字列でもよ い。 eq ne 文字列専用の等値比較演算子。eq は等しいときに 1 を返し、ne は等しくないときに 1 を返す。 & ビット毎の and 演算子。オペランドは整数のみ。 ^ ビット毎の exor 演算子。オペランドは整数のみ。 | ビット毎の or 演算子。オペランドは整数のみ。 && 論理的な "and" 演算子。2つのオペランドがともに非ゼロなら 1 を返し、そうでなければ 0 を返す。 オペランドはブーリアンタイプかまたは数値。 || 論理的な "or" 演算子。2つのオペランドがともにゼロなら 0 を返し、そうでなければ 1 を返す。 オペランドはブーリアンタイプかまたは数値。 x ? y : z C 言語と同様の3項演算子で、x が非ゼロなら y を、そうでなければ z を返す。x はブーリアンタイプか または数値。 9 3.4. ドル記号 $ (変数置換) [その 1] TCL の重要な機能のひとつに変数があります。 この変数機能の提供により、コマンド間でのデータの受け渡しが可能になります。 変数は set コマンドにより生成されます。 TCL パーサー※は、$記号が先頭に付いた要素を変数名とみなし、その変数をその実体に置き換えてからコマンドを 実行します。 これが「変数置換」です。 % set a 100 % puts $a → 「100」 が返されます。 TCL パーサーが、$a (=変数) を 100 (=実体) に変数置換した結果です。 (ちなみに"puts"は、ディスプレイへの標準出力を行うコマンドです。) [※参考] TCL パーサー(Parser)とは パーサー(Parser)は、一般的には、構文解析を行うためのプログラムの総称です。 TCL においてもパーサーが存在しており、「TCL 言語で記載されたスクリプトを解析するプログラム」とお考えくださ い。 以降の解説でも、TCL パーサーという言葉を使います。 10 3.5. ブレス記号:{ } (無効化) アーギュメントをブレス{ }で囲むことで、囲まれた部分に含まれるあらゆる特殊文字の機能を無効化しま す。 なので、ブレス{ }内はバックスラッシュ(\)=エスケープなしで改行できますし、ブランクやタブを要素の中 に含めることもできます。 以下の文字列は、3 つの要素からなるリストです。"a f5 fan"はブランクを含んでいますが、{ }によって無効化さ れ、ひとつの要素として扱われます。 You are {a f5 fan} コマンドも一つの要素です。 したがって、以下の文字列は、3 つの要素からなる一つのリストです。 if {$a > 0} {set a 0} ブレス{ }内は改行文字も無効化されるので、以下の形が成り立ちます。 if {$a > 0} { set a 0 } しかし、以下の形は成り立ちません。 if {$a > 0} { set a 0 } これが成り立たないのは、ブレス{ }の制限ではなく、if コマンドの制限によるものです。 if コマンドに続く第 1 アーギュメントの直後で改行されているので、そこでコマンド行の終了を意味します。 よって、if コマンドが求める第 2 アーギュメントがコマンド行に存在しない、という理由で、このコマンドが成り立たな くなります。 以下 3 つを、tclsh で実行してみてください。 (1) サンプル 1 % set a 100 % if {$a > 0} {set a 0} (2) サンプル 2 % set a 100 % if {$a > 0} { set a 0 } (3) サンプル 3 % set a 100 % if {$a > 0} { set a 0 } ←ここでエラーになります。 11 3.6. ドル記号 $ (変数置換) [その 2] 変数について、もう少し踏み込んで解説します。 (1) 変数置換とブレス{ } 前項でブレス{ }について触れましたので、変数置換とブレス{ }の関係についても触れておきます。 以下のような文字列もブレス{ }に囲まれると一つの要素となるので、これも変数に取込むことができます。 % set a {You are a f5 fan.} % puts $a → 「You are a f5 fan.」 が返されます。 これは、TCL パーサーが $a (=変数) を You are a f5 fan. (=実体) に変数置換した結果です。 尚、TCL パーサーによる変数置換は 1 回しか実行されない、という点に注意してください。 よって、変数置換結果に「$」が含まれていても、再置換が行われることはありません。 % set a {You are a $a fan.} % puts $a → 「You are a $a fan.」が返されます。 また、変数置換後の結果にブランクが含まれていても、複数のアーギュメントとしてみなされることはなく、ブランクが 含まれた 1 つのアーギュメントと判断されます。(上記例のとおりです。) これは、変数置換を行った後では、ブランク区切りによるリスト構造の認識は行われない、ということを意味します。 その他、少し変則的な変数の使い方を以下 2 つ紹介しておきます。 (2) $をつけない変数 変数の値を直接処理するコマンドの場合、変数の先頭に"$"を付けずに利用する場合が多いです。 以下は、変数「int」に"1"を加える例です("1"は省略されています)。 % set int 1 % incr int →「2」が返されます。 (3) 変数と文字を繋げたい(ブランクで区切りたくない)場合 変数の文字部分($を含まない)をブレス{ }で囲むことで、変数と連続したキャラクタ(ブランクで区切らないキャラク タ)を繋げることができます。 以下は、「int」の実体が数字であり、その数字の後ろに"th"をつけることで、日付を表現する例です。 % set int 5 % puts "Today's date is the ${int}th" →「Today's date is the 5th」が返されます。 12 3.7. ブラケット記号 [ ] (コマンド置換) TCL は、リストの先頭要素を常にコマンド名として認識します。 それ以外の要素はコマンドに渡すべきアーギュメントとして認識します。 しかし、そのアーギュメント要素がブラケット[ ]で挟まれていると、TCL パーサーはその中身をコマンド行と認識し、 それを実行して、本来のアーギュメント値に置き換えてくれます。 コマンドを実体値に置き換える、これが「コマンド置換」です。 % set a [expr 1000 * 5] % puts $a ※ → 「5000」が返されます。 上記の※行は、TCL パーサーが[ ]の中を計算して 5000 に置き換えているので、 「 set a 5000 」という指 定をしているのと同じ結果になります。 また、コマンド置換は以下のようにネストすることも可能です。 % set b 3 % set a [expr 5 + [expr $b * 70]] % puts $a → 「215」が返されます。 13 3.8. ダブルクォーテーション記号 " " 既述のように、ブレス{ }は、改行コードなどの特殊文字の機能を無効化します。 この法則はコマンド置換子であるブラケット[ ]や、変数置換子である$記号に対しても同様です。 そのため、下記のコードではコマンド置換も変数置換も行われません。 % set num 5 % puts {[expr 100 * $num] Yen} よって、この実行結果として出力される文字列は以下です。 [expr 100 * $num] Yen コマンド置換も変数置換も機能させ、かつブランクを含む文字列をひとつのアーギュメントとして puts コマンドに渡 したい場合には、ブレスの代わりにダブルクォーテーション(")で挟みます。 % set num 5 % puts "[expr 100 * $num] Yen" このコマンドの実行結果として、 500 Yen が出力されます。 このように、ダブルクォーテーションの機能は、コマンド置換と変数置換を許すところが、ブレス{ }と異なる点です。 14 3.9. ブレス{ }の中身をコマンド内部で評価するもの ブレス{ }で囲むと特殊文字の機能が無効化されてしまうのであれば、{ }で囲むと何も実行されなくなるのではな いか?と思われたかもしれません。ある意味では正しいです。 事実として、例えば既述の set や puts コマンドでは、{ }内のコマンド置換や変数置換は実施されず、{ }はただ単 に文字列として返されました。 % set a {You are a $a fan.} % puts $a → 「You are a $a fan.」が返されます。 変数置換が行われません。 %puts {[expr 100 * $num] Yen} →「 [expr 100 * $num] Yen 」が返されます。変数置換もコマンド置換も行われません。 しかし、コマンドによっては、TCL パーサーがそのブレス{ }で囲まれたアーギュメントをコマンドに引渡し、そのコマン ドが内部で評価を行う (=コマンド置換や変数置換する) ものがあります。 その代表が「expr」や「if」や「while」や「for」コマンドなどです。 expr 算術演算を行う expr コマンドは、アーギュメントをコマンド内部で評価します。 よって、以下の 2 つのコマンド (① と ②) は、同じ結果を返します。 % % % % set a 11 set b 22 expr $a * $b expr { $a * $b } ① ② →①も②も「242」が返されます。 上記②に関しては、ブレス{ }で囲まれている部分は無効化されているので、TCL パーサーは変数置換を行いませ ん。 しかし、TCL パーサーが変数置換を行ってくれなくても、expr がコマンドの内部でブレス{ }内の変数置換を実行す るので、同じ結果が得られる、ということです。 上記①の場合、TCL パーサーによる変数置換の後に expr 内で計算を行う、という 2 回の処理に対し、②は expr 内 で一度に処理するので、②の方が効率は良い、といえます。 15 if if は、その第 1 アーギュメントが「真」なら、第 2 アーギュメントをコマンド内部で評価する、というコマンドです。 また if コマンドは、第 1 アーギュメントをコマンド内部で expr によって評価し、その結果を使います。 % set val 1 % if $val { set a 111 } TCL パーサーは、if コマンド行の第 1 アーギュメントの「$val」を評価して、「1」に書き換えます(変数置換)。 同様に TCL パーサーは、第 2 アーギュメントの{ set a 111 }を評価し、ブレス{ }で囲まれているので文字列とし て処理し、以下のようにします。 % if 1 { set a 111 } TCL バーサーはこの後、「1」と 「set a 111」を if コマンドに渡します。 if コマンド側は、受け取った第 1 アーギュメントの文字列を expr コマンドに [expr 1] として渡し、その結果が真 なので、第 2 アーギュメントの set a 111 を処理します。 第 1 アーギュメントをブレス{ }で囲んでも、同じ結果が得られます。 % set val 1 % if {$val} { set a 111 } この場合、TCL パーサーは、if コマンド行の第 1 アーギュメントを 「$val」 という 4 文字の文字列として処理し、 第 2 アーギュメントも「set a 111」を文字列として処理し、if コマンドに渡します。 if コマンド側は、受け取った文字列を expr コマンドに [expr {$val}] として渡し、その結果が真なので、 「set a 111」を処理します。 if のように、コマンドがアーギュメントを内部で評価してくれるならば、そのアーギュメントはブレス{ }で挟んで渡し た方が、効率がよくなります。 このことで、TCL パーサーと if コマンドによる計 2 回の評価処理を 1 回に減らすことができるからです。 16 while while コマンドも if コマンドと同様に、第 1 アーギュメントとして与えられた文字列を、while コマンド内部で expr に よって評価し、その結果を使います。 while は、第 1 アーギュメントが真の場合に、第 2 アーギュメントを処理する、というところまでは if と同じです。 if と異なるのは、第 2 アーギュメントを処理し終えると再び第 1 アーギュメントを評価し、それが真なら、再び第 2 ア ーギュメントの処理を行う、という繰り返し実行がなされる点です。 したがって、以下の形では問題が発生します。 % set val 1 % while $val { set a 111 } TCL パーサーが変数置換を行うので、$val は「1」です。 よって、while 行は実質、以下の形になっています。 % while 1 { set a 111 } この状態だと常に真であるため、永遠に 「set a 111」が繰り返される、無限ループに陥ります。 例えば、以下のような形は、無限ループに陥ります。 % set a 100 % set val 1 % while $val { if {$a > 0} { set val 0 puts $val } } 5 行目で「set val 0」を実行しても、while のあとの$val は「1」のままなので、「0」の出力が延々と続きます。 この無限ループを回避するためには、while の後ろの$val をブレス{ }で囲みます。 % set a 100 % set val 1 % while {$val} { if {$a > 0} { set val 0 puts $val } } このことによって、ブレス{ }内は、TCL パーサーによる変数置換が無効化され、while コマンドに$val という文字列 として渡されます。 while が 1 回目の処理を終え、2 回目の処理に入る際に$val が while コマンド内で再評価 (変数置換) されるの で、$val は「0」=偽となり、while 処理が終了します。 よって、このような無限ループを回避するためには、第 1 アーギュメントをブレス{ }で囲む必要があります。 17 for for ループは、while ループと似ていますが、ループに入る前の初期化(カウンタ用の変数の初期化を行なう)を含 む点が while ループとは異なります。 for {init} {test} {next} {body} (1) {init} ループに入る前に一度だけ実行される、「初期化」と呼ばれる処理です。 例: set i 1 最初だけ、変数 i に 1 をセットする。 (2) {test} 終了条件を判断するものです。 もし、test が真ならば、{body}の中が実行されます。test が偽ならループから抜け出します。 例: $i<=3 $i が 3 以下ならば、{body}を実行する。 (3) {next} {body}の中が実行された後で実行されるもので、一般的には増分を指定します。 例: incr i {body}の処理が終わったら、$i の値を 1 ずつ増やす。 % for {set i 1} {$i<=3} {incr i} { puts $i } → 出力結果は、1, 2, 3 です。 "for"の場合、{test}を for コマンドの内部で評価するように作られており、{init}および{next}はそれぞれ構文 で指定することから、全てをブレス{ }で囲む必要があります。 これらの理由から、if, while, for コマンドのアーギュメントは、常にブレス{ }で挟んでおくことで、不要なエラー を避けることができます。 18 3.10. if, else, elseif if, else, elseif を使って、複雑な条件分岐を行うことができます。 (1) サンプル 1 $var の値が 1 なら、変数 a に値 123 をセットします。 % set var □ % if {$var == 1} { set a 123 } ←□に、1 または 1 以外を入力 (2) サンプル 2 $var の値が 1 なら、変数 a に値 123 をセット、それ以外であれば変数 a に値 456 をセットします。 % set var □ % if {$var == 1} { set a 123 } else { set a 456 } ←□に、1 または 1 以外を入力 (3) サンプル 3 $var の値が 1 なら、変数 a に値 123 をセット、$var の値が 2 なら、変数 a に値 456 をセット、それ以外であれば変 数 a に値 777 をセットします。 % set var □ ←□に、1 または 1 以外を入力 % if {$var == 1} { set a 123 } elseif {$var == 2} { set a 456 } else { set a 777 } 19 3.11. switch switch コマンドは、複数の分岐条件の中から一致する条件を見つけ出し、そこに指定された処理を実行します。 switch コマンドは、以下のような構文になっています。 switch string { pattern1 {body-1} pattern2 {body-2} default {body-default} } switch コマンドは、最初のアーギュメント (String) を、後続のアーギュメント (pattern1, pattern2) と比較しま す。 string にマッチする pattern を見つけると、その pattern に続く body を TCL パーサーに渡し、その実行結果を返 します。 最後の pattern を"default"で指定すると、前行のどの pattern にもマッチしなかった場合に、default の body を実行します。 もし、どの pattern もマッチせず、"default"も設定していない場合、switch コマンドは、空の string を返します。 switch の基本サンプル % set fruit "Lemon" % switch $fruit { "Apple" {puts "RED"} "Grape" {puts "PURPLE"} "Lemon" {puts "YELLOW"} default {puts "What color is that fruit?"} } → 「YELLOW」が返されます。 switch のオプション Switch コマンドに続くアーギュメントが「-」(ハイフン)で始まっている場合は、オプションとして扱われます。 switch コマンドには、以下のようなオプションが用意されています; (1) -exact string と pattern の文字が一字一句完全に一致しなければなりません。これがデフォルトの動作です。 (2) -glob String と pattern を比較するときに、正規表現の glob スタイルを使います。 (3) -regexp String と pattern を比較するときに、正規表現が使われます。 20 [参考] glob と regexp の違い 正規表現には、glob スタイルと regexp スタイルがあり、両者の違いは以下の通りです。 glob のほうが比較的シンプルに作られています。 glob スタイル 0 文字以上の文字にマッチ 1 文字にマッチ * ? [chars] ¥x {a,b,...} chars の 1 文字にマッチ。 [a-z]などが使える 文字 x にマッチ a,b 等文字列にマッチ * . + ? ^ $ [chars] ¥x {a,b,...} exp1 | exp2 ( exp ) regexp スタイル 0 文字以上の文字にマッチ 1 文字にマッチ + 1 文字以上にマッチ 0 または 1 文字にマッチ 行の先頭にマッチ 行の最後にマッチ chars の 1 文字にマッチ。 [a-z]などが使える 文字 x にマッチ a,b 等文字列にマッチ 選択 部分パターン (その他、省略) switch の glob オプションの例 (1) "?"を使ってみる % set fruit "Lemon" % switch -glob $fruit { "Ap*" {puts "RED"} "Gr???" {puts "PURPLE"} "Le???" {puts "YELLOW"} ←Le に 3 文字続く必要があるが、どのような文字でもよい。 default {puts "What color is that fruit?"} } → 「YELLOW」 が返されます。 (2) [a-zA-Z]を使ってみる % set fruit "Lemon" % switch -glob $fruit { "Ap*" {puts "RED"} "Gr???" {puts "PURPLE"} "Lem[a-zA-Z][a-zA-Z]" {puts "YELLOW"} ←Lem に続く 2 文字が a~z か A~Z のいずれか。 default {puts "What color is that fruit?"} } → 「YELLOW」 が返されます。 21 3.12. 配列変数 TCL でも配列を扱うことができます。 TCL での配列変数は「変数名(添え字)」で表されます。 配列変数としての宣言や要素数の指定は必要なく、()が付いた変数に値がセットされるときに配列変数とし て認識・登録されます。 % set i 0 % while {$i < 3} { set abc($i) $i puts "abc($i) = $abc($i)" incr i } →出力結果は以下です。 abc(0) = 0 abc(1) = 1 abc(2) = 2 要素を , や . で区切って複数記述することによって、多次元配列を使用できます。 % set i 0 % set k 0 % while {$i < 3} { while {$k < 3} { set abc($i.$k) [expr $i+$k] puts "abc($i.$k) = $abc($i.$k)" incr k } incr i set k 0 } →出力結果は以下です。 abc(0.0) = 0 abc(0.1) = 1 abc(0.2) = 2 abc(1.0) = 1 abc(1.1) = 2 abc(1.2) = 3 abc(2.0) = 2 abc(2.1) = 3 abc(2.2) = 4 22 以下のように、同名の通常変数と配列変数を同一のスクリプト内で使用することはできません。 使うとエラーになります。 % set a 300 % set a(1) 400 can't set "a(1)": variable isn't array また、要素数は数字である必要は無く、文字列も使用できます。 % unset -nocomplain a % set a(jkl) 200 ← 一旦、変数"a"を削除。 ただし、利用の利便性を考えると数字を使用するのが一般的です。 23 3.13. 文字列操作 以下のコマンドで、文字列操作が行えます。 string (1) string compare string1 string2 文字列の比較を行います。 文字列 string1 と string2 を文字毎に比較して、-1、0、1 のいずれかを返します。 string1 と string2 等しければ 0 を返します。 辞書順で比較するので、 string1 の方が string2 よりも辞書順で前に出現する文字列なら「-1」を、 後で出現す る文字列なら「1」を返し、返します。 % string compare abc abc →「0」が返されます。 % string compare abc def →「-1」が返されます。 % string compare abc ABC →「1」が返されます。 (2) string toupper 小文字を大文字に変換します。 % string toupper AbCdEfgHiJkLmN →「ABCDEFGHIJKLMN」が返されます。 (3) string tolower 大文字を小文字に変換します。 % string tolower AbCdEfgHiJkLmN →「abcdefghijklmn」が返されます。 (4) string length 文字列の長さを返します。 % string length AbCdEfgHiJkLmN → 「14」が返されます。 24 split 文字列を、決められたデリミタで区切ったリストを返します。 % split "abcXdefXghiXjkl" X →「abc def ghi jkl」が返されます。 join リストを、決められたデリミタで文字列として結合して返します。 % join "abc def ghi jkl" # →「abc#def#ghi#jkl」が返されます。 append 既に存在する変数にデータを付け足す時に使います。 (Note: もし変数が存在していなければ、このコマンドが変数を作ります。) % set var 0 % for {set i 1} {$i<=10} {incr i} { append var "," $i } % puts $var → 「0,1,2,3,4,5,6,7,8,9,10」が返されます。 (変数の値を直接処理するコマンドなので、変数 var の前に$をつけません。) concat 各アーギュメントの先頭と末尾のスペースをカットし、全てのアーギュメントをスペースで連結します。 アーギュメントの個数はいくつでもかまいません。以下は 3 つのアーギュメントです。 % concat " a b {c " d " e} f " →「a b {c d e} f」が返されます。 25 3.14. リスト操作 以下のコマンドで、リスト(要素を並べたもの)の操作が行えます。 list 変数群$val1, $val2…を要素としたリストを返します。 list $val1 $val2 … % list AAAA BBBB "CCCC DDDD" EEE →「AAAA BBBB {CCCC DDDD} EEE」が返されます。 lindex リストから$index 番目の要素を取り出します。 lindex $list $index % set LIST [list AAAA BBBB "CCCC DDDD" EEE] % lindex $LIST 1 →「BBBB」が返されます。 llength リストの要素の数を返します。 llength $list % set LIST [list AAAA BBBB "CCCC DDDD" EEE] % llength $LIST →「4」が返されます。 lappend 変数に対してリスト要素の追加し、その結果のリストを返します。 lappend variable $var1 $var2… % set LIST [list AAAA BBBB "CCCC DDDD" EEE] % lappend LIST 111 222 333 → 「AAAA BBBB {CCCC DDDD} EEE 111 222 333」が返されます。 (変数の値を直接処理するコマンドなので、変数 LIST の前に$をつけません。) 26 linsert リストの$index 番目の要素の前に、要素$val1, $val2,…を挿入したリストを返します。 linsert $list $index $val1 $val2 … % set LIST [list AAAA BBBB "CCCC DDDD" EEE] % linsert $LIST 0 111 222 333 →「111 222 333 AAAA BBBB {CCCC DDDD} EEE」が返されます。 lrange リスト$list の$index_s 番目から$index_e 番目までの要素をリストとして返します。 最後までの場合は$last の中身を文字列 end にします。 lrange $list $index_s $index_e % set LIST [list AAAA BBBB "CCCC DDDD" EEE] % lrange $LIST 1 3 →「BBBB {CCCC DDDD} EEE」が返されます。 lreplace リスト$list の$s 番目から$e 番目までの連続した要素をすべての要素$val1, $val2,…で置き換え、新しいリス トを返します。 lreplace $list $s $e $val1 $val2… % set LIST [list AAAA BBBB "CCCC DDDD" EEE] % lreplace $LIST 1 3 QQQ PP →「AAAA QQQ PPP」が返されます。 lsearch リスト$list から、$sw で任意で与えられたパターンマッチング方式で、$pattern に合致する最初の要素のインデ ックスを返します。 $sw は-glob(方式)、 –exact(完全一致)、 –regexp(正表現)などが用意されます。 lsearch $sw $list $pattern % set LIST [list AAAA BBBB "CCCC DDDD" EEE] % lsearch -glob $LIST E?? →「3」が返されます。 27 lsort リスト$list の要素をソートしたリストを返します。 $switch には、-ascii(ASCII コード順)、-integer(数字順) などが用意されています。 lsort $switch $list % set LIST [list CCCC QQQQ 108Z AAAA LLLL 3333 5555 2222 4444 1111] % lsort -ascii $LIST →「1111 2222 3333 4444 5555 AAAA CCCC LLLL QQQQ 108Z」が返されます。 28 3.15. foreach foreach コマンドは、リストを使ったループです。 リストの要素を左から一つずつ変数に代入して、ループの処理を実行します。 書式は次のようになります。 foreach valName $list {body} $list から要素を一つずつ取り出し、変数 valName に順番に代入し、body を実行します。 この処理を要素数の分だけ繰り返し行います。 % set LIST [list AAAA BBBB "CCCC DDDD" EEE] % foreach item $LIST { puts "item is $item" } → 出力結果は以下です。 item item item item is is is is AAAA BBBB CCCC DDDD EEE 3.16. TCL のマニュアル TCL はこの他にも多数のコマンドを持っています。 また、コマンドによっては、ここに紹介したもの以外にも多数のオプションを持っているものがあります。 実際の TCL コマンド利用に際しては、以下リンクを参照して、より要件にあうコマンドやオプション指定がないかを確 認してください。 英語: http://www.tcl.tk/ 日本語: http://www.freesoftnet.co.jp/tclkits/doc/TclCmdRef/tcl_contents_jp.htm 29 4. iRules の概要 ここからは、iRules の特徴について解説します。 尚、iRules のより詳細な情報や多数のサンプルは F5 の DevCentral サイトに掲載していますので、必要に応じてこ ちらもご参照ください。 [DevCentral] https://devcentral.f5.com/wiki/iRules.HomePage.ashx 4.1. イベント EVENT は、F5 が追加した TCL 拡張です。 あるコネクションが TMOS に入力されてから出力されるまでの間に、BIG-IP 内部で、ある一連の複数の内部状態の 変化が発生します。 これらそれぞれの状態と、iRule の EVENT とが一致するように作られており、この EVENT が iRule を発動するトリガ ーになります。 例えば CLIENT_ACCEPTED は、どのような Profile が Virtual Servers に割当てられているかに関わらず、全ての TCP コネクションに対して利用することができます。 その他の状態(例:HTTP_REQUEST, CLIENTSSL_CLIENTCERT, RTSP_RESPONSE, ...)に達することができるのは、必 要な profile が Virtual Server に割当てられる場合に限られる場合もあります。 例えば HTTP_REQUEST イベントが利用できるのは、Virtual Server に HTTP Profile が割り当てられている場合に 限られます。 Event は、f5 が独自に追加した「when」ステートメントを使って、以下のような形で宣言されます。 when EVENT 名 { TCL コード } EVENT 名で指定されたイベントが発動すると、そこに指定された TCL コードだけが実行されるので、このイ ベントを内部ステートの一連の流れ通りに記載する必要はなく、順番が異なってもかまいません。 よく使うイベント: イベント CLIENT_ACCEPTED CLIENT_DATA HTTP_REQUEST HTTP_RESPONSE RULE_INIT LB_FAILED 概要 クライアントがコネクションを確立したときにトリガーされる。 コネクションが TCP::collecct(TCP データを取得する)状態にあるとき、クライアントから新し いデータを受け取るたびにトリガーされる。 クライアントからの HTTP リクエストヘッダを解析できる状態(HTTP Profile が有効になってい る状態)にあって、HTTP リクエストを受信したときにトリガーされる。 サーバからの HTTP レスポンスのステータス及びヘッダを解析できる状態(HTTP Profile が有効 になっている状態)にあって、サーバからの HTTP レスポンスを受信したときにトリガーされ る。 iRule が追加されたとき、または変更されたときにトリガーされる。 pool または pool member の選択に失敗したときにトリガーされる。または選択した node,pool member に到達できないときにもトリガーされる。 これらの EVENT については、iRule の具体例のセクションにて、サンプルを使って説明します。 30 4.2. 変数 (variables) について 変数には大きく、以下の 3 つのタイプがあります。 ① ローカル変数 ② グローバル変数 ③ コネクション間で読み書き可能な変数 ローカル変数 (Local variables) ローカル変数は、iRule 内だけで有効な変数です。 すべての iRules はセッション毎に動作するので、ローカル変数もまた同じくセッション毎に有効です。 よって、あるセッションに与えられた iRules のローカル変数やデータに対してのメモリ領域は、そのセッションによっ て決定されることを意味しています。 例えば、コネクション 1 が BIG-IP に到達し、ある iRule が実行され、5 つのローカル変数が生成されたとします。 これらの変数は、そのコネクションが閉じられるまでの間だけしか存続しません。 コネクションが閉じられた後、そのコネクションに割当てられたメモリは解放され、iRule がそのコネクションのために 生成した 5 つのローカル変数は使えなくなります。 このように、ローカル変数は、コネクション(またはセッション)が終了すればメモリは自動的に解放されるので、メモリ 管理を気にする必要はありません。 ローカル変数の使い方は、「TCL の基礎」の説明に何度も出現した方法と同じです。 例:HTTP リクエストの Host ヘッダ値を取り出してログに出力。 when HTTP_REQUEST { set host [HTTP::host] log "HOST header of HTTP Request is $host" } 逆に、複数の iRules で同じ変数を共用したい場合、ローカル変数は使えません。 その場合は、以降で紹介するグローバル変数または table コマンドによる変数を使います。 31 グローバル変数 (Global variables) グローバル変数は、各 iRules が共通で利用できる変数です。 例えば、複数の iRules を設定する予定があり、それら全ての iRules のログは共通のロギングサーバへ出力した い、という要件があるとします。 一つ一つの iRule にそのロギングサーバの IP アドレスを設定していくのは非効率なので、全 iRules で共有できる 変数にその IP アドレスを持たせて、その変数を利用したい、というような要望はあると思います。 このような要件を解決するのがグローバル変数です。 TCL 自身にもグローバル変数は用意されていますが、TCL のグローバル変数を使うためには、各 CPU コアが利用で きる共有メモリに保存する必要があります。 しかし、BIG-IP は、CMP(Clusterd Multi Processing)テクノロジーを使っています。 sol14358: Overview of Clustered Multiprocessing (11.3.0 and later) http://support.f5.com/kb/en-us/solutions/public/14000/300/sol14358.html CMP は、複数の CPU コアにタスクを分配してスケールすることを可能にするテクノロジーであり、それぞれの CPU コア が独立したメモリを持っています。 CMP では各 CPU コア同士が使える共有メモリを持たないので、TCL のグローバル変数を使うとなると、CMP を無効化 し、シングルコアで処理する必要があります。これはパフォーマンスの妨げとなります。 そこで、F5 は「static::」ネームスペースと呼ばれる新しいネームスペースを用意しています。 このことによって、CMP を無効化しない=パフォーマンスを犠牲にしないで、グローバル変数を利用することが可能に なります。 RULE_INIT イベントの中で、「static::変数名」 として設定することで、ロードの際に各 CPU 用のメモリ領域に読み 込まれ、変数として利用することができます。 この変数は、コンフィグが再読み込みされるまで消えません。 例: RULE_INIT で、コンフィグをリロードまで存続する Static 変数に Syslog サーバの IP アドレスを設定。 その Static 変数を iRule 内で利用して、その Syslog サーバへログを出力する。 when RULE_INIT { set static::logserver "10.10.1.145" } when HTTP_REQUEST { log $static::logserver "Got HTTP Request now." } [Tips] 実は、Static::変数で指定された Global 変数の値は、RULE_INIT の外であっても、set コマンドを使うことで書き 換えることができてしまいます。 しかし、この書き換えられた値は、その書換えが実行された TMM 内だけで有効であり、他 TMM へ伝播されないので、 TMM 間で不整合が起きた状態になってしまい、期待する動作が得られない場合が考えられます。 よって、F5 では、RULE_INIT の外での Static::変数の書換えは行わないことを強く推奨しています。 sol13033: Constructing CMP-compatible iRules http://support.f5.com/kb/en-us/solutions/public/13000/000/sol13033.html TMM 間で共有する必要のある変数で書換えを行いたい場合には、以下の table コマンドの利用を推奨します。 32 iRules 間で読み書き可能な変数:Table コマンド Table は、読み書き可能なメモリ構造であり、コネクション間で共有できる、というのが特徴的です。 iRules のローカル変数のような、コネクション毎にしか利用できないものとは違い、Table には持続する必要がある データを格納できる、という特徴があります。 Table には、key:value (変数:値) という複数のレコードを、リストとして保存することができます。 また sub tables という機能を使うことで、1 つのフラットなリストを作るだけでなく、名前つきのリストを個別に作るこ とができるので、その名前ごとにデータを分離することができます。 さらに、コンフィグ可能な timeout と lifetime オプションがあり、これらによって、メモリ管理または Table をプログ ラム的にクリーンアップする心配は必要なくなります。 timeout: lifetime: レコードの最終更新からの秒数。アイドルタイムアウト的。 レコードが作成されてからの秒数。更新されたかどうかは関係ない。 ------- <Session コマンドについて> ------Table コマンドがリリースされる以前(v10.1 より前)から、同様の動作を行う Session コマンドが存在しています。 Table コマンドは、この Session コマンドの使い難さを改善することを目的としてリリースされました。 Session コマンドは、以下のようなシンタックスになっています。 session add <mode> <key> <data> [<timeout>] session lookup <mode> <key> session delete <mode> <key> <mode>については、v10 以降は実質的な意味を持っておらず、"uie"という値だけが使われます。 また、<key>については、以下のようなやや奇妙なシンタックスになっていますが、v10 からは key がこのような形に なっている意味はありません。 session add uie "$key any pool any virtual" $data 180 session lookup uie "$key any pool" session delete uie "$key" 古くから iRules に親しみのあるユーザでなければ、「uie って何?」、「なぜ、key に Pool を指定するの?」となって しまうと思います。 そもそも session というコマンド名が、「session とどのように関係しているの?」と思ってしまうので、混乱を招きや すいネーミングであることも否めません。 このような使い難さを改善するために、v10.1 で Table コマンドがリリースされました。 ---------------------------------------Table は、以下のようなシンタックスになっています。 table set $key $data 180 table lookup $key table delete $key Table については、iRule の具体例のセクションにて、サンプルを使って説明します。 33 iRules の変数一覧 iRules で利用可能な変数の一覧です。 これらのうち、本ガイドの具体例では、推奨フィールドに○がついた変数のみ利用します。 推奨 変数 × Global TCL 形式 ○ ○ Global static:: Local △ session ○ Table CMP 対応 × 設定 (生成、読出し、削除) set ::<key> <value> $::<key> unset ::<key> ○ set static::<key> <value> $static::<key> ○ set <key> <value> $key unset <key> ×:v 9.0 session add uie <key> <value> ○:v10.0 session lookup uie <key> session delete uid <key> ○ table set <key> <value> table lookup <key> table delete <key> 34 変数の解除 Unset コマンド Standby 最小 への Mirror Version × v9.0 できない。 ○ v9.7 1)Unset コマンド 2)コネクションの終了 × v9.0 1)Timeout 2)session delete コマンド ○ v9.0 1)Timeout 2)table delete コマンド ○ v10.1 4.3. 演算子 ( Operators ) iRules では、演算子(Operators)は 2 つの値を比較したい場合によく利用されます。 TCL が標準で持つ演算子(==, <=, >=, ...)に加えて、F5 は、starts_with, contains, ends_with のような比 較補助のための演算子を追加しています。 演算子 "A" contains "B" "A" ends_with "B" "A" equals "B" "A" matches_glob "B" "A" matches_regex "B" "A" starts_with "B" "A" and "B" "A" not "B" "A" or "B" 解説 "A"文字列が、"B"文字列を含むかどうか "A"文字列が、"B"文字列で終わるかどうか "A"文字列と"B"文字列が一致するかどうか "A"文字列と"B"文字列が glob 形式での比較で一致するかどうか "A"文字列と"B"文字列が regex 形式での比較で一致するかどうか "A"文字列が、"B"文字列で始まるかどうか "A"と"B"の値を、AND 条件で評価する (例: "A"と"B"の両方が真ならば、次のアクション) "A"と"B"の値を、NOT 条件で評価する (例: "A"と"B"の値が異なるのならば、次のアクション) "A"と"B"の値を、OR 条件で評価する (例: "A"または"B"の値が真ならば、次のアクション) 35 4.4. ファンクション ファンクション(Functions)は、検索した結果の値を返すのに役立つコマンドです。 大きく、以下 2 つに分類されます。 (1) Class ファンクション 事前に作成した key:value タイプのデータベースから情報を検索して値を戻します。 Class については、後述します。 (2) 文字列ファンクション ある文字列から値を返す操作を行います。 F5 では、以下のような独自の文字列ファンクションを用意しています。 ファンクション findstr 解説 findstr <string> <search_string> [<skip_count> [<terminator count or string>]] substr <string>の文字列から、<search_string>の文字を見つけ出し、見つけ出した文字の先 頭から<skip_count>分オフセットしたところを始点とした文字を返す。 また、<terminator count or string>を指定すると、その手前までの文字を返す。 例: findstr www.sub.my.domain.com sub 7 .com 結果: domain substr <string> <skip_count> [<terminator>] getfield <string>の文字列の先頭から<skip_count>で指定した文字数分をスキップし、 <terminator>で指定した文字で終わるまでの文字を返す。 例: substr www.sub.my.domain.com 11 .com 結果: domain getfield <string> <split> <field_number> domain <string>の文字列を、<split>で指定した文字で分割し、<field_number>で指定したフ ィールドの文字を返す。 例: getfield www.sub.my.domain.com . 4 結果: domain domain <string> <count> "."で区切られたドメイン名:<string>を"."単位で区切って、<count>指定した数の後 ろからの区切り数分の文字を返す。 例: domain www.sub.my.domain.com 2 結果: domain.com 36 4.5. ステートメント ステートメント (Statements) は一般的には「何かを実行する」ものであり、値を戻さないコマンドです。 例えば TCL では、条件分岐を行う「if」、「switch」、「while」、「for」などがステートメントに該当します。 f5 では独自に、以下のようなステートメントを用意しています。 ステートメント when log pool 解説 iRule のイベントを指定する場合に使う。 syslog-ng ユーティリティへ、ログを出力する。 モニターステータスに関わらず、指定した Pool へロードバランスまたは Pool Member へ トラフィックを送る。 node 指定されたサーバノードへ直接トラフィックを送る。 persist 指定したパーシステンスを使う。 snat 指定した変換アドレスを、コネクションの送信元 IP アドレスに割当てる。 snatpool 指定した SNAT Pool 内の IP アドレスのいずれかを、コネクションの送信元 IP アドレス に割当てる。また、SNAT Pool 内の member を指定することもできる。 discard コネクションやパケットを Drop/Disacard する。drop コマンドと同じ。 drop コネクションやパケットを Drop/Disacard する。discard コマンドと同じ。 reject コネクションをリジェクトする(TCP RST を返す)。 forward LTM のルーティングテーブルにしたがって、パケットを転送する。 nexthop BIG-IP からサーバ側への Nexthop を指定する。 lasthop クライアントへパケットを戻す際の lasthop(MAC または IP アドレス)を指定する。 rateclass パケット転送時に、指定した Rate Class を使う。 clone モニターステータスに関係なく、指定した Pool または Pool Member にトラフィックをク ローン(コピー)する。 event このコネクションで、ある iRule イベント(または全ての iRule イベント)の評価を有効 化/無効化する。 clientside 指定した iRule コマンドを、BIG-IP から見てクライアント側の情報(IP アドレス/ポート 番号等)に基づいて実行する。 serverside 指定した iRule コマンドを、BIG-IP から見てクライアント側の情報(IP アドレス/ポート 番号等)に基づいて実行する。 peer コンテキストの反対側(サーバ側ならクライアント側、またはその逆)で指定された iRule コマンドを実行する。 (↓例外的に値を返すもの) TCL_platform プラットフォームの情報(OS Version など)を返す。 cpu あるインターバルにおける TMM CPU の平均負荷値を返す。 37 4.6. コマンド Commands は、TCL 内で利用できる制御構造です。 例えば、HTTP::uri を使うことで HTTP リクエストの URI を取得できますし、AES::encrypt によって AES 鍵を使って 暗号化を実行する、というようなことが可能です。 標準 TCL のコマンドセットに加えて、F5 はグローバルな範囲で使えるコマンド(TCP::client_port, IP::addr など) や、特定の Profile で使えるコマンド(HTTP::uri,SSL::sessionid 等)を追加しています。 出現頻度の高いコマンド かなり多くのコマンドが存在しますので、ここでは、以降のサンプルで現れるコマンド及び比較的出現頻度の高いコ マンドについて紹介します。 (1) IP IP IP::client_addr IP::server_addr IP::remote_addr IP::local_addr IP::addr 概要 クライアント IP アドレスを返す。 サーバの IP アドレスを返す。 BIG-IP から見てリモートの IP アドレスを返す。 (クライアント IP の場合もあれば、サーバ IP の場合もある。) クライアントまたはサーバから接続される、BIG-IP が持つ IP アドレス(Virtual Server の IP または Self-IP)を返す。 または、サーバ側では、クライアント IP を SNAT 変換しないで出力する場合はその アドレスを、SNAT する場合には SNAT アドレスが該当する。 IP アドレス/サブネット と IP アドレス/サブネットの比較を行い、真偽を返す。 例:[IP::addr [IP::client_addr]/8 equals 10.0.0.0] (2) TCP TCP TCP::client_port TCP::server_port TCP::local_port TCP::remote_port TCP::collect TCP::payload TCP::release TCP::bandwidth TCP::respond TCP::close 概要 クライアント側の TCP コネクションの、クライアント PC のポート番号を返す。 サーバ側の TCP コネクションの、サーバの TCP ポート番号を返す。 TCP コネクションの、BIG-IP 側の TCP ポート番号を返す。 クライアント/サーバ側両方の、BIG-IP から見てリモートの TCP ポート番号を返 す。 指定したバイト数のコンテンツデータを収集する。 TCP::collect 取得した TCP データコンテンツを変更 or 返す。 TCP::collect で収集したデータを消去&リリースし、処理を再開する。 対向端との帯域幅を返す。 対向端へ、特定データを直接送る。 TCP コネクションを閉じる。 (3) HTTP HTTP HTTP::request HTTP::header HTTP::uri HTTP::host HTTP::cookie 概要 HTTP リクエストのヘッダを全て返す。 HTTP ヘッダのいずれかを指定し、その値を取得または変更する。 HTTP リクエストの URI 部分を返す or セットする。 例:http://www.example.com:8080/main/index.jsp?user=test&login=check URI は「/main/index.jsp?user=test&login=check」 HTTP ホストヘッダの値を返す。 HTTP リクエスト及びレスポンスに対して、Cookie の挿入、削除、値の取得といっ た操作を行う。 Usage 例: HTTP::cookie namesTLC の List 形式で、HTTP ヘッダ内にある全 Cookie 名を返す。 HTTP::cookie insert name <name> value <value> <name>と<vaule>の組合せの Cookie を挿入する 38 HTTP::path HTTP::query HTTP::collect HTTP::release HTTP::payload HTTP::redirect HTTP::respond HTTP::status (4) AES AES AES::key AES::decrypt AES::encrypt HTTP リクエストの Path 部分を返す or セットする。 ("?"以降のクエリ文字列は含まない。) 例:http://www.example.com:8080/main/index.jsp?user=test&login=check Path は「/main/index.jsp」 HTTP リクエストのクエリ文字列部分を返す。 例:http://www.example.com:8080/main/index.jsp?user=test&login=check Query は「user=test&login=check」 HTTP ボディデータの、指定したバイト数分を収集する。 HTTP::collect で集めたデータをリリースする。 Queries for or manipulates HTTP payload information. HTTP ペイロード情報の要求 or ペイロード情報を操作する。 Usage 例: HTTP::payload <length> HTTP::collect コマンドが収集したコンテンツを、指定 した byte 数分返す。 HTTP::payload length HTTP::collect コマンドが収集したコンテンツの長さを返 す。 HTTP リクエストを受けたとき、またはレスポンスを返すときに、指定した URL へリ ダイレクトさせる。 まるでサーバからレスポンスが来たかのように、HTTP レスポンスを生成してクライ アントに返す。 HTTP レスポンスのステータスコードを返す。 概要 データを暗号化/複合化するための AES Key を生成する。 事前に生成された AES Key を使ってデータを複合化する。 事前に生成された AES Key を使ってデータを暗号化する。 (5) LB LB LB::detach LB::down LB::mode LB::persist LB::reselect LB::select LB::server LB::snat LB::status LB::up 概要 サーバ側コネクションを切断する。 node または pool member のステータスを Down 状態にセットする。 ロードバランシングモードをセットする。 パーシステンスレコードの検索を強制し、結果を返す。 ロードバランシング先を再選択する。 ロードバランシングセレクションを強制し、結果を返す。 今選ばれたサーバについての情報を返す。 Virtual Server の SNAT コンフィグレーションについての情報を返す。 node アドレスまたは pool member のステータスを返す。 node または pool member のステータスを Up 状態にする。 39 コマンドの注意点 コマンドについての注意点について触れておきます。 (1) コマンド毎に利用できる Event と利用できない Event が存在 コマンドによって、どの Event 内なら利用できるかが決まっています。 例) 以下は DevCentral 上の「HTTP::url」のマニュアル画面です。 https://devcentral.f5.com/wiki/iRules.HTTP__uri.ashx ~略~ 利用できる Event この「HTTP::uri」コマンドは、上記の「Valid Events:」に記載された Event 内だけで有効であり、これら以外の Event では利用できません。 利用したいコマンドが、利用したい Event との組合せで利用できるかどうかが明確ではない場合には、DevCentral のマニュアルを参照して確認してください。 https://devcentral.f5.com/wiki/iRules.Commands.ashx (2) 無効化された TCL コマンド TCL 言語が標準で持っているいくつかの Commands は、iRules 実装の中では無効にされています。 一般的に、トラフィックフローの中で予期しない停止を引き起こす可能性のあるコマンド(例:file IO、socket call 等)が取り除かれています。 利用できない TCL コマンドについては、以下を参照ください。 https://devcentral.f5.com/wiki/iRules.DisabledTclCommands.ashx 40 5. iRules 動作確認用のネットワーク構成サンプル 以下のネットワーク構成を使って、以降のセクションで紹介する iRules の動作を確認します。 web-vs/secure-vs ともに、デフォルトの Pool は、http-pool(10.99.100.216)として設定します。 A-pool、B-pool も設定しておきます。VS との紐付けは行いません。 Node(10.99.100.211,10.99.100.213)は、LTM 上での設定は不要ですが、サンプル iRule で利用します。 41 6. LTM の設定 LTM 設定のより詳細は、「LTM かんたんセットアップガイド」を参照ください。 ここでは、以降の iRule サンプルを動作させるために必要な LTM の設定箇所を示します。 6.1. Platform 設定 以下は、初期ウィザードの流れの中で設定します。 設定した内容は、「System」→「Platform」で確認できます。 ホスト名。FQDN 形式で指定。 Asia/Tokyo を選択。 CLI アクセス用 root アカウントの パスワード WebUI アクセス用 admin アカウントの パスワード 6.2. VLAN 設定 「Network」→「VLANs」で、以下の状態になるように設定します。 42 6.3. Self IP 設定 「Network」→「Self IPs」で、以下の状態になるように設定します。 6.4. Routing 設定 「Network」→「Routes」で、以下の状態になるように設定します。 43 6.5. Pool の設定 「Local Traffic」→「Pools」で設定します。 http-pool 任意の名前を入力。 ヘルスモニター(http)を設定。 Pool Member のアドレスと Port 番号を 入力して、「Add」ボタンを押す。 44 A-pool 任意の名前を入力。 ヘルスモニター(http)を設定。 Pool Member のアドレスと Port 番号を 入力して、「Add」ボタンを押す。 B-pool 任意の名前を入力。 ヘルスモニター(http)を設定。 Pool Member のアドレスと Port 番号を 入力して、「Add」ボタンを押す。 45 6.6. Virtual Server の設定 Web-vs (Port:80) 任意の名前を入力。 IP アドレスとポート番号を入力。 HTTP Profile を選択。 環境に応じて設定。 ~略~ 設定済みの「http-pool」を選択。 46 Secure-vs (Port:443) 任意の名前を入力。 IP アドレスとポート番号を入力。 HTTP Profile を選択。 本ガイドでは簡易的に、 デフォルトで用意されている、 clientssl を選択。 環境に応じて設定。 ~略~ 設定済みの「http-pool」を選択。 47 7. iRules の使い方 iRules の設定方法に慣れるために、簡易的に以下のような iRule を設定してみます。 「HTTP リクエストに含まれる User-Agent ヘッダ情報をログへ出力する」 具体的には、2 つのブラウザ:「Internet Explorer」 と 「Firefox」を使って Virtual Server にアクセスし、それ らのブラウザの User-Agent ヘッダの情報が BIG-IP 内部へログが出力されることを確認します。 iRules の作成方法には、大きく以下の 2 パターンがあります。 7.1. [パターン 1] iRule Editor を使う iRule Editor は、DevCentral から無償でダウンロードできるエディタです。 iRule Editor のダウンロード用リンク: https://devcentral.f5.com/d/tag/irules%20editor このエディタは、iRule の構文チェック、コマンドの補完、コマンドをクリックすることで DevCentral のオンラインマニ ュアルページへアクセスしてくれるなど、iRules 作成のための支援機能を備えたエディタです。 BIG-IP の Web-GUI からも iRule 作成は可能ですが、このエディタを使うほうが iRule は作りやすいと思います。 本エディタは、不定期に Version Up がなされるので、できるだけ最新版をご利用ください。 (1) PC で、iRule Editor を起動し、以下の赤点線部分をクリックします。 (2) 以下のように値を入力し、OK を押します。 ① BIG-IP のマネージメント IP を入力。 ③ OK をクリック。 ② Admin のパスワードを入力。 48 (3) 以下の赤点線部分をクリックします。 (4) iRule の名前を入力します。 iRule の名称(任意)を入力。 (5) User-Agent を、ログファイルへ出力する iRule を入力します。 設定後、save ボタンを押します。 Save ボタン 上記の iRule: when HTTP_REQUEST { log local0. "USER-AGENT is [string tolower [HTTP::header "User-Agent"]]" } 49 7.2. [パターン 2] BIG-IP の Web GUI を使う BIG-IP の Web GUI インタフェースから直接 iRule を作成・編集することも可能です。 「Local Traffic」→「iRules」で表示された画面右上の「Create」ボタンを押して表示された画面で、以下のように設 定します。 iRule の名称(任意)を入力。 iRule を入力。 50 iRule の適用 作成した iRule を Virtual Server へ適用します。 (1) 「Local Traffic」 → 「Virtual Server」で表示された設定済みの Virtual Server:Web-vs を選択し、画面の 上に表示された「Resources」タブをクリックします。 iRules の部分の「Manage」ボタンを押します。 (2) 作成した iRule を選択し、「<<」ボタンを押します。 (3) 以下の状態になります。 51 出力されるログの確認 iRule で出力されるログは、以下の手順で BIG-IP に SSH でアクセスし、コマンドラインで確認します。 (1) 以下のコマンドを実行します。 [root@big208:Active:In Sync] config #tail –f /var/log/ltm (2) iRule を設定した Virutal Server へ、クライアント PC から、以下の 2 つのブラウザを使ってアクセスしてみま す。 ① FireFox ② Internet Explorer (3) /var/log/ltm に、以下のようなログが出力されます。 ① Firefox Aug 26 03:04:05 big208 info tmm1[11991]: Rule /Common/User-Agent_check <HTTP_REQUEST>: is mozilla/5.0 (windows nt 6.1; rv:30.0) gecko/20100101 firefox/30.0 USER-AGENT ② Internet Explorer Aug 26 03:04:21 big208 info tmm3[11991]: Rule /Common/User-Agent_check <HTTP_REQUEST>: is mozilla/5.0 (windows nt 6.1; trident/7.0; rv:11.0) like gecko 以上が、iRule の基本的な使い方です。 52 USER-AGENT 8. iRules の具体例 具体的な iRule のサンプルを紹介します。 8.1. よく使う EVENT の例 iRule には多くのイベントが存在しますが、このセクションでは、よく利用するイベントを使ったサンプルを紹介しま す。 尚、EVENT 発動のタイミングの詳細は Appendix に記載しましたので、必要に応じて参照ください。 CLIENT_ACCEPTED あるエントリが、BIG-IP のコネクションテーブルに挿入されたときに、このイベントが発動します。 TCP の場合は、3WAY ハンドシェーク完了時に発動します。 (1) サンプル iRule の動作概要 以下のサンプルは、クライアントと BIG-IP の間で TCP コネクションが確立された時刻をログ出力する、というもので す。 No. サンプル iRule ・① ・② ・③ ・④ when CLIENT_ACCEPTED { set curtime [clock seconds] set formattedtime [clock format $curtime -format {%H:%M:%S} ] log "the time is: $formattedtime" } ① ② ③ ④ TCP 3WAY ハンドシェークが完了したとき、 その時刻を変数にセットし、 時刻のフォーマットを人が読み取りやすい形に整形し、 それをログとして出力する。 (2) この iRule を web-vs に適用してください。(「iRule の使い方」のセクションを参照) (3) /var/log/ltm へ出力されるログが確認できる状態にしてください。(「iRule の使い方」のセクションを参照) (4) クライアントから web-vs(http://10.99.1.108)へブラウザでアクセスしてください。 (5) ブラウザと BIG-IP の間で確立される TCP コネクション数分のログが出力されます。 例: May the May the 18 18:42:44 big208 info tmm[13467]: 01220002:6: Rule /Common/current_time <CLIENT_ACCEPTED>: time is: 18:42:44 18 18:42:44 big208 info tmm1[13467]: 01220002:6: Rule /Common/current_time <CLIENT_ACCEPTED>: time is: 18:42:44 [参考] UDP の場合は、TCP のようなハンドシェークは存在しないので、コネクションテーブルにエントリされたタイミングで発 動され、その UDP のエントリは、アイドルタイムアウトになる(デフォルト 60 秒)まで存続し続けます。 よって、タイムアウトまでの間にそのエントリと同じ情報を持つ UDP パケットが到達しても、このイベントは新規と見な されないため、発動しません。 53 CLIENT_DATA ある TCP コネクションが TCP::collect の状態にあるとき、クライアントから新しいデータを受け取るたびにこの CLIENT_DATA イベントが発動します。 (1) サンプル iRule の動作概要 以下のサンプルは、Web ブラウザの種類に応じて、振り分ける Pool を変える、というものです。 具体的には、Firefox なら A-Pool、それ以外なら B-Pool という振り分けにしています。 No. サンプル iRule ・① ・② when CLIENT_ACCEPTED { TCP::collect } when CLIENT_DATA { if { [TCP::payload] contains " Firefox" } { log local0. "PAYLOAD is [TCP::payload]" pool A-pool } else { pool B-pool } TCP::release } ・③ ・④ ・⑤ ・⑥ ・⑦ ・⑧ ・⑨ ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ 3WAY ハンドシェークが完了したとき、 その TCP データを収集する。 ②で TCP データを受け取ったので、このイベントが発動。 そのデータ(Payload)が Firefox を含んでいたら、 その Payload 部分をログ出力し、 A-Pool に送る。 それ以外は、 B-Pool に送る。 そして、取得した TCP データを開放する。 (2) この iRule を web-vs に適用してください。(「iRule の使い方」のセクションを参照) (3) /var/log/ltm へ出力されるログが確認できる状態にしてください。(「iRule の使い方」のセクションを参照) (4) クライアントから web-vs(http://10.99.1.108)へ Firefox ブラウザでアクセスしてください。 → "A-pool"からのレスポンスを受け取ります。 (5) クライアントから web-vs(http://10.99.1.108)へ Internet Explorer ブラウザでアクセスしてください。 → "B-pool"からのレスポンスを受け取ります。 [参考] UDP の場合は、UDP セグメントを受け取るたびに発動します。 また、UDP の場合は TCP のような collect コマンドによるデータ取得は必要ありません。 54 HTTP_REQUEST HTTP リクエストを受け取ったときに発動します。 (1) サンプル iRule の動作概要 以下のサンプルは、URI に応じて、SSL の Virtual Server へリダイレクトする、というものです。 具体的には、"secure"という URI の場合に、HTTPS の VS にリダイレクトさせます。 No. サンプル iRule ・① ・② ・③ ・④ when HTTP_REQUEST { if { [HTTP::uri] contains "secure"} { log local0. "URI is [HTTP::uri]" HTTP::redirect https://[HTTP::host] } } ① ② ③ ④ HTTP リクエストを受け取ったとき、 URI が"secure"の文字を含んでいたら、 URI をログ出力し、 SSL の Virtual Server(HTTPS)へリダイレクトさせる。 (2) この iRule を web-vs に適用してください。(「iRule の使い方」のセクションを参照) (3) /var/log/ltm へ出力されるログが確認できる状態にしてください。(「iRule の使い方」のセクションを参照) (4) クライアントのブラウザから web-vs へ、「http://10.99.1.108/secure」でアクセスしてください。 (5) 「https://10.99.1.108」へリダイレクトされます。 55 HTTP_RESPONSE HTTP レスポンスを受け取ったときに発動します。 (1) サンプル iRule の動作概要 以下のサンプルは、レスポンスのステータスコードが 404 なら、クライアントとの TCP コネクションを切断する、というも のです。 No. サンプル iRule ・① ・② ・③ ・④ ・⑤ when HTTP_RESPONSE { if { [HTTP::status] == 404 } { log local0. "HTTP Status is [HTTP::status]" HTTP::collect reject } } ① ② ③ ④ ⑤ HTTP レスポンスを受け取ったとき、 HTTP のステータスコードが 404(Not Found)だったら、 そのステータスコードをログ出力し、 HTTP データを収集※して、 TCP を切断する。 [※Tips] このイベントの中で HTTP::collect を使わないで reject コマンドを使った場合には、BIG-IP はサーバが生成した HTTP ヘッダをクライアントに送ってから、TCP リセットを送ります。 HTTP ヘッダを送らずに TCP リセットを送りたい場合には、reject コマンドの前に HTTP::collect が必要です。 HTTP::collect がなくても、結果は同じように見えます。 しかし、例えば、404 で返される HTTP リクエストヘッダの中に、攻撃者が攻撃を成立させるための手がかりになる情 報が入っているかもしれません。そのような場合に備え、404 レスポンスの場合にはクライアントに何も返さない、という ことを想定した iRule になっています。 (2) まず、この iRule を適用する前に、クライアントのブラウザから web-vs へ、「http://10.99.1.108/XXX」 (存在し ない URI)でアクセスして、ブラウザ上に「404」の表示があることを確認してください。 例:IE の場合 (3) この iRule を web-vs に適用してください。(「iRule の使い方」のセクションを参照) (4) /var/log/ltm へ出力されるログが確認できる状態にしてください。(「iRule の使い方」のセクションを参照) (5) クライアントのブラウザを再起動してから、再度 web-vs へ、「http://10.99.1.108/XXX」(存在しない URI)でアク セスしてください。 (6) 今度はブラウザの画面上に「404」の表示が無い状態で切断されます。 56 RULE_INIT このイベントは、iRules の中で使われる static 変数を初期化するために使います。 この RULE_INIT で指定した変数は、全ての Virtual Server で共通で利用できます。 このイベントは、以下の状態の時に発動します。 このイベントを使った iRule が save されたとき デバイスが起動したとき ソフトウェアが再起動されたとき (1) サンプル iRule の動作概要 以下のサンプルは、サーバから発行された Cookie(平文)を、クライアントと BIG-IP の間は暗号化する、というもの です。 本ガイドで使っている Web サーバの Cookie 変数名は"SESSION"です。環境に応じて変更してください。 No. サンプル iRule ・① ・② when RULE_INIT { set static::key [AES::key 256] } ・③ ・④ ・⑤ ・⑥ ・⑦ ・⑧ ・⑨ when HTTP_RESPONSE { if {[HTTP::cookie exists "SESSION"]} { set decrypted [HTTP::cookie "SESSION"] HTTP::cookie remove "SESSION" set encrypted [b64encode [AES::encrypt $static::key $decrypted]] HTTP::cookie insert name "SESSION" value $encrypted log local0. "DEC=$decrypted , ENC=$encrypted" } } ・⑩ ・⑪ ・⑫ ・⑬ ・⑭ ・⑮ ・⑯ when HTTP_REQUEST { if {[HTTP::cookie exists "SESSION"]} { set encrypted [HTTP::cookie "SESSION"] HTTP::cookie remove "SESSION" set decrypted [AES::decrypt $static::key [b64decode $encrypted]] HTTP::cookie insert name "SESSION" value $decrypted log local0. "DEC=$decrypted , ENC=$encrypted" } } 57 ① この iRule が save されたとき、 ② 256bit の AES 鍵を変数(static::key)に入れる。 ③ ④ ⑤ ⑥ ⑦ HTTP レスポンスを受信したとき、 もし、SESSION という名前の Cookie が存在していたら、 変数:decrypted にその Cookie の値を入れ、 一旦、その Cookie(SESSION)を削除する。 $decrypted に入った Cookie 値を、$static::key の AES 鍵で暗号化&base64 に変換し、変数:encrypted に 入れる。 ⑧ 暗号化したその Cookie 値($encrypted)を、SESSION という名の Cookie として HTTP レスポンスに付け加える。 ⑨ 暗号前の値および暗号後の値をログ出力する。 ⑩ ⑪ ⑫ ⑬ ⑭ HTTP リクエストを受信したとき、 もし、SESSION という名前の Cookie が存在していたら、 変数:encrypted にその Cookie の値を入れ、 一旦、その Cookie(SESSION)を削除する。 $encrypted に入った Cookie 値を、base64 でデコード$static::key の AES 鍵で複合化し、変数:decrypted に入れる。 ⑮ 複合化したその Cookie 値($decrypted)を、SESSION という名の Cookie として HTTP レスポンスに付け加える。 ⑯ 複合後の値および複合前の値をログ出力する。 (2) この iRule を web-vs に適用してください。(「iRule の使い方」のセクションを参照) (3) /var/log/ltm へ出力されるログが確認できる状態にしてください。(「iRule の使い方」のセクションを参照) (4) Web ブラウザから web-vs(http://10.99.1.108)に初めてアクセスします。 もし、以下の Error に遭遇したら、一旦 Web ブラウザを再起動して、アクセスし直して下さい。 この Error は、Web ブラウザが始めてこの Web ページにアクセスするのではなく、以前に既にアクセスしたことが あって、そのときの「暗号化されてない Cookie」が Web ブラウザに残っていることが原因です。 May 22 10:00:50 big208 err tmm[10621]: 01220001:3: TCL error: /Common/RULE_INIT <HTTP_REQUEST> conversion error (line 1) invoked from within "b64decode $encrypted" (5) HTTP レスポンスで Web サーバから SESSION Cooike が発行されます。これが DEC=に入った値です。 これを、この iRule を使って AES 鍵で暗号化したものが、ENC=に入った値で、これが Web ブラウザに渡されます。 May 22 10:00:55 big208 info tmm[13467]: Rule /Common/RULE_INIT <HTTP_RESPONSE>: DEC=fhfuk4jn79kql0e0lhtjdleu55 , ENC=TbiL4Kh2c7EMfOggwnOd4kx+rkRc+EDp2X28PPvD5EC8YvORYoTaDR57dncmUVmf1+ixuEpLl11YTHzluytOxgAAAAE= (6) この web アプリケーションのフォームに username と password を入れてログインすると、HTTP リクエストに SESSION Cookie として、ENC=の値でログインします。 これを、この iRule を使って AES 鍵で複合化したのが、DEC=に入った値です。 DEC=、ENC= のどちらの値も(4)同じになっています。 May 22 10:01:07 big208 info tmm[13467]: Rule /Common/RULE_INIT <HTTP_REQUEST>: DEC=fhfuk4jn79kql0e0lhtjdleu55 , ENC=TbiL4Kh2c7EMfOggwnOd4kx+rkRc+EDp2X28PPvD5EC8YvORYoTaDR57dncmUVmf1+ixuEpLl11YTHzluytOxgAAAAE= 58 LB_FAILED このイベントは、LTM が Pool Member にリクエストを送る準備ができたときに、その Pool Member へ以下のような理 由でそのリクエストを送れないときに発動します。 Pool Member に到達できなかった場合(例:経路ダウン/ルーティング設定ミス) Pool Member から TCP SYN への反応が無かった場合(例:Pool Member が停止している) BIG-IP が、Pool または Pool Member を選択できなかった場合(例:pool コマンドの設定ミス) もし、ヘルスモニターが設定されていない状態で、iRule が pool または member を選んだ場合や、node コマンドを使 って、モニターしてない宛先へトラフィックを送った場合には、選択された宛先は、そのリクエストに対して返答できる状 態ではないかもしれません。 そのケースでは、"LB_FAILED"イベントがトリガーされ、その状況を処理するようにロジックを組むことができます。 (1) サンプル iRule の動作概要 以下のサンプルは、URI が"/admin"で始まるリクエストは、10.99.100.211 のアドレスを持つサーバに送るが、その サーバが返答しなかった場合に、次の候補のノードに送る、というものです。 No. サンプル iRule ・① ・② ・③ ・④ ・⑤ ・⑥ ・⑦ when HTTP_REQUEST { if { [HTTP::uri] starts_with "/admin" } { set admin 1 node 10.99.100.211 80 } else { set admin 0 pool http-pool } } ・⑧ ・⑨ ・⑩ ・⑪ ・⑫ when LB_FAILED { switch $admin { 1 { log local0. "Server 10.99.100.211:80 not responding" LB::reselect node 10.99.100.215 80 } 2 { log local0. "Server 10.99.100.215:80 not responding" LB::reselect node 10.99.100.217 80 } 3 { log local0. "Server 10.99.100.217:80 not responding" reject } } incr admin } ・(a) ・(b) ・(c) ・(d) ・(e) ・(f) ・⑬ ① ② ③ ④ ⑤ HTTP リクエストを受け取ったとき、 URI が"/admin"の文字で始まっていたら、 変数:admin に"1"をセットし、 10.99.100.211:80 に、この HTTP リクエストを送る。 URI が"/admin"以外なら、 59 ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ 変数:admin に"0"をセットし、 http-pool に送る。 サーバが応答しなかった場合、この LB_FAILED イベントが発動。 $admin に"1"がセットされていたら、 この"1 {処理}"が実行される。 "1 {処理}"の 1 行目:サーバが応答しなかったことをログ出力する。 "1 {処理}"の 2 行目:10.99.100.215:80 へ送る。 $admin に 1 を加算する。(=$admin は"2") もし、⑫の 10.99.100.215:80 も応答しなかったら、再び⑧の LB_FAILED が発動。 上記⑬で、$admin には"2"がセットされているので、 (a) この"2 {処理}"が実行される。 (b) "2 {処理}"の 1 行目:サーバが応答しなかったことをログ出力する。 (c) "2 {処理}"の 2 行目:10.99.100.217:80 へ送る。 再び⑬で、$admin に 1 を加算する。(=$admin は"3") もし、(c)の 10.99.100.217:80 も応答しなかったら、再び⑧の LB_FAILED が発動。 上記⑬で、$admin には"3"がセットされているので (d) この"3 {処理}"が実行される。 (e) "3 {処理}"の 1 行目:サーバが応答しなかったことをログ出力する。 (f) "3 {処理}"の 2 行目:コネクションを RST で切断する。 (2) この iRule を web-vs に適用してください。(「iRule の使い方」のセクションを参照) (3) /var/log/ltm へ出力されるログが確認できる状態にしてください。(「iRule の使い方」のセクションを参照) (4) Web ブラウザで、http://10.99.1.108/admin にアクセスし、10.99.100.211 からのレスポンスが得られることを 確認してください。 (5) 10.99.100.211 が停止した、という形を模擬します。 iRule の④の行を、存在しないアドレス(例:10.99.100.111)に変更して save してください。 (存在しないアドレスに変更することで、停止したことと同じ結果になります。) (6) Web ブラウザで、http://10.99.1.108/admin にアクセスし、10.99.100.215 からのレスポンスが得られることを 確認してください。 (7) 10.99.100.215 も停止した、という形を模擬します。 iRule の⑫の行を、存在しないアドレス(例:10.99.100.115)に変更して save してください。 (存在しないアドレスに変更することで、停止したことと同じ結果になります。) (8) Web ブラウザで、http://10.99.1.108/admin にアクセスし、10.99.100.217 からのレスポンスが得られることを 確認してください。 60 9. Class / Data-Group の使い方 iRules を使うときに、検索可能なリストがほしい場合があります。 例えば、HTTP リクエストの URI を見て、あるリストの中からヒットする URI の文字列を見つけ、そこに指定されたプー ルに振り分ける、というような場合です。 このような場合に、Class/Data-Group が役に立ちます。 F5 が言う、"class" と"Data-Group"には、明確な違いはありません。 GUI では「Data-Group(s)」と呼ばれ、iRules コマンドでは「Class(es)」と呼ばれています。 本ガイドでは便宜上、リストを Data-Group、そのデータを呼び出す iRule コマンドを Class と呼ぶことにします。 Data-Group の種類には 2 つあります。 Internal Data-Group:BIG-IP のコンフィグファイル(bigip.conf)内に設定する場合 External Data-Group:外部ファイルとして保存する場合(=Host 側(Linux 側)のファイルとして保存する場合) External Data-Group は V11.4 から実装された機能です。 Internal Data-Group は多くても 100,000 エントリ程度が限界でしたが、External Data-Group を使うことで、 2,000,000~3,000,000 のエントリまで扱うことができるように拡張されています。 以降、Data-Group の Type 及びこれら 2 つの方式それぞれの利用方法を解説します。 61 Data-Group のデータの Type Data-Group のデータ(エントリ)には、以下のような Type が存在します。 (1) String (文字列) 最も一般的なタイプです。 string(文字列)フォーマットのあらゆるタイプのデータをストアすることができるので、URL スイッチングのようなこと を実行する場合に、高い頻度で使われます。 例: /admin := 10.99.100.215, /user := 10.99.100.217, (2) IP IP アドレスやアドレスレンジをストアできるタイプです。 例えば、送信元 IP アドレス毎に振分け先の Pool を変更したいような場合に便利なタイプです。 例: host 10.99.4.19 := "1", host 10.99.4.228 := "2", network 10.99.4.0/24 := "0", (3) Integer (数値) 整数値をストアすることを可能にするタイプです。 何らかのコマンド実行結果が数値となる場合(例えば演算や、何かをカウントする場合)に便利です。 例: 1 := "test 1", 2 := "test 2", 62 Internal Data-Group BIG-IP のコンフィグレーションファイル(bigip.conf)内に Data-Group を作り、それを参照する方法です。 このサンプルでは、まず以下の Data-Group を作ります。Type は String です。 /admin := 10.99.100.215, /user := 10.99.100.217, そして、以下のような iRule を作ります。 HTTP リクエストを受信したら、その URI と上記の Data-Group を比較。 URI と Data-Group 内の文字列が一致したら、そこに指定された IP アドレスへその HTTP リクエストを 送る。 具体的には、 ・ URI が「/admin」なら 10.99.100.215 へその HTTP リクエストを送る。 ・ URI が「/user」なら 10.99.100.217 へその HTTP リクエストを送る。 となる iRule を作ります。 63 9.1.2.1. Internal Data-Group の作成 BIG-IP のコンフィグファイル(bigip.conf)内に Data-Group を作ります。 (1) tmsh の場合は、以下のコマンドで、Data-Group を生成できます。 (tmos)# create ltm data-group internal TEST_Class { records add { /admin { data 10.99.100.215 } /user { data 10.99.100.217 } } type string } (2) 以下のコマンドで、Data-Group の設定内容を確認できます。 (tmos)# list ltm data-group ltm Data-Group internal TEST_Class { records { /admin { data 10.99.100.215 } /user { data 10.99.100.217 } } type string } (3) GUI からも作成/編集できます。 以下は、「Local Traffic」→「iRules」→「Data Group List」で、上記 tmsh で作った Data-Group を選択した画面 です。ここで編集が可能です。 64 9.1.2.2. Internal Data-Group を使った iRules 作成した Data-Group を iRule で参照するには、"class"コマンドを使います。 (1) サンプル iRule の動作概要 本サンプルは、HTTP リクエスト内の URL と Data-Group を比較し、ヒットしたら、そこに記載された IP アドレスへその リクエストを送る、というものです。 No. ・① ・② ・③ ・④ ・⑤ ① ② ③ ④ ⑤ サンプル iRule when HTTP_REQUEST { if {[class match [HTTP::uri] contains TEST_Class]} { set NODE [class match -value [HTTP::uri] contains TEST_Class] log local0. "$NODE" node $NODE 80 } } HTTP リクエストを受け取ったとき、 URI が Data-Group の TEST_Class 内の文字にヒットしたら、 NODE 変数に、ヒットした URI に記載された値(IP アドレス)を格納し、 その IP アドレスをログ出力し、 NODE の 80 番ポートに送る。 (2) コマンドの解説 class match このコマンドは、特定の検索パラメータが正確にマッチする Member を Data-Group list から検索し、マッチが成功 したかどうかを示す True/False 値(0/1)を返します。 class match -value このコマンドは、Class 内の Key/value の vaule を返答することができます。 例えば、class に、URI と Pool が key と value として記載されたものがあるとします。 Class の行が「/admin := 10.99.100.215」であった場合、検索値(key)が「/admin」であれば、その 2 番目の値 (value):10.99.100.215 を戻り値とします。 (3) この iRule を web-vs に適用してください。(「iRule の使い方」のセクションを参照) (4) /var/log/ltm へ出力されるログが確認できる状態にしてください。(「iRule の使い方」のセクションを参照) (5) Web ブラウザで、http://10.99.1.108/admin にアクセスし、10.99.100.215 からのレスポンスが得られることを 確認してください。 (6) Web ブラウザで、http://10.99.1.108/user にアクセスし、10.99.100.217 からのレスポンスが得られることを確 認してください。 65 External Data-Group (その 1:String 形式) 今度は、BIG-IP のコンフィグ内ではなく、BIG-IP の Host 側(Linux 側)に保存されたファイルを Data-Group として 利用する方法を示します。 まずは Internal Data-Group と同様に、String 形式で作成してみます。 9.1.3.1. External Data-Group 用ファイルの作成 BIG-IP の Host 側(Linux 側)に、Data-Group 用の外部ファイルを作成します。 ファイルを保存するディレクトリはどこでもかまいません。 よって、本ガイドでは、/var/tmp ディレクトリに保存することにします。 [root@big208:Active:In Sync] config # cd /var/tmp vi エディタなどを利用して、以下の 2 行を追加してください。 [root@big208:Active:In Sync] tmp # vi ext_TEST_Class.file /admin := 10.99.100.211, /user := 10.99.100.213, 注意点: 改行コードは「LF のみ」に対応しています。 Windows の「CRLF」などは読み込みエラーとなります。 よって、Windows のテキストエディタで作成した Data-Group をそのまま貼り付けても、エラーとなる場合があります のでご注意ください。 9.1.3.2. External Data-Group ファイルの読み込み 以下の TMSH コマンドで、外部ファイルをオブジェクトとして読み込みます。 (tmos)# create sys file data-group ext_TEST_Class_Object type string source-path file:/var/tmp/ext_TEST_Class.file Copying file "file:/var/tmp/ext_TEST_Class.file" ... % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 49 0 49 0 0 92627 0 --:--:-- --:--:-- --:--:-0 9.1.3.3. External Data-Group の作成 以下のコマンドで、上記で生成したオブジェクトを、iRule が参照できる Data-Group に変換します。 (tmos)# create ltm data-group external ext_TEST_Class external-file-name ext_TEST_Class_Object 以下のコマンドで、参照先を確認できます。 (tmos)# list ltm data-group external ltm data-group external ext_TEST_Class { external-file-name ext_TEST_Class_Object type string } 66 9.1.3.4. External Data-Group を使った iRule (1) サンプル iRule の概要 以下の iRule は、internal Data-Group の場合と同じ動作を行うルールです。 参照する先が、bigip.conf 内ではなく、外部ファイルから生成した Data-Group になる、と点だけが異なります。 No. ・① ・② ・③ ・④ ・⑤ サンプル iRule when HTTP_REQUEST { if {[class match [HTTP::uri] contains ext_TEST_Class]} { set NODE [class match -value [HTTP::uri] contains ext_TEST_Class] log local0. "$NODE" node $NODE 80 } } (2) この iRule を web-vs に適用してください。(「iRule の使い方」のセクションを参照) (3) /var/log/ltm へ出力されるログが確認できる状態にしてください。(「iRule の使い方」のセクションを参照) (4) Web ブラウザで、http://10.99.1.108/admin にアクセスし、10.99.100.211 からのレスポンスが得られることを 確認してください。 (5) Web ブラウザで、http://10.99.1.108/user にアクセスし、10.99.100.213 からのレスポンスが得られることを確 認してください。 (6) 外部ファイルの内容を変更して、Data-Group に反映させてみます。 vi エディタなどを使って、外部ファイルを変更してください。 [root@big208:Active:In Sync] tmp # vi ext_TEST_Class.file /admin := 10.99.100.215, /user := 10.99.100.217, 変更後、tmsh で以下のコマンドを実行することで、Data-Group に反映できます。 (tmos)# modify sys file data-group ext_TEST_Class_Object source-path file:/var/tmp/ext_TEST_Class.file (7) Web ブラウザで、http://10.99.1.108/admin にアクセスし、10.99.100.215 からのレスポンスが得られることを 確認してください。 (8) Web ブラウザで、http://10.99.1.108/user にアクセスし、10.99.100.217 からのレスポンスが得られることを確 認してください。 67 External Data-Group (その 2:Address 形式) 今度は、データ Type を Address 形式で作成したものを使って、動作を確認します。 9.1.4.1. External Data-Group ファイルの作成 BIG-IP の Host 側(Linux 側)に、Data-Group 用の外部ファイルを作成します。 vi エディタなどを利用して、以下の 3 行を追加してください。 [root@big208:Active:In Sync] tmp # vi ext_TEST_IP_Class.file host 10.99.4.19 := "1", host 10.99.4.228 := "2", network 10.99.4.0/24 := "0", 9.1.4.2. External Data-Group ファイルの読み込み 以下の TMSH コマンドで、外部ファイルをオブジェクトとして読み込みます。 (tmos)# create sys file data-group ext_TEST_IP_Class_Object type ip source-path file:/var/tmp/ext_TEST_IP_Class.file Copying file "file:/var/tmp/ext_TEST_IP_Class.file" ... % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 78 0 78 0 0 108k 0 --:--:-- --:--:-- --:--:-0 9.1.4.3. External Data-Group の作成 以下のコマンドで、上記で生成したオブジェクトを、iRule が参照できる Data-Group に変換します。 (tmos)# create ltm Data-Group external ext_TEST_IP_Class external-file-name ext_TEST_IP_Class_Object 以下のコマンドで、参照先を確認できます。 (tmos)# list ltm data-group external ext_TEST_IP_Class ltm Data-Group external ext_TEST_IP_Class { external-file-name ext_TEST_IP_Class_Object type ip } 68 9.1.4.4. External Data-Group を使った iRule (1) サンプル iRule の概要 クライアントの IP アドレスに応じて、利用する Pool Member を変える、というルールです。 No. ・① ・② ・③ ・④ ・⑤ ・⑥ ① ② ③ ④ ⑤ ⑥ サンプル iRule when CLIENT_ACCEPTED { switch [class match -value [IP::client_addr] equals ext_TEST_IP_Class] { "0" { reject } "1" { node 10.99.100.213 80 } "2" { node 10.99.100.215 80 } default { log local0. "Address not found or invalid value." } } } クライアント側の TCP コネクションが確立されたとき、 クライアントの IP アドレスで ext_TEST_IP_Class 内を検索し、 戻り値が"0"なら TCP RST を送る。 戻り値が"1"なら、10.99.100.213:80 へ。 戻り値が"2"なら、10.99.100.215:80 へ。 何もヒットしなければ、ログを出力。 (2) この iRule を web-vs に適用してください。(「iRule の使い方」のセクションを参照) (3) /var/log/ltm へ出力されるログが確認できる状態にしてください。(「iRule の使い方」のセクションを参照) (4) Web ブラウザで、http://10.99.1.108 にアクセスし、10.99.100.213 からのレスポンスのみが得られることを確 認してください。 (5) Web ブラウザを Forward Proxy(Squid)経由(=10.99.4.228 から BIG-IP へアクセス)に変更します。 例)Internet Explorer の場合: 「ツール」→「インターネットオプション」→「接続」タブ→「LAN の設定」ボタンを押す。 69 サンプルネットワーク構成図中の Proxy(Squid)サーバのアドレス / ポート=10.99.4.228 / 3128 を入力。 (6) Web ブラウザで、http://10.99.1.108 にアクセスし、10.99.100.215 からのレスポンスのみが得られることを確 認してください。 (7) Web ブラウザの Forward Proxy(Squid)経由を解除します。 (8) 外部ファイルの内容を変更して、Data-Group に反映させてみます。 vi エディタなどを使って、例えば外部ファイルを以下のように変更してください。 [root@big208:Active:In Sync] tmp # vi ext_TEST_IP_Class.file host 10.99.4.19 := "2", host 10.99.4.228 := "1", network 10.99.4.0/24 := "0", 変更後、tmsh で以下のコマンドを実行することで、Data-Group に反映できます。 (tmos)# modify sys file data-group ext_TEST_IP_Class_Object source-path file:/var/tmp/ext_TEST_IP_Class.file (9) Web ブラウザで、http://10.99.1.108 にアクセスし、10.99.100.215 からのレスポンスのみが得られることを確 認してください。 (10)Web ブラウザを Proxy(Squid)経由に変更します。 http://10.99.1.108 にアクセスし、10.99.100.213 からのレスポンスのみが得られることを確認してください。 70 9.2. table の使い方 table コマンドは、メモリ内に「小さなデータベースに相当するもの」を作成してくれます。 table を使うことで、例えば送信元 IP アドレス単位にアクセス数をカウントし、ある IP アドレスからのコネクションが 一定数を超えたら、その IP アドレスからのアクセスはドロップする、というような、よりきめ細かい単位での制御が可能 になります。 (1) サンプル iRule の動作概要 本サンプルは、1 秒間に 100 以上のアクセス(TCP コネクション)が発生する IP アドレスは一定時間ブロックする と いう iRule です。 上図を簡単に解説します。 1.1.1.1 と 2.2.2.2 のクライアントからのアクセスがあり、それぞれの IP アドレス単位に、1 秒間に発生するコネク ション数を、table を使ってカウントします。 2.2.2.2 からのアクセスは 100/秒を超えたので、Subtable:blacklist にレコードを追加します。 そのレコードの Lifetime(生存時間)は 20 秒にセットされます。 この後、2.2.2.2 からの後続のアクセスは、20 秒の間ブロックされ続けます。 このような動作イメージのルールを作成します。 No. サンプル iRule ・① ・② ・③ when RULE_INIT { set static::maxquery 100 set static::holdtime 20 } ・④ ・⑤ ・⑥ ・⑦ ・⑧ ・⑨ ・⑩ ・⑪ ・⑫ when CLIENT_ACCEPTED { set srcip [IP::remote_addr] if { [table lookup -subtable "blacklist" $srcip] != "" } { log local0. "BList $srcip is: [table lookup -subtable "blacklist" $srcip]" drop return } else { set curtime [clock second] set key "count:$srcip:$curtime" 71 ・⑬ ・⑭ ・⑮ set count [table incr $key] table lifetime $key 1 log local0. "COUNT/sec of $key is: $count" } if { $count >= $static::maxquery } { table add -subtable "blacklist" $srcip "blocked" indef $static::holdtime table delete $key drop return ・⑯ ・⑰ ・⑱ ・⑲ ・⑳ } } ① この iRule が save されたとき、 ② Static 変数(static::maxquery)に 100 を入れる。(最大コネクション数) ③ Static 変数(static::holdtime)に 20 を入れる。 (ブラックリストとなったレコードの生存時間) ④ クライアントとの TCP コネクションが確立されたとき、 ⑤ 変数(srcip)に、クライアントの IP アドレスを入れる。 ⑥ ⑦ ⑧ ⑨ もし、"blacklist"という名の subtable に、$srcip の IP アドレスが存在していたら、 その IP アドレスのログを出力し、 その IP アドレスからのパケットをドロップし、 この処理から抜ける。 ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ もし、⑥ではなかったら(=ブラックリストに IP アドレスが存在しなかったら)、 変数(curtime)に現在時刻を入れ、 変数(key)に"count:IP アドレス:現在時刻 "の形で値を入れ、 テーブルに$key のレコードを追加 & $key の値を 1 つ増加 & その値を変数(count)に入れ、 テーブルの$key レコードのライフタイムを 1 秒にセット。 $key の 1 秒あたりのコネクション数をログ出力。 秒間のコネクション数が 100 に達するまでは、⑩~⑮が繰り返される。 (厳密には⑩~⑯が繰り返されるが、⑯の if 条件には合致しないので、それ以降の処理は行われない。) ⑯ $count が 100(static::maxquery の値)に達したら、 ⑰ "blacklist"という名のサブテーブルに、以下を追加。 (ア) $srcip(クライアントの IP アドレス)を Key に。 (イ) "blocked"を Value に。 (ウ) timeout(アイドルタイムアウト)は無限に。 (エ) lifetime(このレコードが作られてからの生存時間)は 20 秒(static::holdtime)に。 ⑱ ⑬の$key レコードは削除。(コネクションが 100 になるまでカウントするための一時的なレコードであるため。) ⑲ クライアントからのパケットはドロップ。 ⑳ この処理から抜ける。 72 (2) コマンド解説 table incr <key> - - table 上にある、指定された Key の Value に、1 を加えます。 もし、table 上に Key が存在していなかったら、デフォルト value には"0"が使われ、そのエントリが追加され ます。 incr 処理が完了すると、そのエントリ(key)の値を返します。 table add -subtable <name> <key> <value> <timeout> <lifetime> - <name>に指定された"名前つきテーブル"=subtable を生成します。 そのサブテーブルのレコードとして、<key> <value>の形でエントリされます。 <timeout>に indef が指定されると、アイドルタイムアウトは発生しなくなります。 <lifetime>には、このレコードが生成された時刻から何秒後に消去するかを指定します。 table lookup -subtable <name> <key> - <name>に指定された"名前つきテーブル"=subtable 内を<key>で検索し、それに紐付く value を返します。 table lifetime <key> <value> - table 内の、<key>の lifetime(レコードが作成されてから消去するまでの時間)を、<value>に指定された 秒数にセットします。 table delete <key> - table 内の<key>のレコードを削除します。 (3) この iRule を web-vs に適用してください。(「iRule の使い方」のセクションを参照) (4) /var/log/ltm へ出力されるログが確認できる状態にしてください。(「iRule の使い方」のセクションを参照) (5) 10.99.4.228(Linux)で、以下のコマンド(Apache Bench)を実行してください。 # ab –n 999999 –c 100 http://10.99.1.108/ [参考:Apache Bench] https://httpd.apache.org/docs/2.2/programs/ab.html (6) /var/log/ltm を見ていると、100 コネクションに達したとき、以下のログが出力されます。 Jun 11 19:27:20 big208 info tmm1[11003]: Rule /Common/TABLE <CLIENT_ACCEPTED>: COUNT/sec of count:10.99.4.228:1434018440 is: 99 Jun 11 19:27:20 big208 info tmm[11003]: Rule /Common/TABLE <CLIENT_ACCEPTED>: COUNT/sec of count:10.99.4.228:1434018440 is: 100 Jun 11 19:27:20 big208 info tmm1[11003]: Rule /Common/TABLE <CLIENT_ACCEPTED>: BList 10.99.4.228 is: blocked (7) blacklist テーブル上のレコードは通信の有無に関係なく 20 秒で消えますので、もう一度実行する場合には 20 秒待ってから実施してください。 73 10. iRule 作成のテクニック 10.1. デバッグのやり方 iRule は多様な機能を持つので、要件によってはコードが複雑になる場合があります。 複雑なコードはエラーを誘発しやすくなるので、デバッグが必要になることがあると思います。 デバッグ手段として有効なのは、とにもかくにもログ出力することです。 以下の要領で各所にロギングの行を挿入し、変数の値が想定どおりにセットされているか、またはコマンド の実行結果や戻り値が想定通りか、等をチェックします。 when HTTP_REQUEST { … log local0. "section1, a is $a" … もちろん変数に限らず、コマンドを記述することもできます。 when CLIENT_ACCEPTED { … log local0. "section1, Bandwidth is [TCP::bandwidth]" … 本番環境でのロギング有効化/無効化 デバッグロギングは、アプリケーションのテストを行うときや、本番サーバの問題を修正するような場合に有効なツー ルです。しかし、ロギングによる CPU 負荷は比較的高く、またロギングし続けると、かなり大きな Syslog サーバのディ スクが必要となる場合があります。 よって、多くのケースでは、不具合修正ができた後では、デバッグログは無効化しておくことが推奨されます。 無効化の方法には、以下のようにいくつかの方法が存在します。 10.1.1.1. iRule 内からログコマンドを削除する これは最も簡単な方法です。log の行を削除して保存するだけです。 10.1.1.2. iRule 内の log 行をコメントアウトする log コマンド行の先頭に#をつけてコメントアウトする方法です。 この方法であれば、log 設定を簡単に復活できるので、アプリケーションの新しい問題が発生した場合にも直ぐにロ ギングできます。 10.1.1.3. 変数を使った、条件つきロギングを行う "if"コマンドを使って、変数の値をチェックすることで、ログ行を有効化/無効化する方法です。 変数値を変えるだけで、シンプルにロギングの ON/OFF ができます。 例えば、LB_FAILED イベントのサンプルで使った iRule に、この方法を適用してみます。 74 No. ・① ・② ・③ サンプル iRule when HTTP_REQUEST { set DEBUG 1 if { $DEBUG } { log local0. "Request: [HTTP::uri]"} if { [HTTP::uri] starts_with "/admin" } { set admin 1 node 10.99.100.211 80 } else { set admin 0 pool http-pool } } when LB_FAILED { switch $admin { 1 { if { $DEBUG } {log local0. "Server 10.99.100.211:80 not responding"} LB::reselect node 10.99.100.215 80 } 2 { if { $DEBUG } {log local0. "Server 10.99.100.215:80 not responding"} LB::reselect node 10.99.100.217 80 } 3 { if { $DEBUG } {log local0. "Server 10.99.100.217:80 not responding"} reject } } incr admin } (1) この iRule を web-vs に適用してください。(「iRule の使い方」のセクションを参照) (2) /var/log/ltm へ出力されるログが確認できる状態にしてください。(「iRule の使い方」のセクションを参照) (3) Web ブラウザで、http://10.99.1.108/admin にアクセスし、10.99.100.211 からのレスポンスが得られることを 確認してください。 期待するログが出力されていることを確認してください。 (4) 以下 2 つの方法のどちらかを実施してください。 10.99.100.211 を停止 停止できない場合、iRule の③の行を、存在しないアドレス(例:10.99.100.111)に変更 (存在しないアドレスに変更することで、停止したことと同じ結果になります。) 期待するログが出力されていることを確認してください。 (5) Web ブラウザで、http://10.99.1.108/admin にアクセスし、10.99.100.215 からのレスポンスが得られることを 確認してください。 期待するログが出力されていることを確認してください。 (6) ①の「set DEBUG 1」を「set DEBUG 0」に変更し、同様の動作確認を行ってください。 ログが出力されなくなることを確認してください。 75 10.2. iRule による CPU 使用率の測定 iRule を設定した際には、どの程度のパフォーマンス劣化が発生するのかが気になる場合があります。 そのような場合には、"timing"コマンドを使うことによって、iRule がどの程度 CPU サイクルを使っているのかを確 認することができます。 2 つの iRule で CPU 使用率を比較 「TCL の基礎」の章で、計算式をブレス{ }で囲むか囲まないかで計算効率が変わる、という点に少し触れました。 どれぐらい違うのか、2 つを比べてみます。 (1) expr {$a*$b} 以下は、HTTP リクエストを受信したときに、2 つ数を計算する、という iRule です。 変数を使った計算式を{ }で囲むことで、効率的に計算を行うパターンです。 No. ・① ・② ・③ ・④ サンプル iRule 名:TMINIG_TEST when HTTP_REQUEST timing on { set a 100000 set b 100000 set c [expr {$a*$b}] } 以下のコマンドで、この iRule が使用した CPU サイクルを確認できます。 root@(big208)(cfg-sync In Sync)(Active)(/Common)(tmos)# show ltm rule TIMING_TEST raw (raw) ----------------------------------------Ltm::Rule Event: TIMING_TEST:HTTP_REQUEST ----------------------------------------Priority 500 Executions Total 49998 Failures 0 Aborts 0 CPU Cycles on Executing Average 19951 Maximum 569256 Minimum 0 以下のコマンドで、上記の Statistics を消去できます。 (tmos)# reset-stats ltm rule TIMING_TEST 76 (2) expr $a*$b 変数を使った計算式をブレス{ }で囲まないパターンです。 {}で囲まないので、TCL パーサーによる変数置換が実施された後に計算する、という 2 つの処理が入るため、効率 が悪くなります。 No. ・① ・② ・③ ・④ サンプル iRule when HTTP_REQUEST timing on { set a 100000 set b 100000 set c [expr $a*$b] } 以下のコマンドで、この iRule が使用した CPU サイクルを確認できます。 root@(big208)(cfg-sync In Sync)(Active)(/Common)(tmos)# show ltm rule TIMING_TEST raw (raw) ----------------------------------------Ltm::Rule Event: TIMING_TEST:HTTP_REQUEST ----------------------------------------Priority 500 Executions Total 100003 Failures 0 Aborts 0 CPU Cycles on Executing Average 34972 Maximum 23861033 Minimum 12407 { }で囲んだ場合と比べると、平均値で約 1.7 倍の CPU サイクルを使用していることがわかります。 77 iRule の CPU 使用率の計算 利用する予定の iRule がどの程度 CPU へインパクトを与えるのかを知りたい場合があります。 その場合の計算方法を示します。 厳密な計算は難しいですが、目安にはなりえます。 10.2.2.1. プラットフォームの CPU クロック数を求める まず、プラットフォームの CPU を調べます。 本ガイドで利用している BIG-IP は Virtual Edition であり、CPU を 2 個使っています。 root@(big208)(cfg-sync In Sync)(Active)(/Common)(tmos)# show sys hardware Chassis Information Maximum MAC Count Registration Key 1 - Hardware Version Information Name cpus Type base-board Model Intel(R) Xeon(R) CPU Parameters --cache size 8192 KB cores 2 cpu MHz 2527.000 Platform Name BIOS Revision Base MAC ~省略~ 10.2.2.2. E5540 @ 2.53GHz BIG-IP Virtual Edition 00:50:56:bd:a4:0b 計算 Timing コマンドで出力された CPU サイクルを、CPU クロックの合計値で割る、という単純計算です。 1 つの HTTP リクエストが発生した際の CPU 使用率、という値となります。 CPU クロックの合計: 2,527,000,000 Hz * 2 Core = 5,054,000,000Hz (1) expr {$a*$b}の場合 19951 / 5,054,000,000Hz ≒ 0.0003948% (2) expr $a*$b の場合 34972 / 5,054,000,000Hz ≒ 0.0006920% 例えば(2)の場合は、10,000 リクエスト/秒のアクセスがあれば、CPU は 6%上昇する、と見込まれます。 78 10.3. iRule を最適化する iRule を最適に利用するために考慮すべきポイントについてまとめました。 (1) iRule を使う前にまず Profile でできないかを確認する iRule は様々なことが行える強力なスクリプトですが、BIG-IP に標準で実装されている機能に比べると、オーバーヘ ッドが大きくなりがちです。 よって、何でも iRule で実装してしまう前に、BIG-IP に標準実装されている Profile の設定で実施できないかを調 査し、Profile でできるのならば、それを利用するほうがパフォーマンスへのインパクトは少なくすみます。 例: HTTP header insert and erase HTTP fallback HTTP compress uri <exclude|include> HTTP redirect rewrite HTTP insert X-Forwarded-For HTTP ramcache uri <exclude|include|pinned> Stream profile for content replacement Class profile for URI matching. (2) 最適な制御ステートメントを利用する (if/elseif/else,switch,class/Data-Group) 条件分岐を行う制御ステートメントは if,switch など、複数存在します。 それぞれの制御ステートメントには得手/不得手な部分があるので、それぞれを見極めて利用することによって、不 要な CPU リソースを消費しないようすることが望ましいです。 if/elseif を使うよりもまず、switch または Class/Data-Group を使うことを考える。 - 100 エントリ以下の条件分岐なら Switch を使う。 - 100 エントリ以上の条件分岐なら Class/Data-Group を使う。 しかし、if/elseif のほうが switch や Class よりも柔軟性が高いので、適材適所で利用する。 79 if の連続使用よりも if/elseif を使う。 例えば以下 2 つの iRule は同じ結果を導き出します。 if/if/if if/elseif/elseif when HTTP_REQUEST { set uri [HTTP::uri] if { $uri equals "/" } { pool http-pool } if { $uri contains "admin" } { pool A-pool } if { $uri contains "user" } { pool B-pool } } when HTTP_REQUEST { set uri [HTTP::uri] if { $uri equals "/" } { pool http-pool } elseif { $uri contains "admin" } { pool A-pool } elseif { $uri contains "user" } { pool B-pool } } しかし、if/if/if の場合は、例えば 1 つ目の if で条件がヒットして Pool 選択ができた(http-pool の選択ができ た)場合でも、後続の 2 つの if が同様の処理を実施する、というムダが生じます。 一方、if/elseif/elseif の方は、最初の if の条件がヒットしなかった場合にのみ、以降の elseif を実行するの で、if/if/if のルールよりも効率が良くなります。 このことは、どの条件にヒットする割合が大きいかによっても影響があると考えられます。 もし、B-Pool が選ばれる条件が 9 割以上、という場合には、両者の効率は大差ないかもしれません。 (3) for よりも foreach の利用を考える 以下の for と foreach は、それぞれ同じ結果を導き出します。 for when HTTP_REQUEST { set domains [bob.com ted.com domain.com] set countDomains [llength $domains] for {set i 0} { $i < $countDomains } {incr i} { set domain [lindex $domains $i] foreach when HTTP_REQUEST { set domains [bob.com ted.com domain.com] foreach domain $domains { # This is faster, and more elegant # This is slower } } } } しかし、条件を多数指定する for に対し、foreach は 1 つの行で同じ形を実現できます。 よって、foreach で要件を見たせるならばその方が効率はよく、また、見た目も美しくなります。 80 (4) 最適なオペレータの利用 (contains, equals) "contains"よりも"equals"を使う contains ではなく equals で要件を満たせるなら、検索ロジックが少ない equals を使ったほうが CPU リソースの消 費は少ないです。 (5) 正規表現の利用は極力避ける 正規表現(Regular Expressions)は非常に便利な機能である反面、メモリや CPU リソースを多く消費しがちです。 多くのケースで、正規表現を使わずとも要件を満たせるコマンドがあるはずなので、極力そちらを利用することを検 討すべきです。 "string match"や"switch -glob"を使う "string match"や"switch -glob"のほうが正規表現よりも CPU 負荷が軽いので、これらで要件が満たせるなら ば、正規表現は極力使うことを避けるべきです。 "regex"よりも"start_with" 悪い例: when HTTP_REQUEST { if { [regexp {^/admin} [HTTP::uri]] } { regsub {/admin} [HTTP::uri] "/UserPortal" newUri log local0. "$newUri" HTTP::uri $newUri } } よい例: when HTTP_REQUEST { if { [HTTP::uri] starts_with "/adimin" } { set newUri [string map {admin UserPortal} [HTTP::uri]] HTTP::uri $newUri } } 81 (6) 変数を使わないほうがいい場合 変数は比較的オーバーヘッドの大きい機能です。 よって、変数を使わずに実装できるならば、使わないほうがよい場合があります。 例えば以下のように、ただ単にコマンド出力結果を変数に入れるだけならば、変数を使わないほうが効率がよいで す。 変数を使う、効率がよくない例: when HTTP_REQUEST { set host [HTTP::host] set uri [HTTP::uri] if { $host equals "bob.com" } { log "Host = $host; URI = $uri" pool http_pool1 } } 上記と同じことは、変数を使わない以下の iRule でも実施できます。 when HTTP_REQUEST { if { [HTTP::host] equals "bob.com" } { log "Host = [HTTP::host]; URI = [HTTP::uri]" pool http_pool1 } } (7) 変数を使ったほうがいい場合 一方、何度も同じコマンドを実行するのならば、変数を使ったほうが、効率がよくなります。 悪い例: 繰り返し同じ処理をすると、メモリ消費が多くなる when HTTP_REQUEST { if { [string tolower [HTTP::uri]] starts_with "/img" } { pool imagePool } elseif { ([string tolower [HTTP::uri]] ends_with ".gif") || ([string tolower [HTTP::uri]] ends_with ".jpg") } { pool imagePool } } 良い例: 変数を使って、同じ処理を繰り返し実施しないようにする when HTTP_REQUEST { set uri [string tolower [HTTP::uri]] if { $uri starts_with "/img" } { pool imagePool } elseif { ($uri ends_with ".gif") || ($uri ends_with ".jpg") } { pool imagePool } } 82 (8) 変数名は短めに 以下は上記と同じ事を行う iRule ですが、変数名が長い、悪い例です。 TCL は Lookup 用テーブルに変数を格納するので、長い名前はオーバーヘッドが多くなります。 できるだけ短い変数名にすることをお勧めします。 悪い例: when HTTP_REQUEST { set theUriThatIAmMatchingInThisiRule [string tolower [HTTP::uri]] if { $theUriThatIAmMatchingInThisiRule starts_with "/img" } { pool imagePool } elseif { ($theUriThatIAmMatchingInThisiRule ends_with ".gif") || ($theUriThatIAmMatchingInThisiRule ends_with ".jpg") } { pool imagePool } } (9) オペレータの注意点 これは最適化というよりも注意点です。 比較演算子(オペレータ)には、文字列に適したものと数字に適したものが存在します。 これらを適切に利用しないと、誤った判断になる場合が発生します。 文字列の比較には eq や ne を使う 数字の比較には == や != を使う 例えば、"5"と"05"の比較の結果を同じとしたい(=数字として比較したい)のか、違うものとして扱いたい(文字列と して扱いたい)のかによって、利用すべきオペレータは異なります。 set x 5 if { $x if { $x if { $x if { $x == eq == eq 5 5 05 05 } } } } { { { { } } } } # # # # evaluates evaluates evaluates evaluates to to to to true true true false よって、要件に応じて、適切なオペレータを使い分けるようにしてください。 83 11. おわりに 基本的な iRules セットアップに関しては以上で終了となります。 BIG-IP シリーズ製品ラインナップにおいては、ソフトウェアモジュールライセンスを追加することで、サーバ負荷分散 はもちろんのこと、広域負荷分散やリモートアクセス機能、ネットワークファイアウォール機能など、アプリケーションア クセスを最適化する為の多彩な機能が使用できるようになります。 詳細は各種 WEB サイトにてご確認いただくか、購入元にお問い合わせください。 <F5 ネットワークス WEB サイトの紹介> F5 ネットワークスジャパン総合サイト https://f5.com/jp/homepage F5 Tech Depot:エンジニア向け製品関連情報サイト http://www.f5networks.co.jp/depot/ AskF5:ナレッジベース総合サイト(英語) http://support.f5.com/kb/en-us.html DevCentral:F5 ユーザコミュニティサイト(英語:アカウント登録が必要です) https://devcentral.f5.com/ 以上 引用文献: ウィキペディア:Tcl/Tk http://ja.wikipedia.org/wiki/Tcl/Tk F5 ネットワークスジャパン合同会社 〒107-0052 東京都港区赤坂 4-15-1 赤坂ガーデンシティ 19 階 本資料は F5 ネットワークスジャパンのエンジニアが特定のソフトウェアバージョンの動作仕様に基づいて作成した構築・設計を補助するための資料であり、メーカー公式資料とは異なります。資料 の記載内容に誤りがあった際には指摘に基づいて修正を行いますが、内容についての責任は一切負いません。また、修正、変更、改訂は予告無く行われます。 84 12. Appendix 12.1. EVENT 発動のタイミング EVENT のフロー 85 EVENT 発動を確認するためだけの iRule どのタイミングで EVENT が発動するかを確認することだけを目的とした iRule です。 No. サンプル iRule ・① when CLIENT_ACCEPTED { log local0. "TCP 3WAY Hand-Shake from [IP::remote_addr] is established!!!" TCP::collect } ・② when CLIENT_DATA { log local0. "TCP's payload of client-side is \"[TCP::payload]\"" TCP::release } ・③ when HTTP_REQUEST { log local0. "Got HTTP REQUEST!!! \"[HTTP::method] [HTTP::uri]\"" if { [HTTP::uri] starts_with "/admin" } { set admin 1 node 10.99.100.111 80 } HTTP::collect 100 } ・④ when HTTP_REQUEST_DATA { log local0. "HTTP REQUEST Payload is \"[HTTP::payload]\"" HTTP::release } ・⑤ when LB_SELECTED { log local0. "Selected pool member is [LB::server]" } ・⑥ when LB_FAILED { switch $admin { 1 { log local0. "Server [LB::server] is not responding" LB::reselect node 10.99.100.215 80 } } } ・⑦ when SERVER_CONNECTED { log local0. "connection to [IP::server_addr]:[serverside {TCP::remote_port}]" TCP::collect } ・⑧ when HTTP_REQUEST_RELEASE { log local0. "[HTTP::method] to [HTTP::host][HTTP::uri] using pool [LB::server]" } ・⑨ when SERVER_DATA { log local0. "TCP's payload is \"[TCP::payload]\"" TCP::release } 86 ・⑩ when HTTP_RESPONSE { log local0. "Got HTTP RESPONSE of [HTTP::status]!!!" set content_length [HTTP::header "Content-Length"] HTTP::collect $content_length } ・⑪ when HTTP_RESPONSE_DATA { log local0. "HTTP RESPONSE Payload is \"[HTTP::payload]\"" HTTP::release } ・⑫ when CLIENT_CLOSED { log local0. "CLIENT SIDE CONNECTION to [IP::remote_addr] was closed" } ・⑬ when SERVER_CLOSED { log local0. "SERVER SIDE CONNECTION to [IP::server_addr] was closed" } 出力されたログ 上記 iRule を VS に適用して、クライアントのブラウザでその VS にアクセスした際に出力されたログです。 クライアントは、「http://10.99.111.89/admin」へアクセスしています。 ↓BIG-IP のクライアント側で、クライアント PC:「10.99.4.19」とのコネクションを確立。 Jun 26 17:36:21 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <CLIENT_ACCEPTED>: TCP 3WAY Hand-Shake from 10.99.4.19 is established!!! ↓クライアント側で TCP::collect で取得した TCP ペイロード。 Jun 26 17:36:21 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <CLIENT_DATA>: TCP's payload of clientside is "GET /admin/ HTTP/1.1 Accept: text/html, application/xhtml+xml, */* Accept-Language: ja-JP UserAgent: Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko Accept-Encoding: gzip, deflate Host: 10.99.111.89 DNT: 1 Connection: Keep-Alive Cookie: SESSION=3g2uvte5h5n1nu4f87dog5cph0; PHPSESSID=fo650gjem5ps5fbr8k8k983tj0 " ↓クライアント側で HTTP リクエスト(GET)を受信。 Jun 26 17:36:21 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <HTTP_REQUEST>: Got HTTP REQUEST!!! "GET /admin/" この HTTP リクエストは GET なので、Body を持たない。(POST の場合は POST データが存在する) よって、HTTP::collect によるデータを持たないので、HTTP_REQUEST_DATA は発動しない。 ↓Pool Member = 10.99.100.235:80 が選択される。 Jun 26 17:36:21 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <LB_SELECTED>: Selected pool member is 10.99.100.111 80 ↓Pool Member = 10.99.100.111:80 は存在しないので、FAILED。 Jun 26 17:36:24 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <LB_FAILED>: Server 10.99.100.111 80 is not responding ↓ロードバランシング先として、Pool Member = 10.99.100.215:80 を選択。 Jun 26 17:36:24 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <LB_SELECTED>: Selected pool member is 10.99.100.215 80 87 ↓Pool Member = 10.99.100.111:80 とのコネクションは閉じる。(実際にはコネクションは確立されていないが。) Jun 26 17:36:24 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <SERVER_CLOSED>: SERVER SIDE CONNECTION to 10.99.100.111 was closed ↓Pool Member = 10.99.100.215:80 とのコネクションを確立。 Jun 26 17:36:24 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <SERVER_CONNECTED>: connection to 10.99.100.215:80 ↓ HTTP リクエストを Pool Member へ送り出す。 Jun 26 17:36:24 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <HTTP_REQUEST_RELEASE>: GET to 10.99.111.89/admin/ using pool 10.99.100.215 80 ↓Pool Member = 10.99.100.215:80 から発生された TCP ペイロード。 Jun 26 17:36:24 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <SERVER_DATA>: TCP's payload is "HTTP/1.1 200 OK Date: Fri, 26 Jun 2015 08:36:24 GMT Server: Apache/2.2.15 (CentOS) X-Powered-By: PHP/5.3.3 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 1549 Connection: close Content-Type: text/html; charset=UTF-8 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xttml1-transitional.dtd"> <html xmlns="http://www.w3.org.1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>f5-test-web</title> <head> <body> <p> <img src="f5-logo.png" /></p> <font size=5 face=Terminal color="red"><b>a??a?!a??a? ̄ a?10.99.100.215/admina?a?§a??a ?</b></font><br /> <br /> <br /> <font face=Terminal color="red"><br /> <b>REMOTE_ADDR: 10.99.2.251 </b> <br/> <b>REMOTE_PORT: 41950 </b> <br/> <b>SERVER_ADD ↓HTTP レスポンス 200 を受信。 Jun 26 17:36:24 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <HTTP_RESPONSE>: Got HTTP RESPONSE of 200!!! ↓HTTP レスポンスの HTML ボディデータ。 Jun 26 17:36:24 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <HTTP_RESPONSE_DATA>: HTTP RESPONSE Payload is "<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xttml1-transitional.dtd"> <html xmlns="http://www.w3.org.1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>f5-test-web</title> <head> <body> <p> <img src="f5-logo.png" /></p> <font size=5 face=Terminal color="red"><b>a??a?!a??a? ̄ a?10.99.100.215/admina?a?§a??a ?</b></font><br /> <br /> <br /> <font face=Terminal color="red"><br /> <b>REMOTE_ADDR: 10.99.2.251 </b> <br/> <b>REMOTE_PORT: 41950 </b> <br/> <b>SERVER_ADDR: 10.99.100.215 </b> <br/> <b>SERVER_PORT: 80 </b> <br/> </font><br /> <font face=Terminal color="blue"><b>METHOD : GET </b> <br/> <b>URI : /admin/ </b><br/> <b>QUERY_STRING: </b><br/> </font><br /> <font face=Terminal color="green"><b>Accept: text/html, application/xhtml+xml, */* </b><br/> <b> ↓クライアントからの TCP クローズ。 Jun 26 17:36:24 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <CLIENT_CLOSED>: CLIENT SIDE CONNECTION to 10.99.4.19 was closed ↓サーバからの TCP クローズ。 Jun 26 17:36:24 big189 info tmm[11003]: Rule /Common/SEVERAL_EVENT <SERVER_CLOSED>: SERVER SIDE CONNECTION to 10.99.100.215 was closed 88 12.2. コマンド一覧 (2015/6 現在) IP IP::client_addr IP::server_addr IP::remote_addr IP::local_addr IP::addr IP::version IP::tos IP::ttl IP::protocol IP::reputation IP::intelligence (v11.6.0~) IP::hops IP::stats IP::idle_timeout TCP TCP::client_port TCP::server_port TCP::local_port TCP::remote_port TCP::collect TCP::payload TCP::offset TCP::release TCP::delayed_ack TCP::dsack TCP::nagle TCP::idletime TCP::congestion TCP::option TCP::mss TCP::notify TCP::bandwidth TCP::respond TCP::rtt TCP::unused_port TCP::close TCP::abc (v11.6.0~) TCP::ecn (v11.6.0~) TCP::limxmit (v11.6.0~) 概要 クライアント IP アドレスを返す。 サーバの IP アドレスを返す。 BIG-IP から見てリモートの IP アドレスを返す。 (クライアント IP の場合もあれば、サーバ IP の場合もある。) クライアントまたはサーバから接続される、BIG-IP が持つ IP アドレス(Virtual Server の IP または Self-IP)を返す。 IP アドレス/サブネット と IP アドレス/サブネットの比較を行い、真偽を返す。 例:[IP::addr [IP::client_addr]/8 equals 10.0.0.0] IP パケットのバージョン(v4,v6)を返す。 IP パケットの ToS 値を返す。 IP パケットの TTL を返す。 IP パケットのプロトコル番号を返す。 IP インテリジェンスのデータベース内の IP アドレスを検索し、レピュテーション カテゴリを含んだ TCL リストを返す。 IP インテリジェンスのデータベース内の IP アドレスを検索し、レピュテーション カテゴリを含んだ TCL リストを返す。 更に、ユーザが定義した feed list も検索対象に含めることができる。 対抗端の IP 装置から BIG-IP までのホップ数を返す。 コネクション内で送られた or 受信されたパケット数を返す。 アイドルタイムアウト値を返す or セットする。 概要 クライアント側の TCP コネクションの、クライアント PC のポート番号を返す。 サーバ側の TCP コネクションの、サーバの TCP ポート番号を返す。 TCP コネクションの、BIG-IP 側の TCP ポート番号を返す。 クライアント/サーバ側両方の、BIG-IP から見てリモートの TCP ポート番号を返 す。 指定したバイト数のコンテンツデータを収集する。 TCP::collect 取得した TCP データコンテンツを変更 or 返す。 TCP::collect によって占有されたメモリ量(bytes)を返す。 TCP::collect で収集したデータを消去&リリースし、処理を再開する。 TCP delayed ACK を有効化/無効化する。 TCP duplicate selective ack を有効化/無効化する。 TCP コネクション上の Nagle アルゴリズムを有効化/無効化する。 TCP アイドルタイムアウトをセットする。 TCP 輻輳制御アルゴリズムをセットする。 TCP ヘッダから、指定されたオプションの値を得る or セットする。 TCP コネクションの Maximum Segment Size (MSS)を返す。 USER_REQUEST または USER_RESPONSE イベントを呼び出す。 対向端との帯域幅を返す。 対向端へ、特定データを直接送る。 TCP コネクションの Round Trip Time(RTT)値を返す。 指定した IP の組合せで、使われていない TCP ポートを返す。 TCP コネクションを閉じる。 TCP の適切な byte カウンティングを有効化/無効化する。 TCP explicit congestion notification を有効化/無効化する。 TCP limited transmit recovery を有効化/無効化する。 89 TCP::lossfilter (V11.6.0~) TCP::pacing (V11.6.0~) TCP::proxybuffer (V11.6.0~) TCP::recvwnd (V11.6.0~) TCP::sendbuf (V11.6.0~) TCP::setmss (V11.6.0~) TCP がロスを無視するレベルのバーストとレートをセットする。 UDP UDP::client_port UDP::server_port UDP::local_port UDP::remote_port 概要 UDP::unused_port UDP::mss UDP::payload UDP::respond UDP::drop TCP rate pace を有効化/無効化する。 TCP Proxy バッファの閾値をセットする。 TCP レシーブウィンドウをセットする TCP センドバッファサイズをセットする。 TCP MSS(max segment size)をセットする。 クライアントの UDP ポート番号を返す。 サーバの UDP ポート番号を返す。 BIG-IP 側の UDP ポート番号を返す。 クライアント側/サーバ側関係なく、BIG-IP から見てリモートの装置の UDP ポート 番号を返す。 指定した IP の組合せで、利用していない UDP ポートを返す。 UDP コネクションの Maximum Segment Size (MSS)を返す。 UDP ペイロードの指定した長さのコンテンツを返す。 TCP のように、collect する必要は無く使える。また CLIENT_DATA や SERVER_DATA イベントでなくても使える。 対向端へ直接データを送る。 コネクションテーブルからフローを取り除くことなく、UDP パケットをドロップす る。 SSL SSL::authenticate SSL::cert SSL::cipher SSL::collect SSL::disable SSL::enable SSL::extensions SSL::forward_proxy SSL::handshake SSL::is_renegotiation_secure SSL::mode SSL::modssl_sessionid_headers SSL::payload SSL::profile SSL::release SSL::renegotiate SSL::respond SSL::secure_renegotiation SSL::session SSL::sessionid 概要 現在の認証頻度 or 証明書チェーンの最大深度の設定を上書きする。 X509 SSL 証明書データを返す。 SSL cipher の情報を返す。 SSL オフローディング後のプレーンテキストデータを収集する。 SSL 処理を無効化する。 SSL 処理を再有効化する。 SSL extensions を返す or 操作する。 SSL forward proxy バイパス機能を bypass or intersept にセット する。 SSL アクティビティを停止 or 再開する。 SSL セキュア再ネゴシエーションの現状の状態を返す。 SSL の有効/無効状態を返す。 HTTP ヘッダのフィールドの List を返す。 SSL::collect によって収集されたプレーンテキストデータを返す or 操作する。 Switch between different SSL profiles 異なる SSL プロファイルにスイッチ(変更)する。 収集されたプレーンテキストデータをリリースする。 SSL コネクションの再ネゴシエーションを制御する。 SSL の送信元へ、データを送り返す。 SSL セキュア再ネゴシエーションモードを制御する。 SSL セッションキャッシュからセッションをドロップする。 SSL セッション ID を得る。 90 SSL::sessionticket SSL::unclean_shutdown SSL::verify_result HTTP HTTP::close HTTP::cookie HTTP::fallback HTTP::header HTTP::request HTTP::host HTTP::is_keepalive HTTP::is_redirect HTTP::method HTTP::disable HTTP::enable HTTP::passthrough_reason (V11.5.0~) HTTP::username HTTP::password HTTP::uri HTTP::path HTTP::query HTTP::collect HTTP::release HTTP::payload SSL フローに紐付いたセッションチケットを返す。 不正な shutdown 設定の値をセットする。 対向端の証明書検証 (クライアント証明書?) の結果コードを得る or セットする。 概要 その HTTP のコネクションを閉じる。 HTTP リクエスト及びレスポンスに対して、Cookie の挿入、削除、値の取得といっ た操作を行う。 Usage 例: HTTP::cookie namesTLC の List 形式で、HTTP ヘッダ内にある全 Cookie 名を返 す。 HTTP::cookie insert name <name> value <value> <name>と<vaule>の組合せの Cookie を挿入する HTTP Profile 内に指定された fallback ホストを指定 or 上書きする。 HTTP ヘッダのいずれかを指定し、その値を取得または変更する。 HTTP リクエストのヘッダを全て返す。 HTTP ホストヘッダの値を返す。 このコネクションが Keep-Alive 状態なら、"真"を返す。 このレスポンスがリダイレクトなら、"真"を返す。 HTTP リクエストメソッドのタイプを返す。 HTTP フィルタを、フル解析モードからパススルーモードへ変更する。 HTTP フィルタを、パススルーモードからフル解析モードへ変更する。 HTTP フィルタによってパススルーモードに変わった理由として、以下のいずれかを 返す。(例えば、HTTP プロファイル内に、「Web ソケットが来たらパススルーにす る」、という HTTP フィルタが設定されている、と考える。) ・ Unknown ・ iRule ・ Connect ・ Web Sockets ・ Oversize Client Headers ・ Excess Client Headers ・ Oversize Server Headers ・ Excess Server Headers ・ Unknown Method ・ Pipelined Data HTTP ベーシック認証の username 部分を返す。 HTTP ベーシック認証の password 部分を返す。 HTTP リクエストの URI 部分を返す or セットする。 例:http://www.example.com:8080/main/index.jsp?user=test&login=check URI は「/main/index.jsp?user=test&login=check」 HTTP リクエストの Path 部分を返す or セットする。 ("?"以降のクエリ文字列は含まない。) 例:http://www.example.com:8080/main/index.jsp?user=test&login=check Path は「/main/index.jsp」 HTTP リクエストのクエリ文字列部分を返す。 例:http://www.example.com:8080/main/index.jsp?user=test&login=check Query は「user=test&login=check」 HTTP ボディデータの、指定したバイト数分を収集する。 HTTP::collect で集めたデータをリリースする。 Queries for or manipulates HTTP payload information. HTTP ペイロード情報の要求 or ペイロード情報を操作する。 Usage 例: HTTP::payload <length> HTTP::collect コマンドが収集したコンテンツを、指定 した byte 数分返す。 HTTP::payload length HTTP::collect コマンドが収集したコンテンツの長さを返 す。 91 HTTP::redirect HTTP::request_num HTTP::respond HTTP::retry HTTP::status HTTP::version HTTP::proxy (V11.6.0~) LB LB::class LB::context_id LB::detach LB::down LB::dst_tag LB::mode LB::persist LB::prime LB::reselect LB::select LB::server LB::snat LB::src_tag LB::status LB::up LB::queue HTTP リクエストを受けたとき、またはレスポンスを返すときに、指定した URL へリ ダイレクトさせる。 あるコネクション上でクライアントが生成した HTTP リクエストの数量を返す。 まるでサーバからレスポンスが来たかのように、HTTP レスポンスを生成してクライ アントに返す。 HTTP リクエストをサーバへ再送する。 Usage: set request_headers [HTTP::request] HTTP::retry $request_headers HTTP レスポンスのステータスコードを返す。 HTTP リクエストまたはレスポンスの HTTP バージョンを返す or セットする。 Explict HTTP profile を使っているときに、HTTP Proxy のアプリケーションを制 御する。 概要 コネクションにマッチしたトラフィック Class の名前を提供する。 現在のコネクションを、名前付きコンテキストにアサインする。 サーバ側コネクションを切断する。 node または pool member のステータスを Down 状態にセットする。 現在のリクエストに、宛先 tag をセットする。 ロードバランシングモードをセットする。 パーシステンスレコードの検索を強制し、結果を返す。 クライアントからのトラフィックが来る前に、サーバ側コネクションをセットす る。 ロードバランシング先を再選択する。 ロードバランシングセレクションを強制し、結果を返す。 今選ばれたサーバについての情報を返す。 Virtual Server の SNAT コンフィグレーションについての情報を返す、 現在のリクエストに、送信元 tag をセットする。 node アドレスまたは pool member のステータスを返す。 node または pool member のステータスを Up 状態にする。 キューの情報を返す。 AES 概要 AES::key AES::decrypt AES::encrypt データを暗号化/複合化するための AES Key を生成する。 事前に生成された AES Key を使ってデータを複合化する。 事前に生成された AES Key を使ってデータを暗号化する。 92
© Copyright 2024 Paperzz