VPN技术通过密钥交换、封装、认证、加密手段在公共网络上建立起私密的隧道,保障传输数据的完整性、私密性和有效性。OpenVPN是近年来新出现的开放源码项目,实现了SSL VPN的一种解决方案。 传统SSL VPN通过端口代理的方法实现,代理服务器根据应用协议的类型(如http,telnet等)做相应的端口代理,客户端与代理服务器之间建立SSL安全连接,客户端与应用服务器之间的所有数据传输通过代理服务器转发。这种实现方式烦琐,应用范围也比较窄:仅适用于用TCP固定端口进行通信的应用系统,且对每个需要代理的端口进行单独配置;对于每个需要用到动态端口的协议都必须重新开发,且在代理中解析应用协议才能实现代理,如FTP协议;不能对TCP以外的其它网络通信协议进行代理;代理服务器前端的防火墙也要根据代理端口的配置变化进行相应调整。 OpenVPN以一种全新的方式实现了SSL VPN的功能,克服了传统SSL VPN的一些缺陷,扩展了应用领域,并且防火墙上只需开放TCP或UDP协议的一个端口。
有一些类似这样的情形或需求: 隐藏自己的真实IP去访问某个网站 在家里想进入公司网站的管理界面,但管理系统限制了仅允许来自公司IP可以访问想连接到某个特别网站的特别网络应用,但本地的ISP或路由节点不允许您去连接它本地的ISP或路由节点可能会监听您的数据而您不想被它拦截,想找一种可以跳过它的办法,您想访问的网站和应用是基于明文传输,但您希望这个线路是私密的和可靠的, 这时候就需要用到VPN来实现
它可以“跳”过部分路由节点直接和服务器建立虚拟局域网 它可以让传输的数据基于一个SSL加密的通道 为什么是 OpenVPN (这个软件)是开源的,这一点很重要,是基于SSL的连接和传输,配置简单且灵活
一台位于目标网络的独立主机或VPS。由于需要修改防火墙以实现包转发,所以还得有root权限。这台主机将作为Server端。 这台主机最好是基于Linux或BSD系统, 如果您能搞定其他系统的安装和配置当然也没问题。 作为Client端, 可以是Windows、 Linux、 BSD等 (MacOSX当然也行的)。 所有平台的openvpn配置文件和证书都是通用的
VPN 不会直接提高数据传输率(速度),由于是加密传输数据,甚至会减速(一点点而已啦)。 VPN建立了一 个和服务器的局域网,相当于长连接,这减去了其他网络应用路由时间,有时会让人感觉网络更快了。 如果和VPN服务器有一个相对较好的网络连 接线路,相较于之前的不同且糟糕的路由线路,它确实是会提高数据传输速度。
在Linux2.4版本以上,操作系统支持一个名为tun的设备,tun设备的驱动程序中包含两个部分,一部分是字符设备驱动,一部分是网卡驱动。网卡的驱动把从TCP/IP协议栈收到的数据包结构skb放于tun设备的读取队列,用户进程通过调用字符设备接口read获得完整的IP数据包,字符驱动read函数的功能是从设备的读取队列读取数据,将核心态的skb传递给用户;反过来字符驱动write函数给用户提供了把用户态的数据写入核心态的接口,write函数把用户数据写入核心空间并穿入TCP/IP协议栈。该设备既能以字符设备的方式被读写,作为系统的虚拟网卡,也具有和物理网卡相同的特点:能够配置IP地址和路由。对虚拟网卡的使用是OpenVPN实现其SSL VPN功能的关键。
OpenVPN服务器一般需要配置一个虚拟IP地址池和一个自用的静态虚拟IP地址(静态地址和地址池必须在同一个子网中),然后为每一个成功建立SSL连接的客户端动态分配一个虚拟IP地址池中未分配的地址。这样,物理网络中的客户端和OpenVPN服务器就连接成一个虚拟网络上的星型结构局域网,OpenVPN服务器成为每个客户端在虚拟网络上的网关。OpenVPN服务器同时提供对客户端虚拟网卡的路由管理。当客户端对OpenVPN服务器后端的应用服务器的任何访问时,数据包都会经过路由流经虚拟网卡,OpenVPN程序在虚拟网卡上截获数据IP报文,然后使用SSL协议将这些IP报文封装起来,再经过物理网卡发送出去。OpenVPN的服务器和客户端在虚拟网卡之上建立起一个虚拟的局域网络,这个虚拟的局域网对系统的用户来说是透明的。
OpenVPN的服务器和客户端支持tcp和udp两种连接方式,只需在服务端和客户端预先定义好使用的连接方式(tcp或udp)和端口号,客户端和服务端在这个连接的基础上进行SSL握手。连接过程包括SSL的握手以及虚拟网络上的管理信息,OpenVPN将虚拟网上的网段、地址、路由发送给客户端。连接成功后,客户端和服务端建立起SSL安全连接,客户端和服务端的数据都流入虚拟网卡做SSL的处理,再在tcp或udp的连接上从物理网卡发送出去。
发送数据流程
应用层的外出数据,经过系统调用接口传入核心TCP/IP层做处理,在TCP/IP经过路由到虚拟网卡,虚拟网卡的网卡驱动发送处理程序hard_start_xmit()将数据包加入skb表并完成数据包从核心区到用户区的复制,OpenVPN调用虚拟网卡的字符处理程序tun_read(),读取到设备上的数据包,对读取的数据包使用SSL协议做封装处理后,通过socket系统调用发送出去。
接受数据流程
物理网卡接收数据包,经过核心TCP/IP上传到OpenVPN,OpenVPN通过link_socket_read()接收数据包,使用SSL协议进行解包处理,经过处理的数据包OpenVPN调用虚拟网卡的字符处理程序tun_write()写入虚拟网卡的字符设备,设备驱动程序完成数据从用户区到核心区的复制,并将数据写入skb链表,然后调用网卡netif_rx()接收程序,数据包再次进入系统TCP/IP协议栈,传到上层应用程序。如图1所示。
数据包的封装
OpenVPN提供tun和tap两种工作模式。在tun模式下,从虚拟网卡上收到的是不含物理帧头IP数据包,SSL处理模块对IP包进行SSL封装;在tap模式下,从虚拟网卡上收到的是包含物理帧头的数据包,SSL处理模块对整个物理帧进行SSL封装。Tap模式称为网桥模式,整个虚拟的网络就像网桥方式连接的物理网络。这种模式可以传输以太网帧、IPX、NETBIOS等数据包,应用范围更广。
OpenVPN与Openssl
OpenVPN软件包需要和openssl软件一起安装,因为OpenVPN调用了Openssl函数库,OpenVPN的客户端和服务端建立SSL链接的过程是通过调用Openssl来实现的。通过bio_write()/函数把数据写入Openssl的状态机通道,bio_read()从Openssl读取结果。OpenVPN还调用Openssl的加解密函数处理转发的数据包。
小结
OpenVPN是一款基于SSL的开源VPN软件,它实现了利用SSL来保证网络通讯安全性的目的,同时避免了传统SSL VPN仅提供简单的Web应用的不足,它具有支持各种应用协议,支持Windows,Linux,BSD,MAC OS等多平台的特点。在上面的应用系统中,通过对OpenVPN的灵活部署,实现了五种访问形式。其中部门内用户点到点通信、用户跨部门访问应用服务器、用户跨部门点到点通信、数据包在客户端到SSL VPN服务器以及SSL VPN服务器间接力传送;跨部门的应用服务器数据通信时,SSL VPN服务器要做内网数据向外网转发的反向代理,而这些应用需求在传统SSL代理服务器中是比较难实现的。
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -ivh epel-release-latest-7.noarch.rpm
yum clean all
yum makecache
# 安装依赖软件包
yum install -y lzo lzo-devel openssl openssl-devel pam pam-devel
yum install -y pkcs11-helper pkcs11-helper-devel rpm-build
# 下载OpenVPN源码包
wget http://oss.aliyuncs.com/aliyunecs/openvpn-2.2.2.tar.gz
# 使用rpmbuild将源码包编译成rpm包来进行安装
rpmbuild -tb openvpn-2.2.2.tar.gz
# 编译完成就会发现以下这个目录会生成一个openvpn的rpm包
ls /root/rpmbuild/RPMS/x86_64/
openvpn-2.2.2-1.x86_64.rpm
# 以rpm方式安装openvpn
rpm -ivh openvpn-2.2.2-1.x86_64.rpm
# 初始化PKI
cd /usr/share/doc/openvpn-2.2.2/easy-rsa/
# 在这个目录下找到vars证书环境文件,修改以下几行export定义的参数值
cd /usr/share/doc/openvpn-2.2.2/easy-rsa/2.0
vim vars
export KEY_COUNTRY="CN" # 国家
export KEY_PROVINCE="BJ" # 省
export KEY_CITY="BEIJING" # 城市
export KEY_ORG="youmen" # 组织
export KEY_EMAIL="18621048481@163.com" # 邮箱
# 生成服务端的证书
ln -s openssl-1.0.0.cnf openssl.cnf
ll openssl*
-rwxr-xr-x 1 root root 7768 Oct 21 2010 openssl-0.9.6.cnf
-rwxr-xr-x 1 root root 8325 Nov 25 2011 openssl-0.9.8.cnf
-rwxr-xr-x 1 root root 8222 Nov 25 2011 openssl-1.0.0.cnf
lrwxrwxrwx 1 root root 17 Jun 16 23:00 openssl.cnf -> openssl-1.0.0.cnf
source ./vars
./clean-all
# 生成CA证书,上面已经在vars文件配置了默认参数值,多次回车完成就可以
./build-ca
Generating a 1024 bit RSA private key
...........................++++++
...............++++++
writing new private key to 'ca.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [CN]:
State or Province Name (full name) [BJ]:
Locality Name (eg, city) [BEIJING]:
Organization Name (eg, company) [youmen]:
Organizational Unit Name (eg, section) [changeme]:
Common Name (eg, your name or your server's hostname) [changeme]:
Name [changeme]:
Email Address [mail@host.domain]:
# 生成服务器证书
# 如下huanqiuvpn是自定义的名字,一直回车,到最后会有两次交互,
# 输入y确认,完成后会在keys目录下保存了huanqiuvpn.key、huanqiuvpn.csr和huanqiuvpn.crt 三个文件。
./build-key-server youmenvpn
Generating a 1024 bit RSA private key
.............................++++++
...................................++++++
writing new private key to 'youmenvpn.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [CN]:
State or Province Name (full name) [BJ]:
Locality Name (eg, city) [BEIJING]:
Organization Name (eg, company) [youmen]:
Organizational Unit Name (eg, section) [changeme]:
Common Name (eg, your name or your server's hostname) [youmenvpn]:
Name [changeme]:
Email Address [mail@host.domain]:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /usr/share/doc/openvpn-2.2.2/easy-rsa/2.0/openssl-1.0.0.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'CN'
stateOrProvinceName :PRINTABLE:'BJ'
localityName :PRINTABLE:'BEIJING'
organizationName :PRINTABLE:'youmen'
organizationalUnitName:PRINTABLE:'changeme'
commonName :PRINTABLE:'youmenvpn'
name :PRINTABLE:'changeme'
emailAddress :IA5STRING:'mail@host.domain'
Certificate is to be certified until Jun 14 15:11:46 2030 GMT (3650 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
ls keys/
01.pem index.txt serial youmenvpn.csr
ca.crt index.txt.attr serial.old youmenvpn.key
ca.key index.txt.old youmenvpn.crt
# 如果创建用户证书时报错,可以将keys整个目录删除,然后从source ./vars这一步开始重新操作(慎重,否则之前在keys目录里的用户数据就会都删除)
# 生成Diffie Hellman参数
./build-dh
# 执行了./build-dh后,会在 keys 目录下生成 dh 参数文件 dh1024.pem。该文件客户端验证的时候会用到
ls keys/dh1024.pem
keys/dh1024.pem
cp -r /usr/share/doc/openvpn-2.2.2/easy-rsa/2.0/keys/* /etc/openvpn/
cp -a /usr/share/doc/openvpn-2.2.2/sample-config-files/server.conf /etc/openvpn/
# 配置server.conf
egrep -v "^$|^#|^;" /etc/openvpn/server.conf
local 192.168.0.100
# 监听地址(内网或外网地址),最好填写openvpn服务器的公网IP地址(使用"curl ifconfig.me"命令查看)。
# 或者这一行直接注释掉!(我在线上配置的就是注释这行)
port 1194
proto udp
dev tun
ca ca.crt
cert youmenvpn.crt # 此处crt以及下一行的key,请填写生成服务器端证书时用户自定义的名称
key youmenvpn.key # This file should be kept secret
dh dh1024.pem
server 10.8.0.0 255.255.255.0 # 给vpn客户机分配的地址池。最好别和openvpn部署机的内网ip在一个网段内
ifconfig-pool-persist ipp.txt
push "route 10.0.0.0 255.0.0.0"
client-to-client
keepalive 10 120
comp-lzo
user nobody
group nobody
persist-key
persist-tun
status openvpn-status.log
log openvpn.log
verb 3
# 设置iptables
# 先设置转发
vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
sysctl -p # 使内核生效
yum install iptables-services iptables -y
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -j MASQUERADE
service iptables save
iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 10.8.0.0/24 anywhere
/etc/init.d/openvpn start
lsof -i:1194
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
openvpn 5390 nobody 5u IPv4 22897 0t0 UDP prometheus:openvpn
# 如果1194端口启动不起来,可以通过查看/etc/openvpn/openvpn.log日志进行原因排查
# 国内公有云好像不让绑定IP
# 后续给同事开vpn账号,只需要下面几步(比如给youmen同事开vpn)
./build-key youmen
cp -a /usr/share/doc/openvpn-2.2.2/easy-rsa/2.0/keys/youmen.* /etc/openvpn/
/etc/init.d/openvpn restart
lsof -i:1194
# 然后编写youmen用户的config.ovpn客户端配置文件:
cat /tmp/config.ovpn
client
dev tun
proto udp
remote 192.168.0.100 1194
resolv-retry infinite
nobind
mute-replay-warnings
ca ca.crt
cert youmen.crt
key youmen.key
comp-lzo
mkdir /tmp/youmen
cd keys/
cp ca.crt /tmp/config.ovpn youmen.crt youmen.csr youmen.key /tmp/youmen/
# 到时候将这些文件拷贝给同事即可,让他在客户端配置openvpn连接
cd /tmp && tar -zvcf youmen.tar.gz youmen
sz youmen.tar.gz
# 1.向管理员申请配置及秘钥文件(即那5个文件:ca.crt、config.ovpn、user.crt、user.csr、user.key。将这5个文件打包成user.tar.gz,然后传给user用户).
# 2.安装文末的程序
# 3.删除管理员给你文档中的.csr结尾的文件
# 4.给上层文件夹加上.tblk,然后双击载入,添加到VPN的配置里面
# 5.在菜单栏,左键点击图标选择连接,连接成功就是以下状态.
# 我们连接vpn后,查看本机分配的vpn地址,可以看到已经成功分配到vpn地址范围内地址了