桥接多进程OpenVPN虚拟网卡解决多处理问题

来源:互联网 发布:考勤机采集数据超时 编辑:程序博客网 时间:2024/05/21 17:22
既然有了一个OpenVPN的前端控制程序,那么就可以在一台机器上启动多个OpenVPN实例了,不同的客户端只要连接不同的实例就好。事实证明,这种方式可以完美利用多处理器的优势,比在OpenVPN内部实现的多进程或者多线程等多处理方式要好很多,这也是广义的KISS原则,也遵循了“每次做好一件事”的原则。
        现在的关键问题是如何将这多个OpenVPN实例集合在一起作为一个整体。既然OpenVPN使用了更底层的虚拟网卡技术,那么做这件事的技术也和这些底层技术有关了,我试了下bridge方式,非常不错,bridge在Linux上的实现非常棒,工具也很齐全,不过一个brctl够了。方法是,将多个OpenVPN服务端实例的tap网卡bridge在一起,这样它们就可以共享一个IP地址了,也就可以使用同一个地址段了,剩下的事情,由bridge来完成吧!
        我的bridge-multiVPN实现使用“预生成实例”的方式,也就是预先生成一组OpenVPN服务端实例,生成多少由CPU的个数决定,一般生成“CPU*2-2”个即可,我还是相信“操作系统的调度要比OpenVPN本身的调度做得好”...当然也可以使用“每客户端一例”的方式,不过那样对于管理不是很方便,具体也没有测试。
#!/usr/bin/python#coding=gbkimport signalimport socket  import sysimport os  def signal_handler(signal, frame):    os.popen("goaway.sh")    sys.exit(0)if __name__ == '__main__':      signal.signal(signal.SIGINT, signal_handler)    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)      sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)    sock.bind(('0.0.0.0', 61195))      sock.listen(1024)          # 起始端口    minport = 6119    # 结束端口    maxport = 6125    # 起始虚拟IP地址分量    minsubnet = 2    delta = 8    currport = minport    # 启动(maxport-minport)个OpenVPN实例,侦听不同的端口,分配不同的地址段    while currport <= maxport:        if currport == maxport:            cmd =     "openvpn --config"\                " server.conf"\                " --up createBR.sh"\                " --port %s"\                " --ifconfig-pool 10.8.0.%s 10.8.0.%s 255.255.255.0"\                % (currport, minsubnet, minsubnet+delta)                    else:            cmd =     "/root/openvpn-ipv6/openvpn --config"\                " /root/openvpn-ipv6/server.conf"\                " --port %s"\                " --ifconfig-pool 10.8.0.%s 10.8.0.%s 255.255.255.0"\                % (currport, minsubnet, minsubnet+delta)        os.popen(cmd)        print cmd        currport = currport + 1        minsubnet = minsubnet + delta + 1    currport = minport    while True:          connection,address = sock.accept()          try:              connection.settimeout(5)              buf = connection.recv(1024)              if buf == 'getport':                  # 按照轮转的方式为客户端分配OpenVPN实例                connection.send(str(currport))                currport = currport + 1                if currport > maxport:                      currport = minport        except socket.timeout:              os.popen("goaway.sh")            print 'time out'          connection.close()      os.popen("goaway.sh")

最后一个OpenVPN的虚拟网卡启动的时候,调用createBR.sh,将所有的虚拟网卡和bridge联系起来:
#!/bin/bash# 获取服务端的IP地址,实际只需要第一个,因为大家最终都一样virtual_GW=$(ifconfig tap0|awk -F 'inet addr:' '/inet addr/{print $2}'|awk -F ' ' '{print $1}');# 创建一个bridgebrctl addbr virtual_BR;# 将各个虚拟网卡陆续添加到bridgefor virtual_interface in $(ifconfig |grep -o tap[0-9]);do        brctl addif virtual_BR $virtual_interface;        # 清除已经有的地址        ifconfig $virtual_interface 0.0.0.0;done;# 将地址赋予bridgeifconfig virtual_BR $virtual_GW up

类似的,清理程序goaway.sh:
killall -9 openvpnifconfig virtual_BR downbrctl delbr virtual_BR
服务端的配置文件:
daemon VPNS
script-security 2
mode server
tls-server
tls-cipher RC4-MD5
cipher BF-CBC
duplicate-cn
dev tap
proto udp
keepalive 10 60
# 配置本地的虚拟地址
ifconfig 10.8.0.1 255.255.255.0

local 0.0.0.0
# 留给server.py去设置,多个实例设置成不同的
;port 6119
verb 4
dh dh1024.pem.dh.confca CA.cer
cert A.pem
key  A.key

客户端的前端程序:

#!/usr/bin/python#coding=gbkif __name__ == '__main__':          import socket          import os          sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)          sock.connect(('192.168.2.249', 61195))          # 请求连接端口        sock.send('getport')        # 接收连接端口        port = sock.recv(1024)          sock.close()        # 根据服务器的建议,启动OpenVPN客户端实例        cmd = 'openvpn --config client.conf --remote 192.168.2.249 %s ' % (port)        os.popen(cmd)


原创粉丝点击