上一集最後有談到,在建立VPN 連線時,可以再加入帳號密碼的認證,同時可以做一些Log 及特別的管制。

例如:記錄對方什麼時間點登入,由那個IP登入進來,使用了多少流量,同時可以限制User 幾點可以登入,User可以使用的流量等等...

這一集主要來跟大家分享這些功能要如何實現。


OpenVPN
OpenVPN: Building and Integrating Virtual Private Networks

前情提要:OpenVPN 建置筆記(第7集)

小瑞使用了,部份的shell script + PHP + MySql 來實作這些功能。

首先是在 server.conf 增加一些設定。

[root@vpnserver1 ~]# vi /etc/openvpn/server.conf
在最後加入

tmp-dir /etc/openvpn/temp

auth-user-pass-verify /etc/openvpn/auth_sh.sh via-file

client-connect /etc/openvpn/client_connect.php

client-disconnect /etc/openvpn/client_disconnect.php

1. 建立一個 temp 目錄,如果不指定,會直接使用到/tmp 目錄。
2. 指定 auth-user-pass-verify 要認證的指令碼,及使用何種帳密傳遞的方式。
3. 指定 client-connect 連線後要執行的指令碼。
4. 指定 client-disconnect 斷線後要執行的指令碼。

在使用者登入時,系統會記錄一個環境變數,叫做common_name,記錄使用者登入的帳號,基本上就是使用這個User所分配憑證上的common name。
如果你完全不想用使用者憑證,只想使用自建的帳號密碼管理,那就在server.conf 中再加入:

client-cert-not-required
username-as-common-name

加入後,在後面的指令碼,取得common_name 時,就會變成使用者輸入的帳號。至於要用什麼方式,看各位朋友想怎麼控制?小瑞還是使用憑證上的common name,進行後續的控制,同時管控,一個憑證只可以登入一次。在登入中,其它有同樣憑證的人,就不可以重複登入。

小瑞寫了幾支控制的程式如下,請參考:

認證的shell script

[root@vpnserver1 ~]# vi /etc/openvpn/auth_sh.sh

#!/bin/bash

for stat in `php /etc/openvpn/auth_sql.php $1`
do
if [ "$stat" = "1" ]; then
echo "fall"
exit 1
else
echo "ok"
exit 0
fi
done

認證的php程式

[root@vpnserver1 ~]# vi /etc/openvpn/auth_sql.php

#! /usr/bin/php
《?PHP
include 'connect.php';
$i_filename = $argv[1];
$i_fp = fopen($i_filename,'r');
$i_username = chop(fgets($i_fp,4096));
$i_passwd = chop(fgets($i_fp,4096));
fclose ($i_fp);

// get user info
$v_sql = "select userId,userPwd,timelimit,startTime,endTime from users where effective='Y' and userAcc='".$i_username."' and currentLogId is NULL";
$v_res = mysql_query($v_sql);

// 沒有這個帳號
if (mysql_num_rows($v_res)==0)
{
echo '1';
exit;
}

// get user info
list($userId,$userPwd,$timelimit,$startTime,$endTime)=mysql_fetch_row($v_res);

// check passwd 密碼錯誤
if ($userPwd != $i_passwd)
{
echo '2';
exit;
}

// check time limit 不在允許的時間內登入
if ($timelimit == 'Y') {
if (($startTime>date('H')) or ($endTime 《 date('H'))) {
echo '3';
exit;
}
}
// check pass 過關了
echo '0';

連線後要執行指令碼-php程式

[root@vpnserver1 ~]# vi /etc/openvpn/client_connect.php

#! /usr/bin/php
《?PHP
//資料庫連接
include 'connect.php';

// get user common name 前面有提到的環境變數
$i_common_name = getenv(common_name);
$i_trusted_ip = getenv(trusted_ip);

// get userId
$v_sql = "select userId from users where userAcc='".$i_common_name."'";
$v_res = mysql_query($v_sql);
list($userId)=mysql_fetch_row($v_res);

// insert into logs 寫入記錄檔
$v_sql = "insert into logs (userId,loginTime,loginIp) values('".$userId."',now(),'".$i_trusted_ip."')";
$v_res = mysql_query($v_sql);

// get logId
$logId = mysql_insert_id();

// update users info 把目前的log id 更新回user 主檔
// 如果有別的電腦使用同一個帳號登入,這個 log id 帳不是空的null ,
// 認證程式就會認證失敗,可實現一個帳號只可以同時上線1次,除非登出,
// 才可以在別台電腦上登入
$v_sql = "update users set currentLogId='".$logId."' where userId='".$userId."'";
$v_res = mysql_query($v_sql);

// pass 0 to end

echo '0';

?》

斷線後要執行指令碼-php程式

[root@vpnserver1 ~]# vi /etc/openvpn/client_disconnect.php

#! /usr/bin/php
《?PHP
//資料庫連接
include 'connect.php';

// get user common name 前面有提到的環境變數
$i_common_name = getenv(common_name);
// user 的傳輸資料量
$i_bytes_received = getenv(bytes_received);
$i_bytes_sent = getenv(bytes_sent);

// get userId
$v_sql = "select userId,currentLogId from users where userAcc='".$i_common_name."'";
$v_res = mysql_query($v_sql);
list($userId,$currentLogId)=mysql_fetch_row($v_res);

// update logs 更新記錄檔
$v_sql = "update logs set logoutTime=now(), bytes_received='".$i_bytes_received."', bytes_sent='".$i_bytes_sent."' where logId = '".$currentLogId."'";
$v_res = mysql_query($v_sql);

// update users info 把log id 清空,以便下次user 可以通過認證,登入系統
$v_sql = "update users set currentLogId = NULL where userAcc='".$i_common_name."'";
$v_res = mysql_query($v_sql);

// pass 0 to end

echo '0';

?》

資料庫連接程式-php程式

[root@vpnserver1 ~]# vi /etc/openvpn/connect.php

《?PHP
$hostname = 'localhost';
$dbname = 'vpn';
$username = 'vpn';
$passwd = 'vpn999';

if (!($link=mysql_connect($hostname , $username ,$passwd ))) {
printf("內部錯誤%d:%s\n",mysql_errno(),mysql_error());

exit();

}

if (!mysql_select_db($dbname,$link)) {

printf("選擇%s資料庫錯誤",$dbname);

printf("內部錯誤%d:%s\n",mysql_errno(),mysql_error());

exit();

}

?》

將這些控制的程式,設定為可執行檔。

[root@vpnserver1 ~]# chmod +x /etc/openvpn/*.php
[root@vpnserver1 ~]# chmod +x /etc/openvpn/*.sh

控制的程式,只有這些,各位可以按自己的狀況做調整。 接著進入mysql 資料庫,建立相關的DB登入資料,及VPN控制的Table 及使用者資料。

資料庫啟動(如果沒有啟動的話)

[root@vpnserver1 ~]# service mysqld start

資料庫安全設定(如果之前沒有設定過的話)

[root@vpnserver1 ~]# /usr/bin/mysql_secure_installation

登入mysql(也可以使用phpMyAdmin,看個人習慣)

[root@vpnserver1 ~]# mysql -u root -p

建立VPN資料庫


mysql> CREATE DATABASE `vpn` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

建立VPN資料庫-使用者


mysql> CREATE USER 'vpn'@'localhost' IDENTIFIED BY 'vpn999'; (密碼自己更改)

開放vpn使用者可以使用VPN資料庫權限

mysql> GRANT USAGE ON *.* TO 'vpn'@'localhost' IDENTIFIED BY 'vpn999' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;

mysql> GRANT ALL PRIVILEGES ON `vpn` . * TO 'vpn'@'localhost' WITH GRANT OPTION ;

選擇使用VPN資料庫

mysql> use vpn ;

建立VPN User 表格

mysql> CREATE TABLE `users` (
`userId` int(11) NOT NULL auto_increment,
`userAcc` varchar(20) collate utf8_unicode_ci NOT NULL,
`userPwd` varchar(255) collate utf8_unicode_ci NOT NULL,
`userName` varchar(255) collate utf8_unicode_ci default NULL,
`userEmail` varchar(255) collate utf8_unicode_ci default NULL,
`desc` varchar(255) collate utf8_unicode_ci default NULL,
`effective` enum('Y','N') collate utf8_unicode_ci NOT NULL default 'Y',
`timelimit` enum('Y','N') collate utf8_unicode_ci NOT NULL default 'N',
`startTime` int(11) default '8',
`endTime` int(11) default '19',
`adminAcc` enum('Y','N') collate utf8_unicode_ci NOT NULL default 'N',
`currentLogId` int(11) default NULL,
PRIMARY KEY (`userId`),
UNIQUE KEY `userAcc` (`userAcc`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

程式碼有點亂,看一下貼圖,比較清楚。

openvpn 帳號認證 使用者 table

建立使用者登入記錄檔表格

mysql> CREATE TABLE `logs` (
`logId` int(11) NOT NULL auto_increment,
`userId` int(11) NOT NULL,
`loginTime` datetime default NULL,
`logoutTime` datetime default NULL,
`loginIp` varchar(255) collate utf8_unicode_ci default NULL,
`bytes_received` int(11) default NULL,
`bytes_sent` int(11) default NULL,
PRIMARY KEY (`logId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

程式碼有點亂,看一下貼圖,比較清楚。

openvpn 帳號認證 記錄檔 table

新增使用者帳號及密碼

mysql> INSERT INTO `vpn`.`users` (`userId`, `userAcc`, `userPwd`, `userName`, `userEmail`, `desc`, `effective`, `timelimit`, `startTime`, `endTime`, `adminAcc`, `currentLogId`) VALUES (NULL, 'client1', 'client999', 'Rico', 'rico@nuface.tw', 'Test Account', 'Y', 'Y', '8', '19', 'N', NULL);

程式碼有點亂,看一下貼圖,比較清楚。

openvpn 帳號認證 帳號資料

到這裏,server 端的工作就己經完成了,接著修改 user 端的設定檔。
打開client1.opvn (視各位自己的狀況),在最後加入 :

auth-user-pass

Open VPN 認證 client 設定

到這個步驟,使用者就必須在登入時輸入帳號跟密碼了。

Open VPN 帳號認證

之後所有的登入資料,都會記錄在資料庫中。管理者可以知道User 什麼時候登入系統;什麼時候登出系統;傳輸了多少流量;由那個IP登入進來;都可以在資料庫中,看的一目了然了。至於更進階的控制,小瑞就不再獻醜,由各位同好自行發揮囉!以上希望對大家有幫助。

openvpn 帳號認證 記錄資料

還有什麼還沒有寫的呢?其實做到這裏,包袱己經抖的差不多了,再抖的話,內衣內褲都快掉出來啦....會讓大家見笑的^_^

不過在VPN的應用上,真的還有終極的一招,也是小瑞OpenVPN剩下的最後一招。就是 site to site 的VPN建置,等下次有時間,再把這最後一招貼出來,跟大家分享,我的OpenVPN也就算是功德圓滿了。

site to site open vpn….待續!

OpenVPN 建置筆記(第9集)

日期:2012/09/14 | 留言:16 個 | 作者:Rico | 瀏覽:
分類:MIS易筋經,網路篇
標籤:, , ,
  1. 2012/12/24 at 22:57:29 | 1

    請問怎樣登入到mysql的網頁?
    還有如果參照上面的指令 帳號 密碼是多少?
    謝謝您的回答

  2. 2012/12/25 at 11:27:56 | 2
    Rico

    看你在開立 vpn 資料庫是, 的帳號密碼為何, 可以自己設定, 在範例文章中, 使用的帳號是VPN , 密碼是 vpn999 至於登入資料庫, 我都是用phpMyAdmin , 直接登入資料庫管理的頁面, 就可以查看, 使用者登入的狀況了!

  3. 2013/05/01 at 14:12:48 | 3
    David Lin

    大大你好,看完了你的介紹,受益良多,想請教一個關於SITE 2 SITE VPN問題
    目前MOBILE01上面有一篇文章到使用多台 [TOMATO ROUTER] 架設SITE 2 SITE VPN,他們使用憑證的方式來建置,已經可達到多client/Server的實現,但大多是選用TAP模式來連接。想請問如果用TUN方式連接。

    問題一 先決條件 是否就一定得先把每一SITE的subnet 錯開
    否則會架設不起來 ex : 兩ROUTER皆使用192.168.1.x網段,是否就絕對的,無法建構起來site2site VPN

    問題二 如果錯開了以後,那建構起來的VPN可以公同享有彼此的資源麼 ? ex : 區網遊戲,NAS存取,印表機分享,網方存取

    問題三 如果要滿足問題二,是否一定得建置WINS server
    WINS Server 可否建置在Tomato Router上面 ,避免End User的困擾。

  4. 2013/05/02 at 08:38:15 | 4
    Rico

    如果建置 site to site VPN , 使用TAP/TUN 我覺得已經沒有差異了! 只要兩台router 可以連接, 在User 端都沒有感覺了!針對第1個問題, 要不要把兩個區域的subnet 錯開呢?我的建議是錯開, 在管理上會比較好.如果不錯開,在router 端,就要做NAT, 否則在routing 上會無法連通,因為2個區的網段一樣,封包真的不知要怎麼送!

    問題二,錯開後,可以分享彼此的資源,因為你列的那些服務,都是走TCP/IP 的, 所以沒有問題

    問題三, 我沒有 wins server , 就都可以通了, 不過我是用openvpn 架的, 我不是很確定, TOMATO ROUTER 的架法是不是也ok, 如果你是這TOMATO ROUTER 的架法…你可能要再測試看看!

    以上參考囉^^

  5. 2017/05/05 at 16:56:46 | 5
    Darren

    connect.php
    這個程式的內容要空白嗎??
    其他PHP不用include他來連線MYSQL嗎?

  6. 2017/05/05 at 17:24:43 | 6
    Darren

    測試後可以! 感謝
    但是用戶資料表裡面的startTime, endTime 有功能嗎?限制他們使用時間?

  7. 2017/05/05 at 17:32:31 | 7
    Darren

    logs裡面沒有紀錄?是不是可以給完整的php?

  8. 2017/05/05 at 18:26:22 | 8
    Darren

    如果有套用client-cert-not-required
    username-as-common-name
    那可以過濾同時只能單一帳號登入嗎?

  9. 2017/05/05 at 18:53:58 | 9
    Darren

    任何帳號亂輸入都可以進去

  10. 2017/05/19 at 11:19:14 | 10
    Rico

    抱歉,程式碼好像因為blog 的系統, 無法顯示出來, 我把部份字元改為全型字,應該可正常顯示,在COPY 程式用去應用時,要注意一下。

  11. 2017/05/19 at 11:19:43 | 11
    Rico

    程式中有可以限制時間的功能,可以自行再發揮一下。

  12. 2017/05/19 at 11:20:03 | 12
    Rico

    己更新原交章,請參考。

  13. 2017/05/19 at 11:21:11 | 13
    Rico

    可以在PHP 認證時,先確認一下資料庫中的狀況, 如果己有登入,就不要通過認邆,這樣可以做到單一帳號登入。

  14. 2017/05/19 at 11:21:51 | 14
    Rico

    請按之前的回覆,再測試看看。

  1. |
    2012/09/14 at 14:24:24 | 1

    […] OpenVPN 建置筆記(第8集) window.___gcfg = {lang: 'zh-TW'}; (function() { var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; po.src = 'https://apis.google.com/js/plusone.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); })(); 日期:2010/06/07 | 留言:3 個 | 作者:Rico | 瀏覽: 分類:MIS易筋經,網路篇 標籤:CentOS 5.4, Open VPN, OpenVPN 留言 (2) 引用 (1) […]

  2. |
    2017/06/06 at 18:42:01 | 2

    […] 前情提要:OpenVPN 建置筆記(第8集) […]

*

Copyright -0001 紐菲斯的部落格