1 |
On Sun, Aug 4, 2019 at 9:40 AM Mike Gilbert <floppym@g.o> wrote: |
2 |
> |
3 |
> On Sun, Aug 4, 2019 at 9:34 AM Mike Gilbert <floppym@g.o> wrote: |
4 |
> > |
5 |
> > On Sat, Aug 3, 2019 at 7:37 PM Mike Gilbert <floppym@g.o> wrote: |
6 |
> > > |
7 |
> > > On Sat, Aug 3, 2019 at 3:30 PM Zac Medico <zmedico@g.o> wrote: |
8 |
> > > > |
9 |
> > > > Add _has_ipv6() function and use it in _configure_loopback_interface() |
10 |
> > > > to decide whether to add an IPv6 address. |
11 |
> > > > |
12 |
> > > > Bug: https://bugs.gentoo.org/691290 |
13 |
> > > > --- |
14 |
> > > > lib/portage/process.py | 40 +++++++++++++++++++++++++++++++++++++--- |
15 |
> > > > 1 file changed, 37 insertions(+), 3 deletions(-) |
16 |
> > > > |
17 |
> > > > diff --git a/lib/portage/process.py b/lib/portage/process.py |
18 |
> > > > index 690421815..ca8b0c172 100644 |
19 |
> > > > --- a/lib/portage/process.py |
20 |
> > > > +++ b/lib/portage/process.py |
21 |
> > > > @@ -339,6 +339,9 @@ def spawn(mycommand, env=None, opt_name=None, fd_pipes=None, returnpid=False, |
22 |
> > > > fd_pipes[1] = pw |
23 |
> > > > fd_pipes[2] = pw |
24 |
> > > > |
25 |
> > > > + # Cache _has_ipv6() result for use in child processes. |
26 |
> > > > + _has_ipv6() |
27 |
> > > > + |
28 |
> > > > # This caches the libc library lookup and _unshare_validator results |
29 |
> > > > # in the current process, so that results are cached for use in |
30 |
> > > > # child processes. |
31 |
> > > > @@ -446,6 +449,38 @@ def spawn(mycommand, env=None, opt_name=None, fd_pipes=None, returnpid=False, |
32 |
> > > > # Everything succeeded |
33 |
> > > > return 0 |
34 |
> > > > |
35 |
> > > > +__has_ipv6 = None |
36 |
> > > > + |
37 |
> > > > +def _has_ipv6(): |
38 |
> > > > + """ |
39 |
> > > > + Test that both userland and kernel support IPv6, by attempting |
40 |
> > > > + to create a socket and listen on any unused port of the IPv6 |
41 |
> > > > + ::1 loopback address. |
42 |
> > > > + |
43 |
> > > > + @rtype: bool |
44 |
> > > > + @return: True if IPv6 is supported, False otherwise. |
45 |
> > > > + """ |
46 |
> > > > + global __has_ipv6 |
47 |
> > > > + |
48 |
> > > > + if __has_ipv6 is None: |
49 |
> > > > + if socket.has_ipv6: |
50 |
> > > > + sock = None |
51 |
> > > > + try: |
52 |
> > > > + # python2.7 sockets do not support context management protocol |
53 |
> > > > + sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) |
54 |
> > > > + sock.bind(('::1', 0)) |
55 |
> > > > + except EnvironmentError: |
56 |
> > > > + __has_ipv6 = False |
57 |
> > > > + else: |
58 |
> > > > + __has_ipv6 = True |
59 |
> > > > + finally: |
60 |
> > > > + if sock is not None: |
61 |
> > > > + sock.close() |
62 |
> > > > + else: |
63 |
> > > > + __has_ipv6 = False |
64 |
> > > > + |
65 |
> > > > + return __has_ipv6 |
66 |
> > > > + |
67 |
> > > > def _configure_loopback_interface(): |
68 |
> > > > """ |
69 |
> > > > Configure the loopback interface. |
70 |
> > > > @@ -478,9 +513,8 @@ def _configure_loopback_interface(): |
71 |
> > > > |
72 |
> > > > try: |
73 |
> > > > subprocess.call(['ip', 'address', 'add', '10.0.0.1/8', 'dev', 'lo']) |
74 |
> > > > - with open(os.devnull, 'wb', 0) as devnull: |
75 |
> > > > - subprocess.call(['ip', 'address', 'add', 'fd00::1/8', 'dev', 'lo'], |
76 |
> > > > - stdout=devnull, stderr=devnull) |
77 |
> > > > + if _has_ipv6(): |
78 |
> > > > + subprocess.call(['ip', 'address', 'add', 'fd00::1/8', 'dev', 'lo']) |
79 |
> > > > except EnvironmentError as e: |
80 |
> > > > writemsg("Error calling 'ip': %s\n" % e.strerror, noiselevel=-1) |
81 |
> > > > |
82 |
> > > > -- |
83 |
> > > > 2.21.0 |
84 |
> > > > |
85 |
> > > |
86 |
> > > This seems reasonable, though I don't have an IPv6-less system to test it on. |
87 |
> > |
88 |
> > While chatting in #gentoo-desktop, we found that it is possible to |
89 |
> > have IPv6 enabled, but prohibit IPv6 addresses from being added to |
90 |
> > interfaces. This produces the following error from ip: |
91 |
> > |
92 |
> > RTNETLINK answers: Permission denied |
93 |
> > |
94 |
> > https://www.kernel.org/doc/Documentation/networking/ipv6.txt |
95 |
> > |
96 |
> > ipv6.disabled = 0 |
97 |
> > ipv6.disable_ipv6 = 1 |
98 |
> > |
99 |
> > I don't think your __has_ipv6 function will catch this. |
100 |
> |
101 |
> Possibly the bind('::1', 0) call will fail if the loopback interface |
102 |
> doesn't have that address configured. This appears to be the case when |
103 |
> disable_ipv6 = 1. |
104 |
|
105 |
We confirmed that the bind() call will raise this error, which is good. |
106 |
|
107 |
OSError: [Errno 99] Cannot assign requested address |