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

Add support for OpenVPN tunnels over IPv6

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