From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 48869138334 for ; Fri, 30 Aug 2019 18:24:55 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 6A2B1E083D; Fri, 30 Aug 2019 18:24:53 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 35C0AE0826 for ; Fri, 30 Aug 2019 18:24:52 +0000 (UTC) Received: from naomi.gilbertsystems.net (d192-24-229-26.try.wideopenwest.com [24.192.26.229]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: floppym) by smtp.gentoo.org (Postfix) with ESMTPSA id 8E37F34A701 for ; Fri, 30 Aug 2019 18:24:51 +0000 (UTC) From: Mike Gilbert To: gentoo-portage-dev@lists.gentoo.org Subject: [gentoo-portage-dev] [PATCH 1/2] Use RTNETLINK to configure the loopback interface Date: Fri, 30 Aug 2019 14:24:47 -0400 Message-Id: <20190830182448.1203327-1-floppym@gentoo.org> X-Mailer: git-send-email 2.23.0 Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-portage-dev@lists.gentoo.org Reply-to: gentoo-portage-dev@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Archives-Salt: ab08b204-a2e4-49fd-90d8-5cd04083d52a X-Archives-Hash: 27e6188c2892b53396e43c72888647f8 This eliminates the dependency on iproute2 on Linux. Signed-off-by: Mike Gilbert --- lib/portage/process.py | 26 ++++------ lib/portage/util/netlink.py | 98 +++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 lib/portage/util/netlink.py diff --git a/lib/portage/process.py b/lib/portage/process.py index 2a2cbd972..df63ae72f 100644 --- a/lib/portage/process.py +++ b/lib/portage/process.py @@ -10,7 +10,6 @@ import multiprocessing import platform import signal import socket -import struct import subprocess import sys import traceback @@ -489,17 +488,6 @@ def _configure_loopback_interface(): Configure the loopback interface. """ - IFF_UP = 0x1 - ifreq = struct.pack('16sh', b'lo', IFF_UP) - SIOCSIFFLAGS = 0x8914 - - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) - try: - fcntl.ioctl(sock, SIOCSIFFLAGS, ifreq) - except IOError as e: - writemsg("Unable to enable loopback interface: %s\n" % e.strerror, noiselevel=-1) - sock.close() - # We add some additional addresses to work around odd behavior in glibc's # getaddrinfo() implementation when the AI_ADDRCONFIG flag is set. # @@ -514,12 +502,18 @@ def _configure_loopback_interface(): # Bug: https://bugs.gentoo.org/690758 # Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=12377#c13 + # Avoid importing this module on systems that may not support netlink sockets. + from portage.util.netlink import RtNetlink + try: - subprocess.call(['ip', 'address', 'add', '10.0.0.1/8', 'dev', 'lo']) - if _has_ipv6(): - subprocess.call(['ip', 'address', 'add', 'fd00::1/8', 'dev', 'lo']) + with RtNetlink() as rtnl: + ifindex = rtnl.get_link_ifindex(b'lo') + rtnl.set_link_up(ifindex) + rtnl.add_address(ifindex, socket.AF_INET, '10.0.0.1', 8) + if _has_ipv6(): + rtnl.add_address(ifindex, socket.AF_INET6, 'fd::1', 8) except EnvironmentError as e: - writemsg("Error calling 'ip': %s\n" % e.strerror, noiselevel=-1) + writemsg("Unable to configure loopback interface: %s\n" % e.strerror, noiselevel=-1) def _exec(binary, mycommand, opt_name, fd_pipes, env, gid, groups, uid, umask, cwd, diff --git a/lib/portage/util/netlink.py b/lib/portage/util/netlink.py new file mode 100644 index 000000000..950ed8f69 --- /dev/null +++ b/lib/portage/util/netlink.py @@ -0,0 +1,98 @@ +# Copyright 2019 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +from io import BytesIO +from os import strerror +from struct import Struct + +import socket +from socket import ( + AF_NETLINK, AF_UNSPEC, + MSG_PEEK, MSG_TRUNC, + NETLINK_ROUTE, + SOCK_DGRAM, + inet_pton, +) + +IFA_LOCAL = 2 +IFF_UP = 0x1 +IFLA_IFNAME = 3 +NLMSG_ERROR = 2 +RTM_NEWLINK = 16 +RTM_GETLINK = 18 +RTM_NEWADDR = 20 +NLM_F_REQUEST = 0x1 +NLM_F_ACK = 0x4 +NLM_F_EXCL = 0x200 +NLM_F_CREATE = 0x400 + +nlmsghdr = Struct('=IHHII') +nlmsgerr = Struct('i') +rtattr = Struct('HH') +ifinfomsg = Struct('BHiII') +ifaddrmsg = Struct('BBBBi') + +def create_nlmsg(nlmsg_type, nlmsg_flags, nlmsg_seq, nlmsg_pid, data): + nlmsg_len = nlmsghdr.size + len(data) + return nlmsghdr.pack(nlmsg_len, nlmsg_type, nlmsg_flags, nlmsg_seq, nlmsg_pid) + data + +def create_rtattr(rta_type, data): + rta_len = rtattr.size + len(data) + return rtattr.pack(rta_len, rta_type) + data + +def parse_message(msg): + buf = BytesIO(msg) + hdr = nlmsghdr.unpack(buf.read(nlmsghdr.size)) + if hdr[1] == NLMSG_ERROR: + err = nlmsgerr.unpack(buf.read(nlmsgerr.size)) + error = -err[0] + if error != 0: + raise OSError(error, strerror(error)) + elif hdr[1] == RTM_NEWLINK: + # kernel responds to RTM_GETLINK with RTM_NEWLINK. + # We only care about the ifindex for get_link_ifindex. + return ifinfomsg.unpack(buf.read(ifinfomsg.size)) + +class RtNetlink: + def __init__(self): + self.sock = socket.socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE) + self.addr = (0, 0) + try: + self.sock.bind(self.addr) + except socket.error: + self.sock.close() + raise + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.sock.close() + + def send_message(self, msg): + self.sock.sendto(msg, self.addr) + # Messages are variable length, but 128 is enough for the the ones we care about. + resp = self.sock.recv(128) + return parse_message(resp) + + def get_link_ifindex(self, ifname): + body = ifinfomsg.pack(AF_UNSPEC, 0, 0, 0, 0) + body += create_rtattr(IFLA_IFNAME, ifname) + flags = NLM_F_REQUEST + msg = create_nlmsg(RTM_GETLINK, flags, 1, 0, body) + resp = self.send_message(msg) + return resp[2] + + def set_link_up(self, ifindex): + body = ifinfomsg.pack(AF_UNSPEC, 0, ifindex, IFF_UP, IFF_UP) + flags = NLM_F_REQUEST|NLM_F_ACK + msg = create_nlmsg(RTM_NEWLINK, flags, 1, 0, body) + self.send_message(msg) + + def add_address(self, ifindex, family, address, prefixlen): + body = ifaddrmsg.pack(family, prefixlen, 0, 0, ifindex) + addr = inet_pton(family, address) + body += create_rtattr(IFA_LOCAL, addr) + flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL|NLM_F_CREATE + msg = create_nlmsg(RTM_NEWADDR, flags, 1, 0, body) + self.send_message(msg) -- 2.23.0