Gentoo Archives: gentoo-commits

From: Zac Medico <zmedico@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:master commit in: lib/portage/util/, lib/portage/
Date: Sat, 31 Aug 2019 03:11:00
Message-Id: 1567221003.70ec13029e5cc8a1decfab7134d3addea8612bd7.zmedico@gentoo
1 commit: 70ec13029e5cc8a1decfab7134d3addea8612bd7
2 Author: Mike Gilbert <floppym <AT> gentoo <DOT> org>
3 AuthorDate: Fri Aug 30 18:24:47 2019 +0000
4 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org>
5 CommitDate: Sat Aug 31 03:10:03 2019 +0000
6 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=70ec1302
7
8 Use RTNETLINK to configure the loopback interface
9
10 This eliminates the dependency on iproute2 on Linux.
11
12 Bug: https://bugs.gentoo.org/690758
13 Signed-off-by: Mike Gilbert <floppym <AT> gentoo.org>
14 Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>
15
16 lib/portage/process.py | 26 +++++-------
17 lib/portage/util/netlink.py | 98 +++++++++++++++++++++++++++++++++++++++++++++
18 2 files changed, 108 insertions(+), 16 deletions(-)
19
20 diff --git a/lib/portage/process.py b/lib/portage/process.py
21 index 2a2cbd972..df63ae72f 100644
22 --- a/lib/portage/process.py
23 +++ b/lib/portage/process.py
24 @@ -10,7 +10,6 @@ import multiprocessing
25 import platform
26 import signal
27 import socket
28 -import struct
29 import subprocess
30 import sys
31 import traceback
32 @@ -489,17 +488,6 @@ def _configure_loopback_interface():
33 Configure the loopback interface.
34 """
35
36 - IFF_UP = 0x1
37 - ifreq = struct.pack('16sh', b'lo', IFF_UP)
38 - SIOCSIFFLAGS = 0x8914
39 -
40 - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
41 - try:
42 - fcntl.ioctl(sock, SIOCSIFFLAGS, ifreq)
43 - except IOError as e:
44 - writemsg("Unable to enable loopback interface: %s\n" % e.strerror, noiselevel=-1)
45 - sock.close()
46 -
47 # We add some additional addresses to work around odd behavior in glibc's
48 # getaddrinfo() implementation when the AI_ADDRCONFIG flag is set.
49 #
50 @@ -514,12 +502,18 @@ def _configure_loopback_interface():
51 # Bug: https://bugs.gentoo.org/690758
52 # Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=12377#c13
53
54 + # Avoid importing this module on systems that may not support netlink sockets.
55 + from portage.util.netlink import RtNetlink
56 +
57 try:
58 - subprocess.call(['ip', 'address', 'add', '10.0.0.1/8', 'dev', 'lo'])
59 - if _has_ipv6():
60 - subprocess.call(['ip', 'address', 'add', 'fd00::1/8', 'dev', 'lo'])
61 + with RtNetlink() as rtnl:
62 + ifindex = rtnl.get_link_ifindex(b'lo')
63 + rtnl.set_link_up(ifindex)
64 + rtnl.add_address(ifindex, socket.AF_INET, '10.0.0.1', 8)
65 + if _has_ipv6():
66 + rtnl.add_address(ifindex, socket.AF_INET6, 'fd::1', 8)
67 except EnvironmentError as e:
68 - writemsg("Error calling 'ip': %s\n" % e.strerror, noiselevel=-1)
69 + writemsg("Unable to configure loopback interface: %s\n" % e.strerror, noiselevel=-1)
70
71 def _exec(binary, mycommand, opt_name, fd_pipes,
72 env, gid, groups, uid, umask, cwd,
73
74 diff --git a/lib/portage/util/netlink.py b/lib/portage/util/netlink.py
75 new file mode 100644
76 index 000000000..950ed8f69
77 --- /dev/null
78 +++ b/lib/portage/util/netlink.py
79 @@ -0,0 +1,98 @@
80 +# Copyright 2019 Gentoo Authors
81 +# Distributed under the terms of the GNU General Public License v2
82 +
83 +from io import BytesIO
84 +from os import strerror
85 +from struct import Struct
86 +
87 +import socket
88 +from socket import (
89 + AF_NETLINK, AF_UNSPEC,
90 + MSG_PEEK, MSG_TRUNC,
91 + NETLINK_ROUTE,
92 + SOCK_DGRAM,
93 + inet_pton,
94 +)
95 +
96 +IFA_LOCAL = 2
97 +IFF_UP = 0x1
98 +IFLA_IFNAME = 3
99 +NLMSG_ERROR = 2
100 +RTM_NEWLINK = 16
101 +RTM_GETLINK = 18
102 +RTM_NEWADDR = 20
103 +NLM_F_REQUEST = 0x1
104 +NLM_F_ACK = 0x4
105 +NLM_F_EXCL = 0x200
106 +NLM_F_CREATE = 0x400
107 +
108 +nlmsghdr = Struct('=IHHII')
109 +nlmsgerr = Struct('i')
110 +rtattr = Struct('HH')
111 +ifinfomsg = Struct('BHiII')
112 +ifaddrmsg = Struct('BBBBi')
113 +
114 +def create_nlmsg(nlmsg_type, nlmsg_flags, nlmsg_seq, nlmsg_pid, data):
115 + nlmsg_len = nlmsghdr.size + len(data)
116 + return nlmsghdr.pack(nlmsg_len, nlmsg_type, nlmsg_flags, nlmsg_seq, nlmsg_pid) + data
117 +
118 +def create_rtattr(rta_type, data):
119 + rta_len = rtattr.size + len(data)
120 + return rtattr.pack(rta_len, rta_type) + data
121 +
122 +def parse_message(msg):
123 + buf = BytesIO(msg)
124 + hdr = nlmsghdr.unpack(buf.read(nlmsghdr.size))
125 + if hdr[1] == NLMSG_ERROR:
126 + err = nlmsgerr.unpack(buf.read(nlmsgerr.size))
127 + error = -err[0]
128 + if error != 0:
129 + raise OSError(error, strerror(error))
130 + elif hdr[1] == RTM_NEWLINK:
131 + # kernel responds to RTM_GETLINK with RTM_NEWLINK.
132 + # We only care about the ifindex for get_link_ifindex.
133 + return ifinfomsg.unpack(buf.read(ifinfomsg.size))
134 +
135 +class RtNetlink:
136 + def __init__(self):
137 + self.sock = socket.socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)
138 + self.addr = (0, 0)
139 + try:
140 + self.sock.bind(self.addr)
141 + except socket.error:
142 + self.sock.close()
143 + raise
144 +
145 + def __enter__(self):
146 + return self
147 +
148 + def __exit__(self, exc_type, exc_value, traceback):
149 + self.sock.close()
150 +
151 + def send_message(self, msg):
152 + self.sock.sendto(msg, self.addr)
153 + # Messages are variable length, but 128 is enough for the the ones we care about.
154 + resp = self.sock.recv(128)
155 + return parse_message(resp)
156 +
157 + def get_link_ifindex(self, ifname):
158 + body = ifinfomsg.pack(AF_UNSPEC, 0, 0, 0, 0)
159 + body += create_rtattr(IFLA_IFNAME, ifname)
160 + flags = NLM_F_REQUEST
161 + msg = create_nlmsg(RTM_GETLINK, flags, 1, 0, body)
162 + resp = self.send_message(msg)
163 + return resp[2]
164 +
165 + def set_link_up(self, ifindex):
166 + body = ifinfomsg.pack(AF_UNSPEC, 0, ifindex, IFF_UP, IFF_UP)
167 + flags = NLM_F_REQUEST|NLM_F_ACK
168 + msg = create_nlmsg(RTM_NEWLINK, flags, 1, 0, body)
169 + self.send_message(msg)
170 +
171 + def add_address(self, ifindex, family, address, prefixlen):
172 + body = ifaddrmsg.pack(family, prefixlen, 0, 0, ifindex)
173 + addr = inet_pton(family, address)
174 + body += create_rtattr(IFA_LOCAL, addr)
175 + flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL|NLM_F_CREATE
176 + msg = create_nlmsg(RTM_NEWADDR, flags, 1, 0, body)
177 + self.send_message(msg)