Cisco WLC5508、FreeRadius、MySQL、およびEasyhotspotを備えたHotSpot

この記事では、 HotSpotを作成および構成する方法について説明します。 同時に、内部からどのように見えるかを詳細に説明し、freeRadius、MySQL、および簡単な請求Easyhotspotの作業に焦点を当てたいと思いました。



したがって、システムはCisco WLC5508およびCentOS上に構築されます。 これが互いにどのように相互作用するかを理解するために、図を見てみましょう。







それはすべてEasyhotspotサービスから始まります。実際には、Webインターフェースを介して制御される請求書です。 これはオープンソースプロジェクトであり、その主な利点は、理解と管理が簡単であることです。



それを使用して、ユーザー名とパスワードを生成します。これらは、MySQLデータベースに書き込まれ、使用するためにユーザーに転送されます。 次に、ユーザーはCisco WLCによって制御されるアクセスポイントに接続します。 ブラウザでページを開こうとすると、ユーザーは承認ページにリダイレクトされ、受け取ったクレジットを入力します。



その後、コントローラーはそれらをインターセプトし、アクセス要求メッセージで確認のためにFreeRadius承認サーバーに送信します。 彼はデータベースに目を向け、適切なログインとパスワードを見つけ、Wi-Fiコントローラーにすべてが大丈夫だと応答し、同時にユーザーがアクティブにできる時間を与えます。 RADIUSの用語では、Cisco WLC Wi-FiコントローラーはRADIUSサーバーのネットワークアクセスサーバーです。ホットスポットの用語では、このサービスはキャプティブポータルとも呼ばれます 。 このサービスの目的は、ユーザーに認証ウィンドウを表示し、クレジットをRADIUSサーバーに転送し、属性付きの応答を受け取り、適切に処理することです。



また、Easyhotspotはもともと、Chillispotと呼ばれるキャプティブポータルで動作するように設計されていましたが、基本的には気にしません。

ユーザーが承認された後、NASはユーザーセッション中にユーザーが使用したリソース(時間、トラフィックなど)に関するレポートをRADIUSサーバーに送信する必要があります。 このすべてのビジネスfreeRadiusはデータベースにログインします。 そして、次に接続しようとすると、ユーザーが何をどれだけ費やし、それがどれだけ利用可能になっているかをユーザーに確認します。



半径が何であるかを思い出してください。 これはプロトコルであり、条件付きで2つの部分に分割されます。これは、認証/許可およびアカウンティングです。 最初はRFC 2865で、2番目はRFC 2866で記述されています 。 それらが別々に動作するという事実は、サーバーが異なるポート1812および1813でそれらの要求を受け入れるという事実によっても示されます。



次に、リクエストとレスポンスがどのように見え、FreeRadiusでどのように処理されるかを詳細に分析し、インストールを進めます。 構成されたネットワークとインターネットアクセスを備えたCentOS 6.5サーバーがあるとします。 ネットワークからファイルをダウンロードするプログラムをインストールします。



yum install wget
      
      





リポジトリをダウンロードしてインストールします。



 wget http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm rpm -ivh epel-release-6-8.noarch.rpm
      
      





リポジトリとインストールされたプログラムを更新します。



 yum repolist yum update
      
      





有用なユーティリティ、MySQL、Apache、およびphpをインストールします。



 yum install mc vim unzip gcc gcc-c++ make git svn nano yum install mysql-server php httpd php-mysql php-xml php-gd php-pear php-db yum install patch mod_ssl openssl dnsmasq
      
      





/etc/php.iniファイルで、次の行のコメントを解除する必要があります。



 short_open_tag = On
      
      





このパラメーターを忘れた場合、請求ページを開こうとすると、次のメッセージが表示されます。



 EasyHotSpot config->item('EASYHOTSPOT_VERSION');?> load->view($this->config->item('FAL_template_dir').'template/menu');?> EasyHotspot - Hotspot Management System GNU Public License
      
      





/etc/php.iniの同じファイル内:



 date.timezone = Europe/Moscow
      
      





システムの起動後にMySQLとApacheが自動的に起動するようにしましょう。



 chkconfig --level 235 httpd on chkconfig --level 235 mysqld on chkconfig --level 235 dnsmasq on
      
      





Easyhotspotをインストールします。 github.com/rafeequlからeasyhotspotをダウンロードします。



 cd /opt git clone https://github.com/rafeequl/EasyHotspot ln -s /opt/EasyHotspot/htdocs /var/www/html/easyhotspot
      
      





easyhotspot_opensourceデータベースを作成します。



 mysql mysql> create database easyhotspot_opensource; mysql> CREATE USER 'easyhotspot'@'localhost'; mysql> SET PASSWORD FOR 'easyhotspot'@'localhost' = PASSWORD('easyhotspot'); mysql> GRANT ALL ON easyhotspot_opensource.* to 'easyhotspot'@'localhost'; mysql> quit mysql -u root easyhotspot_opensource < /opt/EasyHotspot/install/database_with_sample.sql
      
      





EasyHotspotでは、メニューにChillispotページがあります。 クリックすると、エラーが表示されます。 これを回避するには、削除してください。 これを行うには、/ opt / EasyHotspot / htdocs / system / application / views / admin / header.phpファイルの次の行を削除またはコメントアウトします。



 <!-- <li class="chillispot"><?=anchor('admin/chillispot','Chillispot')?></li> --> <!-- <li class="radius"><?=anchor('admin/freeradius','FreeRadius')?></li> -->
      
      





phpMyAdminをインストールします。これはMySQLの一種のGUIであり、テーブルの調査に役立ちます。



 wget https://files.phpmyadmin.net/phpMyAdmin/3.5.5/phpMyAdmin-3.5.5-all-languages.zip unzip phpMyAdmin-3.5.5-all-languages.zip cp phpMyAdmin-3.5.5-all-languages EasyHotspot/htdocs/phpmyadmin -rf
      
      





config.inc.phpを作成します。



 vi EasyHotspot/htdocs/phpmyadmin/config.inc.php
      
      





 <?php $i = 0; $i++; $cfg['ThemeDefault'] = 'original'; $cfg['Servers'][$i]['host'] = 'localhost'; $cfg['Servers'][$i]['extension'] = 'mysqli'; $cfg['Servers'][$i]['connect_type'] = 'tcp'; $cfg['Servers'][$i]['compress'] = false; $cfg['Servers'][$i]['auth_type'] = 'config'; // - phpmyadmin     .   ,      , 'config'   'http' $cfg['Servers'][$i]['user'] = 'easyhotspot'; $cfg['Servers'][$i]['password'] = 'easyhotspot'; /* End of servers configuration */ $cfg['UploadDir'] = ''; $cfg['SaveDir'] = ''; $cfg['BZipDump'] = false; $cfg['DefaultLang'] = 'ru'; $cfg['ThemeDefault'] = 'original'; $cfg['ServerDefault'] = 1; $cfg['CompressOnFly'] = false; $cfg['UserprefsDeveloperTab'] = true; $cfg['HideStructureActions'] = false; $cfg['LoginCookieDeleteAll'] = false; $cfg['QueryHistoryDB'] = true; $cfg['RetainQueryBox'] = true; $cfg['blowfish_secret'] = '51a360783193d3.45092927'; $cfg['LeftDefaultTabTable'] = 'tbl_select.php'; $cfg['MaxTableList'] = 500; ?>
      
      





Apacheを再起動します。



 service httpd restart
      
      





FreeRadiusをインストールして構成する



freeridius、mysqlサポート、およびシステムのテストに役立つユーティリティをインストールします。



 yum install freeradius freeradius-mysql freeradius-utils
      
      





システムの起動後にfreeradiuを自動的に実行させましょう:



 chkconfig --level 235 radiusd on
      
      





「client localhost」セクションの/etc/raddb/clients.confファイルで、次の手順を実行します。



 ipaddr = 127.0.0.1 secret = easyhotspot nastype = other
      
      





「モジュール」セクションの/etc/raddb/radiusd.confファイルで、コメントを外します。



 $INCLUDE sql.conf $INCLUDE sql/mysql/counter.conf
      
      





「インスタンス化」セクションに以下を追加します。



 noresetcounter
      
      





「authorize」セクションのファイル/ etc / raddb / sites-enabled / defaultで、「sql」のコメントを外し、「noresetcounter」を追加します。



 sql noresetcounter
      
      





次に、「アカウンティング」セクションの/ etc / raddb / sites-enabled / defaultで、「sql」のコメントを外します。



 sql
      
      





次に、「session」セクションの/ etc / raddb / sites-enabled / defaultで、「sql」のコメントを外し、「radutmp」をコメントアウトします。



 sql #radutmp
      
      





次に、「post-auth」セクションの「/ etc / raddb / sites-enabled / default」で「sql」のコメントを解除します。



 sql
      
      





最後の/etc/raddb/sql/mysql/counter.confファイルで、noresetcounterカウンターは既に定義されています。編集します。



 sqlcounter noresetcounter { counter-name = Session-Timeout check-name = Session-Timeout reply-name = Session-Timeout sqlmod-inst = sql key = User-Name reset = never query = "SELECT IFNULL(SUM(AcctSessionTime),0) FROM radacct WHERE UserName='%{${key}}'" }
      
      





同時使用で作業するためのファイル/etc/raddb/sql/mysql/dialup.confで、次のコメントを外します。



 simul_count_query = "SELECT COUNT(*) \ FROM ${acct_table1} \ WHERE username = '%{SQL-User-Name}' \ AND acctstoptime IS NULL"
      
      





「sql」セクションのファイル/etc/raddb/sql.confで、これを実行します。



  database = "mysql" driver = "rlm_sql_${database}" server = "localhost" #port = 3306 login = "easyhotspot" password = "easyhotspot" radius_db = "easyhotspot_opensource"
      
      





freeRadiusを再起動します。



 service radiusd start
      
      





Cisco WLCを設定して下さい



RadiusサーバーをWLCに接続します:SECURITY-> Authentication。 セキュリティ->会計。 設定時には、IPと共有秘密を入力する必要があります。







ログインとパスワードを入力する必要があるページをリクエストすると、許可されていないユーザーが認証ページにリダイレクトされるように、リダイレクトを設定します。







アクセスリストを設定します。 実際、ユーザーがSSIDに接続すると、Webブラウザーからの彼のすべてのリクエストは認証ページにリダイレクトされますが、これとは別に、本質的に何にも制限されません。



ユーザーが承認ページにのみアクセスでき、他の場所にはアクセスできないACLを作成する必要があります。







SSIDを作成し、[セキュリティ]-> [レイヤー2]タブで[なし]を選択します。 [セキュリティ]-> [レイヤー3]タブで、[Webポリシー-認証]を選択し、[事前認証ACL]ドロップダウンリストで、以前に作成したACLを選択します。







ドロップダウンリストから、以前に追加したRADIUSサーバーを選択します。







半径を調整するために残ります。 WLCとシークレットのIPアドレスを追加します

vi /etc/raddb/clients.conf



 client 192.168.0.5 { # # secret and password are mapped through the "secrets" file. secret = ololo,karl! # shortname = liv1 # # the following three fields are optional, but may be used by # # checkrad.pl for simultaneous usage checks nastype = cisco # login = !root # password = someadminpas }
      
      





freeRadiusを再起動します。



 service radiusd restart
      
      





これで、アドレスh.kh.kh.kh / easyhotspotで認証ページが利用可能になります。







ログイン:admin

パスワード:admin123



Webインターフェースの[キャッシャーメニュー]と[管理メニュー]には2つのメインメニューがあります。







管理メニューでは、請求計画とアカウント計画を作成して、それらに基づいてユーザー名/パスワードを生成できます。 1時間の請求プランを作成し、それに基づいて生成されたバウチャーは、作成の瞬間から翌日の終わりまで有効です(有効期間= 1)。アイドルタイムアウトには5分かかります。







[キャッシャーメニュー]-> [バウチャー管理]に移動して、1つのバウチャーを生成します。







システムをテストします。 radtestユーティリティを使用して、NASと同じ方法で承認のためにRADIUSサーバーにリクエストを送信します。 生成されたユーザー名/パスワードを使用します。「easyhotspot」は/etc/raddb/clients.confファイルの秘密です:



 radtest zupvez10 palkipud 127.0.0.1 100 easyhotspot
      
      





ここでエラーが発生する場合があります。



 [root@FreeRadius ~]# radtest zupvez10 palkipud 127.0.0.1 100 esyhotspot radclient:: Failed to find IP address for FreeRadius radclient: Nothing to send. [root@FreeRadius ~]#
      
      





これは、RADIUSパケットを送信するときに、ユーティリティがサーバー名を解決してNAS-IP-Addressに追加しようとするという事実に関連しています。 名前がlocalhostでない場合は、/ etc / hostsに追加する必要があります。 だから:



 [root@FreeRadius ~]# radtest zupvez10 palkipud 127.0.0.1 100 easyhotspot Sending Access-Request of id 189 to 127.0.0.1 port 1812 User-Name = "zupvez10" User-Password = "palkipud" NAS-IP-Address = 127.0.0.1 NAS-Port = 100 Message-Authenticator = 0x00000000000000000000000000000000 rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=189, length=63 WISPr-Session-Terminate-Time = "2016-1-6T24:00:00" Session-Timeout = 3600 Idle-Timeout = 300 Acct-Interim-Interval = 120 [root@FreeRadius ~]#
      
      





承認が成功したことがわかりましたが、それに応じて一連の属性を受け取りました。





素晴らしいですが、NASの作業の半分しか行いませんでした。認証と承認の後、アカウンティングを実行する必要があります。 これを行うには、属性を持つ3つのファイルを作成します。 User-Name = ""フィールドで、ユーザー名の指定を忘れないでください。



vi start.txt:



 Packet-Type=4 Packet-Dst-Port=1813 Acct-Session-Id = "4D2BB8AC-00000098" Acct-Status-Type = Start Acct-Authentic = RADIUS User-Name = "zupvez10" NAS-Port = 0 Called-Station-Id = "00-02-6F-AA-AA-AA:My Wireless" Calling-Station-Id = "00-1C-B3-AA-AA-AA" NAS-Port-Type = Wireless-802.11 Connect-Info = "CONNECT 48Mbps 802.11b"
      
      





User-Name = ""フィールドで、ユーザー名の指定を忘れないでください。



vi interim-update.txt:



 Packet-Type=4 Packet-Dst-Port=1813 Acct-Session-Id = "4D2BB8AC-00000098" Acct-Status-Type = Interim-Update Acct-Authentic = RADIUS User-Name = "zupvez10" NAS-Port = 0 Called-Station-Id = "00-02-6F-AA-AA-AA:My Wireless" Calling-Station-Id = "00-1C-B3-AA-AA-AA" NAS-Port-Type = Wireless-802.11 Connect-Info = "CONNECT 48Mbps 802.11b" Acct-Session-Time = 11 Acct-Input-Packets = 15 Acct-Output-Packets = 3 Acct-Input-Octets = 1407 Acct-Output-Octets = 467
      
      





User-Name = ""フィールドで、ユーザー名の指定を忘れないでください。



vi stop.txt:



 Packet-Type=4 Packet-Dst-Port=1813 Acct-Session-Id = "4D2BB8AC-00000098" Acct-Status-Type = Stop Acct-Authentic = RADIUS User-Name = "zupvez10" NAS-Port = 0 Called-Station-Id = "00-02-6F-AA-AA-AA:My Wireless" Calling-Station-Id = "00-1C-B3-AA-AA-AA" NAS-Port-Type = Wireless-802.11 Connect-Info = "CONNECT 48Mbps 802.11b" Acct-Session-Time = 30 Acct-Input-Packets = 25 Acct-Output-Packets = 7 Acct-Input-Octets = 3407 Acct-Output-Octets = 867 Acct-Terminate-Cause = User-Request
      
      





radclientユーティリティを使用して、開始アカウンティングパッケージをradiusサーバーに送信します。



radclient 127.0.0.1 auto easyhotspot -f start.txt:



 [root@FreeRadius ~]# radclient 127.0.0.1 auto easyhotspot -f start.txt Received response ID 50, code 5, length = 20
      
      





答えを受け取った場合、コード5はすべてが正常であることを意味します。 [キャッシャーメニュー]->オンラインユーザーに移動します。







ユーザーとセッションの開始時刻が表示されます。 次に、中間更新アカウンティングパッケージを送信します。 今回は、パッケージに新しい属性が追加されます。





radclient 127.0.0.1 auto easyhotspot -f interim-update.txt:



 [root@FreeRadius ~]# radclient 127.0.0.1 auto easyhotspot -f interim-update.txt Received response ID 226, code 5, length = 20
      
      





オンラインユーザーを見てみましょう。







これで、ユーザーが割り当てられた時間から11秒と1874バイトを費やしたことがわかります。 アカウンティング停止パッケージを送信します。



radclient 127.0.0.1 auto easyhotspot -f stop.txt:



 [root@FreeRadius ~]# radclient 127.0.0.1 auto easyhotspot -f stop.txt Received response ID 166, code 5, length = 20
      
      





セッションは終了しました。 [キャッシャーメニュー]-> [バウチャー管理]に移動します。







ユーザーの残り時間が59分であることがわかります。 時間は四捨五入されますが、これは請求のみで、freeRadiusは最も近い秒にカウントされます。 チェック:



radtest zupvez10 palkipud 127.0.0.1 100 easyhotspot:



 [root@FreeRadius ~]# radtest zupvez10 palkipud 127.0.0.1 100 easyhotspot Sending Access-Request of id 93 to 127.0.0.1 port 1812 User-Name = "zupvez10" User-Password = "palkipud" NAS-IP-Address = 127.0.0.1 NAS-Port = 100 Message-Authenticator = 0x00000000000000000000000000000000 rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=93, length=63 WISPr-Session-Terminate-Time = "2016-1-6T24:00:00" Session-Timeout = 3570 Idle-Timeout = 300 Acct-Interim-Interval = 120
      
      





受け取った回答から推測できるように、元々設定されていた3600の値からfreeRadiusはユーザーが使用した30を取り除いて3570を返しました。今度は会計セッションの開始にパッケージを送信しましょう。



radclient 127.0.0.1 auto easyhotspot -f start.txt:



 [root@FreeRadius ~]# radclient 127.0.0.1 auto easyhotspot -f start.txt Received response ID 15, code 5, length = 20
      
      





そして再び、アクセスを取得したユーザーが友人に資格情報を提供したことを想像して、ログインを試みます。



radtest zupvez10 palkipud 127.0.0.1 100 easyhotspot:



 Sending Access-Request of id 99 to 127.0.0.1 port 1812 User-Name = "zupvez10" User-Password = "palkipud" NAS-IP-Address = 127.0.0.1 NAS-Port = 100 Message-Authenticator = 0x00000000000000000000000000000000 rad_recv: Access-Reject packet from host 127.0.0.1 port 1812, id=99, length=68 Reply-Message = "\r\nYou are already logged in - access denied\r\n\n"
      
      





ボルト! セッションが完了するまで、誰も再びログインできません。 セッションを終了します。



radclient 127.0.0.1 auto easyhotspot -f stop.txt:



 [root@FreeRadius ~]# radclient 127.0.0.1 auto easyhotspot -f stop.txt Received response ID 143, code 5, length = 20
      
      





リクエストが処理されるときにfreeRadius内で何が起こるか見てみましょう。 freeRadiusを停止します。



 service radiusd stop
      
      





freeRadiusをデバッグモードで実行し、バックグラウンドで出力をlog.txtファイルに書き込みます。



radiusd -X> log.txt&



承認リクエストを送信します。



radtest zupvez10 palkipud 127.0.0.1 100 easyhotspot



セッションの開始と終了のリクエスト:



radclient 127.0.0.1 auto easyhotspot -f start.txt

radclient 127.0.0.1 auto easyhotspot -f interim-update.txt

radclient 127.0.0.1 auto easyhotspot -f stop.txt



デバッグモードを停止します。



kill-独自の値が必要です。コマンドradiusd -X> log.txt&の後に発行されます



 [root@FreeRadius ~]# service radiusd stop Stopping radiusd: [ OK ] [root@FreeRadius ~]# radiusd -X > log.txt & [1] 4215 [root@FreeRadius ~]# radtest zupvez10 palkipud 127.0.0.1 100 easyhotspot Sending Access-Request of id 200 to 127.0.0.1 port 1812 User-Name = "zupvez10" User-Password = "palkipud" NAS-IP-Address = 127.0.0.1 NAS-Port = 100 Message-Authenticator = 0x00000000000000000000000000000000 rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=200, length=63 WISPr-Session-Terminate-Time = "2016-1-6T24:00:00" Session-Timeout = 3540 Idle-Timeout = 300 Acct-Interim-Interval = 120 [root@FreeRadius ~]# radclient 127.0.0.1 auto easyhotspot -f start.txt Received response ID 68, code 5, length = 20 [root@FreeRadius ~]# radclient 127.0.0.1 auto easyhotspot -f interim-update.txt Received response ID 142, code 5, length = 20 [root@FreeRadius ~]# radclient 127.0.0.1 auto easyhotspot -f stop.txt Received response ID 37, code 5, length = 20 [root@FreeRadius ~]# kill 4215 [root@FreeRadius ~]# kill 4215 bash: kill: (4215) - No such process [1]+ Done radiusd -X > log.txt
      
      





ログを見てみましょう:



 less log.txt
      
      





debug_Authenticationおよび承認
 rad_recv: Access-Request packet from host 127.0.0.1 port 50024, id=200, length=78 User-Name = "zupvez10" User-Password = "palkipud" NAS-IP-Address = 127.0.0.1 NAS-Port = 100 Message-Authenticator = 0x9159a59b8e5c58fe44a95a199f84f9cf # Executing section authorize from file /etc/raddb/sites-enabled/default +group authorize { ++[preprocess] = ok ++[chap] = noop ++[mschap] = noop ++[digest] = noop [suffix] No '@' in User-Name = "zupvez10", looking up realm NULL [suffix] No such realm "NULL" ++[suffix] = noop [eap] No EAP-Message, not doing EAP ++[eap] = noop ++[files] = noop [sql] expand: %{User-Name} -> zupvez10 [sql] sql_set_user escaped user --> 'zupvez10' rlm_sql (sql): Reserving sql socket id: 31 [sql] expand: SELECT id, username, attribute, value, op FROM radcheck WHERE username = '%{SQL-User-Name}' ORDER BY id -> SELECT id, username, attribute, value, op FROM radcheck WHERE username = 'zupvez10' ORDER BY id [sql] User found in radcheck table [sql] expand: SELECT id, username, attribute, value, op FROM radreply WHERE username = '%{SQL-User-Name}' ORDER BY id -> SELECT id, username, attribute, value, op FROM radreply WHERE username = 'zupvez10' ORDER BY id [sql] expand: SELECT groupname FROM radusergroup WHERE username = '%{SQL-User-Name}' ORDER BY priority -> SELECT groupname FROM radusergroup WHER E username = 'zupvez10' ORDER BY priority [sql] expand: SELECT id, groupname, attribute, Value, op FROM radgroupcheck WHERE groupname = '%{Sql-Group}' ORDER BY id -> SELECT id, groupname, attribute , Value, op FROM radgroupcheck WHERE groupname = '1hour' ORDER BY id [sql] User found in group 1hour [sql] expand: SELECT id, groupname, attribute, value, op FROM radgroupreply WHERE groupname = '%{Sql-Group}' ORDER BY id -> SELECT id, groupname, attribute , value, op FROM radgroupreply WHERE groupname = '1hour' ORDER BY id rlm_sql (sql): Released sql socket id: 31 ++[sql] = ok rlm_sqlcounter: Entering module authorize code sqlcounter_expand: 'SELECT IFNULL(SUM(AcctSessionTime),0) FROM radacct WHERE UserName='%{User-Name}'' [noresetcounter] expand: SELECT IFNULL(SUM(AcctSessionTime),0) FROM radacct WHERE UserName='%{User-Name}' -> SELECT IFNULL(SUM(AcctSessionTime),0) FROM radacct WHERE UserName='zupvez10' WARNING: Please replace '%S' with '${sqlmod-inst}' sqlcounter_expand: '%{sql:SELECT IFNULL(SUM(AcctSessionTime),0) FROM radacct WHERE UserName='zupvez10'}' [noresetcounter] sql_xlat [noresetcounter] expand: %{User-Name} -> zupvez10 [noresetcounter] sql_set_user escaped user --> 'zupvez10' [noresetcounter] expand: SELECT IFNULL(SUM(AcctSessionTime),0) FROM radacct WHERE UserName='zupvez10' -> SELECT IFNULL(SUM(AcctSessionTime),0) FROM radacct WHERE UserName='zupvez10' rlm_sql (sql): Reserving sql socket id: 30 [noresetcounter] sql_xlat finished rlm_sql (sql): Released sql socket id: 30 [noresetcounter] expand: %{sql:SELECT IFNULL(SUM(AcctSessionTime),0) FROM radacct WHERE UserName='zupvez10'} -> 60 rlm_sqlcounter: Check item is greater than query result rlm_sqlcounter: Authorized user zupvez10, check_item=3600, counter=60 rlm_sqlcounter: Sent Reply-Item for user zupvez10, Type=Session-Timeout, value=3540 ++[noresetcounter] = ok [expiration] Checking Expiration time: 'January 6 2016 24:00:00' ++[expiration] = ok ++[logintime] = noop ++[pap] = updated +} # group authorize = updated Found Auth-Type = PAP # Executing group from file /etc/raddb/sites-enabled/default +group PAP { [pap] login attempt with password "palkipud" [pap] Using clear text password "palkipud" [pap] User authenticated successfully ++[pap] = ok +} # group PAP = ok # Executing section session from file /etc/raddb/sites-enabled/default +group session { [sql] expand: %{User-Name} -> zupvez10 [sql] sql_set_user escaped user --> 'zupvez10' [sql] expand: SELECT COUNT(*) FROM radacct WHERE username = '%{SQL-User-Name}' AND acctstoptime IS NULL -> SELECT COUNT(*) FROM radacct WHERE username = 'zupvez10' AND acctstoptime IS NULL rlm_sql (sql): Reserving sql socket id: 29 rlm_sql (sql): Released sql socket id: 29 ++[sql] = ok +} # group session = ok # Executing section post-auth from file /etc/raddb/sites-enabled/default +group post-auth { [sql] expand: %{User-Name} -> zupvez10 [sql] sql_set_user escaped user --> 'zupvez10' [sql] expand: %{User-Password} -> palkipud [sql] expand: INSERT INTO radpostauth (username, pass, reply, authdate) VALUES ( '%{User-Name}', '%{%{User-Password}:-%{Chap-Password}}', '%{reply:Packet-Type}', '%S') -> INSERT INTO radpostauth (username, pass, reply, authdate) VALUES ( 'zupvez10', 'palkipud', 'Access-Accept', '2016-01-05 21:20:45') rlm_sql (sql) in sql_postauth: query is INSERT INTO radpostauth (username, pass, reply, authdate) VALUES ( 'zupvez10', 'palkipud', 'Access-Accept', '2016-01-05 21:20:45') rlm_sql (sql): Reserving sql socket id: 28 rlm_sql (sql): Released sql socket id: 28 ++[sql] = ok ++[exec] = noop +} # group post-auth = ok Sending Access-Accept of id 200 to 127.0.0.1 port 50024 WISPr-Session-Terminate-Time := "2016-1-6T24:00:00" Session-Timeout := 3540 Idle-Timeout := 300 Acct-Interim-Interval := 120 Finished request 0. Going to the next request
      
      







FreeRadiusはパッケージを受け取り、最初にファイル/ etc / raddb / sites-enabled / defaultに記述されている承認セクションを起動しました

角括弧は、リクエストを1つずつ処理するモジュールを示しています。





デバッグ出力から、5つのデータベースクエリが5つの異なるテーブルに対して行われたことは明らかです。後でそれらを検討しますが、現時点ではユーザーが見つかり、すべてが問題ないことを理解しています。





認証セクションに渡し、ここで[pap]はユーザーが正常に認証されたことを決定します。 次に、セクションセクションが起動され、[sql]セッションが現在アクティブであるかどうかが判断されます。アクティブである場合は、誰かが既にログインしており、アクセスが拒否されます。 要求自体は/etc/raddb/sql/mysql/dialup.confに記述されています。 post-authセクションは、成功した認証をデータベース、radpostauthテーブルに記録します。 その後、答えが送信されます。



したがって、承認および認証パッケージを処理するとき、freeRadiusは6つのテーブルで機能することがわかります。





認証と承認が合格しました。今度はアカウンティングを扱います。



debug_Accounting
 rad_recv: Accounting-Request packet from host 127.0.0.1 port 58851, id=142, length=177 Acct-Session-Id = "4D2BB8AC-00000098" Acct-Status-Type = Interim-Update Acct-Authentic = RADIUS User-Name = "zupvez10" NAS-Port = 0 Called-Station-Id = "00-02-6F-AA-AA-AA:My Wireless" Calling-Station-Id = "00-1C-B3-AA-AA-AA" NAS-Port-Type = Wireless-802.11 Connect-Info = "CONNECT 48Mbps 802.11b" Acct-Session-Time = 11 Acct-Input-Packets = 15 Acct-Output-Packets = 3 Acct-Input-Octets = 1407 Acct-Output-Octets = 467 # Executing section preacct from file /etc/raddb/sites-enabled/default +group preacct { ++[preprocess] = ok [acct_unique] WARNING: Attribute NAS-Identifier was not found in request, unique ID MAY be inconsistent [acct_unique] Hashing 'NAS-Port = 0,,NAS-IP-Address = 127.0.0.1,Acct-Session-Id = "4D2BB8AC-00000098",User-Name = "zupvez10"' [acct_unique] Acct-Unique-Session-ID = "55c4c93f54bb88a7". ++[acct_unique] = ok [suffix] No '@' in User-Name = "zupvez10", looking up realm NULL [suffix] No such realm "NULL" ++[suffix] = noop ++[files] = noop +} # group preacct = ok # Executing section accounting from file /etc/raddb/sites-enabled/default +group accounting { [detail] expand: %{Packet-Src-IP-Address} -> 127.0.0.1 [detail] expand: /var/log/radius/radacct/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/detail-%Y%m%d -> /var/log/radius/radacct/127.0.0.1/detail-20160105 [detail] /var/log/radius/radacct/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/detail-%Y%m%d expands to /var/log/radius/radacct/127.0.0.1/detail-20160105 [detail] expand: %t -> Tue Jan 5 21:21:18 2016 ++[detail] = ok [sql] expand: %{User-Name} -> zupvez10 [sql] sql_set_user escaped user --> 'zupvez10' [sql] expand: %{Acct-Session-Time} -> 11 [sql] expand: %{Acct-Input-Gigawords} -> [sql] ... expanding second conditional [sql] expand: %{Acct-Input-Octets} -> 1407 [sql] expand: %{Acct-Output-Gigawords} -> [sql] ... expanding second conditional [sql] expand: %{Acct-Output-Octets} -> 467 [sql] expand: UPDATE radacct SET framedipaddress = '%{Framed-IP-Address}', acctsessiontime = '%{%{Acct-Session-Time}:-0}', acctinpu toctets = '%{%{Acct-Input-Gigawords}:-0}' << 32 | '%{%{Acct-Input-Octets}:-0}', acctoutputoctets = '%{%{Acct-Output-Gigawords}:-0}' << 32 | '%{%{Acct-Output-Octets}:-0}' WHERE acctsessionid = '%{Acct-Session-Id}' AND username = '%{SQL-User-Name}' AND nasipaddress = '%{NAS-IP-Address}' -> UPDATE radacct SET framedipaddress = '', acctsessiontime = '11', acctinputoctets = '0' << 32 | '1407', acctoutputoctets = '0' << 32 | '467' WHERE acctsessionid = '4D2BB8AC-00000098' AND username = 'zupvez10' AND nas rlm_sql (sql): Reserving sql socket id: 26 rlm_sql (sql): Released sql socket id: 26 ++[sql] = ok ++[exec] = noop [attr_filter.accounting_response] expand: %{User-Name} -> zupvez10 attr_filter: Matched entry DEFAULT at line 12 ++[attr_filter.accounting_response] = updated +} # group accounting = updated Sending Accounting-Response of id 142 to 127.0.0.1 port 58851 Finished request 2. Cleaning up request 2 ID 142 with timestamp +40 Going to the next request
      
      







Interim-Updateパッケージの処理プロセスを検討してください。 preacctセクションが開始され、ファイル/ etc / raddb / sites-enabled / defaultで説明されています。





アカウンティングセクションが開始されます





応答が送信されます。したがって、アカウンティングパッケージを処理するとき、freeRadiusは1つのテーブルのみで機能することがわかります。





MySQLデータベースのテーブルを検討する



アドレスh.kh.kh.kh / easyhotspot / phpmyadminで、GUIを使用してテーブルを確認できます。 easyhotspot_opensourceデータベースに移動します。 freeRadiusが機能する上記の7つのテーブルに興味があり







ます。それぞれを個別に検討し、radcheckから始めましょう。







ここでは、ユーザーの2行が表示されています。最初はCleartext-Password属性を使用してパスワードが設定され、2番目はExpiration属性を使用して資格情報の有効期限が切れる日付が設定されます。



我々は、パスワード処理モジュール[PAP]セクションでログのdebug属性で見てきたように認証中、および有効期限の属性処理モジュール[有効期限]セクションAUTHORIZE



明らかに、私たちの請求easyhotspotはこれらの行を生成して記録してくれました。 radcheckテーブルは、テストされる属性を記録するために必要であり、応答で渡される属性はradreplyテーブルに書き込まれます。







ただし、ここではWISPr-Session-Terminate-Time:= "2016-1-6T24:00:00"のみが表示されます。これは、属性をグループ化できるためです。同じ属性セットを持つ共通の請求プランがある場合、各ユーザーのradreplyテーブルにそれらを書き込む必要があるのはなぜですか。

radusergroupテーブルでユーザーのユーザー名を指定し、groupnameでグループのメンバーシップと優先順位を指定します。







そして、groupnameのradgroupreplyテーブルで同じグループを指定し、そのグループにいるユーザーに渡す必要のあるすべての属性をリストします。







そして、ここでは、freeRadiusからの応答で私たちに届いた残りの3つの属性が表示されます。送信のためだけでなく、チェックのためにもグループに属性を持たせたい場合はどうでしょうか?ここで、radgroupcheckテーブルが役立ちます。







その中には、authorizeセクションの[noresetcounter]モジュールによってチェックされるSession-Timeoutと、sessionセクションの[sql]モジュールによって処理されるSimultaneous-Useがあります。値= 1は、一度に1つのアクティブセッションしか存在できないことを半径に伝え、それ以降のログイン試行はすべて拒否されます。



そして、これらすべてが私たちの請求をeasyhotspotにします。請求プランを作成し、「バウチャーを生成」ボタンをクリックすると、easyhotspotは必要なすべての属性を最適な方法でテーブルに分散しました。 post-authセクションの[sql]モジュールを使用して、成功した認証試行のログがradpostauthテーブルに書き込まれます。







成功した試みの2つの記録があります。最も大きなradacctテーブルが残っています。これは、会計用のパッケージを処理するときにfreeRadiusによって作成されます。課金システムは、どのユーザーがオンラインで、どのくらいの時間とトラフィックを費やしたかを表示するように彼に依頼すると、連絡します。 FreeRadius自体も、NASからの要求を処理するときに同じ目的でアクセスします。



ここで、NAS-freeRadius-MySQL-Easyhotspotがどのように連携して機能するかを見て、実際の部分に移りましょう。しばらくして運用を開始すると、「オンラインユーザー」メニューに次の画像が表示されます。







ポピーのアドレスはどこから来たのか、そのようなユーザー名は生成しませんでしたか?問題は、認証/許可とアカウンティングが互いに独立して機能できることを、tsiskaが再び証明することです。開いたSSIDがあります。ユーザーがピックアップしてログインした後、彼の会計パッケージのtsiskaは、ユーザー名フィールドに許可されているユーザー名を入力します。



そして、あなたが承認されていない場合は?その後、tsiskaは引き続きアカウンティングパケットを送信し、ユーザー名フィールドにポピーアドレスを挿入します。オープンSSIDにしがみついて何日もハングするすべてのデバイスは、これに気づかずに、radacctテーブルでいっぱいになることがわかりました。もちろん、これは私たちには合いません。この問題を解決するために、unlangおよびregular expressionと呼ばれるfreeRadius組み込み言語を使用します



最初のpreacctセクションの/ etc / raddb / sites-enabled / defaultファイルに、次の式を記述します。



 # Pre-accounting. Decide which accounting type to use. # preacct { if (User-Name=~ /^[A-Fa-f0-9]{12}$/) { reject }
      
      





User-Name属性が次の条件を作成します。





そして、そのようなパッケージは「拒否」アクションを待ちます。つまり、ドロップされます。デバッグモードで確認します。



 rad_recv: Accounting-Request packet from host 192.168.80.100 port 32770, id=138, length=246 User-Name = "6c709f251ec4" NAS-Port = 13 NAS-IP-Address = 192.168.0.5 Framed-IP-Address = 192.168.13.80 NAS-Identifier = "5508" Airespace-Wlan-Id = 2 Acct-Session-Id = "567be2a8/6c:70:9f:25:1e:c4/217989" Acct-Authentic = Remote Tunnel-Type:0 = VLAN Tunnel-Medium-Type:0 = IEEE-802 Tunnel-Private-Group-Id:0 = "13" Acct-Status-Type = Interim-Update Acct-Input-Octets = 3566315 Acct-Output-Octets = 99562740 Acct-Input-Packets = 41757 Acct-Output-Packets = 66012 Acct-Session-Time = 8345 Acct-Delay-Time = 0 Calling-Station-Id = "6c-70-9f-25-2-b2" Called-Station-Id = "28-94-0f-ae-be-13" Cisco-AVPair = "nas-update=true" # Executing section preacct from file /etc/raddb/sites-enabled/default +- entering group preacct {...} ++? if (User-Name=~ /^[A-Fa-f0-9]{12}$/) ? Evaluating (User-Name=~ /^[A-Fa-f0-9]{12}$/) -> TRUE ++? if (User-Name=~ /^[A-Fa-f0-9]{12}$/) -> TRUE ++- entering if (User-Name=~ /^[A-Fa-f0-9]{12}$/) {...} +++[reject] returns reject ++- if (User-Name=~ /^[A-Fa-f0-9]{12}$/) returns reject Finished request 7.
      
      





それは機能します。クレジットを作成するとき、私たち自身がこれらの条件に該当するべきではないことを覚えています。 「オンラインユーザー」テーブルの外観を見てみましょう。







その中のMacアドレスはもはや観測されていませんが、一部のセッションが明らかにフリーズしていることがわかります。 radacctテーブルをチェックして、ユーザー「detpis7」に何が起こったのかを見てみましょう。







そして彼のセッションでは、すべてが大丈夫です。 2015-12-24 18:18:00に開始し、2015-12-24 19:11:37に終了したことがわかり

ます。それでは、開始時間2015-12-24 18:18:00に請求にハングアップします。 ?データベースへのクエリがどのように形成されるかを見てみましょう。これは、ファイル/opt/EasyHotspot/htdocs/system/application/models/onlineusermodel.phpで発生します。



 return $this->db->query('select username, MAX(acctstarttime) as start, (acctstoptime) as stop, sum(acctsessiontime) as time,sum(acctoutputoctets)+sum(acctinputoctets) as packet from radacct where (acctstoptime IS NULL) group by username');
      
      





クエリは、各ユーザーについて、セッションの最大開始時間に従ってレコードがグループ化され、acctstoptimeにNULLが書き込まれる行が選択されることを示しています。請求に関して、このリクエストは次の2つの理由で正しく機能しません。



まず、テストクエリを思い出してください。通常の場合、テーブル内の1つのセッションが1行を占有する必要があることがわかりました。開始パッケージが到着すると作成され、更新されるだけです。 /etc/raddb/sql/mysql/dialup.confファイルのaccounting_update_queryクエリがこれを担当しますが、失敗した場合、freeRadiusはaccounting_update_query_altクエリを使用して新しい行を作成します。



次に、1つのセッション内のセッションの開始時間が1秒間変化することがわかります。これはどのように行われますか? NASはAcct-Session-Timeのみを送信しますが、radacctテーブルfreeRadiusのacctstarttimeはそれを自分で考慮します。 /etc/raddb/sql/mysql/dialup.confファイルのaccounting_update_query_altクエリを見てみましょう。



 DATE_SUB('%S', \ INTERVAL (%{%{Acct-Session-Time}:-0} + \ %{%{Acct-Delay-Time}:-0}) SECOND)
      
      





これにより、サーバーが現在の時刻を取得し、Acct-Session-Time(Acct-Delay-Timeが0)を取得して、セッションの開始時刻を受け取ることが明らかになります。



したがって、メカニズム全体は次のように機能します。ユーザーが12.00.00にシステムにログインし、12.00.20にNASがInterim-updateパッケージの送信を決定し、12.00.20から12.00.00を減算し、20を受信し、属性Acct-Session-Time = 20を送信したとしますfreeRadius。この値を受け取ったサーバーは、12.00.20から20を減算したMySQL DATE_SUB(日付、INTERVAL exprタイプ)関数を使用し、12.00.00を受け取り、この値をacctstarttimeとしてテーブルに書き込みました。



20秒後にNASが同じ操作を行い、Acct-Session-Time = 40を送信したが、パケットがネットワーク上のどこかで1秒間遅延し、サーバーに到着したときに既に12.00.41、12.00.41-40 = 12.00だったとします.01は、radacct acctstarttime = 12.00.01というテーブルの新しい行になりました。



前の表をもう一度見てください。したがって、acctstoptime = NULLの場合、課金MAX(acctstarttime)を要求すると、セッションがハングします。



同時に、表の請求とacctsessiontimeのDuration値に注意してください。これも誤っていると見なされます。クエリでは、これらの値はユーザーごとに合計されますが、セッションのテーブルに複数の行がある場合、これらの値を合計することはできません。



次のようにリクエストを変更します:



vi /opt/EasyHotspot/htdocs/system/application/models/onlineusermodel.php



 return $this->db->query('SELECT username, MAX(radacctid), MAX(acctstarttime) as start, MAX(acctstoptime) as stop, CAST(max(acctsessiontime)/60 AS UNSIGNED) as time,max(acctoutputoctets)+max(acctinputoctets) as packet, framedipaddress FROM radacct GROUP BY acctuniqueid HAVING stop IS NULL');
      
      





最初に、リクエストをユーザー名ではなくacctuniqueidでグループ化します。これは、セッション内で一意の値です。 MAX(acctstarttime)に依存することはできないため、合計ではなくセッション内のradacctidの最大値を取得しますが、セッション内のacctsessiontimeの最大値を60で除算し、すぐに結果を数分で取得して最大値を追加しますacctoutputoctetsとacctinputoctetsの値。これから、stop = NULLの行を見つけます。



これらは、以前に特定した問題を考慮して、時間とトラフィックの正しい値を持つアクティブなセッションになります。同時に、リクエストにframedipaddress列を追加すると、ユーザーのIPアドレスが表示されます。請求書に追加します。



vi /opt/EasyHotspot/htdocs/system/application/views/onlineusers_view.php



 <?php if (!defined('BASEPATH')) exit('No direct script access allowed'); ?> <?php $this->load->view('header') ?> <h1><?=$action?></h1> <table class="stripe"> <tbody> <tr> <th><?=$this->lang->line('username')?></th> <th>Start</th> <th>Duration</th> <th>Packet</th> <th>IP-Address</th> <th>Force Disconnect</th> </tr> <?php foreach ($onlineusers->result() as $row): ?> <tr> <td><?=$row->username;?></td> <td><?=$row->start;?></td> <td><?=$row->time;?></td> <td><?=$row->packet;?></td> <td><?=$row->framedipaddress;?></td> <td><?=anchor('onlineuser/disconnect/'.$row->username,'disconnect','class="disconnect" ')?></td> </tr> <?php endforeach;?> </tbody> </table> <? $this->load->view('footer'); ?>
      
      





[キャッシャーメニュー]-> [バウチャー管理]ページでデータがどのように要求されるかを検討してください。



vi /opt/EasyHotspot/htdocs/system/application/models/vouchermodel.php +22



voucher_listテーブルにクエリがありますこれは実際にはテーブルではなく、ビューです。その説明は、作成されたすべてのテーブルに関して、ファイル/opt/EasyHotspot/install/database_with_sample.sqlにあります。



 VIEW `voucher_list` AS select `v`.`id` AS `id`,`v`.`username` AS `username`,`v`.`password` AS `password`,`v`.`billingplan` AS `billingplan`,`v`.`valid_until` AS `valid_until`,`b`.`type` AS `type`,`b`.`amount` AS `amount`,`b`.`valid_for` AS `valid_for`,`b`.`price` AS `price`,(sum(`ra`.`acctsessiontime`) / 60) AS `time_used`,if((`b`.`type` = _latin1'time'),(`b`.`amount` - (sum(`ra`.`acctsessiontime`) / 60)),_latin1'null') AS `time_remain`,((sum(`ra`.`acctoutputoctets`) + sum(`ra`.`acctinputoctets`)) / 1048576) AS `packet_used`,if((`b`.`type` = _latin1'packet'),(`b`.`amount` - (sum((`ra`.`acctoutputoctets` + `ra`.`acctinputoctets`)) / 1048576)),_latin1'null') AS `packet_remain`,`v`.`isexported` AS `isexported`,`v`.`isprinted` AS `isprinted`,if((`b`.`type` = _latin1'time'),if(((sum(`ra`.`acctsessiontime`) / 60) >= `b`.`amount`),_latin1'exp',_latin1'valid'),if((((sum(`ra`.`acctoutputoctets`) + sum(`ra`.`acctinputoctets`)) / 1048576) >= `b`.`amount`),_latin1'exp',_latin1'valid')) AS `valid` from ((`voucher` `v` left join `radacct` `ra` on((`v`.`username` = `ra`.`username`))) join `billingplan` `b` on((`b`.`name` = `v`.`billingplan`))) group by `v`.`username
      
      





ポイントは、通常のクエリのように、ビューが他のテーブルからデータを収集することであり、ビューを通常のテーブルと呼びます。



表現を通常のリクエストと見なす場合は、次のようにやり直す必要があります。



 select id, username, password, billingplan, valid_until, type, amount, valid_for, price, sum(time_used) AS time_used, if((type = _latin1'time'),(amount - sum(time_used)),_latin1'null') AS time_remain, sum(packet_used) AS packet_used, if((type = _latin1'packet'),((amount - sum(packet_used)) / 1048576),_latin1'null') AS packet_remain, isexported, isprinted, if((type = _latin1'time'),if((sum(time_used) >= amount),_latin1'exp',_latin1'valid'),if((sum(packet_used) >= amount),_latin1'exp',_latin1'valid')) AS valid from (select v.id AS id,v.username AS username,v.password AS password, v.created_by AS created, v.created_time AS created_time, ra.acctuniqueid as acctuniqueid, v.billingplan AS billingplan,v.valid_until AS valid_until,b.type AS type,b.amount AS amount,b.valid_for AS valid_for,b.price AS price,(max(ra.acctsessiontime) / 60) AS time_used,if((b.type = _latin1'time'),(b.amount - (max(ra.acctsessiontime) / 60)),_latin1'null') AS time_remain,((max(ra.acctoutputoctets) + max(ra.acctinputoctets)) / 1048576) AS packet_used,if((b.type = _latin1'packet'),(b.amount - (max((ra.acctoutputoctets + ra.acctinputoctets)) / 1048576)),_latin1'null') AS packet_remain,v.isexported AS isexported,v.isprinted AS isprinted,if((b.type = _latin1'time'),if(((max(ra.acctsessiontime) / 60) >= b.amount),_latin1'exp',_latin1'valid'),if((((max(ra.acctoutputoctets) + max(ra.acctinputoctets)) / 1048576) >= b.amount),_latin1'exp',_latin1'valid')) AS valid from ((voucher v left join radacct ra on((v.username = ra.username))) join billingplan b on((b.name = v.billingplan))) group by v.username, ra.acctuniqueid) as b group by username
      
      





ここでは、各ユーザーのセッション内の各グループ化されたデータから、すべてのセッションのacctsessiontime、acctoutputoctets、acctinputoctetsの最大値の合計を取得できるサブクエリを含むクエリを使用します。



ロジックは次のとおりです。ユーザーに3つのセッションがあり、radacctテーブルにセッションあたり5行の15行がある場合、サブクエリは各セッションの最大データ値を持つ3行を表示します。そして、メインリクエストは各ユーザーのこれらのセッションデータを要約します。その結果、列構造の表示が元のものと同じになるように、すべてのデータを収集します。



ここでの注意点は、ビューにサブクエリを含めることができないことです。ただし、あるビューが別のビューからデータを要求する場合があります。メインのvoucher_listビューのベースとなるvoucher_list_0ビューを作成します。



 mysql -u easyhotspot -p easyhotspot_opensource Enter password: easyhotspot create VIEW voucher_list_0 AS select v.id AS id,v.username AS username,v.password AS password,ra.acctuniqueid as acctuniqueid, v.billingplan AS billingplan, v.valid_until AS valid_until,b.type AS type,b.amount AS amount,b.valid_for AS valid_for,b.price AS price,(max(ra.acctsessiontime) / 60) AS time_used,if((b.type = _latin1'time'),(b.amount - (max(ra.acctsessiontime) / 60)),_latin1'null') AS time_remain,((max(ra.acctoutputoctets) + max(ra.acctinputoctets)) / 1048576) AS packet_used,if((b.type = _latin1'packet'),(b.amount - (max((ra.acctoutputoctets + ra.acctinputoctets)) / 1048576)),_latin1'null') AS packet_remain,v.isexported AS isexported,v.isprinted AS isprinted,if((b.type = _latin1'time'),if(((max(ra.acctsessiontime) / 60) >= b.amount),_latin1'exp',_latin1'valid'),if((((max(ra.acctoutputoctets) + max(ra.acctinputoctets)) / 1048576) >= b.amount),_latin1'exp',_latin1'valid')) AS valid from ((voucher v left join radacct ra on((v.username = ra.username))) join billingplan b on((b.name = v.billingplan))) group by v.username, ra.acctuniqueid;
      
      





古いビューを削除します。



 drop view voucher_list;
      
      





新しいものと交換します。



 create VIEW voucher_list AS select id, username, password, billingplan, valid_until, type, amount, valid_for, price, sum(time_used) AS time_used, if((type = _latin1'time'),(amount - sum(time_used)),_latin1'null') AS time_remain, sum(packet_used) AS packet_used, if((type = _latin1'packet'),((amount - sum(packet_used)) / 1048576),_latin1'null') AS packet_remain, isexported, isprinted, if((type = _latin1'time'),if((sum(time_used) >= amount),_latin1'exp',_latin1'valid'),if((sum(packet_used) >= amount),_latin1'exp',_latin1'valid')) AS valid from voucher_list_0 group by username;
      
      





これで、[キャッシャーメニュー]->後払いのページでも同じことを行う必要があります。元のビューは次のようになります。



 VIEW `postpaid_account_list` AS select `postpaid_account`.`id` AS `id`,`postpaid_account`.`realname` AS `realname`,`postpaid_account`.`username` AS `username`,`postpaid_account`.`password` AS `password`,(sum(`radacct`.`acctsessiontime`) / 60) AS `time_used`,(sum((`radacct`.`acctoutputoctets` + `radacct`.`acctinputoctets`)) / 1048576) AS `packet_used`,`postpaid_account`.`bill_by` AS `bill_by`,(`postplan`.`price` * (sum(`radacct`.`acctsessiontime`) / 60)) AS `time_price`,(`postplan`.`price` * (sum((`radacct`.`acctoutputoctets` + `radacct`.`acctinputoctets`)) / 1048576)) AS `packet_price`,`postpaid_account`.`valid_until` AS `valid_until` from ((`postpaid_account` left join `radacct` on((`postpaid_account`.`username` = `radacct`.`username`))) join `postplan` on((`postplan`.`name` = `postpaid_account`.`bill_by`))) group by `postpaid_account`.`username`
      
      





`postpaid_account_list`を置き換えるサブクエリを含む終了したリクエストは次のようになります。



 select id, realname, username, password, sum(time_used) AS time_used, sum(packet_used) AS packet_used, bill_by, time_price, packet_price, valid_until from (select `postpaid_account`.`id` AS `id`,`postpaid_account`.`realname` AS `realname`,`postpaid_account`.`username` AS `username`,`postpaid_account`.`password` AS `password`,(max(`radacct`.`acctsessiontime`)/60 ) AS `time_used`,(max((`radacct`.`acctoutputoctets` + `radacct`.`acctinputoctets`)) / 1048576) AS `packet_used`,`postpaid_account`.`bill_by` AS `bill_by`,(`postplan`.`price` * (max(`radacct`.`acctsessiontime`) / 60)) AS `time_price`,(`postplan`.`price` * (max((`radacct`.`acctoutputoctets` + `radacct`.`acctinputoctets`)) / 1048576)) AS `packet_price`,`postpaid_account`.`valid_until` AS `valid_until` from ((`postpaid_account` left join `radacct` on((`postpaid_account`.`username` = `radacct`.`username`))) join `postplan` on((`postplan`.`name` = `postpaid_account`.`bill_by`))) group by `postpaid_account`.`username`, radacct.acctuniqueid ) list group by username
      
      





メインのpostpaid_account_listビューのベースとなるpostpaid_account_list_0ビューを作成します。



 create VIEW postpaid_account_list_0 AS select `postpaid_account`.`id` AS `id`,`postpaid_account`.`realname` AS `realname`,`postpaid_account`.`username` AS `username`,`postpaid_account`.`password` AS `password`,(max(`radacct`.`acctsessiontime`)/60 ) AS `time_used`,(max((`radacct`.`acctoutputoctets` + `radacct`.`acctinputoctets`)) / 1048576) AS `packet_used`,`postpaid_account`.`bill_by` AS `bill_by`,(`postplan`.`price` * (max(`radacct`.`acctsessiontime`) / 60)) AS `time_price`,(`postplan`.`price` * (max((`radacct`.`acctoutputoctets` + `radacct`.`acctinputoctets`)) / 1048576)) AS `packet_price`,`postpaid_account`.`valid_until` AS `valid_until` from ((`postpaid_account` left join `radacct` on((`postpaid_account`.`username` = `radacct`.`username`))) join `postplan` on((`postplan`.`name` = `postpaid_account`.`bill_by`))) group by `postpaid_account`.`username`, radacct.acctuniqueid;
      
      





古いビューを削除します。



 drop view postpaid_account_list;
      
      





そして、新しいものを作成します。



 create VIEW postpaid_account_list AS select id, realname, username, password, sum(time_used) AS time_used, sum(packet_used) AS packet_used, bill_by, time_price, packet_price, valid_until from postpaid_account_list_0 group by username;
      
      





ここで、freeRadiusもモジュールでradacctを使用することを覚えておく必要があります。/etc/raddb/sql/mysql/counter.confで説明されている[noresetcounter]モジュールを思い出してください。



vi /etc/raddb/sql/mysql/counter.conf +110



 sqlcounter noresetcounter { counter-name = Session-Timeout check-name = Session-Timeout reply-name = Session-Timeout sqlmod-inst = sql key = User-Name reset = never query = "SELECT IFNULL(SUM(AcctSessionTime),0) FROM radacct WHERE UserName='%{${key}}'" }
      
      





この構成では、さまざまなカウンターを構成できます。noresetcounterは、名前が示すとおり、リセットされません。つまり、ユーザーに3600秒が与えられた場合、それらのユーザーはこれらのクレジットを使用できなくなります。カウンターを構成することもできます。カウンターは、1日、1週間、1か月に1回割引されます。





しかし、最も興味深いのはクエリです。このパラメーターは、ユーザーが既に使用した数値を返す必要があります。リクエストのロジックは以前と同じになります。サブクエリでは、指定されたユーザーのすべてのセッションでAcctSessionTimeの最大値を取得し、メインリクエストでそれらを一緒に追加します。組み込みのmysql IFNULL関数を使用します。テーブルに何も見つからない場合、0を返します。行を置き換えます



 query = "SELECT IFNULL(SUM(AcctSessionTime),0) FROM radacct WHERE UserName='%{${key}}'"
      
      









 query = "SELECT SUM(b) FROM (SELECT IFNULL(MAX(AcctSessionTime),0) as b FROM radacct WHERE UserName='%{${key}}'GROUP BY acctuniqueid) as list"
      
      





次のモジュール、または使い慣れたセッションセクションとその[sql]セクションに移りましょう。このモジュールのリクエストは、「同時使用チェッククエリ」セクションの/etc/raddb/sql/mysql/dialup.confファイルに記述されています。



 simul_count_query = "SELECT COUNT(*) \ FROM ${acct_table1} \ WHERE username = '%{SQL-User-Name}' \ AND acctstoptime IS NULL"
      
      





このクエリは、ユーザーが利用できるアクティブなセッションの数を決定します。要求は数量を返し、radgroupcheckテーブルには属性Simultaneous-Use:= 1があります。つまり、一度に1人のユーザーのみが発行されたクレジットを使用できます。



もう一度、ユーザーdetpis7のアカウントデータを見てみましょう:



画像



simul_count_queryクエリは何を返しますか?推測しないで、チェックしてください:



 mysql> SELECT COUNT(*) -> FROM radacct -> WHERE username = 'detpis7' -> AND acctstoptime IS NULL; +----------+ | COUNT(*) | +----------+ | 3 | +----------+ 1 row in set (0.00 sec)
      
      





アクティブなセッションはありませんが、そのようなリクエストでは、detpis7は二度とログインできなくなります。リクエストを変更します:



vi /etc/raddb/sql/mysql/dialup.conf +300



 simul_count_query = "SELECT COUNT(*) FROM (SELECT username, MAX(radacctid), MAX(acctstoptime) as stop, MAX(acctstarttime) FROM ${acct_table1} GROUP BY acctuniqueid HAVING username = '%{SQL-User-Name}' AND stop IS NULL) list"
      
      





mysqlをチェックインします。



 mysql> SELECT COUNT(*) FROM (SELECT username, MAX(radacctid), MAX(acctstoptime) as stop, MAX(acctstarttime) FROM radacct GROUP BY acctuniqueid HAVING username = 'detpis7' AND stop IS NULL) list -> ; +----------+ | COUNT(*) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec)
      
      





そこで、基本的な課金機能を使用してホットスポットをインストールおよび構成する方法を検討しました。



All Articles