□FreeRADIUSでradutmpベース(というか、NASを参照しない)での同時接続制限(Simultaneous-Use := 1)
タイトルは長いが、まぁやりたいことを書くとこういう事。
FreeRADIUSで「同時接続制限(Simultaneous-Use := 1)」(のテスト)をしようとすると
checkrad(Perlのスクリプト)が呼び出されて、その結果によりOK/NGを返すわけだが、
当然実機がないと(もしくは実機にアクセスできないと)、テストができない。
で、処理の流れ的にclient.confにnas_typeをいろいろ書かないと、そもそも同時接続
制限はできないということになっている。
radiusd -Xで起動して、処理の流れを見ると判るが、
-------------------------------- : (0) # Executing section session from file /etc/raddb/sites-enabled/default (0) session { (0) radutmp : EXPAND /var/log/radius/radutmp (0) radutmp : --> /var/log/radius/radutmp (0) radutmp : EXPAND %{User-Name} (0) radutmp : --> USER-ID checkrad: No NAS type, or type "other" not checking (0) [radutmp] = fail (0) } # session = fail : --------------------------------
ということで、NASタイプが設定されていないか、otherになっていると、チェックを
しない。
まぁ確かにradutmpの情報が正しいかどうかは疑わしいところだし、RADIUSを複数台
動かしておく場合には接続情報をどこで保持するのか、ということになるのであれだ
けどね。
まぁその辺「テストがしたい」と割り切るのであれば、checkradを適当にいじればいい。
checkradの最後の方を見ると、
-------------------------------- : } elsif ($ARGV[0] eq 'dot1x'){ $ret = &dot1x_snmp; } elsif ($ARGV[0] eq 'other') { $ret = 1; } else { print LOG " checkrad: unknown NAS type $ARGV[0]\n" if ($debug); print STDERR "checkrad: unknown NAS type $ARGV[0]\n"; $ret = 2; } : --------------------------------
というように、第一引数($ARGV[0])によりいろいろ処理しているが、otherの場合は
1を返すようになっているのに、そもそもfreeRADIUS自体の方でotherなら同時接続の
チェックをしないようになっているのだからなぁ…
というわけで、ここに
-------------------------------- : } elsif ($ARGV[0] eq 'dot1x'){ $ret = &dot1x_snmp; } elsif ($ARGV[0] eq 'other') { $ret = 1; } elsif ($ARGV[0] eq 'simltest') { $ret = 1; } else { print LOG " checkrad: unknown NAS type $ARGV[0]\n" if ($debug); print STDERR "checkrad: unknown NAS type $ARGV[0]\n"; $ret = 2; } : --------------------------------
とか追加してみる。もちろんclient.confにも
-------------------------------- client localhost { ipaddr = 127.0.0.1 secret = gotorun nas_type = simltest } --------------------------------
としてみる。
これで、誰かが接続している状態を作り出して、
cat > /test_login
-------------------------------- Acct-Status-Type = Start Acct-Session-Id = 1111111111 User-Name = USER-ID NAS-Port = 1 Framed-IP-Address = 1.1.1.1 Caller-Id = 1111111111 --------------------------------
radclient -x -f ./test_login localhost acct gotorun
radlastで
-------------------------------- USER-ID 001:localhos 1.1.1.1 Tue Jun 7 11:41 still logged in --------------------------------
接続中である状態になっていることを確認したら、別途radtestで
radtest USER-ID PASSWORD localhost 1 gotorun
としてみると…
-------------------------------- : (1) # Executing section session from file /etc/raddb/sites-enabled/default (1) session { (1) radutmp : EXPAND /var/log/radius/radutmp (1) radutmp : --> /var/log/radius/radutmp (1) radutmp : EXPAND %{User-Name} (1) radutmp : --> USER-ID (1) [radutmp] = fail (1) } # session = fail (1) Login OK: [USER-ID/PASSWORD] (from client localhost port 1) : --------------------------------
と、radutmp(session)としてはfailなのに、Login OKとなってしまう。
これにはからくりがあり、中の人が
http://freeradius.1045715.n5.nabble.com/Trying-to-restrict-simultaneous-use-td5739700.html
で、「Because it’s fail-safe.」とか言ってしまっている。
いやね、fail-safeにする必要ないのだけど(同時接続制限の動作確認したいから)、
そのための設定とか作ってくれよ。
というのも、該当部分のソースを確認すると、
/usr/src/freeradius-server-3.0.4/src/main/modules.c
-------------------------------- : #ifdef WITH_SESSION_MGMT /* * See if a user is already logged in. * * Returns: 0 == OK, 1 == double logins, 2 == multilink attempt */ int process_checksimul(int sess_type, REQUEST *request, int maxsimul) { rlm_rcode_t rcode; if(!request->username) return 0; request->simul_count = 0; request->simul_max = maxsimul; request->simul_mpp = 1; rcode = indexed_modcall(RLM_COMPONENT_SESS, sess_type, request); if (rcode != RLM_MODULE_OK) { /* FIXME: Good spot for a *rate-limited* warning to the log */ return 0; } return (request->simul_count < maxsimul) ? 0 : request->simul_mpp; } #endif : --------------------------------
で、indexed_modcall()でいろいろな(radutmp意外にもsqlとかでも)、とにかく
RLM_MODULE_OK(=2)以外が返ってきたとしても「return 0;」、つまりOKを返して
しまっている。
※ちなみにradutmpで同時接続が確認されたときのrcodeは1で、RLM_MODULE_OK(=2)
とは明らかに異なっている。
これはなぁ…。
ちなみにこれを調査しているときの最新?のVer.3.0.11のソースを見てみると、
/usr/src/freeradius-server-3.0.11/src/main/modules.c
-------------------------------- : #ifdef WITH_SESSION_MGMT /* * See if a user is already logged in. * * Returns: 0 == OK, 1 == double logins, 2 == multilink attempt */ int process_checksimul(int sess_type, REQUEST *request, int maxsimul) { rlm_rcode_t rcode; if(!request->username) return 0; request->simul_count = 0; request->simul_max = maxsimul; request->simul_mpp = 1; rcode = indexed_modcall(MOD_SESSION, sess_type, request); if (rcode != RLM_MODULE_OK) { /* FIXME: Good spot for a *rate-limited* warning to the log */ return 0; } return (request->simul_count < maxsimul) ? 0 : request->simul_mpp; } #endif : --------------------------------
同じかよ!!
というわけで、「modules.c」の問題のところを
-------------------------------- : #ifdef WITH_SESSION_MGMT /* * See if a user is already logged in. * * Returns: 0 == OK, 1 == double logins, 2 == multilink attempt */ int process_checksimul(int sess_type, REQUEST *request, int maxsimul) { rlm_rcode_t rcode; if(!request->username) return 0; request->simul_count = 0; request->simul_max = maxsimul; request->simul_mpp = 1; rcode = indexed_modcall(RLM_COMPONENT_SESS, sess_type, request); /// if (rcode != RLM_MODULE_OK) { /// /* FIXME: Good spot for a *rate-limited* warning to the log */ /// return 0; /// } return (request->simul_count < maxsimul) ? 0 : request->simul_mpp; } #endif : --------------------------------
とコメントアウトしてradiusdを作り直せば、ちゃんと同時接続制限が効く。
皆さん、できないできないっていうけどオープンソースなのでソース見てくださいねー。
(っていうか、fail-safeのON/OFFをするパラメータを用意してくれ、Alan DeKokさん…あー疲れた)