On Sun, Aug 4, 2019 at 9:34 AM Mike Gilbert <flop...@gentoo.org> wrote: > > On Sat, Aug 3, 2019 at 7:37 PM Mike Gilbert <flop...@gentoo.org> wrote: > > > > On Sat, Aug 3, 2019 at 3:30 PM Zac Medico <zmed...@gentoo.org> wrote: > > > > > > Add _has_ipv6() function and use it in _configure_loopback_interface() > > > to decide whether to add an IPv6 address. > > > > > > Bug: https://bugs.gentoo.org/691290 > > > --- > > > lib/portage/process.py | 40 +++++++++++++++++++++++++++++++++++++--- > > > 1 file changed, 37 insertions(+), 3 deletions(-) > > > > > > diff --git a/lib/portage/process.py b/lib/portage/process.py > > > index 690421815..ca8b0c172 100644 > > > --- a/lib/portage/process.py > > > +++ b/lib/portage/process.py > > > @@ -339,6 +339,9 @@ def spawn(mycommand, env=None, opt_name=None, > > > fd_pipes=None, returnpid=False, > > > fd_pipes[1] = pw > > > fd_pipes[2] = pw > > > > > > + # Cache _has_ipv6() result for use in child processes. > > > + _has_ipv6() > > > + > > > # This caches the libc library lookup and _unshare_validator > > > results > > > # in the current process, so that results are cached for use in > > > # child processes. > > > @@ -446,6 +449,38 @@ def spawn(mycommand, env=None, opt_name=None, > > > fd_pipes=None, returnpid=False, > > > # Everything succeeded > > > return 0 > > > > > > +__has_ipv6 = None > > > + > > > +def _has_ipv6(): > > > + """ > > > + Test that both userland and kernel support IPv6, by attempting > > > + to create a socket and listen on any unused port of the IPv6 > > > + ::1 loopback address. > > > + > > > + @rtype: bool > > > + @return: True if IPv6 is supported, False otherwise. > > > + """ > > > + global __has_ipv6 > > > + > > > + if __has_ipv6 is None: > > > + if socket.has_ipv6: > > > + sock = None > > > + try: > > > + # python2.7 sockets do not support > > > context management protocol > > > + sock = socket.socket(socket.AF_INET6, > > > socket.SOCK_DGRAM) > > > + sock.bind(('::1', 0)) > > > + except EnvironmentError: > > > + __has_ipv6 = False > > > + else: > > > + __has_ipv6 = True > > > + finally: > > > + if sock is not None: > > > + sock.close() > > > + else: > > > + __has_ipv6 = False > > > + > > > + return __has_ipv6 > > > + > > > def _configure_loopback_interface(): > > > """ > > > Configure the loopback interface. > > > @@ -478,9 +513,8 @@ def _configure_loopback_interface(): > > > > > > try: > > > subprocess.call(['ip', 'address', 'add', '10.0.0.1/8', > > > 'dev', 'lo']) > > > - with open(os.devnull, 'wb', 0) as devnull: > > > - subprocess.call(['ip', 'address', 'add', > > > 'fd00::1/8', 'dev', 'lo'], > > > - stdout=devnull, stderr=devnull) > > > + if _has_ipv6(): > > > + subprocess.call(['ip', 'address', 'add', > > > 'fd00::1/8', 'dev', 'lo']) > > > except EnvironmentError as e: > > > writemsg("Error calling 'ip': %s\n" % e.strerror, > > > noiselevel=-1) > > > > > > -- > > > 2.21.0 > > > > > > > This seems reasonable, though I don't have an IPv6-less system to test it > > on. > > While chatting in #gentoo-desktop, we found that it is possible to > have IPv6 enabled, but prohibit IPv6 addresses from being added to > interfaces. This produces the following error from ip: > > RTNETLINK answers: Permission denied > > https://www.kernel.org/doc/Documentation/networking/ipv6.txt > > ipv6.disabled = 0 > ipv6.disable_ipv6 = 1 > > I don't think your __has_ipv6 function will catch this.
Possibly the bind('::1', 0) call will fail if the loopback interface doesn't have that address configured. This appears to be the case when disable_ipv6 = 1.