Commit 031c5e34 authored by Julien Muchembled's avatar Julien Muchembled

Add support for OpenVPN tunnels over IPv6

parent f5b794e8
#!/usr/bin/python -S
import os, sys
if os.environ['script_type'] == 'client-connect':
script_type = os.environ['script_type']
external_ip = lambda: os.getenv('trusted_ip') or os.environ['trusted_ip6']
if script_type == 'client-connect':
# Send client its external ip address
with open(sys.argv[2], 'w') as f:
f.write('push "setenv-safe external_ip %s"\n'
% os.environ['trusted_ip'])
f.write('push "setenv-safe external_ip %s"\n' % external_ip())
# Write into pipe connect/disconnect events
arg1 = sys.argv[1]
if arg1 != 'None':
os.write(int(arg1), '%(script_type)s %(common_name)s %(trusted_ip)s\n'
% os.environ)
os.write(int(arg1), '%s %s %s\n' % (
script_type, os.environ['common_name'], external_ip()))
......@@ -35,7 +35,7 @@ def server(iface, max_clients, dh_path, pipe_fd, port, proto, encrypt, *args, **
'--dh', dh_path,
'--max-clients', str(max_clients),
'--port', str(port),
'--proto', 'tcp-server' if proto == 'tcp' else proto,
'--proto', proto + '-server' if proto in ('tcp', 'tcp6') else proto,
*args, **kw)
......@@ -43,7 +43,7 @@ def client(iface, address_list, encrypt, *args, **kw):
remote = ['--nobind', '--client']
for ip, port, proto in address_list:
remote += '--remote', ip, port, \
'tcp-client' if proto == 'tcp' else proto
proto + '-client' if proto in ('tcp', 'tcp6') else proto
remote += args
return openvpn(iface, encrypt, *remote, **kw)
import logging, random, socket, subprocess, time
from collections import deque
from collections import defaultdict, deque
from . import plib, utils
PORT = 326
......@@ -120,7 +120,12 @@ class TunnelManager(object):
self._network = network
self._iface_list = iface_list
self._prefix = prefix
self._address = utils.dump_address(address)
address_dict = defaultdict(list)
for family, address in address:
address_dict[family] += address
self._address = dict((family, utils.dump_address(address))
for family, address in address_dict.iteritems()
if address)
self._ip_changed = ip_changed
self._gateway_manager = MultiGatewayManager(remote_gateway) \
if remote_gateway else None
......@@ -408,7 +413,9 @@ class TunnelManager(object):
except KeyError:
if self._ip_changed:
self._address = utils.dump_address(self._ip_changed(ip))
family, address = self._ip_changed(ip)
if address:
self._address[family] = utils.dump_address(address)
def handlePeerEvent(self):
msg, address = self.sock.recvfrom(1<<16)
......@@ -440,7 +447,8 @@ class TunnelManager(object):
self._makeTunnel(prefix, address)
elif code == 2: # request
if self._address:
msg = '\1%s %s\n' % (self._prefix, self._address)
msg = '\1%s %s\n' % (self._prefix,
self.sock.sendto(msg, address[:2])
except socket.error, e:
from functools import wraps
import logging, socket, time
import miniupnpc
import logging
import time
class UPnPException(Exception):
......@@ -33,10 +32,10 @@ class Forwarder(object):
if not ip:
ip = self.refresh()
if not ip:
return ()
return socket.AF_INET, ()
# If port is None, we assume we're not NATed.
return [(ip, str(port or local), proto)
for local, proto, port in self._rules]
return socket.AF_INET, [(ip, str(port or local), proto)
for local, proto, port in self._rules]
def addRule(self, local_port, proto):
self._rules.append([local_port, proto, None])
import atexit, errno, logging, os, select, signal
import atexit, errno, logging, os, select, signal, socket
import sqlite3, subprocess, sys, time, threading
from collections import deque
from OpenSSL import crypto
......@@ -84,7 +84,7 @@ def getConfig():
help='Specify that tunnels should be encrypted.')
_('--pp', nargs=2, action='append', metavar=('PORT', 'PROTO'),
help="Port and protocol to be announced to other peers, ordered by"
" preference. For each protocol (either udp or tcp), start one"
" preference. For each protocol (udp, tcp, udp6, tcp6), start one"
" openvpn server on the first given port."
" (default: --pp 1194 udp --pp 1194 tcp)")
......@@ -108,8 +108,8 @@ def getConfig():
_('--remote-gateway', action='append', dest='gw_list',
help="Force each tunnel to be created through one the given gateways,"
" in a round-robin fashion.")
_('--disable-proto', action='append', choices=('none', 'udp', 'tcp'),
_('--disable-proto', action='append',
choices=('none', 'udp', 'tcp', 'udp6', 'tcp6'), default=['udp', 'udp6'],
help="Do never try to create tunnels using given protocols."
" 'none' has precedence over other options.")
_('--client', metavar='HOST,PORT,PROTO[;...]',
......@@ -195,7 +195,11 @@ def main():
if 'none' in config.disable_proto:
config.disable_proto = ()
address = []
if not config.table:
# Make sure we won't tunnel over re6st.
config.disable_proto = tuple(set(('tcp6', 'udp6')).union(
address = ()
server_tunnels = {}
forwarder = None
if config.client:
......@@ -210,7 +214,18 @@ def main():
pp = [x for x in ((1194, 'udp'), (1194, 'tcp'))
if x[1] not in config.disable_proto]
ip_changed = lambda ip: [(ip, str(port), proto) for port, proto in pp]
def ip_changed(ip):
for family, proto_list in ((socket.AF_INET, ('tcp', 'udp')),
(socket.AF_INET6, ('tcp6', 'udp6'))):
socket.inet_pton(family, ip)
except socket.error:
family = None
return family, [(ip, str(port), proto) for port, proto in pp
if not family or proto in proto_list]
if config.gw_list:
gw_list = deque(config.gw_list)
def remote_gateway(dest):
......@@ -241,9 +256,9 @@ def main():
for port, proto in pp:
forwarder.addRule(port, proto)
ip_changed = forwarder.checkExternalIp
address = ip_changed()
address = ip_changed(),
elif 'any' not in config.ip:
address = sum(map(ip_changed, config.ip), [])
address = map(ip_changed, config.ip)
ip_changed = None
for x in pp:
server_tunnels.setdefault('re6stnet-' + x[1], x)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment