[enh] Determine the public IPv6 locally

Avoid depending on a remote service to fetch the globally routable IPv6
address.

discussed in #89
This commit is contained in:
Jocelyn Delande 2015-09-27 01:16:56 +02:00
parent 8e818d54a6
commit 7c6f2b9373
2 changed files with 44 additions and 5 deletions

3
debian/control vendored
View file

@ -19,6 +19,7 @@ Depends: moulinette (>= 2.2.1),
python-apt, python-apt,
ca-certificates, ca-certificates,
python-dnspython, python-dnspython,
netcat-openbsd netcat-openbsd,
iproute2
Description: YunoHost Python scripts Description: YunoHost Python scripts
Python functions to manage a YunoHost instance Python functions to manage a YunoHost instance

View file

@ -26,14 +26,39 @@
import os import os
import sys import sys
import requests import requests
import re
import json import json
import glob import glob
import base64 import base64
import errno import errno
import subprocess
from moulinette.core import MoulinetteError from moulinette.core import MoulinetteError
class IPRouteLine(object):
""" Utility class to parse an ip route output line
The output of ip ro is variable and hard to parse completly, it would
require a real parser, not just a regexp, so do minimal parsing here...
>>> a = IPRouteLine('2001:: from :: via fe80::c23f:fe:1e:cafe dev eth0 src 2000:de:beef:ca:0:fe:1e:cafe metric 0')
>>> a.src_addr
"2000:de:beef:ca:0:fe:1e:cafe"
"""
regexp = re.compile(
r'(?P<unreachable>unreachable)?.*src\s+(?P<src_addr>[0-9a-f:]+).*')
def __init__(self, line):
self.m = self.regexp.match(line)
if not self.m:
raise ValueError("Not a valid ip route get line")
# make regexp group available as object attributes
for k, v in self.m.groupdict().items():
setattr(self, k, v)
def dyndns_subscribe(subscribe_host="dyndns.yunohost.org", domain=None, key=None): def dyndns_subscribe(subscribe_host="dyndns.yunohost.org", domain=None, key=None):
""" """
Subscribe to a DynDNS service Subscribe to a DynDNS service
@ -120,10 +145,23 @@ def dyndns_update(dyn_host="dynhost.yunohost.org", domain=None, key=None, ip=Non
if ipv6 is None: if ipv6 is None:
new_ipv6 = None new_ipv6 = None
try: try:
new_ipv6 = requests.get('http://ip6.yunohost.org').text ip_route_out = subprocess.check_output(
except ConnectionError: ['ip', 'route', 'get', '2000::']).split('\n')
msignals.display(m18n.n('no_ipv6_connectivity'),
'warning') if len(ip_route_out) > 0:
route = IPRouteLine(ip_route_out[0])
if not route.unreachable:
new_ipv6 = route.src_addr
except (OSError, ValueError) as e:
# Unlikely case "ip route" does not return status 0
# or produces unexpected output
raise MoulinetteError(errno.EBADMSG,
"ip route cmd error : {}".format(e))
if new_ipv6 is None:
msignals.display(m18n.n('no_ipv6_connectivity'), 'warning')
else: else:
new_ipv6 = ipv6 new_ipv6 = ipv6