上一集最後有談到,在建立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/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 紐菲斯的部落格