前面几节介绍了整体架构和Open***/IPtables的主要方向。本节将会增加一些干货,具体来分析Connect/Disconnect脚本以及相关的配置数据库的设计,跑通整个登录和访问权限设置的流程。
1首先,介绍一下connect/disconnect能够使用的环境变量。完整的环境变量列表可以manopen***,然后查看Environmental Variables这一段的内容。这里我挑了一些常用的和特别需要关注的。
bytes_received:接收到的字节数
bytes_sent:发送的字节数
这两个变量可以用来作为open***计费用。你可以很容易的计算一个用户的流量,唯一不方便的是,这个值只有在disconnect之后才能够获取到。
common_name:X509格式的用户名
ifconfig_pool_remote_ip:客户端获得的地址
password:用户密码
trusted_ip:客户端请求登陆时的地址
username:用户名
你需要在connect/disconnect脚本里面使用${Variable name}来调用相关的参数。
2一个简单的配置数据库的结构说明如下。
wKiom1LSJUqi9DMAAAJNI4AfPrQ288.jpg
user/user_group_names/network_group_names/port_group_names定义各种名字;user_group/network_group/port_group定义相关的组;Rules表,定义具体规则。
相关的字段的意义都比较直白。
建表脚本如下:
open***.sql
CREATE DATABASE`open***`;
USE `open***`;
CREATE TABLE `user`(
`user_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_name` varchar(255) NOT NULL,
`full_name` varchar(255) NOT NULL,
PRIMARY KEY (`user_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `user_group_names`(
`user_group_name_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_group_name` varchar(255) NOT NULL,
PRIMARY KEY (`user_group_name_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `user_group`(
`user_group_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_group_name_id` bigint(20) NOT NULL,
`user_id` bigint(20) NOT NULL,
PRIMARY KEY (`user_group_id`),
UNIQUE KEY `user_group_uq` (`user_group_name_id`,`user_id`),
FOREIGN KEY `user_group_user_id_fkey` (`user_id`) REFERENCES `user`(`user_id`),
FOREIGN KEY `user_group_user_group_name_id_fkey` (`user_group_name_id`) REFERENCES `user_group_names`(`user_group_name_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `network_group_names`(
`network_group_name_id` bigint(20) NOT NULL AUTO_INCREMENT,
`network_group_name` varchar(255) NOT NULL,
PRIMARY KEY (`network_group_name_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `network_group`(
`network_group_id` bigint(20) NOT NULL AUTO_INCREMENT,
`network_group_name_id` bigint(20) NOT NULL,
`network` varchar(15) NOT NULL,
`netmask` int NOT NULL,
PRIMARY KEY (`network_group_id`),
UNIQUE KEY `network_group_uq` (`network_group_name_id`,`network`,`netmask`),
FOREIGN KEY `network_group_network_group_name_id_fkey` (`network_group_name_id`) REFERENCES `network_group_names`(`network_group_name_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `port_group_names`(
`port_group_name_id` bigint(20) NOT NULL AUTO_INCREMENT,
`port_group_name` varchar(255) NOT NULL,
PRIMARY KEY (`port_group_name_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `port_group`(
`port_group_id` bigint(20) NOT NULL AUTO_INCREMENT,
`port_group_name_id` bigint(20) NOT NULL,
`port_type` enum('TCP','UDP','ICMP'),
`start_port` int NOT NULL,
`end_port` int NOT NULL,
PRIMARY KEY (`port_group_id`),
UNIQUE KEY `port_group_uq` (`port_group_name_id`,`port_type`,`start_port`,`end_port`),
FOREIGN KEY `port_group_network_group_name_id_fkey` (`port_group_name_id`) REFERENCES `port_group_names`(`port_group_name_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `rules` (
`rule_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_group_name_id` bigint(20) NOT NULL,
`network_group_name_id` bigint(20) NOT NULL,
`port_group_name_id` bigint(20) NOT NULL,
PRIMARY KEY (`rule_id`),
UNIQUE KEY `rule_uq` (`user_group_name_id`,`network_group_name_id`,`port_group_name_id`),
FOREIGN KEY `rule_user_group_name_fkey` (user_group_name_id) REFERENCES user_group_names(user_group_name_id),
FOREIGN KEY `rule_network_group_name_fkey` (network_group_name_id) REFERENCES network_group_names(network_group_name_id),
FOREIGN KEY `port_network_group_name_fkey` (port_group_name_id) REFERENCES port_group_names(port_group_name_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
为了能够对系统进行测试,我们插入一些测试数据。
INSERT INTO `port_group_names` VALUES
(1,'RemoteControl'),
(2,'Web');
INSERT INTO `port_group` VALUES
(1,1,'TCP',22,22),
(2,1,'TCP',3389,3389),
(3,2,'TCP',80,80),
(4,2,'TCP',443,443);
INSERT INTO `network_group_names` VALUES
(1,'AllProduct'),
(2,'WebSite');
INSERT INTO `network_group` VALUES
(1,1,'10.0.0.0',8),
(2,2,'10.1.1.0',24),
(3,2,'10.1.2.0',24);
INSERT INTO `user` VALUES
(1,'admin','Admin User'),
(2,'testuser','Test User');
INSERT INTO `user_group_names` VALUES
(1,'admin'),
(2,'user');
INSERT INTO `user_group` VALUES
(1,1,1),
(2,2,2);
INSERT INTO `rules` VALUES
(1,1,1,1),
(2,1,1,2),
(3,2,2,2);
3 系统初始化。系统启动时,IPTABLES需要先初始化相关的规则。这样当用户登录时,只需要把该用户的IP地址加入到UserGroup Chain中即可。本例仅仅使用Bash来实现这一功能,Bash对于Mysql的操作界面不是很友好,你也可以使用其它语言例如perl python或者C来实现。
#!/bin/sh
#首先需要清理自定义的所有Chain;清理Chain是有顺序要求的,引用其它Chain的Chain必须首先被清除,否则被引用的Chain无法清除;本例的顺序为清空FORWARD链->清空和删除User Group相关链->清空和删除Rule相关链->清空和删除Port相关链
echo "Clean All Chains"
iptables -F FORWARD
iptables –I FORWARD –j DROP
user_group_chains=(`iptables -L -n | grep 'Chain user_group_' | awk '{print $2}'`)
let "user_group_chain_length=${#user_group_chains[@]}"
for (( user_group_chain_idx=0 ; user_group_chain_idx<$user_group_chain_length ; user_group_chain_idx++ ))
do
user_group_chain_name=${user_group_chains[$user_group_chain_idx]}
iptables -F $user_group_chain_name
iptables -X $user_group_chain_name
done
echo ">>Clean "$user_group_chain_length" Chains"
rule_chains=(`iptables -L -n | grep 'Chain rule_' | awk '{print $2}'`)
let "rule_chain_length=${#rule_chains[@]}"
for (( rule_chain_idx=0 ; rule_chain_idx<$rule_chain_length ; rule_chain_idx++ ))
{
rule_chain_name=${rule_chains[$rule_chain_idx]}
iptables -F $rule_chain_name
iptables -X $rule_chain_name
}
echo ">>Clean "$rule_chain_length" Chains"
port_group_chains=(`iptables -L -n | grep 'Chain port_group_' | awk '{print $2}'`)
let "port_group_chain_length=${#port_group_chains[@]}"
for (( port_group_chain_idx=0 ; port_group_chain_idx<$port_group_chain_length ; port_group_chain_idx++ ))
{
port_group_chain_name=${port_group_chains[$port_group_chain_idx]}
iptables -F $port_group_chain_name
iptables -X $port_group_chain_name
}
echo ">>Clean "$rule_chain_length" Chains"
#初始化各个Port Chain
#获取Port List
echo "Init Port Chains"
port_list=(`mysql -uroot open***<<EOF
select port_group_name_id,port_type,start_port,end_port from port_group order by port_group_name_id;
EOF`);
let "port_idx_length=${#port_list[@]}/4"
for (( port_idx=1 ; port_idx<$port_idx_length ; port_idx++ ))
#mysql命令返回的第一行是列名,需要取除
do
let "port_group_name_id_idx=( $port_idx * 4 )"
let "port_type_idx=( $port_idx * 4 ) + 1"
let "start_port_idx=( $port_idx * 4 ) + 2"
let "end_port_idx=( $port_idx * 4 ) + 3"
port_group_name_id=${port_list[$port_group_name_id_idx]}
port_type=${port_list[$port_type_idx]}
start_port=${port_list[$start_port_idx]}
end_port=${port_list[$end_port_idx]}
port_group_chain_name="port_group_"$port_group_name_id
iptables -L $port_group_chain_name -n 1>/dev/null 2>/dev/null
if [ $? == 1 ]
then
#当chain不存在时,创建之,默认处理方式为DROP
echo ">>Create The Port Group Chain "$port_group_chain_name
iptables -N $port_group_chain_name
iptables -I $port_group_chain_name -j DROP
fi
#插入规则
iptables -I $port_group_chain_name -p $port_type --dport=$start_port:$end_port -j ACCEPT
done
#初始化Rule Chain
#获取Rule List
echo "Init Rule Chains"
rule_list=(`mysql -uroot open***<<EOF
select rule_id,network,netmask,port_group_name_id,user_group_name_id from rules a,network_group b where a.network_group_name_id=b.network_group_id order by user_group_name_id
EOF`);
let "rule_idx_length=${#rule_list[@]}/5"
for (( rule_idx=1 ; rule_idx<rule_idx_length ; rule_idx++ ))
#mysql命令返回的第一行是列名,需要取除
do
let "rule_id_idx=( $rule_idx * 5 )"
let "network_idx=( $rule_idx * 5 ) + 1"
let "netmask_idx=( $rule_idx * 5 ) + 2"
let "port_group_name_id_idx=( $rule_idx * 5 ) + 3"
let "user_group_name_id_idx=( $rule_idx * 5 ) + 4"
rule_id=${rule_list[$rule_id_idx]}
network=${rule_list[$network_idx]}
netmask=${rule_list[$netmask_idx]}
port_group_name_id=${rule_list[$port_group_name_id_idx]}
user_group_name_id=${rule_list[$user_group_name_id_idx]}
port_group_chain_name="port_group_"$port_group_name_id
user_group_chain_name="user_group_"$user_group_name_id
rule_chain_name="rule_"$rule_id
iptables -L $rule_chain_name -n 1>/dev/null 2>/dev/null
if [ $? == 1 ]
then
#当Rule chain不存在时,创建之,默认处理方式为DROP
echo ">>Create The Rule Chain "$rule_chain_name
iptables -N $rule_chain_name
iptables -I $rule_chain_name -j DROP
iptables -L $user_group_chain_name -n 1>/dev/null 2>/dev/null
if [ $? == 1 ]
then
#当User Group chain不存在时,创建之,默认处理方式为DROP
echo ">>Create The User Group Chain "$user_group_chain_name
iptables -N $user_group_chain_name
iptables -I $user_group_chain_name -j DROP
fi
iptables -I $user_group_chain_name -j $rule_chain_name
fi
#插入规则
echo ">>>>Insert Rule To Chain "$rule_chain_name
iptables -I $rule_chain_name -s $network/$netmask -j $port_group_chain_name
done
这时我们可以看一下IPTABLES创建的规则列表:
我们可以看到此时FORWARD Chain应该只有一条DROP的默认规则。
Chain FORWARD (policy ACCEPT)
targetprot opt sourcedestination
DROPall--0.0.0.0/00.0.0.0/0
Chain port_group_1 (1 references)
targetprot opt sourcedestination
ACCEPTtcp--0.0.0.0/00.0.0.0/0tcp dpt:3389
ACCEPTtcp--0.0.0.0/00.0.0.0/0tcp dpt:22
DROPall--0.0.0.0/00.0.0.0/0
Chain port_group_2 (2 references)
targetprot opt sourcedestination
ACCEPTtcp--0.0.0.0/00.0.0.0/0tcp dpt:443
ACCEPTtcp--0.0.0.0/00.0.0.0/0tcp dpt:80
DROPall--0.0.0.0/00.0.0.0/0
Chain rule_1 (1 references)
targetprot opt sourcedestination
port_group_1all--10.0.0.0/80.0.0.0/0
DROPall--0.0.0.0/00.0.0.0/0
Chain rule_2 (1 references)
targetprot opt sourcedestination
port_group_2all--10.0.0.0/80.0.0.0/0
DROPall--0.0.0.0/00.0.0.0/0
Chain rule_3 (1 references)
targetprot opt sourcedestination
port_group_2all--10.1.1.0/240.0.0.0/0
DROPall--0.0.0.0/00.0.0.0/0
Chain user_group_1 (0 references)
targetprot opt sourcedestination
rule_2all--0.0.0.0/00.0.0.0/0
rule_1all--0.0.0.0/00.0.0.0/0
DROPall--0.0.0.0/00.0.0.0/0
Chain user_group_2 (0 references)
targetprot opt sourcedestination
rule_3all--0.0.0.0/00.0.0.0/0
DROPall--0.0.0.0/00.0.0.0/0
4 Connect
前面介绍了IPTables初始化的工作。我们在这里假设用户已经正常通过验证,开始connect脚本了。
#!/bin/bash
username=${common_name}
tunnelip=${ifconfig_pool_remote_ip}
[ "x$username" == 'x' ] && exit 0
[ "x$tunnelip" == 'x' ] && exit 0
#首先需要清理自定义的所有该IP相关Chain
echo "Clean All Chains"
user_chains=(`iptables -L -n | grep $tunnelip | awk '{print $1" "$4}'`)
let "user_chain_length=${#user_chains[@]}/2"
for (( user_chain_idx=0 ; user_chain_idx < $user_chain_length ; user_chain_idx++ ))
do
let "chain_name_idx=user_chain_idx * 2"
let "ip_idx=( user_chain_idx * 2 ) + 1 "
chain_name=${user_chains[$chain_name_idx]}
ip=${user_chains[$ip_idx]}
iptables -D FORWARD -s $ip/32 -j $chain_name
done
#创建用户相关规则
user_groups=(`mysql -uroot open***<<EOF
select user_group_name_id from user a,user_group b where a.user_name="$username" and b.user_id=a.user_id
EOF`)
let "user_group_length=${#user_groups[@]}"
for (( user_group_idx=1 ; user_group_idx<$user_group_length ; user_group_idx++ ))
do
user_group_chain_name="user_group_"${user_groups[$user_group_idx]}
iptables -I FORWARD -s $tunnelip/32 -j $user_group_chain_name
done
假设我们以admin用户登录,Open***分配的IP地址为172.18.1.1。用户登录Open***
之后,IPTABLES的FILTER/FORWARD Chain增加如下规则:
Chain FORWARD (policy ACCEPT)
targetprot opt sourcedestination
user_group_1 all -- 172.18.1.10.0.0.0/0
DROP all -- 0.0.0.0/0 0.0.0.0/0
5 Disconnect
用户正常登出后,应该清除用户所属IP的相关规则,这实际上是connect脚本的上半段。
#!/bin/bash
username=${common_name}
tunnelip=${ifconfig_pool_remote_ip}
[ "x$username" == 'x' ] && exit 0
[ "x$tunnelip" == 'x' ] && exit 0
#清理自定义的所有该IP相关Chain
echo "Clean All Chains"
user_chains=(`iptables -L -n | grep $tunnelip | awk '{print $1" "$4}'`)
let "user_chain_length=${#user_chains[@]}/2"
for (( user_chain_idx=0 ; user_chain_idx < $user_chain_length ; user_chain_idx++ ))
do
let "chain_name_idx=user_chain_idx * 2"
let "ip_idx=( user_chain_idx * 2 ) + 1 "
chain_name=${user_chains[$chain_name_idx]}
ip=${user_chains[$ip_idx]}
iptables -D FORWARD -s $ip/32 -j $chain_name
done
前面用户登出之后,FORWARD Chain中的记录被清空:
Chain FORWARD (policy ACCEPT)
targetprot opt sourcedestination
DROP all -- 0.0.0.0/00.0.0.0/0
本节详细介绍了Connect/Disconnect动作的所有操作。你还可以在Connect和Disconnect脚本中插入流量或者计费的功能,这里我就不赘述了。所有脚本都在附件的压缩包里。
附件:http://down.51cto.com/data/2363975
©著作权归作者所有:来自51CTO博客作者xudatie的原创作品,谢绝转载,否则将追究法律责任
运维之术
共同学习,写下你的评论
评论加载中...
作者其他优质文章