基于OpenVPN与Socks5代理的企业VPN的设计与实现

  因为部门的需要,需要整个部门的网络能够访问google等被墙的网站,恰逢部门上网一直走的笔者写的代理程序,自然想到在代理端挂上vpn,然后通过一些规则实现over the wall,因为过程比较复杂,所以开文记录整个搭建过程,公司有需要的童鞋可以参考。

注:笔者介绍的大部分内容都只是适用于Linux平台下的操作,笔者使用了代理端和存根端,读者只需要将代理端和存根端合并成一个代理端看待即可。

Over the wall

  目前主流的翻墙的方法主要有以下两种:

  • VPN(目前存在PPTP/L2TP/OpenVPN/IPSec等协议,这里强烈推荐只使用OpenVPN方式)
  • ShadowSocks
      以上两者也都可以自己租用vps服务器自己搭建服务器端,也可以直接像账号提供商租用。笔者这里选择了DouJia提供的香港10M专线线路,虽然提供的美国专线是100M,但是那速度测试过十分慢。当然如果大家有速度和可靠性更好的提供商选择,可以选择自己觉得更好的。

系统整体结构

  系统的整体结构如下图所示:
architecture
  其中Proxy代表代理端,也就是客户端需要直接通信的对象;Stub代表存根端,也就是直接与我们的Internet/VPN以及外部资源直接通信的对象。因为该结构为目前部门代理上网的结构,读者只需要将两者合并到一起(即Stub合并到Proxy,Proxy本身就可以直接与外界通信)。
  proxy,代理程序(这里用的是自己实现的socks5协议的服务器);dns2socks,将dns查询转换成socks5协议的程序(因为这里Proxy端并不能直接与外网通信,需要转发到Stub端)。
  stub,存根程序(主要是实现proxy程序的实际操作);dnsmasq,一个小巧的DNS/DHCP服务器工具;eth0,与Internet互联的物理以太网接口(机器不一样,名字也可能不一样);ppp0,与VPN互联的虚拟以太网卡接口(VPN走的协议不一样,名字也可能不一样,比如OpenVPN这里的名字可能是tun0)。   

保障未被墙网站访问速度的方案

  目前可行的代理方案如下:

  • 单代理,通过路由表去判断走电信网还是走VPN
  • 双代理,一条代理走电信网,一条代理走VPN,不用修改路由表,通过在客户端做PAC规则。

  笔者这里选择的是双代理方案,在客户端通过pac文件做规则过滤(比如:baidu.com -> SOCKS 192.168.6.2:1080, google.com -> SOCKS 192.168.6.2:2080)。

Linux network namepace

  由于要创建两条代理链路,一条用于电信,一条用于VPN,以防止当VPN崩掉访问国外网站也不能访问(因为不会修改路由表),也就是要实现能指定程序走某个网卡出去,superuser上提供了两种方法,第一种就是在客户端程序connect之前调用bind绑定某个地址,第二种就是我们要介绍的network namespace:

Generally speaking, an installation of Linux shares a single set of network interfaces and routing table entries. You can modify the routing table entries using policy routing (here’s an introduction I wrote and here’s a write-up on a potential use case for policy routing), but that doesn’t fundamentally change the fact that the set of network interfaces and routing tables/entries are shared across the entire OS. Network namespaces change that fundamental assumption. With network namespaces, you can have different and separate instances of network interfaces and routing tables that operate independent of each other.

  简单点说就是Linux提供了一种虚拟化的机制,可以共享一些东西(比如:文件系统中的文件等),可以独享一些东西(比如:端口、路由表等)。

配置步骤

  整个过程主要是配置一些网络相关的东西,比如:路由、ip等,具体的配置命令及解释如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 启动OpenVPN,配置文件为第三方VPN服务商提供
openvpn --config your-vpn-config-file.ovpn
# 添加一个新的network namespace名字为netns1
ip netns add netns1
# 添加一对虚拟以太网卡veth1与veth2,并且veth1与veth2相当于通过管道相连
ip link add veth1 type veth peer name veth2
# 将veth1加入到netns1 network namespace
ip link set dev veth1 netns netns1
# 创建一个网桥名字为br1
brctl addbr br1
# 清除掉本地网卡所拥有的ip地址(因为加入到网桥之后,网卡就变成了网桥的接口,拥有ip是无无意义的)
ifconfig em1 0.0.0.0
# 为网桥添加网卡设备
brctl addif em1
brctl addif veth2
# 设置对应网桥的ip为本地网卡的ip地址
ifconfig br1 192.168.2.200/24 up
# 启动veth2网卡
ifconfig veth2 up
# 设置netns1中的veth1网卡并启动
ip netns exec netns1 ifconfig veth1 192.168.2.202/24 up
ip netns exec netns1 ifconfig lo up
# 添加网桥相关的路由
route add default gw 192.168.2.254 dev br1
# 添加netns1的路由
ip netns exec netns1 route add default gw 192.168.2.254 dev veth1
# 要保证非墙的网站的DNS解析也要走电信的网出去,所以这里需要指定一条静态路由
ip netns exec netns1 route add -host 114.114.114.114 gw 192.168.2.254 dev veth1
vim /etc/resolv.conf
# 修改内容为 192.168.2.200
# 这里要记住要设置为物理网卡(网桥)的ip,而不是环回接口的地址
vim /etc/dnsmasq.conf
#反注释no-resolv no-poll
#添加server=114.114.114.114
#反注释最后一行conf-dir=/etc/dnsmasq.d
# 拷贝根据gfwlist生成的dnsmasq的conf文件,里面主要格式为server=/被墙的域名/DNS服务器ip地址
cp dfsx.conf /etc/dnsmasq.d
# 最后启动dnsmasq、以及自己的代理程序即可

相关工具下载链接

  1. gfwlist2dnsmasq,Just another script to auto-generate dnsmasq ipset rules using gfwlist  

参考链接

  1. Introducing Linux Network Namespaces,Scott’s,2013-09-04

  2. 使用国外 DNS 造成国内网站访问慢的解决方法,wzyboy,2012-09-06

  3. How to use different network interfaces for different processes?,Andrea Spadaccini,2016-02-03

2016-11-29 于 成都

文章目录
  1. 1. Over the wall
  2. 2. 系统整体结构
  3. 3. 保障未被墙网站访问速度的方案
  4. 4. Linux network namepace
  5. 5. 配置步骤
  6. 6. 相关工具下载链接
  7. 7. 参考链接