□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さん…あー疲れた)