ポート番号とプロトコル名の組み合わせをすぐ忘れるからAlfredのワークフローにした
https://github.com/tap1ra/alfred/tree/master/port2protocolalfred/port2protocol at master · tap1ra/alfred · GitHub
ヤケクソ感が否めないけど意外と便利 その場しのぎなので、いずれちゃんとしたい
(追記) dojineko/listo という便利ツールがあったので乗り換え
githubにスタイルあてとくと見易い
https://github.com/tap1ra/md-sample/issues/1 みたいに、横に長いテーブルがあると、デフォルトの画面だとちょっと見づらい。
こんな感じ
拡張機能を使って横に広げるとみやすくなった
こうなる
CloudFlareのソースIPにマッチするかもしれない正規表現
参考
'103\.21\.24[4-7]\.[0-9]{1,3}|103\.22\.20[0-3]\.[0-9]{1,3}|103\.31\.[4-7]\.[0-9]{1,3}|104\.(1[6-9]|2[0-9]|3[0-1])\.[0-9]{1,3}\.[0-9]{1,3}|108\.162\.(19[2-9]|2[0-5][0-9])\.[0-9]{1,3}|131\.0\.7[2-5]\.[0-9]{1,3}|141\.101\.(6[4-9]|[7-9][0-9]|1[0-1][0-9]|12[0-7])\.[0-9]{1,3}|162\.15[8-9]\.[0-9]{1,3}\.[0-9]{1,3}|172\.(6[4-9]|7[0-1])\.[0-9]{1,3}\.[0-9]{1,3}|173\.245\.(4[8-9]|5[0-9]|6[0-3])\.[0-9]{1,3}|188\.114\.(9[6-9]|10[0-9]|11[0-1])\.[0-9]{1,3}|190\.93\.2[4-5][0-9]\.[0-9]{1,3}|197\.234\.24[0-3]\.[0-9]{1,3}|198\.41\.(12[8-9]|1[3-9][0-9]|2[0-5][0-9])\.[0-9]{1,3}|199\.27\.(12[8-9]|13[0-5])\.[0-9]{1,3}'
https://raw.githubusercontent.com/tap1ra/cloudflare-ip-regex/master/regex.txt
残件
- cloudflare側のIPリストに変更があったときに自動反映
- javascriptに食わせる作業が人力なので自動化
初めてOSS(Apacheモジュール)にPRだした
今回PRをだした対象
ApacheのVirtualHost単位でMaxClientsを設定することが可能な、Apacheモジュールです。 詳細は↓
ApacheのVirtualHost単位でMaxClientsを設定するApacheモジュールをOSS化 - 人間とウェブの未来
どんな機能を実装したか
MaxClientsの設定を有効にする時間帯を指定可能にする機能
本モジュールの利用を予定しているサーバの負荷は、常に一定ではなく高い時もあれば低い時もあります。 負荷の低い時間帯はMaxClientsを設定せず、自由に利用してもらうため、本機能の追加を行いました。
やったこと
途中色々アドバイスを受けながらあれこれ手戻ったりしてますが、簡略化するため一部改変してます。関数とか用語とか勘違いしてたら教えてあげてください やったこと、と言っても別に特別なことをしたわけではない
1. ソースを読む
mod_vhost_maxclients/mod_vhost_maxclients.c at master · matsumoto-r/mod_vhost_maxclients · GitHub
行数が短く、比較的読みやすいコードでした。
以下参考
- Cやってみよう #1 - 臥薪嘗胆 本モジュールのソース解説
- 人間とウェブの未来 - apache2系のmodule開発
- モジュールの Apache 1.3 から Apache 2.0 への移植 - Apache HTTP サーバ バージョン 2.4
- Apache2: Configuration
上から構造体や関数定義などが並んでますが、とりあえず一番したから読む。
apxsを使用してApacheのモジュールを作成する場合、同じ形式になっているもよう。
#ifdef __APACHE24__ AP_DECLARE_MODULE(vhost_maxclients) = { #else module AP_MODULE_DECLARE_DATA vhost_maxclients_module = { #endif STANDARD20_MODULE_STUFF, NULL, /* create per-dir config structures */ NULL, /* merge per-dir config structures */ # サーバ設定作成関数 vhost_maxclients_create_server_config, /* create per-server config structures */ # サーバ設定関数 vhost_maxclients_create_server_merge_conf, /* merge per-server config structures */ # directiveの値を取得する関数 vhost_maxclients_cmds, /* table of config file commands */ # フックするポイントを登録する関数 vhost_maxclients_register_hooks};
それぞれ、登録された関数が何をやっているか見ました。
vhost_maxclients_create_server_config
サーバ設定作成関数の名の通り、本モジュールで使用する設定値がデフォルト値とともに定義されています。
static void *vhost_maxclients_create_server_config(apr_pool_t *p, server_rec *s) { vhost_maxclients_config *scfg = (vhost_maxclients_config *)apr_pcalloc(p, sizeof(*scfg)); scfg->dryrun = -1; scfg->log_path = NULL; scfg->vhost_maxclients = 0; scfg->vhost_maxclients_log = 0; scfg->vhost_maxclients_per_ip = 0; scfg->ignore_extensions = apr_array_make(p, VHOST_MAXEXTENSIONS, sizeof(char *)); return scfg; }
- vhost_maxclients_create_server_merge_conf
static void *vhost_maxclients_create_server_merge_conf(apr_pool_t *p, void *b, void *n) { vhost_maxclients_config *base = (vhost_maxclients_config *)b; vhost_maxclients_config *new = (vhost_maxclients_config *)n; vhost_maxclients_config *scfg = (vhost_maxclients_config *)apr_pcalloc(p, sizeof(*scfg)); if (new->dryrun > -1) { scfg->dryrun = new->dryrun; } else { scfg->dryrun = base->dryrun; } scfg->log_path = base->log_path; scfg->vhost_maxclients = new->vhost_maxclients; scfg->vhost_maxclients_log = new->vhost_maxclients_log; scfg->vhost_maxclients_per_ip = new->vhost_maxclients_per_ip; scfg->ignore_extensions = new->ignore_extensions; return scfg; }
- vhost_maxclients_cmds
ディレクティブの定義をおこなっています。
AP_INIT_TAKE1
を例にすると、directive指定はhoge 100
のようにdirective名 値
と名前の通り一個だけ取得する定義です。
指定しているのはdirective名
,directiveの値を変数にセットするための関数
mconfig(何かよく分かってない)
,定義されている場所
,Help
になります。
static command_rec vhost_maxclients_cmds[] = { AP_INIT_FLAG("VhostMaxClientsDryRun", set_vhost_maxclients_dryrun, NULL, ACCESS_CONF | RSRC_CONF, "Enable dry-run which don't return 503, logging only: On / Off (default Off)"), AP_INIT_TAKE1("VhostMaxClients", set_vhost_maxclientsvhost, NULL, RSRC_CONF | ACCESS_CONF, "maximum connections per Vhost"), AP_INIT_TAKE1("VhostMaxClientsLogOnly", set_vhost_maxclientsvhost_log, NULL, RSRC_CONF | ACCESS_CONF, "loggign only: maximum connections per Vhost"), AP_INIT_TAKE1("VhostMaxClientsLogPath", set_vhost_maxclientsvhost_log_path, NULL, RSRC_CONF | ACCESS_CONF, "logging file path instead of error_log"), AP_INIT_TAKE1("VhostMaxClientsPerIP", set_vhost_maxclientsvhost_perip, NULL, RSRC_CONF | ACCESS_CONF, "maximum connections per IP of Vhost"), AP_INIT_ITERATE("IgnoreVhostMaxClientsExt", set_vhost_ignore_extensions, NULL, ACCESS_CONF | RSRC_CONF, "Set Ignore Extensions."), {NULL}, };
directiveの値を変数にセットするための関数
を一個例に見ると set_vhost_ignore_extensions
をちょっと見てみると、
バリデーションと値の取得をやってました。
static const char *set_vhost_ignore_extensions(cmd_parms *parms, void *mconfig, const char *arg) { vhost_maxclients_config *scfg = (vhost_maxclients_config *)ap_get_module_config(parms->server->module_config, &vhost_maxclients_module); if (VHOST_MAXEXTENSIONS < scfg->ignore_extensions->nelts) { return "the number of ignore extensions exceeded"; } *(const char **)apr_array_push(scfg->ignore_extensions) = arg; return NULL; }
- vhost_maxclients_register_hooks
ハンドラをフックポイントに登録する関数
人間とウェブの未来 - Apache hook関数 が参考になる。
initルーチンとかを呼ぶ時にap_hook_post_config
クライアントが認証受ける前に追加でアクセスチェックをしたい時にap_hook_access_checker
をフックさせてます。本モジュールの役割的にap_hook_access_checker(vhost_maxclients_handler, NULL, NULL, APR_HOOK_MIDDLE);
が実際に制限させる処理をやってるぽいです。
static void vhost_maxclients_register_hooks(apr_pool_t *p) { ap_hook_post_config(vhost_maxclients_init, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_access_checker(vhost_maxclients_handler, NULL, NULL, APR_HOOK_MIDDLE); }
2. 書いてみる
vhost_maxclients_configに追加が必要なものを考える
今回は制限する時間帯を指定したかったので、
制限開始する時間
と制限終了する時間
があればよさそうなので、vhost_maxclients_config構造体に2つ変数を追加
unsigned int vhost_maxclients_time_from; unsigned int vhost_maxclients_time_to;
directiveから値を取得する
2つ数字を渡せればいいので、1directive追加します。これで
VhostMaxClientsTimeSlot 1100 2300
のようにconfに指定できます。AP_INIT_TAKE2
はAP_INIT_TAKE1
の引数が一個増えた版。
AP_INIT_TAKE2("VhostMaxClientsTimeSlot", set_vhost_maxclients_time, NULL, RSRC_CONF | ACCESS_CONF, "Time to enable the VhostMaxClients. (default 0:00 ~ 23:59)"),
TAKE2なのでarg1とarg2に一個目二個目の設定値が入ってくるので、時間のバリデーションをし、取得します。
static const char *set_vhost_maxclients_time(cmd_parms *parms, void *mconfig, const char *arg1, const char *arg2) { vhost_maxclients_config *scfg = (vhost_maxclients_config *)ap_get_module_config(parms->server->module_config, &vhost_maxclients_module); scfg->vhost_maxclients_time_from = atoi(arg1); scfg->vhost_maxclients_time_to = atoi(arg2); if(scfg->vhost_maxclients_time_from < 0 || scfg->vhost_maxclients_time_from > 2359){ return "VhostMaxClientsTimeSlot_From is invalid. should be set range 0 < VhostMaxClientsTimeSlot_From < 2359"; } if (scfg->vhost_maxclients_time_to < 0 || scfg->vhost_maxclients_time_to > 2359){ return "VhostMaxClientsTimeSlot_To is invalid. should be set range 0 < VhostMaxClientsTimeSlot_To < 2359"; } return NULL; }
vhost_maxclients_handlerの処理中で時間を判定する処理の追加
今回の機能は実際に制限をおこなうロジックの手前でやる必要があります。拡張子の判定処理の下あたりに入れます
/* check time */ if (check_time_slot(r->pool, scfg->vhost_maxclients_time_from, scfg->vhost_maxclients_time_to)) { return DECLINED; }
インラインでずらずら処理を書いてもいいのですが、汚いので関数に切り出します。
判定のやりかたは当初request_rec構造体のrequest_timeの値を利用しようとしましたが、apr_time_nowの値を使用することにしました。
apr_time_nowは現在時刻をUTC+マイクロ秒で返すので扱いにくいため、apr_time_exp_ltで人間向けに変換し、 時
分
をとってくっつけてintにしてます。
日をまたいだ指定( 23:00 ~ 2:00
など)のため、toよりfromが小さければ24時間プラスしてます。あとは現在時刻が指定した範囲内か判定します。
static int check_time_slot(apr_pool_t *p, unsigned int from, unsigned int to) { unsigned int cur; apr_time_exp_t tm; apr_time_exp_lt(&tm, apr_time_now()); cur = atoi(apr_psprintf(p, "%02d%02d", tm.tm_hour, tm.tm_min)); if (from > to){ to += 2400; } if ((from < cur) && (to > cur)){ return 0; } return 1; }
だいたい、上記のようなことをやりました。
あとは、以下のようにdirective指定し、想定通りの動作をするか確認します。
<VirtualHost *> DocumentRoot /var/www/html ServerName localhost VhostMaxClients 1 VhostMaxClientsTimeSlot 2130 2300 </VirtualHost>
3. 検証
- 正常動作 既存の同時接続数を制限する機能と時間の指定がどちらも動作するか確認します。
- パフォーマンス 判定を一個入れたので、少なからず遅くなってるはずです。問題ないレベルかチェックします。見た感じ問題なさそう…
# 改修前のバージョン [vagrant@localhost ~]$ ab -n100000 -c100 http://127.0.0.1/ This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 127.0.0.1 (be patient) Completed 10000 requests Completed 20000 requests Completed 30000 requests Completed 40000 requests Completed 50000 requests Completed 60000 requests Completed 70000 requests Completed 80000 requests Completed 90000 requests Completed 100000 requests Finished 100000 requests Server Software: Apache/2.2.15 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: / Document Length: 17 bytes Concurrency Level: 100 Time taken for tests: 16.434 seconds Complete requests: 100000 Failed requests: 0 Write errors: 0 Total transferred: 28507125 bytes HTML transferred: 1700425 bytes Requests per second: 6084.97 [#/sec] (mean) Time per request: 16.434 [ms] (mean) Time per request: 0.164 [ms] (mean, across all concurrent requests) Transfer rate: 1693.99 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 8 3.7 8 43 Processing: 1 9 3.6 8 45 Waiting: 0 7 3.5 7 43 Total: 1 16 4.2 15 57 Percentage of the requests served within a certain time (ms) 50% 15 66% 16 75% 17 80% 18 90% 19 95% 21 98% 33 99% 38 100% 57 (longest request) # 改修後のバージョン_1 制限を行う時間外 [vagrant@localhost ~]$ ab -n100000 -c100 http://127.0.0.1/ This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 127.0.0.1 (be patient) Completed 10000 requests Completed 20000 requests Completed 30000 requests Completed 40000 requests Completed 50000 requests Completed 60000 requests Completed 70000 requests Completed 80000 requests Completed 90000 requests Completed 100000 requests Finished 100000 requests Server Software: Apache/2.2.15 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: / Document Length: 17 bytes Concurrency Level: 100 Time taken for tests: 13.657 seconds Complete requests: 100000 Failed requests: 0 Write errors: 0 Total transferred: 28508550 bytes HTML transferred: 1700510 bytes Requests per second: 7322.41 [#/sec] (mean) Time per request: 13.657 [ms] (mean) Time per request: 0.137 [ms] (mean, across all concurrent requests) Transfer rate: 2038.59 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 4 3.2 5 15 Processing: 2 9 2.7 9 30 Waiting: 0 8 2.8 8 27 Total: 2 14 2.5 13 34 Percentage of the requests served within a certain time (ms) 50% 13 66% 14 75% 15 80% 15 90% 17 95% 18 98% 20 99% 22 100% 34 (longest request) # 改修後のバージョン_2 制限を行う時間内 [vagrant@localhost ~]$ ab -n100000 -c100 http://127.0.0.1/ This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 127.0.0.1 (be patient) Completed 10000 requests Completed 20000 requests Completed 30000 requests Completed 40000 requests Completed 50000 requests Completed 60000 requests Completed 70000 requests Completed 80000 requests Completed 90000 requests Completed 100000 requests Finished 100000 requests Server Software: Apache/2.2.15 Server Hostname: 127.0.0.1 Server Port: 80 Document Path: / Document Length: 17 bytes Concurrency Level: 100 Time taken for tests: 15.214 seconds Complete requests: 100000 Failed requests: 0 Write errors: 0 Total transferred: 28514250 bytes HTML transferred: 1700850 bytes Requests per second: 6572.97 [#/sec] (mean) Time per request: 15.214 [ms] (mean) Time per request: 0.152 [ms] (mean, across all concurrent requests) Transfer rate: 1830.30 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 5 3.6 6 18 Processing: 2 10 3.0 9 39 Waiting: 0 9 2.9 9 35 Total: 2 15 3.1 15 43 Percentage of the requests served within a certain time (ms) 50% 15 66% 16 75% 17 80% 17 90% 19 95% 21 98% 22 99% 24 100% 43 (longest request)
振り返り
apr_xxxxxが便利 Apache Portable Runtimeというサポートライブラリがあって、これが非常に便利なやつでした。
たとえばcur = atoi(apr_psprintf(p, "%02d%02d", tm.tm_hour, tm.tm_min));
の部分
当初は以下のように書いてました。c char hoge[5]; sprintf(hoge,"%02d%02d", tm.tm_hour, tm.tm_min));
apr_psprintfを使用すると、hogeのようなメモリ割り当てが不要になり、request_rec構造体のプールを使わせることができます。
戻り値をそのまま別の関数にくわせて、欲しい型でとれるから便利
人間とウェブの未来 - apr_psprintfはかなり楽(apache2.x系)自分の英語雑過ぎる コメント無し
普段コードを書いていないと基本的なことを忘れていく 関数名・変数名が長い、短くするとき意味がわからない。エラーメッセージに必要な内容が載ってない。
if(!((a!=b)&&(c<b))
みたいなこと書いちゃう。関係性の無い判定をelseifしちゃう。 酷い感じでした- httpdのソースを眺めながら書くとよい 変数の型や、利用する関数でソース中調べると色々助かる。コード量がおおいので、GNU Globalを使いました 人間とウェブの未来 - GNU GLOBALとvimで巨大なコードでも快適にコードリーディング - Forkwell
初めてcを書き、初めてOSSへPRを出すことができました。
cの入門書を眺めてただけだとしれなかったことがたくさんあり、やれてよかったと思います。
びびりまくってましたが、いざやってみるとみんな優しくて色々教えてくださったので、やってみたほうがいいです。
iTerm2 3.0にあげたらAlfredのWorkflowから起動できなくなったから対応
使っているのはこれ github.com
実行するとiTermを起動し、指定したホスト名へSSH接続する
動かなくなった原因はApplescriptの互換性が無いかららしい。iTermの公式ページに対応版コードが載ってたからそれを使うだけ。
手順
- Version 3 Beta - iTerm2 - Mac OS Terminal Replacement へアクセス
Alfred Support
の iTerm2 3.0 Alfred Script を開く- 全文コピーして、以下に貼り付ける
参考
http://harasou.github.io/2015/09/09/Alfred-iTerm2/harasou.github.io