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. ファンクション ......................................................................... 36
4.5. ステートメント ......................................................................... 37
4.6. コマンド .............................................................................. 38
出現頻度の高いコマンド ............................................................ 38
コマンドの注意点 .................................................................. 40
5. iRules動作確認用のネットワーク構成サンプル ................................................ 41
6. LTMの設定 ............................................................................... 42
6.1. Platform設定 ........................................................................ 42
6.2. VLAN設定 ............................................................................ 42
6.3. Self IP設定 ......................................................................... 43
6.4. Routing設定 ......................................................................... 43
6.5. Poolの設定 .......................................................................... 44
http-pool ....................................................................... 44
A-pool .......................................................................... 45
B-pool .......................................................................... 45
6.6. Virtual Serverの設定 ................................................................ 46
Web-vs (Port:80) ................................................................ 46
Secure-vs (Port:443) ............................................................ 47
7. iRulesの使い方 .......................................................................... 48
7.1. [パターン 1] iRule Editor を使う ....................................................... 48
7.2. [パターン 2] BIG-IPの Web GUI を使う ................................................... 50
iRuleの適用 ..................................................................... 51
出力されるログの確認 .............................................................. 52
8. iRulesの具体例 .......................................................................... 53
8.1. よく使う EVENTの例 .................................................................... 53
CLIENT_ACCEPTED ................................................................. 53
CLIENT_DATA ..................................................................... 54
HTTP_REQUEST .................................................................... 55
HTTP_RESPONSE ................................................................... 56
RULE_INIT ....................................................................... 57
LB_FAILED ....................................................................... 59
9. Class / Data-Groupの使い方 .............................................................. 61
Data-Groupのデータの Type ........................................................ 62
Internal Data-Group ............................................................. 63
External Data-Group (その 1:String形式) .......................................... 66
External Data-Group (その 2:Address形式) ......................................... 68
9.2. tableの使い方 ....................................................................... 71
10. iRule作成のテクニック ..................................................................... 74
10.1. デバッグのやり方 ...................................................................... 74
本番環境でのロギング有効化/無効化 ................................................ 74
10.2. iRuleによる CPU使用率の測定 .......................................................... 76
2つの iRuleで CPU使用率を比較 .................................................... 76
iRuleの CPU使用率の計算 ......................................................... 78
10.3. iRule を最適化する ................................................................... 79
11. おわりに ................................................................................. 84
12. Appendix ................................................................................ 85
12.1. EVENT発動のタイミング ................................................................. 85
EVENTのフロー .................................................................... 85
EVENT発動を確認するためだけの iRule ............................................... 86
出力されたログ ................................................................... 87
12.2. コマンド一覧 (2015/6現在) ............................................................ 89
4
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へ送る。
以降、詳細解説に入ります。
5
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でログインします。
(2) User nameに「root」を入力し、Use challenge/response to log in をチェックします。
BIG-IPのマネージメント IPアドレス
6
(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」キーを押してください。
7
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
8
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」 = "真"という値が返されます。
9
[参考] 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 はブーリアンタイプか
または数値。
10
3.4. ドル記号 $ (変数置換) [その 1]
TCLの重要な機能のひとつに変数があります。
この変数機能の提供により、コマンド間でのデータの受け渡しが可能になります。
変数は set コマンドにより生成されます。
TCLパーサー※は、$記号が先頭に付いた要素を変数名とみなし、その変数をその実体に置き換えてからコマンドを
実行します。
これが「変数置換」です。
% set a 100
% puts $a
→ 「100」 が返されます。
TCLパーサーが、$a (=変数) を 100 (=実体) に変数置換した結果です。
(ちなみに"puts"は、ディスプレイへの標準出力を行うコマンドです。)
[※参考] TCLパーサー(Parser)とは
パーサー(Parser)は、一般的には、構文解析を行うためのプログラムの総称です。
TCLにおいてもパーサーが存在しており、「TCL言語で記載されたスクリプトを解析するプログラム」とお考えくださ
い。
以降の解説でも、TCLパーサーという言葉を使います。
11
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
}
12
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」が返されます。
13
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」が返されます。
14
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
が出力されます。
このように、ダブルクォーテーションの機能は、コマンド置換と変数置換を許すところが、ブレス{ }と異なる点です。
15
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内
で一度に処理するので、②の方が効率は良い、といえます。
16
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回に減らすことができるからです。
17
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 アーギュメントをブレス{ }で囲む必要があります。
18
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 コマンドのアーギュメントは、常にブレス{ }で挟んでおくことで、不要なエラー
を避けることができます。
19
3.10. if, else, elseif
if, else, elseif を使って、複雑な条件分岐を行うことができます。
(1) サンプル 1
$varの値が 1なら、変数 aに値 123 をセットします。
% set var □ ←□に、1または 1 以外を入力
% if {$var == 1} {
set a 123
}
(2) サンプル 2
$varの値が 1なら、変数 aに値 123 をセット、それ以外であれば変数 aに値 456 をセットします。
% set var □ ←□に、1または 1 以外を入力
% if {$var == 1} {
set a 123
} else {
set a 456
}
(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
}
20
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 を比較するときに、正規表現が使われます。
21
[参考] glob と regexpの違い
正規表現には、globスタイルと regexpスタイルがあり、両者の違いは以下の通りです。
globのほうが比較的シンプルに作られています。
globスタイル regexpスタイル
* 0文字以上の文字にマッチ * 0文字以上の文字にマッチ
? 1文字にマッチ . 1文字にマッチ
+ + 1文字以上にマッチ
? 0または 1文字にマッチ
^ 行の先頭にマッチ
$ 行の最後にマッチ
[chars] charsの 1文字にマッチ。
[a-z]などが使える
[chars] charsの 1文字にマッチ。
[a-z]などが使える
¥x 文字 xにマッチ ¥x 文字 xにマッチ
{a,b,...} a,b等文字列にマッチ {a,b,...} a,b等文字列にマッチ
exp1 | exp2 選択
( exp ) 部分パターン
(その他、省略)
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」 が返されます。
22
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
23
以下のように、同名の通常変数と配列変数を同一のスクリプト内で使用することはできません。
使うとエラーになります。
% set a 300
% set a(1) 400
can't set "a(1)": variable isn't array
また、要素数は数字である必要は無く、文字列も使用できます。
% unset -nocomplain a ← 一旦、変数"a"を削除。
% set a(jkl) 200
ただし、利用の利便性を考えると数字を使用するのが一般的です。
24
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」が返されます。
25
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」が返されます。
26
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の前に$をつけません。)
27
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」が返されます。
28
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」が返されます。
29
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 is AAAA
item is BBBB
item is CCCC DDDD
item is EEE
3.16. TCLのマニュアル
TCLはこの他にも多数のコマンドを持っています。
また、コマンドによっては、ここに紹介したもの以外にも多数のオプションを持っているものがあります。
実際の TCL コマンド利用に際しては、以下リンクを参照して、より要件にあうコマンドやオプション指定がないかを確
認してください。
英語:
http://www.tcl.tk/
日本語:
http://www.freesoftnet.co.jp/tclkits/doc/TclCmdRef/tcl_contents_jp.htm
30
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 コネクションが TCP::collecct(TCP データを取得する)状態にあるとき、クライアントから新し
いデータを受け取るたびにトリガーされる。
HTTP_REQUEST クライアントからの HTTPリクエストヘッダを解析できる状態(HTTP Profile が有効になってい
る状態)にあって、HTTPリクエストを受信したときにトリガーされる。
HTTP_RESPONSE サーバからの HTTPレスポンスのステータス及びヘッダを解析できる状態(HTTP Profile が有効
になっている状態)にあって、サーバからの HTTPレスポンスを受信したときにトリガーされ
る。
RULE_INIT iRule が追加されたとき、または変更されたときにトリガーされる。
LB_FAILED poolまたは pool member の選択に失敗したときにトリガーされる。または選択した node,pool
member に到達できないときにもトリガーされる。
これらの EVENT については、iRule の具体例のセクションにて、サンプルを使って説明します。
31
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 コマンドによる変数を使います。
32
グローバル変数 (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 コマンドの利用を推奨します。
33
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 の具体例のセクションにて、サンプルを使って説明します。
34
iRulesの変数一覧
iRulesで利用可能な変数の一覧です。
これらのうち、本ガイドの具体例では、推奨フィールドに○がついた変数のみ利用します。
推奨 変数 CMP
対応
設定
(生成、読出し、削除)
変数の解除 Standby
への Mirror
最小
Version
×
Global
TCL形式
× set ::<key> <value>
$::<key>
unset ::<key>
Unsetコマンド × v9.0
○ Global
static::
○ set static::<key> <value>
$static::<key>
できない。 ○ v9.7
○ Local ○ set <key> <value>
$key
unset <key>
1)Unset コマンド
2)コネクションの終了
× v9.0
△ session ×:v 9.0
○:v10.0
session add uie <key> <value>
session lookup uie <key>
session delete uid <key>
1)Timeout
2)session delete コマンド
○ v9.0
○ Table ○ table set <key> <value>
table lookup <key>
table delete <key>
1)Timeout
2)table delete コマンド
○ v10.1
35
4.3. 演算子 ( Operators )
iRulesでは、演算子(Operators)は 2つの値を比較したい場合によく利用されます。
TCLが標準で持つ演算子(==, <=, >=, ...)に加えて、F5は、starts_with, contains, ends_withのような比
較補助のための演算子を追加しています。
演算子 解説
"A" contains "B" "A"文字列が、"B"文字列を含むかどうか
"A" ends_with "B" "A"文字列が、"B"文字列で終わるかどうか
"A" equals "B" "A"文字列と"B"文字列が一致するかどうか
"A" matches_glob "B" "A"文字列と"B"文字列が glob 形式での比較で一致するかどうか
"A" matches_regex "B" "A"文字列と"B"文字列が regex 形式での比較で一致するかどうか
"A" starts_with "B" "A"文字列が、"B"文字列で始まるかどうか
"A" and "B" "A"と"B"の値を、AND条件で評価する
(例: "A"と"B"の両方が真ならば、次のアクション)
"A" not "B" "A"と"B"の値を、NOT条件で評価する
(例: "A"と"B"の値が異なるのならば、次のアクション)
"A" or "B" "A"と"B"の値を、OR条件で評価する
(例: "A"または"B"の値が真ならば、次のアクション)
36
4.4. ファンクション
ファンクション(Functions)は、検索した結果の値を返すのに役立つコマンドです。
大きく、以下 2つに分類されます。
(1) Class ファンクション
事前に作成した key:value タイプのデータベースから情報を検索して値を戻します。
Classについては、後述します。
(2) 文字列ファンクション
ある文字列から値を返す操作を行います。
F5では、以下のような独自の文字列ファンクションを用意しています。
ファンクション 解説
findstr findstr <string> <search_string> [<skip_count> [<terminator count or string>]]
<string>の文字列から、<search_string>の文字を見つけ出し、見つけ出した文字の先
頭から<skip_count>分オフセットしたところを始点とした文字を返す。
また、<terminator count or string>を指定すると、その手前までの文字を返す。
例:
findstr www.sub.my.domain.com sub 7 .com
結果: domain
substr substr <string> <skip_count> [<terminator>]
<string>の文字列の先頭から<skip_count>で指定した文字数分をスキップし、
<terminator>で指定した文字で終わるまでの文字を返す。
例:
substr www.sub.my.domain.com 11 .com
結果: domain
getfield getfield <string> <split> <field_number>
<string>の文字列を、<split>で指定した文字で分割し、<field_number>で指定したフ
ィールドの文字を返す。
例:
getfield www.sub.my.domain.com . 4
結果: domain
domain domain <string> <count>
"."で区切られたドメイン名:<string>を"."単位で区切って、<count>指定した数の後
ろからの区切り数分の文字を返す。
例:
domain www.sub.my.domain.com 2
結果: domain.com
37
4.5. ステートメント
ステートメント (Statements) は一般的には「何かを実行する」ものであり、値を戻さないコマンドです。
例えば TCLでは、条件分岐を行う「if」、「switch」、「while」、「for」などがステートメントに該当します。
f5では独自に、以下のようなステートメントを用意しています。
ステートメント 解説
when iRule のイベントを指定する場合に使う。
log syslog-ngユーティリティへ、ログを出力する。
pool モニターステータスに関わらず、指定した 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 の平均負荷値を返す。
38
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アドレスを返す。
IP::server_addr サーバの IPアドレスを返す。
IP::remote_addr BIG-IPから見てリモートの IPアドレスを返す。
(クライアント IPの場合もあれば、サーバ IPの場合もある。)
IP::local_addr クライアントまたはサーバから接続される、BIG-IPが持つ IPアドレス(Virtual
Serverの IPまたは Self-IP)を返す。
または、サーバ側では、クライアント IPを SNAT変換しないで出力する場合はその
アドレスを、SNATする場合には SNATアドレスが該当する。
IP::addr IPアドレス/サブネット と IPアドレス/サブネットの比較を行い、真偽を返す。
例:[IP::addr [IP::client_addr]/8 equals 10.0.0.0]
(2) TCP
TCP 概要
TCP::client_port クライアント側の TCPコネクションの、クライアント PCのポート番号を返す。
TCP::server_port サーバ側の TCPコネクションの、サーバの TCPポート番号を返す。
TCP::local_port TCPコネクションの、BIG-IP側の TCPポート番号を返す。
TCP::remote_port クライアント/サーバ側両方の、BIG-IPから見てリモートの TCPポート番号を返
す。
TCP::collect 指定したバイト数のコンテンツデータを収集する。
TCP::payload TCP::collect 取得した TCPデータコンテンツを変更 or 返す。
TCP::release TCP::collect で収集したデータを消去&リリースし、処理を再開する。
TCP::bandwidth 対向端との帯域幅を返す。
TCP::respond 対向端へ、特定データを直接送る。
TCP::close TCPコネクションを閉じる。
(3) HTTP
HTTP 概要
HTTP::request HTTPリクエストのヘッダを全て返す。
HTTP::header HTTPヘッダのいずれかを指定し、その値を取得または変更する。
HTTP::uri HTTPリクエストの URI部分を返す or セットする。
例:http://www.example.com:8080/main/index.jsp?user=test&login=check
URIは「/main/index.jsp?user=test&login=check」
HTTP::host HTTPホストヘッダの値を返す。
HTTP::cookie HTTPリクエスト及びレスポンスに対して、Cookieの挿入、削除、値の取得といっ
た操作を行う。
Usage例:
HTTP::cookie namesTLCの List形式で、HTTPヘッダ内にある全 Cookie名を返す。
HTTP::cookie insert name <name> value <value> <name>と<vaule>の組合せの
Cookieを挿入する
39
HTTP::path HTTPリクエストの Path部分を返す or セットする。
("?"以降のクエリ文字列は含まない。)
例:http://www.example.com:8080/main/index.jsp?user=test&login=check
Pathは「/main/index.jsp」
HTTP::query HTTPリクエストのクエリ文字列部分を返す。
例:http://www.example.com:8080/main/index.jsp?user=test&login=check
Queryは「user=test&login=check」
HTTP::collect HTTPボディデータの、指定したバイト数分を収集する。
HTTP::release HTTP::collect で集めたデータをリリースする。
HTTP::payload Queries for or manipulates HTTP payload information.
HTTPペイロード情報の要求 or ペイロード情報を操作する。
Usage例:
HTTP::payload <length> HTTP::collect コマンドが収集したコンテンツを、指定
した byte数分返す。
HTTP::payload length HTTP::collect コマンドが収集したコンテンツの長さを返
す。
HTTP::redirect HTTPリクエストを受けたとき、またはレスポンスを返すときに、指定した URLへリ
ダイレクトさせる。
HTTP::respond まるでサーバからレスポンスが来たかのように、HTTPレスポンスを生成してクライ
アントに返す。
HTTP::status HTTPレスポンスのステータスコードを返す。
(4) AES
AES 概要
AES::key データを暗号化/複合化するための AES Key を生成する。
AES::decrypt 事前に生成された AES Key を使ってデータを複合化する。
AES::encrypt 事前に生成された AES Key を使ってデータを暗号化する。
(5) LB
LB 概要
LB::detach サーバ側コネクションを切断する。
LB::down nodeまたは pool member のステータスを Down状態にセットする。
LB::mode ロードバランシングモードをセットする。
LB::persist パーシステンスレコードの検索を強制し、結果を返す。
LB::reselect ロードバランシング先を再選択する。
LB::select ロードバランシングセレクションを強制し、結果を返す。
LB::server 今選ばれたサーバについての情報を返す。
LB::snat Virtual Server の SNATコンフィグレーションについての情報を返す。
LB::status nodeアドレスまたは pool member のステータスを返す。
LB::up nodeまたは pool member のステータスを Up状態にする。
40
コマンドの注意点
コマンドについての注意点について触れておきます。
(1) コマンド毎に利用できる Event と利用できない Eventが存在
コマンドによって、どの Event内なら利用できるかが決まっています。
例)
以下は DevCentral上の「HTTP::url」のマニュアル画面です。
https://devcentral.f5.com/wiki/iRules.HTTP__uri.ashx
~略~
この「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
利用できる Event
41
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で利用します。
42
6. LTMの設定
LTM設定のより詳細は、「LTMかんたんセットアップガイド」を参照ください。
ここでは、以降の iRuleサンプルを動作させるために必要な LTMの設定箇所を示します。
6.1. Platform設定
以下は、初期ウィザードの流れの中で設定します。
設定した内容は、「System」→「Platform」で確認できます。
6.2. VLAN設定
「Network」→「VLANs」で、以下の状態になるように設定します。
ホスト名。FQDN形式で指定。
Asia/Tokyo を選択。
CLIアクセス用 rootアカウントの
パスワード
WebUIアクセス用 adminアカウントの
パスワード
43
6.3. Self IP設定
「Network」→「Self IPs」で、以下の状態になるように設定します。
6.4. Routing設定
「Network」→「Routes」で、以下の状態になるように設定します。
44
6.5. Poolの設定
「Local Traffic」→「Pools」で設定します。
http-pool
任意の名前を入力。
ヘルスモニター(http)を設定。
Pool Memberのアドレスと Port番号を
入力して、「Add」ボタンを押す。
45
A-pool
B-pool
任意の名前を入力。
ヘルスモニター(http)を設定。
Pool Memberのアドレスと Port番号を
入力して、「Add」ボタンを押す。
任意の名前を入力。
ヘルスモニター(http)を設定。
Pool Memberのアドレスと Port番号を
入力して、「Add」ボタンを押す。
46
6.6. Virtual Serverの設定
Web-vs (Port:80)
~略~
任意の名前を入力。
IPアドレスとポート番号を入力。
環境に応じて設定。
設定済みの「http-pool」を選択。
HTTP Profile を選択。
47
Secure-vs (Port:443)
~略~
任意の名前を入力。
IPアドレスとポート番号を入力。
環境に応じて設定。
設定済みの「http-pool」を選択。
本ガイドでは簡易的に、
デフォルトで用意されている、
clientssl を選択。
HTTP Profile を選択。
48
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 を入力。
② Adminのパスワードを入力。
③ OK をクリック。
49
(3) 以下の赤点線部分をクリックします。
(4) iRuleの名前を入力します。
(5) User-Agent を、ログファイルへ出力する iRule を入力します。
設定後、saveボタンを押します。
上記の iRule:
when HTTP_REQUEST {
log local0. "USER-AGENT is [string tolower [HTTP::header "User-Agent"]]"
}
iRuleの名称(任意)を入力。
Saveボタン
50
7.2. [パターン 2] BIG-IPのWeb GUIを使う
BIG-IPの Web GUI インタフェースから直接 iRule を作成・編集することも可能です。
「Local Traffic」→「iRules」で表示された画面右上の「Create」ボタンを押して表示された画面で、以下のように設
定します。
iRuleの名称(任意)を入力。
iRule を入力。
51
iRuleの適用
作成した iRule を Virtual Serverへ適用します。
(1) 「Local Traffic」 → 「Virtual Server」で表示された設定済みの Virtual Server:Web-vs を選択し、画面の
上に表示された「Resources」タブをクリックします。
iRulesの部分の「Manage」ボタンを押します。
(2) 作成した iRule を選択し、「<<」ボタンを押します。
(3) 以下の状態になります。
52
出力されるログの確認
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>: USER-AGENT
is mozilla/5.0 (windows nt 6.1; rv:30.0) gecko/20100101 firefox/30.0
② Internet Explorer
Aug 26 03:04:21 big208 info tmm3[11991]: Rule /Common/User-Agent_check <HTTP_REQUEST>: USER-AGENT
is mozilla/5.0 (windows nt 6.1; trident/7.0; rv:11.0) like gecko
以上が、iRuleの基本的な使い方です。
53
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 18 18:42:44 big208 info tmm[13467]: 01220002:6: Rule /Common/current_time <CLIENT_ACCEPTED>:
the time is: 18:42:44
May 18 18:42:44 big208 info tmm1[13467]: 01220002:6: Rule /Common/current_time <CLIENT_ACCEPTED>:
the time is: 18:42:44
[参考]
UDPの場合は、TCPのようなハンドシェークは存在しないので、コネクションテーブルにエントリされたタイミングで発
動され、その UDPのエントリは、アイドルタイムアウトになる(デフォルト 60秒)まで存続し続けます。
よって、タイムアウトまでの間にそのエントリと同じ情報を持つ UDPパケットが到達しても、このイベントは新規と見な
されないため、発動しません。
54
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 コマンドによるデータ取得は必要ありません。
55
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」へリダイレクトされます。
56
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」の表示が無い状態で切断されます。
57
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"
}
}
58
① この 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=
59
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
・①
・②
・③
・④
・⑤
・⑥
・⑦
・⑧
・⑨
・⑩
・⑪
・⑫
・(a)
・(b)
・(c)
・(d)
・(e)
・(f)
・⑬
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
}
① HTTP リクエストを受け取ったとき、
② URIが"/admin"の文字で始まっていたら、
③ 変数:adminに"1"をセットし、
④ 10.99.100.211:80に、この HTTP リクエストを送る。
⑤ URIが"/admin"以外なら、
60
⑥ 変数: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からのレスポンスが得られることを
確認してください。
61
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つの方式それぞれの利用方法を解説します。
62
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",
63
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を作ります。
64
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 を選択した画面
です。ここで編集が可能です。
65
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からのレスポンスが得られることを確
認してください。
66
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
}
67
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からのレスポンスが得られることを確
認してください。
68
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
}
69
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の設定」ボタンを押す。
70
サンプルネットワーク構成図中の 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からのレスポンスのみが得られることを確認してください。
71
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"
72
・⑬
・⑭
・⑮
・⑯
・⑰
・⑱
・⑲
・⑳
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になるまでカウントするための一時的なレコードであるため。)
⑲ クライアントからのパケットはドロップ。
⑳ この処理から抜ける。
73
(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
秒待ってから実施してください。
74
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に、この方法を適用してみます。
75
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」に変更し、同様の動作確認を行ってください。
ログが出力されなくなることを確認してください。
76
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
77
(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サイクルを使用していることがわかります。
78
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 1
Registration Key -
Hardware Version Information
Name cpus
Type base-board
Model Intel(R) Xeon(R) CPU E5540 @ 2.53GHz
Parameters -- --
cache size 8192 KB
cores 2
cpu MHz 2527.000
Platform
Name BIG-IP Virtual Edition
BIOS Revision
Base MAC 00:50:56:bd:a4:0b
~省略~
10.2.2.2. 計算
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%上昇する、と見込まれます。
79
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 よりも柔軟性が高いので、適材適所で利用する。
80
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 foreach
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]
# This is slower
}
}
when HTTP_REQUEST {
set domains [bob.com ted.com domain.com]
foreach domain $domains {
# This is faster, and more elegant
}
}
しかし、条件を多数指定する forに対し、foreachは 1つの行で同じ形を実現できます。
よって、foreachで要件を見たせるならばその方が効率はよく、また、見た目も美しくなります。
81
(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
}
}
82
(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
}
}
83
(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 == 5 } { } # evaluates to true
if { $x eq 5 } { } # evaluates to true
if { $x == 05 } { } # evaluates to true
if { $x eq 05 } { } # evaluates to false
よって、要件に応じて、適切なオペレータを使い分けるようにしてください。
84
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ネットワークスジャパンのエンジニアが特定のソフトウェアバージョンの動作仕様に基づいて作成した構築・設計を補助するための資料であり、メーカー公式資料とは異なります。資料
の記載内容に誤りがあった際には指摘に基づいて修正を行いますが、内容についての責任は一切負いません。また、修正、変更、改訂は予告無く行われます。
85
12. Appendix
12.1. EVENT発動のタイミング
EVENTのフロー
86
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
}
87
・⑩
・⑪
・⑫
・⑬
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 client-
side is "GET /admin/ HTTP/1.1 Accept: text/html, application/xhtml+xml, */* Accept-Language: ja-JP User-
Agent: 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
88
↓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
89
12.2. コマンド一覧 (2015/6現在)
IP 概要
IP::client_addr クライアント IPアドレスを返す。
IP::server_addr サーバの IPアドレスを返す。
IP::remote_addr BIG-IPから見てリモートの IPアドレスを返す。
(クライアント IPの場合もあれば、サーバ IPの場合もある。)
IP::local_addr クライアントまたはサーバから接続される、BIG-IPが持つ IPアドレス(Virtual
Serverの IPまたは Self-IP)を返す。
IP::addr IPアドレス/サブネット と IPアドレス/サブネットの比較を行い、真偽を返す。
例:[IP::addr [IP::client_addr]/8 equals 10.0.0.0]
IP::version IPパケットのバージョン(v4,v6)を返す。
IP::tos IPパケットの ToS値を返す。
IP::ttl IPパケットの TTLを返す。
IP::protocol IPパケットのプロトコル番号を返す。
IP::reputation IPインテリジェンスのデータベース内の IPアドレスを検索し、レピュテーション
カテゴリを含んだ TCLリストを返す。
IP::intelligence
(v11.6.0~)
IPインテリジェンスのデータベース内の IPアドレスを検索し、レピュテーション
カテゴリを含んだ TCLリストを返す。
更に、ユーザが定義した feed list も検索対象に含めることができる。
IP::hops 対抗端の IP装置から BIG-IPまでのホップ数を返す。
IP::stats コネクション内で送られた or 受信されたパケット数を返す。
IP::idle_timeout アイドルタイムアウト値を返す or セットする。
TCP 概要
TCP::client_port クライアント側の TCPコネクションの、クライアント PCのポート番号を返す。
TCP::server_port サーバ側の TCPコネクションの、サーバの TCPポート番号を返す。
TCP::local_port TCPコネクションの、BIG-IP側の TCPポート番号を返す。
TCP::remote_port クライアント/サーバ側両方の、BIG-IPから見てリモートの TCPポート番号を返
す。
TCP::collect 指定したバイト数のコンテンツデータを収集する。
TCP::payload TCP::collect 取得した TCPデータコンテンツを変更 or 返す。
TCP::offset TCP::collect によって占有されたメモリ量(bytes)を返す。
TCP::release TCP::collect で収集したデータを消去&リリースし、処理を再開する。
TCP::delayed_ack TCP delayed ACK を有効化/無効化する。
TCP::dsack TCP duplicate selective ack を有効化/無効化する。
TCP::nagle TCPコネクション上の Nagle アルゴリズムを有効化/無効化する。
TCP::idletime TCPアイドルタイムアウトをセットする。
TCP::congestion TCP輻輳制御アルゴリズムをセットする。
TCP::option TCPヘッダから、指定されたオプションの値を得る or セットする。
TCP::mss TCPコネクションの Maximum Segment Size (MSS)を返す。
TCP::notify USER_REQUEST または USER_RESPONSE イベントを呼び出す。
TCP::bandwidth 対向端との帯域幅を返す。
TCP::respond 対向端へ、特定データを直接送る。
TCP::rtt TCPコネクションの Round Trip Time(RTT)値を返す。
TCP::unused_port 指定した IPの組合せで、使われていない TCPポートを返す。
TCP::close TCPコネクションを閉じる。
TCP::abc
(v11.6.0~)
TCPの適切な byteカウンティングを有効化/無効化する。
TCP::ecn
(v11.6.0~)
TCP explicit congestion notification を有効化/無効化する。
TCP::limxmit
(v11.6.0~)
TCP limited transmit recovery を有効化/無効化する。
90
TCP::lossfilter
(V11.6.0~)
TCPがロスを無視するレベルのバーストとレートをセットする。
TCP::pacing
(V11.6.0~)
TCP rate pace を有効化/無効化する。
TCP::proxybuffer
(V11.6.0~)
TCP Proxy バッファの閾値をセットする。
TCP::recvwnd
(V11.6.0~)
TCPレシーブウィンドウをセットする
TCP::sendbuf
(V11.6.0~)
TCPセンドバッファサイズをセットする。
TCP::setmss
(V11.6.0~)
TCP MSS(max segment size)をセットする。
UDP 概要
UDP::client_port クライアントの UDPポート番号を返す。
UDP::server_port サーバの UDPポート番号を返す。
UDP::local_port BIG-IP側の UDPポート番号を返す。
UDP::remote_port クライアント側/サーバ側関係なく、BIG-IPから見てリモートの装置の UDPポート
番号を返す。
UDP::unused_port 指定した IPの組合せで、利用していない UDPポートを返す。
UDP::mss UDPコネクションの Maximum Segment Size (MSS)を返す。
UDP::payload UDPペイロードの指定した長さのコンテンツを返す。
TCPのように、collectする必要は無く使える。また CLIENT_DATA や SERVER_DATA
イベントでなくても使える。
UDP::respond 対向端へ直接データを送る。
UDP::drop コネクションテーブルからフローを取り除くことなく、UDPパケットをドロップす
る。
SSL 概要
SSL::authenticate 現在の認証頻度 or 証明書チェーンの最大深度の設定を上書きする。
SSL::cert X509 SSL 証明書データを返す。
SSL::cipher SSL cipher の情報を返す。
SSL::collect SSLオフローディング後のプレーンテキストデータを収集する。
SSL::disable SSL処理を無効化する。
SSL::enable SSL処理を再有効化する。
SSL::extensions SSL extensions を返す or 操作する。
SSL::forward_proxy SSL forward proxy バイパス機能を bypass or intersept にセット
する。
SSL::handshake SSLアクティビティを停止 or 再開する。
SSL::is_renegotiation_secure SSL セキュア再ネゴシエーションの現状の状態を返す。
SSL::mode SSLの有効/無効状態を返す。
SSL::modssl_sessionid_headers HTTPヘッダのフィールドの Listを返す。
SSL::payload SSL::collect によって収集されたプレーンテキストデータを返す or
操作する。
SSL::profile Switch between different SSL profiles
異なる SSLプロファイルにスイッチ(変更)する。
SSL::release 収集されたプレーンテキストデータをリリースする。
SSL::renegotiate SSLコネクションの再ネゴシエーションを制御する。
SSL::respond SSLの送信元へ、データを送り返す。
SSL::secure_renegotiation SSLセキュア再ネゴシエーションモードを制御する。
SSL::session SSLセッションキャッシュからセッションをドロップする。
SSL::sessionid SSLセッション IDを得る。
91
SSL::sessionticket SSLフローに紐付いたセッションチケットを返す。
SSL::unclean_shutdown 不正な shutdown 設定の値をセットする。
SSL::verify_result 対向端の証明書検証 (クライアント証明書?) の結果コードを得る or
セットする。
HTTP 概要
HTTP::close その HTTPのコネクションを閉じる。
HTTP::cookie HTTPリクエスト及びレスポンスに対して、Cookieの挿入、削除、値の取得といっ
た操作を行う。
Usage例:
HTTP::cookie namesTLC の List形式で、HTTPヘッダ内にある全 Cookie名を返
す。
HTTP::cookie insert name <name> value <value> <name>と<vaule>の組合せの
Cookieを挿入する
HTTP::fallback HTTP Profile 内に指定された fallback ホストを指定 or 上書きする。
HTTP::header HTTPヘッダのいずれかを指定し、その値を取得または変更する。
HTTP::request HTTPリクエストのヘッダを全て返す。
HTTP::host HTTPホストヘッダの値を返す。
HTTP::is_keepalive このコネクションが Keep-Alive状態なら、"真"を返す。
HTTP::is_redirect このレスポンスがリダイレクトなら、"真"を返す。
HTTP::method HTTPリクエストメソッドのタイプを返す。
HTTP::disable HTTPフィルタを、フル解析モードからパススルーモードへ変更する。
HTTP::enable HTTPフィルタを、パススルーモードからフル解析モードへ変更する。
HTTP::passthrough_reason
(V11.5.0~)
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ベーシック認証の username 部分を返す。
HTTP::password HTTPベーシック認証の password 部分を返す。
HTTP::uri 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 HTTPリクエストの Path部分を返す or セットする。
("?"以降のクエリ文字列は含まない。)
例:http://www.example.com:8080/main/index.jsp?user=test&login=check
Pathは「/main/index.jsp」
HTTP::query HTTPリクエストのクエリ文字列部分を返す。
例:http://www.example.com:8080/main/index.jsp?user=test&login=check
Queryは「user=test&login=check」
HTTP::collect HTTPボディデータの、指定したバイト数分を収集する。
HTTP::release HTTP::collect で集めたデータをリリースする。
HTTP::payload Queries for or manipulates HTTP payload information.
HTTPペイロード情報の要求 or ペイロード情報を操作する。
Usage例:
HTTP::payload <length> HTTP::collect コマンドが収集したコンテンツを、指定
した byte数分返す。
HTTP::payload length HTTP::collect コマンドが収集したコンテンツの長さを返
す。
92
HTTP::redirect HTTPリクエストを受けたとき、またはレスポンスを返すときに、指定した URLへリ
ダイレクトさせる。
HTTP::request_num あるコネクション上でクライアントが生成した HTTPリクエストの数量を返す。
HTTP::respond まるでサーバからレスポンスが来たかのように、HTTPレスポンスを生成してクライ
アントに返す。
HTTP::retry HTTPリクエストをサーバへ再送する。
Usage:
set request_headers [HTTP::request]
HTTP::retry $request_headers
HTTP::status HTTPレスポンスのステータスコードを返す。
HTTP::version HTTPリクエストまたはレスポンスの HTTPバージョンを返す or セットする。
HTTP::proxy
(V11.6.0~)
Explict HTTP profile を使っているときに、HTTP Proxy のアプリケーションを制
御する。
LB 概要
LB::class コネクションにマッチしたトラフィック Classの名前を提供する。
LB::context_id 現在のコネクションを、名前付きコンテキストにアサインする。
LB::detach サーバ側コネクションを切断する。
LB::down nodeまたは pool member のステータスを Down状態にセットする。
LB::dst_tag 現在のリクエストに、宛先 tagをセットする。
LB::mode ロードバランシングモードをセットする。
LB::persist パーシステンスレコードの検索を強制し、結果を返す。
LB::prime クライアントからのトラフィックが来る前に、サーバ側コネクションをセットす
る。
LB::reselect ロードバランシング先を再選択する。
LB::select ロードバランシングセレクションを強制し、結果を返す。
LB::server 今選ばれたサーバについての情報を返す。
LB::snat Virtual Server の SNATコンフィグレーションについての情報を返す、
LB::src_tag 現在のリクエストに、送信元 tagをセットする。
LB::status nodeアドレスまたは pool member のステータスを返す。
LB::up nodeまたは pool member のステータスを Up状態にする。
LB::queue キューの情報を返す。
AES 概要
AES::key データを暗号化/複合化するための AES Keyを生成する。
AES::decrypt 事前に生成された AES Key を使ってデータを複合化する。
AES::encrypt 事前に生成された AES Key を使ってデータを暗号化する。