现在的位置: 首页 > 综合 > 正文

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

2013年10月02日 ⁄ 综合 ⁄ 共 2872字 ⁄ 字号 评论关闭
既然有了一个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=gbk

import signal
import socket  
import sys
import 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}');

# 创建一个bridge
brctl addbr virtual_BR;

# 将各个虚拟网卡陆续添加到bridge
for virtual_interface in $(ifconfig |grep -o tap[0-9]);
do
        brctl addif virtual_BR $virtual_interface;
        # 清除已经有的地址
        ifconfig $virtual_interface 0.0.0.0;
done;

# 将地址赋予bridge
ifconfig virtual_BR $virtual_GW up

类似的,清理程序goaway.sh:

killall -9 openvpn
ifconfig virtual_BR down
brctl 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=gbk
if __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)

抱歉!评论已关闭.