public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Lars Wendler" <polynomial-c@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/netifrc:master commit in: net/
Date: Wed, 27 Jan 2021 14:06:06 +0000 (UTC)	[thread overview]
Message-ID: <1611756354.31a05f1b3fb90a3b4e9c0e587bdd5a39e8236f6b.polynomial-c@OpenRC> (raw)

commit:     31a05f1b3fb90a3b4e9c0e587bdd5a39e8236f6b
Author:     Kerin Millar <kfm <AT> plushkava <DOT> net>
AuthorDate: Mon Jan 25 02:40:29 2021 +0000
Commit:     Lars Wendler <polynomial-c <AT> gentoo <DOT> org>
CommitDate: Wed Jan 27 14:05:54 2021 +0000
URL:        https://gitweb.gentoo.org/proj/netifrc.git/commit/?id=31a05f1b

net/apipa.sh: fix broken implementation by way of a rewrite

Sadly, the present implementation has never functioned correctly. The
original author employed incorrect syntax for what was intended to be a
command substitution. As a result, the _random() function is never called.
What actually happens is that arping is needlessly executed exactly 64516
times, with no address ever being considered as a valid candidate.

Furthermore, this module has other bugs and is poorly designed. Here are the
reasons as to why:-

  • the 169.254.0.0/16 block offers 65534 addresses, not 64516
  • the main loop is horrendously slow at enumerating the address block
  • it counts to 64516 but doesn't ensure that each address is unique!
  • it prefers bash for generating entropy (fine, but non-standard)
  • it falls back to a non-standard utility for generating entropy

Therefore, I decided to re-write most of it. The fundamental difference is
that all 65534 octet pairs are generated up front before being processed by
the main loop. At most, every possible address will now be tested exactly
once.

In fact, this approach turns out to be faster by an order of magnitude. The
following synthetic tests - which calculate the time taken to enumerate the
entire address space - demonstrate the tremendous difference between the
existing code and mine. Of course, to ensure that the comparison was
meaningful, I rectified the command substitution bug in the existing code.

  # time bash apipa-old-test.sh
  real    2m34.367s
  user    1m9.959s
  sys     1m37.502s

  # time bash apipa-new-test.sh
  real    0m1.119s
  user    0m0.965s
  sys     0m0.182s

Note that the new _random_apipa_octets() function is responsible for
generating all 65534 combinations of octet pairs in a random order. It
mainly relies on awk(1) and sort(1). Where possible, a seed is obtained from
/dev/urandom for the benefit of awk's RNG, but this is not required.

I have isolated and tested the new functions on GNU/Linux, macOS, FreeBSD,
NetBSD, OpenBSD and MirBSD. I have individually tested gawk, mawk, nawk,
busybox awk and the awk implementations provided by the previously mentioned
operating systems in the case that they are distinct. The only
incompatiblity that I was personally able to find was with the awk
implementation of MirBSD, which affects the final invocation of awk in the
_random_apipa_octets function.  However, MirBSD was forked from an old
version of OpenBSD and seems sufficiently obscure so as not to be worth
worrying about. If someone should try to integrate netifrc into MirBSD one
day then the matter can be dealt with then.

Finally, I want to thank Steve Arnold for bringing the original bug to my
attention. Congratulations, Steve. You may be the only known user of
net/apipa.sh on the planet.

Signed-off-by: Kerin Millar <kfm <AT> plushkava.net>
Reported-by: Steve Arnold <nerdboy <AT> gentoo.org>
Closes: https://bugs.gentoo.org/766890
Signed-off-by: Lars Wendler <polynomial-c <AT> gentoo.org>

 net/apipa.sh | 94 +++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 67 insertions(+), 27 deletions(-)

diff --git a/net/apipa.sh b/net/apipa.sh
index 849728b..f3ec534 100644
--- a/net/apipa.sh
+++ b/net/apipa.sh
@@ -1,49 +1,89 @@
 # Copyright (c) 2007-2008 Roy Marples <roy@marples.name>
 # Released under the 2-clause BSD license.
-# shellcheck shell=sh disable=SC1008
 
 apipa_depend()
 {
 	program /sbin/arping /bin/arping
 }
 
-_random()
+_random_bytes_as_int()
 {
-	local r=${RANDOM} # checkbashisms: false positive, we handle it AFTERWARDS
-	if [ -n "${r}" ]; then
-		echo "${r}"
-	else
-		uuidgen | sed -n -e 's/[^[:digit:]]//g' -e 's/\(^.\{1,7\}\).*/\1/p'
-	fi
+	local hex num_bytes="$1"
+
+	# While POSIX does not require that /dev/urandom exist, it is a
+	# de-facto standard. Therefore, the following approach should be
+	# highly portable in practice. In the case of Linux, and unlike BSD
+	# this interface does not block in the event that the CSRNG has not
+	# yet been seeded. Still, this is acceptable because we do not
+	# require a guarantee that the entropy be cryptographically secure.
+	# It's also worth noting that Linux >=5.4 is faster at seeding in
+	# the absence of RDRAND/RDSEED than previous versions were.
+	test -e /dev/urandom &&
+	hex=$(
+		LC_ALL=C tr -dc '[:xdigit:]' < /dev/urandom |
+		dd bs="$(( num_bytes * 2 ))" count=1 2>/dev/null) &&
+	test "${#hex}" = "$(( num_bytes * 2 ))" &&
+	printf '%d\n' "0x${hex}"
+}
+
+_random_apipa_octets()
+{
+	local seed
+
+	# Obtain a highly random 16-bit seed for use by awk's RNG. In the
+	# unlikely event that the seed ends up being empty, awk will seed
+	# based on the time of day, with a granularity of one second.
+	seed=$(_random_bytes_as_int 2)
+
+	# For APIPA (RFC 3927), the 169.254.0.0/16 address block is
+	# reserved. This provides 65534 addresses, having accounted for the
+	# network and broadcast address. Note that we must count from 1.
+	awk "BEGIN {
+		srand($seed)
+		for (i=1; i<65535; i++) print rand() \" \" i
+	}" |
+	sort -k 1,1 -n |
+	POSIXLY_CORRECT=1 awk '{
+		hex = sprintf("%04x",$2)
+		printf("%d %d\n", "0x" substr(hex,1,2), "0x" substr(hex,3,2))
+	}'
 }
 
 apipa_start()
 {
-	local iface="$1" i1= i2= addr= i=0
+	local addr rc
 
-	_exists true || return 1
+	_exists || return
 
 	einfo "Searching for free addresses in 169.254.0.0/16"
 	eindent
 
-	while [ ${i} -lt 64516 ]; do
-		: $(( i1 = (_random % 255) + 1 ))
-		: $(( i2 = (_random % 255) + 1 ))
-
-		addr="169.254.${i1}.${i2}"
-		vebegin "${addr}/16"
-		if ! arping_address "${addr}"; then
-			eval config_${config_index}="\"${addr}/16 broadcast 169.254.255.255\""
-			: $(( config_index -= 1 ))
-			veend 0
-			eoutdent
-			return 0
-		fi
+	exec 3>&1
+	addr=$(
+		_random_apipa_octets |
+		{
+			while read -r i1 i2; do
+				addr="169.254.${i1}.${i2}"
+				vebegin "${addr}/16" >&3
+				if ! arping_address "${addr}" >&3; then
+					printf '%s\n' "${addr}"
+					exit 0
+				fi
+			done
+			exit 1
+		}
+	)
+	rc=$?
+	exec 3>&-
 
-		: $(( i += 1 ))
-	done
+	if [ "$rc" = 0 ]; then
+		eval "config_${config_index}=\"\${addr}/16 broadcast 169.254.255.255\""
+		: $(( config_index -= 1 ))
+		veend 0
+	else
+		eerror "No free address found!"
+	fi
 
-	eerror "No free address found!"
 	eoutdent
-	return 1
+	return "$rc"
 }


             reply	other threads:[~2021-01-27 14:06 UTC|newest]

Thread overview: 112+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-27 14:06 Lars Wendler [this message]
  -- strict thread matches above, loose matches on Subject: below --
2025-03-18 21:50 [gentoo-commits] proj/netifrc:master commit in: net/ Sam James
2025-03-18 21:50 Sam James
2025-03-18 21:50 Sam James
2024-09-29  0:28 Sam James
2024-09-23 12:02 Sam James
2024-09-09 22:43 Patrick McLean
2024-09-01  9:22 Sam James
2024-09-01  9:21 Sam James
2024-08-28 18:54 Patrick McLean
2024-06-11  0:39 Patrick McLean
2024-06-11  0:39 Patrick McLean
2024-05-23 18:12 Patrick McLean
2023-11-26  5:31 Robin H. Johnson
2023-11-25  4:52 Robin H. Johnson
2023-10-19 22:57 Sam James
2023-09-10 15:15 Sam James
2023-05-29  0:17 Mike Gilbert
2023-04-19 17:14 Robin H. Johnson
2023-04-17  4:35 Sam James
2023-02-12  6:54 Sam James
2023-01-19 18:50 Sam James
2023-01-19 18:50 Sam James
2023-01-17 15:06 Sam James
2023-01-17 15:06 Sam James
2023-01-17 15:06 Sam James
2023-01-15 20:37 Sam James
2023-01-15 14:03 Sam James
2023-01-15 14:03 Sam James
2023-01-15  1:53 Sam James
2023-01-15  1:51 Sam James
2023-01-15  1:51 Sam James
2022-12-25 19:14 Robin H. Johnson
2022-12-25 19:07 Robin H. Johnson
2021-03-31  1:11 Patrick McLean
2021-03-11 16:54 Lars Wendler
2021-03-11 16:54 Lars Wendler
2021-03-11 16:54 Lars Wendler
2021-02-02  8:28 Lars Wendler
2021-01-27 16:55 Lars Wendler
2021-01-27 14:19 Lars Wendler
2021-01-24 10:37 Lars Wendler
2021-01-18 14:40 Lars Wendler
2021-01-18 13:04 Lars Wendler
2021-01-18 12:33 Lars Wendler
2021-01-18 12:33 Lars Wendler
2021-01-05 14:27 Lars Wendler
2021-01-05 12:46 Lars Wendler
2021-01-05 12:46 Lars Wendler
2020-12-15 20:11 Lars Wendler
2020-06-02 21:54 Robin H. Johnson
2020-05-31  6:05 Robin H. Johnson
2020-05-31  5:42 Robin H. Johnson
2020-05-31  5:29 Robin H. Johnson
2020-05-31  5:29 Robin H. Johnson
2020-05-31  5:13 Robin H. Johnson
2020-05-31  5:13 Robin H. Johnson
2020-01-04  8:06 Robin H. Johnson
2020-01-04  7:59 Robin H. Johnson
2019-07-09 19:59 Ben Kohler
2019-07-09 19:59 Ben Kohler
2019-07-09 17:39 Ben Kohler
2019-04-21  4:11 Robin H. Johnson
2018-07-12  6:25 Robin H. Johnson
2018-07-10 21:11 Jason Donenfeld
2018-01-21 21:59 Robin H. Johnson
2017-11-27 20:22 Robin H. Johnson
2017-11-27 20:22 Robin H. Johnson
2017-11-14 20:48 Robin H. Johnson
2017-11-14 20:48 Robin H. Johnson
2017-10-21 20:56 Robin H. Johnson
2017-06-09 23:59 Robin H. Johnson
2017-06-09 23:55 Robin H. Johnson
2017-06-09 23:52 Robin H. Johnson
2017-06-09 23:52 Robin H. Johnson
2017-01-27 21:54 Robin H. Johnson
2016-10-27  1:23 Robin H. Johnson
2016-10-24 23:16 Robin H. Johnson
2016-10-24 20:58 Robin H. Johnson
2016-10-24 16:49 Robin H. Johnson
2016-10-24  0:25 Robin H. Johnson
2016-10-24  0:23 Robin H. Johnson
2016-10-24  0:23 Robin H. Johnson
2016-10-24  0:04 Robin H. Johnson
2016-10-24  0:04 Robin H. Johnson
2016-10-23 23:50 Robin H. Johnson
2016-10-23 23:50 Robin H. Johnson
2016-10-23 23:50 Robin H. Johnson
2016-10-23 22:39 Robin H. Johnson
2016-10-23 22:39 Robin H. Johnson
2016-10-05 14:42 Robin H. Johnson
2016-07-19 19:59 Robin H. Johnson
2016-07-05 18:14 Robin H. Johnson
2016-07-05 18:14 Robin H. Johnson
2016-07-05 18:14 Robin H. Johnson
2016-07-05 18:09 Robin H. Johnson
2015-11-08 14:33 Robin H. Johnson
2015-11-08 14:30 Robin H. Johnson
2015-05-25 10:04 Mike Frysinger
2015-05-25 10:04 Mike Frysinger
2015-05-25 10:04 Mike Frysinger
2015-05-25 10:01 Mike Frysinger
2015-01-22 23:01 Robin H. Johnson
2015-01-22 23:01 Robin H. Johnson
2014-12-11 18:13 Robin H. Johnson
2014-09-24  6:19 Robin H. Johnson
2014-07-17 17:56 Robin H. Johnson
2014-07-17 17:56 Robin H. Johnson
2014-04-15 18:18 Robin H. Johnson
2013-08-28 16:59 Robin H. Johnson
2013-08-27 20:06 Ian Stakenvicius
2013-08-25  8:17 Robin H. Johnson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1611756354.31a05f1b3fb90a3b4e9c0e587bdd5a39e8236f6b.polynomial-c@OpenRC \
    --to=polynomial-c@gentoo.org \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox