BIG-IP IP v9 irule A to Z I. はじめに このドキュメントでは BIG-IP v9 の irule について 機 能 を 紹 介 するとともに 実 際 のサンプルを 用 いながら 解 説 します 尚 特 に 断 りが 無 い 限 り irule の 記 述 方 法 や 使 用 されているコマンドは 9.1 の 仕 様 に 基 づいています このため 文 中 にある v9 という 記 述 は 9.1 を 指 します II. III. irule とは irule とは VirtualServer( 以 下 VS)に 関 連 付 けられるオブジェクトのうちの 1 つで VS に 到 着 したパケットに 対 して 記 述 されたスクリプトの 内 容 をもとに 様 々な 処 理 を 行 います 処 理 されたパケットは VS に 設 定 される Default pool だけではなく irule で 書 かれた pool や node へ 送 ることもできます また v4.x と 同 様 に irule がパーシステンスでも 使 用 でき 更 に 認 証 にも 使 用 されます v9 の irule は TCL 言 語 を 用 いており 従 来 よりも 汎 用 性 の 高 い 実 装 で 様 々な 用 途 に 使 用 できます TCL TCL(ティクル)は Tool Command language の 略 で 標 準 的 なスクリプト 言 語 のうちのひとつです これは 集 積 回 路 の 設 計 に 使 用 されるスクリプトを C 言 語 のライブラリ パッケージとして 組 み 込 んで 汎 用 な 目 的 に 使 用 でき るようにするために 開 発 された 言 語 です スクリプト 言 語 とは ソースコードを 記 述 して 実 行 する 前 にユーザー がコンパイルすることはなく スクリプトを 実 行 するたびに 自 動 的 にコンパイルが 行 われる 種 類 の 言 語 です Ruby や PHP もスクリプト 言 語 です 最 近 TCL は 主 に TCL/Tk(Tool kit)という 形 で GUI アプリケーションの 開 発 に 使 用 されることが 多 くなっています 1. TCL の 文 法 に 関 するルール このセクションでは TCL スクリプトを 作 成 するにあたって 理 解 しておく 必 要 がある 一 般 的 な 文 法 について 解 説 します i. 基 本 のコマンドライン コマンド アーギュメント1 アーギュメント2 という 形 でコマンドの 後 にアーギュメントが 続 きます 例 えば 変 数 に 値 を 格 納 するコマンドである set を 使 用 して a という 変 数 に 1 を 格 納 するコマンドは 以 下 の 通 りです set a 1 ii. ダブルクォーテーション タブ ブランク 改 行 の 制 御 文 字 となる 文 字 を 含 むアーギュメントを 使 用 するにはダブルクォーテーション を 使 用 します set ABC "a b c d" 改 行 コードをアーギュメント 内 に 含 む 際 にこのダブルクォーテーションを 使 用 します set テスト 結 果 " 国 語 30 算 数 20 " この 場 合 はアーギュメントに 含 まれません また "はアーギュメントの 先 頭 に 記 述 される 場 合 においてのみ 上 記 のように 振 舞 います アーギュメント の 途 中 にある 場 合 は 単 に 文 字 列 の 1 つとして 扱 われます iii. $ 文 字 アーギュメント 内 に 記 述 されている$は 変 数 置 換 子 と 呼 ばれ $ 以 降 からつぎのブランク タブ 改 行 まで の 文 字 が 変 数 とみなされます 下 の 例 では a に 1000 がセットされます F5 Networks Japan K.K. 1 July, 2005
iv. set b 1000 set a $b スクウェアブラケット( [, ] ) アーギュメント 内 に 記 述 されている[および]はコマンド 置 換 子 と 呼 ばれ []で 囲 まれた 文 字 列 がコマンドラ インとみなされ その 実 行 結 果 がアーギュメントとしてコマンドに 渡 されます この 動 作 をコマンド 置 換 と 呼 びます 以 下 の 例 は 計 算 結 果 を 変 数 に 格 納 します set a [ expr 1+1 ] また コマンド 置 換 は 以 下 のようにネストすることも 可 能 です 更 に 改 行 コードを 含 むことも 可 能 です set a [ expr 1+ [ expr b*20]] v. バックスラッシュ 記 号 改 行 コード()やタブ()を 記 述 する 際 に 使 用 します また 上 記 の 置 換 子 の 前 にバックスラッシュを 付 加 する と 単 に 文 字 として 扱 われます vi. ブレース 引 用 符 アーギュメントをブレース 引 用 符 で 囲 むことによって 囲 まれた 部 分 に 含 まれるあらゆる 特 殊 文 字 の 機 能 を 無 効 化 します set a {[set テスト $ 国 語 ] この 場 合 変 数 a には[set テスト $ 国 語 ]という 文 字 列 が 格 納 されます また ダブルクォーテーションと 同 様 に この 機 能 はブレースの 開 始 がアーギュメントの 最 初 に 記 述 されているときのみ 有 効 です vii. 変 数 の 型 と 名 前 TCL の 変 数 には 型 が 用 意 されていませんが TCL のコマンドは TCL パーサーから 渡 された 変 数 値 を 整 数 や 実 数 論 理 型 として 取 り 扱 います 変 数 の 名 前 には 全 ての 文 字 が 使 用 可 能 ですが 特 殊 文 字 が 含 まれる 変 数 名 を 使 用 する 際 には 特 殊 文 字 をエス ケープするためにブレースが 必 要 になります puts ${テスト. 国 語 このような 面 倒 を 避 けるために 特 殊 文 字 は 使 用 しないほうが 良 いでしょう viii. ix. 変 数 のスコープ 変 数 の 型 をコマンドで 管 理 しているのに 対 し 変 数 のスコープは TCL パーサが 管 理 しています 変 数 のスコープにはグローバル 変 数 ローカル 変 数 がサポートされています ローカル 変 数 はプロシージャ 内 に 作 成 され 終 了 すると 削 除 されます これに 対 しグローバル 変 数 は 変 数 にアクセスする 前 に 予 め 宣 言 し ておかなければなりません グローバル 変 数 は 宣 言 時 に global コマンドを 使 用 します TCL では 全 ての 変 数 を 削 除 でき それを 明 示 的 に 削 除 したい 場 合 は unset を 使 用 します 配 列 変 数 TCL では 配 列 変 数 は 変 数 名 ( 添 え 字 )で 表 され 他 の 変 数 と 同 様 事 前 の 宣 言 や 要 素 数 の 指 定 は 必 要 ありま せん 以 下 のように 同 名 の 通 常 変 数 と 配 列 変 数 を 同 一 のスクリプト 内 で 使 用 することはできません set a 300 set a(1) 400 また 要 素 数 は 数 字 である 必 要 は 無 く 文 字 列 も 使 用 できます set a(jkl) 200 F5 Networks Japan K.K. 2 July, 2005
ただし 利 用 の 利 便 性 を 考 えると 数 字 を 使 用 するのが 一 般 的 です 要 素 を, や. で 区 切 って 複 数 記 述 することによって 多 次 元 配 列 を 使 用 できます set variable(a.1) 200 set index 1 -> このとき variable(a.$index)は200 x. リスト 複 数 のデータの 集 まりを 1 つのデータのように 処 理 する TCL 特 有 の 機 能 です 配 列 と 異 なり 特 有 の 使 用 方 法 があるわけではなく 扱 いは 普 通 の 変 数 と 同 様 です リストの 要 素 の 区 切 り 文 字 として 使 用 されるのはブランク タブ 改 行 です 要 素 にこれらの 文 字 を 含 む 場 合 は 前 述 の 通 りブラケッ ト({)で 囲 みます math 70 {physical education 80 このリストには 4 個 の 要 素 が 含 まれています また ブラケットはネストすることも 可 能 です 上 記 の 場 合 physical education が 1 つの 要 素 として 得 られますが この 要 素 を 更 に 2 つの 要 素 からなるリストとして 扱 うことができます リストを 操 作 するには 予 め 用 意 されているリスト 操 作 用 コマンドを 使 用 します リストの 生 成 set TESTLIST [list math 70 physical education 80] リストから i 番 目 の 要 素 をの 取 り 出 す set El [lindex $TESTLIST $i] リストの 要 素 を 取 り 出 してループする foreach el $TESTLIST { puts $elem 2. コマンド TCL で 使 用 される 基 本 的 なコマンドとその 例 は Appendix i を 参 照 してください 3. BIG-IP での 利 用 制 限 irule では 使 用 できない TCL コマンドがあります コマンドのリストは Appendix ii を 参 照 してください 4. irule を 使 用 する 際 の 基 本 ルール i. イベントを 指 定 する irule はイベントベースの 設 定 です スクリプトの 本 文 がどのイベントに 基 づいて 使 用 されるかを 記 述 する 必 要 があります イベントの 種 類 と 説 明 は Configuration Guide for Local Traffic Management を 参 照 してください ii. 接 続 先 pool/node の 決 定 v9 の irule では 必 ずしも irule の 中 で 接 続 先 の pool や node を 指 定 する 必 要 はありません ですから 以 下 のように 単 にロギングするための irule を 作 成 することも 可 能 です when HTTP_REQUEST { log local0. this is a test F5 Networks Japan K.K. 3 July, 2005
IV. 設 定 方 法 BIG-IP での Rule の 設 定 方 法 を 以 下 に 示 します 関 連 付 けられる pool や VirtualServer( 以 下 VS)は 予 め 作 成 され ているものとします 1. 新 規 Rule の 作 成 Tips : 新 規 に 作 成 する 場 合 は + 記 号 をクリ ックすることで 一 覧 表 示 画 面 をスキップし て 新 規 作 成 画 面 に 移 ることができます 2. Rule の 編 集 v9 には v4.x のような Rule Builder はありません このため 全 ての Rule をエディタで 記 述 する 必 要 があ ります また スクリプト 本 文 のほかに 名 前 をつける 必 要 があります この 名 前 は 多 くの Rule を 作 成 したと きに 目 的 の Rule を 検 索 する 際 に 便 利 です 記 述 した 後 Finished ボタンをクリックして 保 存 します この 際 Rule 名 と 文 法 および Rule の 中 で 使 用 され るオブジェクトの 存 在 確 認 チェックが 行 われ エラーがあると Rule を 保 存 できません 3. VS への 適 用 作 成 した Rule を VS の 設 定 画 面 を 使 用 して VS に 適 用 します Rule は Pool と 同 様 に Resource の 一 部 として F5 Networks Japan K.K. 4 July, 2005
設 定 されます V. Rule 作 成 のテクニック 1. デバッグ v4 系 と 互 換 性 があるものの irule の 強 みを 最 大 限 に 発 揮 するには v9 固 有 の 考 え 方 やコーディングが 必 要 で ある 上 に より 複 雑 な 処 理 が 可 能 になるためコードが 複 雑 化 しがちです 複 雑 なコードはエラーを 誘 発 しし デバッグが 必 要 になることがあるでしょう デバッグ 手 段 のうちのひとつとして 有 効 なものはログ 出 力 です 以 下 の 要 領 で 各 所 にロギングの 行 を 挿 入 し 変 数 の 値 が 想 定 どおりにセットされているか またはコマンドの 実 行 結 果 や 戻 り 値 が 想 定 どおりか 等 をチェックします もちろん 変 数 に 限 らずコマンドを 記 述 することもできます when HTTP_REQUEST {. log local0. section1, a is $a.. when CLIENT_ACCEPTED {. log local0. section1, Bandwidth is [TCP::bandwidth].. 2. グローバル Rule 一 般 的 に irule のスコープはそのコネクション 内 のみであり 複 数 のコネクションに 跨 った 処 理 をすること ができません しかしながら RULE_INIT イベントを 使 用 することにより その Rule を Resource として 使 用 している 全 ての VS の 情 報 を 一 元 的 に 管 理 することが 出 来 ます 具 体 的 には VS で 保 持 しているコネクション 数 による 制 御 等 が 可 能 です 3. Rule 作 成 時 の 注 意 irule には 一 般 的 なプログラミングの 定 石 が 適 用 されます 従 って ループの 多 用 による 複 雑 な 制 御 やグロ ーバル 変 数 の 利 用 はパフォーマンスに 対 して 影 響 を 与 えることに 注 意 してください F5 Networks Japan K.K. 5 July, 2005
VI. 実 践 編 ここでは 実 際 の Rule を 動 作 を 説 明 しながら 紹 介 していきます 1. BIG-IP に Sorry サーバの 役 割 を 持 たせる Rule サイトが 停 止 しているときに 実 web サーバのかわりにリクエストを 受 け 付 けてクライアントにその 旨 を 伝 えるのが Sorry サーバですが 任 意 のレスポンスをクライアントに 返 すことができる HTTP::respond コマン ドを 使 用 して Sorry サーバのかわりに BIG-IP 自 身 が sorry コンテンツを 返 します 日 本 語 の 直 接 入 力 は GUI でのみ 可 能 です when HTTP_REQUEST { # always_down_pool というpool のアクティブメンバ 数 が0だったら 以 下 の 処 理 を 行 います if { [active_members test_pool] < 1 { # HTTP 200 とそれに 続 くhtml テキストをクライアントに 返 します HTTP::respond 200 Content "<html><body> 現 在 サーバ 停 止 中 です <br>もう 暫 くお 待 ちくだ さい <br><br><font size=-1><i>f5 Networks test</i></font></body></html>" 2. SSL のサイト サイトへリダイレクト リダイレクトするための Rule データグループにリダイレクト 対 象 となる URI を 格 納 しておき そのオブジェクトへの http アクセスが 試 み られたら https にリダイレクトします when HTTP_REQUEST { set uri [findstr [HTTP::uri] "" 1 "/"] if {[matchclass $::redirect_group equals $uri] { redirect to "https://[http::host][http::uri]" ここで 用 意 するデータグループは 以 下 のようなものになります class redirect_group { "test1" "test2" たとえば クライアントが 以 下 のようなリクエストを 送 信 した 場 合 http://www.domain.com/test1/testing/inde.cgi [HTTP::uri]コマンドで 返 される 値 は 以 下 のとおりです /test1/testing/index.cgi 上 記 の Rule では path の 中 のもっとも 上 位 のディレクトリの 内 容 に 応 じて(この 例 の 場 合 は/test1)リダイレ クトを 行 うので [HTTP::uri]で 取 得 できる 値 の 2 文 字 目 から 最 初 の / の 前 の 文 字 までがマッチングの 対 象 と なります これを 以 下 の 記 述 で 抜 き 出 します findstr [HTTP::uri] "" 1 "/" 更 に 以 下 の 記 述 でグループのリストとマッチさせます matchclass $::redirect_group equals $uri データグループを 使 用 する 際 の 変 数 名 は 以 下 のとおりです $:: 設 定 したグループ 名 F5 Networks Japan K.K. 6 July, 2005
3. Web サーバが 返 すエラーコード エラーコードを 200 に 変 換 する Rule web アプリケーションに 対 する 攻 撃 者 は HTTP ヘッダのレスポンスコードならびにエラー 時 のコンテンツか ら 得 られる 情 報 (Web サーバの 種 類 バージョン 等 )を 攻 撃 の 糸 口 の 1 つとします 例 えば 403(Forbidden) や 500(Internal Server Error)であれば そのオブジェクトに 対 して 何 らかの query string を 付 加 してリクエ ストを 送 れば 何 らかのレスポンスが 得 られるかもしれないというヒントを 与 えるし そのエラー 画 面 のコンテ ンツには 多 くの 場 合 web サーバのバージョンや web サーバの 名 前 が 含 まれており これによりそのソフトウ ェア 特 有 の 既 知 の 脆 弱 性 を 知 ることができます 一 般 的 な 商 用 サイトにおいて サイトの 利 用 者 はレスポンス コードやサーバの 種 類 バージョンを 知 る 必 要 は 無 く 主 に 開 発 者 やテスターがテスト 環 境 においてのみ 確 認 できれば 良 いので 以 下 の irule によってクライアントには 全 て 200 を 返 します when HTTP_REQUEST { # リダイレクト 時 のhost 名 取 得 はHTTP_REQUEST イベントで 行 わなければなりません set host [HTTP::host] when HTTP_RESPONSE { if { [regexp {[45].. [HTTP::status]] == 1 { # 4 あるいは5ではじまる3 桁 のレスポンスコードだったときに 200 のコードおよび 自 動 的 にトップ ページに 戻 るためのHTTP コンテンツを 返 します HTTP::respond 200 Content "<html><head><meta http-equiv= "Refresh " CONTENT= "5; URL=http://$host/ "><body> 都 合 によりコンテンツを 表 示 できません <br> 自 動 的 にトップページに 移 ります <br> もし 移 らない 場 合 はブラウザの 戻 るボタンで 前 のページに 戻 ってください <br><br><font size=-1><i>f5 Networks test</i></font> </body></html>" 正 規 表 現 についての 補 足 : 正 規 表 現 [45].. は 4 または 5 の 後 に 任 意 の 文 字 (. )が 2 個 続 く 文 字 列 にマッチします このケースにおいては [45][0-9][0-9] とも 表 すことができます F5 Networks Japan K.K. 7 July, 2005
4. クライアントあたりの TCP コネクション 数 を 制 限 する Rule 1 クライアント(1 ソース IP アドレス)が 確 立 できる TCP コネクション 数 を 制 限 します HTTP1.1 と Keep-Alive を 使 用 する 場 合 一 般 的 に 1 クライアントと VS の 間 で 確 立 される TCP セッションはごく 限 られた 数 になるた め この irule によってリクエストが 多 数 送 られるような 攻 撃 を 防 ぎます when RULE_INIT { # Rule 全 体 で 接 続 数 を 管 理 するための 配 列 を 宣 言 します 添 え 字 はクライアントのIP アドレスです array set ::active_clients { when CLIENT_ACCEPTED { set client_ip [IP::remote_addr] # そのIP アドレスの 添 え 字 を 持 った 要 素 が 存 在 する 場 合 それ 以 下 の 処 理 を 行 います if { [info exists ::active_clients($client_ip)] { # この 場 合 1IP アドレスあたりの 最 大 コネクション 数 は5です 制 限 超 過 分 は 弾 きます if {$::active_clients($client_ip) > 5 { reject return else { # 制 限 数 に 満 たなければカウントアップします incr ::active_clients($client_ip) else { # 要 素 がまだ 無 ければ 新 規 作 成 します set ::active_clients($client_ip) 1 # TCP 接 続 がクローズしたときの 処 理 です when CLIENT_CLOSED { if { [info exists ::active_clients($client_ip)] { # 配 列 要 素 が 存 在 したら カウントを1 下 げます incr ::active_clients($client_ip) -1 if { $::active_clients($client_ip) <= 0 { # カウンタが0 以 下 になったら 要 素 そのものをメモリからクリアします unset ::active_clients($client_ip) F5 Networks Japan K.K. 8 July, 2005
5. 帯 域 幅 によって 圧 縮 のコントロール コントロールを 行 う Rule irule の[TCP::bandwidth]コマンドを 使 用 するとクライアントとの 間 で 確 立 されている TCP セッションの 帯 域 幅 [kbps]を 取 得 することができます この 値 を 使 用 して ナローバンドのクライアントに 対 しては 圧 縮 を 提 供 するのがこの Rule です when HTTP_RESPONSE { if { [TCP::bandwidth] < 1000 { # 1Mbps 未 満 のときは 高 圧 縮 率 COMPRESS::enable COMPRESS::gzip level 9 elseif { [TCP::bandwidth] < 10000 { # 10Mbps 未 満 のときは 低 圧 縮 率 COMPRESS::enable COMPRESS::gzip level 1 else { # それ 以 上 のときは 圧 縮 しません COMPRESS::disable F5 Networks Japan K.K. 9 July, 2005
Appendix I. TCL コマンド 1. リストコマンド リストを 操 作 するためのコマンドです irule で 使 用 できない もしくは 使 用 するケースが 少 ないコマンドは 省 略 しています リストの 結 合 contact $list1 $list2 $list3 変 数 に 対 してリスト 要 素 の 追 加 し その 結 果 のリストを 返 します lappend variable $var1 $var2 リストから$index 番 目 の 要 素 を 取 り 出 します lindex $list $index リストの$index 番 目 の 要 素 の 前 に 要 素 $val1, $val2, を 挿 入 したリストを 返 します linsert $list $index $val1 $val2 変 数 群 $val1, $val2 を 要 素 としたリストを 返 します list $val1 $val2 リストの 要 素 数 を 返 します llength $list リスト$list の$index_s 番 目 から$index_e 番 目 までの 要 素 をリストとして 返 します 最 後 までの 場 合 は$last の 中 身 を 文 字 列 end にします lrange $list $index_s $index_e リスト$list の$s 番 目 から$e 番 目 までの 連 続 した 要 素 をすべての 要 素 $val1, $val2, で 置 き 換 え 新 しいリス トを 返 します lreplace $list $s $e $val1 $val2 リスト$list から $sw で 任 意 で 与 えられたパターンマッチング 方 式 で $pattern に 合 致 する 最 初 の 要 素 のイ ンデックスを 返 す $sw は-glob( 方 式 ) exact( 完 全 一 致 ) regexp( 正 表 現 )が 用 意 されている $sw の 指 定 が 無 いときは blog 方 式 が 使 用 されます lsearch $sw $list $pattern リスト$list の 要 素 をソートしたリストを 返 します lsort $switch command $ com $direction $list リスト$list の 要 素 を$joinString で 結 合 した 文 字 列 を 返 します $joinstring のデフォルト 文 字 はスペースで す join $list $joinstring 文 字 列 $string を $splitchars で 区 切 られた 文 字 列 を 要 素 としたリストを 返 します $splitchars のデフォルト 文 字 はスペースです このコマンドは join とは 逆 の 関 係 にあります split $string $splitchars 2. 制 御 コマンド if { test1 {body 1 elseif { test2 { body2 elseif.. eise { bodyn test1 : body1 を 実 行 するための 条 件 式 真 なら body1 が 実 行 されます test2 : test1 の 条 件 が 偽 のとき 評 価 される 条 件 式 真 なら body2 が 実 行 されます bodyn : 全 ての 条 件 が 偽 のときに 実 行 されます F5 Networks Japan K.K. 10 July, 2005
for { init { test { reinit { body init : 初 期 設 定 Tcl スクリプト test : ループ 条 件 式 ( 真 ならループ 継 続 ) reinit : 再 設 定 Tcl スクリプト body : Tcl スクリプト(メイン 処 理 ) while { test { body test : 条 件 式 ( 真 ならループ 継 続 ) reinit : 再 設 定 Tcl スクリプト body : Tcl スクリプト(メイン 処 理 ) switch $switch $ string {$pattern1 {body. $pattern {body string をチェックし 合 致 した pattern の body を 実 行 -glob exact regexp のマッチング 方 式 があり デフォルトは-glob foreah $valnamelist $list {body list から 要 素 を 取 り 出 し 変 数 valnamelist に 順 番 に 代 入 し body を 実 行 する この 処 理 を 要 素 数 の 分 だけ 繰 り 返 す break for while switch foreach のループ 脱 出 に 使 用 する continue for while foreach において ループの 条 件 式 評 価 にジャンプする eval arg1 arg2. 全 アーギュメントをスペース 区 切 りで 結 合 し その 文 字 列 を Tcl スクリプトとして 実 行 し 結 果 を 返 す 3. 文 字 列 操 作 コマンド format scan regexp regsub string compare string first string last string index string length string match string range string tolower string toupper string trim string trimleft string trimright F5 Networks Japan K.K. 11 July, 2005
II. irule で 使 用 できないコマンド after auto_execok auto_import auto_load auto_mkindex auto_mkindex_old auto_qualify auto_reset bgerror cd close eof exec exit fblocked fconfigure fcopy file fileevent filename flush gets glob http interp load memory namespace open package pid pkg::create pkg_mkindex proc pwd rename seek socket source tcl_findlibrary tell unknown update uplevel upvar vwait F5 Networks Japan K.K. 12 July, 2005