From 0efea4cc37597f48a7ad800b945d43474899748b Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Thu, 13 May 2021 16:08:14 +0300 Subject: [PATCH 1/7] umdns: bump to git HEAD 777a0b service: fix compilation with GCC 10 Signed-off-by: Stijn Tintel --- package/network/services/umdns/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/network/services/umdns/Makefile b/package/network/services/umdns/Makefile index 8dd3bfe22c..d95c61ab16 100644 --- a/package/network/services/umdns/Makefile +++ b/package/network/services/umdns/Makefile @@ -12,9 +12,9 @@ PKG_RELEASE:=4 PKG_SOURCE_URL=$(PROJECT_GIT)/project/mdnsd.git PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2021-01-26 -PKG_SOURCE_VERSION:=78aa36b0e9808e801c527c6dc47320e593309522 -PKG_MIRROR_HASH:=241833f2bf2f3366f356703159be386862ef747d9b253af6c13555f252cc970d +PKG_SOURCE_DATE:=2021-05-13 +PKG_SOURCE_VERSION:=b777a0b53f7d89ab2a60e3eed7d98036806da9a4 +PKG_MIRROR_HASH:=54992acf7edd32610de7bcb0ea7c58b20f69bf1ac20be69e76abcff41f25e775 PKG_MAINTAINER:=John Crispin PKG_LICENSE:=LGPL-2.1 From 0f17c0b485bb06baa4385c11f28168f0888e7379 Mon Sep 17 00:00:00 2001 From: Stijn Tintel Date: Fri, 14 May 2021 17:11:42 +0300 Subject: [PATCH 2/7] grub2: bump to 2.06-rc1 When building GRUB with binutils 2.35.2 or later, an error occurs due to a section .note.gnu.property that is placed at an offset such that objcopy needs to pad the img file with zeros. This in turn causes the following error: "error: Decompressor is too big.". The fix accepted by upstream patches a python script that isn't executed at all when building GRUB with OpenWrt buildroot. There's another patch that patches the files generated by that python script directly, but by including it we would deviate further from upstream. Instead of doing that, simply bump to the latest release candidate. As one of the fixes for the CVEs causes grub to crash on some x86 hardware using legacy BIOS when compiled with -O2, filter -O2 and -O3 out of TARGET_CFLAGS. Fixes the following CVEs: - CVE-2020-14372 - CVE-2020-25632 - CVE-2020-25647 - CVE-2020-27749 - CVE-2020-27779 - CVE-2021-3418 - CVE-2021-20225 - CVE-2021-20233 Runtime-tested on x86/64. Fixes: FS#3790 Suggested-by: Dirk Neukirchen Signed-off-by: Stijn Tintel Acked-by: Kevin Darbyshire-Bryant --- package/boot/grub2/common.mk | 10 ++- .../grub2/patches/100-grub_setup_root.patch | 87 ++++++++++--------- 2 files changed, 50 insertions(+), 47 deletions(-) diff --git a/package/boot/grub2/common.mk b/package/boot/grub2/common.mk index 03e97c1214..dab0a4a8c3 100644 --- a/package/boot/grub2/common.mk +++ b/package/boot/grub2/common.mk @@ -9,15 +9,16 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_CPE_ID:=cpe:/a:gnu:grub2 -PKG_VERSION:=2.04 +PKG_VERSION:=2.06~rc1 PKG_RELEASE:=1 PKG_SOURCE:=grub-$(PKG_VERSION).tar.xz -PKG_SOURCE_URL:=@GNU/grub -PKG_HASH:=e5292496995ad42dabe843a0192cf2a2c502e7ffcc7479398232b10a472df77d +PKG_SOURCE_URL:=https://alpha.gnu.org/gnu/grub +PKG_HASH:=2c87f1f21e2ab50043e6cd9163c08f1b6c3a6171556bf23ff9ed65b074145484 HOST_BUILD_PARALLEL:=1 +PKG_ASLR_PIE:=0 PKG_SSP:=0 PKG_FLAGS:=nonshared @@ -66,8 +67,9 @@ HOST_MAKE_FLAGS += \ TARGET_RANLIB=$(TARGET_RANLIB) \ LIBLZMA=$(STAGING_DIR_HOST)/lib/liblzma.a +TARGET_CFLAGS := $(filter-out -O2 -O3 -fno-plt,$(TARGET_CFLAGS)) + define Host/Configure $(SED) 's,(RANLIB),(TARGET_RANLIB),' $(HOST_BUILD_DIR)/grub-core/Makefile.in $(Host/Configure/Default) endef - diff --git a/package/boot/grub2/patches/100-grub_setup_root.patch b/package/boot/grub2/patches/100-grub_setup_root.patch index 1b1bb34f74..e075d052cb 100644 --- a/package/boot/grub2/patches/100-grub_setup_root.patch +++ b/package/boot/grub2/patches/100-grub_setup_root.patch @@ -1,3 +1,41 @@ +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -198,13 +198,13 @@ grub_install_get_image_target (const cha + void + grub_util_bios_setup (const char *dir, + const char *boot_file, const char *core_file, +- const char *dest, int force, ++ const char *root, const char *dest, int force, + int fs_probe, int allow_floppy, + int add_rs_codes, int warn_short_mbr_gap); + void + grub_util_sparc_setup (const char *dir, + const char *boot_file, const char *core_file, +- const char *dest, int force, ++ const char *root, const char *dest, int force, + int fs_probe, int allow_floppy, + int add_rs_codes, int warn_short_mbr_gap); + +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -1720,7 +1720,7 @@ main (int argc, char *argv[]) + /* Now perform the installation. */ + if (install_bootsector) + grub_util_bios_setup (platdir, "boot.img", "core.img", +- install_drive, force, ++ NULL, install_drive, force, + fs_probe, allow_floppy, add_rs_codes, + !grub_install_is_short_mbrgap_supported ()); + break; +@@ -1747,7 +1747,7 @@ main (int argc, char *argv[]) + /* Now perform the installation. */ + if (install_bootsector) + grub_util_sparc_setup (platdir, "boot.img", "core.img", +- install_drive, force, ++ NULL, install_drive, force, + fs_probe, allow_floppy, + 0 /* unused */, 0 /* unused */ ); + break; --- a/util/grub-setup.c +++ b/util/grub-setup.c @@ -87,6 +87,8 @@ static struct argp_option options[] = { @@ -38,18 +76,19 @@ - dest_dev, arguments.force, + arguments.root_dev, dest_dev, arguments.force, arguments.fs_probe, arguments.allow_floppy, - arguments.add_rs_codes); + arguments.add_rs_codes, 0); --- a/util/setup.c +++ b/util/setup.c -@@ -247,13 +247,12 @@ identify_partmap (grub_disk_t disk __att +@@ -252,14 +252,13 @@ identify_partmap (grub_disk_t disk __att void SETUP (const char *dir, const char *boot_file, const char *core_file, - const char *dest, int force, + const char *root, const char *dest, int force, int fs_probe, int allow_floppy, - int add_rs_codes __attribute__ ((unused))) /* unused on sparc64 */ + int add_rs_codes __attribute__ ((unused)), /* unused on sparc64 */ + int warn_small) { char *core_path; char *boot_img, *core_img, *boot_path; @@ -57,7 +96,7 @@ size_t boot_size, core_size; grub_uint16_t core_sectors; grub_device_t root_dev = 0, dest_dev, core_dev; -@@ -307,7 +306,10 @@ SETUP (const char *dir, +@@ -311,7 +310,10 @@ SETUP (const char *dir, core_dev = dest_dev; @@ -69,7 +108,7 @@ char **root_devices = grub_guess_root_devices (dir); char **cur; int found = 0; -@@ -320,6 +322,8 @@ SETUP (const char *dir, +@@ -324,6 +326,8 @@ SETUP (const char *dir, char *drive; grub_device_t try_dev; @@ -78,41 +117,3 @@ drive = grub_util_get_grub_dev (*cur); if (!drive) continue; ---- a/include/grub/util/install.h -+++ b/include/grub/util/install.h -@@ -191,13 +191,13 @@ grub_install_get_image_target (const cha - void - grub_util_bios_setup (const char *dir, - const char *boot_file, const char *core_file, -- const char *dest, int force, -+ const char *root, const char *dest, int force, - int fs_probe, int allow_floppy, - int add_rs_codes); - void - grub_util_sparc_setup (const char *dir, - const char *boot_file, const char *core_file, -- const char *dest, int force, -+ const char *root, const char *dest, int force, - int fs_probe, int allow_floppy, - int add_rs_codes); - ---- a/util/grub-install.c -+++ b/util/grub-install.c -@@ -1712,7 +1712,7 @@ main (int argc, char *argv[]) - /* Now perform the installation. */ - if (install_bootsector) - grub_util_bios_setup (platdir, "boot.img", "core.img", -- install_drive, force, -+ NULL, install_drive, force, - fs_probe, allow_floppy, add_rs_codes); - break; - } -@@ -1738,7 +1738,7 @@ main (int argc, char *argv[]) - /* Now perform the installation. */ - if (install_bootsector) - grub_util_sparc_setup (platdir, "boot.img", "core.img", -- install_drive, force, -+ NULL, install_drive, force, - fs_probe, allow_floppy, - 0 /* unused */ ); - break; From 57e05130b45476422485716494302111ddccc1fc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 17 May 2021 17:16:56 +0200 Subject: [PATCH 3/7] toolchain/gdb: fix broken configure test for ELF support A missing #include was causing gdb on macOS to be compiled without ELF support Signed-off-by: Felix Fietkau --- .../patches/100-fix-elf-support-check.patch | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 toolchain/gdb/patches/100-fix-elf-support-check.patch diff --git a/toolchain/gdb/patches/100-fix-elf-support-check.patch b/toolchain/gdb/patches/100-fix-elf-support-check.patch new file mode 100644 index 0000000000..fe612c38db --- /dev/null +++ b/toolchain/gdb/patches/100-fix-elf-support-check.patch @@ -0,0 +1,20 @@ +--- a/gdb/configure ++++ b/gdb/configure +@@ -16818,6 +16818,7 @@ else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + #include ++#include + #include "bfd.h" + #include "elf-bfd.h" + +--- a/gdb/acinclude.m4 ++++ b/gdb/acinclude.m4 +@@ -362,6 +362,7 @@ AC_DEFUN([GDB_AC_CHECK_BFD], [ + AC_CACHE_CHECK([$1], [$2], + [AC_TRY_LINK( + [#include ++ #include + #include "bfd.h" + #include "$4" + ], From 583739d22052de9bd89f5bd2ad31d8f33d23bea4 Mon Sep 17 00:00:00 2001 From: Paul Spooren Date: Tue, 18 May 2021 15:36:10 +0200 Subject: [PATCH 4/7] busybox: use $(AUTORELEASE) and SPDX use AUTORELEASE since BusyBox is often updaten and PKG_RELEASE is not consistently bumped. Also use SPDX license headers to be machine readable and bump the copyright year to 2021. Signed-off-by: Paul Spooren --- package/utils/busybox/Makefile | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/package/utils/busybox/Makefile b/package/utils/busybox/Makefile index 914507d364..d5253d60a7 100644 --- a/package/utils/busybox/Makefile +++ b/package/utils/busybox/Makefile @@ -1,15 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later # -# Copyright (C) 2006-2020 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# +# Copyright (C) 2006-2021 OpenWrt.org include $(TOPDIR)/rules.mk PKG_NAME:=busybox PKG_VERSION:=1.33.1 -PKG_RELEASE:=1 +PKG_RELEASE:=$(AUTORELEASE) PKG_FLAGS:=essential PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 From 7488eea6357506208c40a7f6d70e2ef659749ea7 Mon Sep 17 00:00:00 2001 From: Paul Spooren Date: Thu, 13 May 2021 23:57:45 +0200 Subject: [PATCH 5/7] busybox: show reproducible timestamp On login busybox shows a timestamp per default contianing the build date. Since the build date isn't reproducible per default this behaviour was disabled by default via 34df4d40 "busybox: disable timestamp in version". This commit modifies busybox so that the printed timestamp reproducible using SOURCE_DATE_EPOCH and therefore shouldn't be disabled anymore. Before: BusyBox v1.33.1 () built-in shell (ash) After: BusyBox v1.33.1 (2021-05-13 09:34:34 UTC) built-in shell (ash) Signed-off-by: Paul Spooren --- package/utils/busybox/Makefile | 4 - ...ATE_EPOCH-for-timestamp-if-available.patch | 80 +++++++++++++++++++ 2 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 package/utils/busybox/patches/530-use-SOURCE_DATE_EPOCH-for-timestamp-if-available.patch diff --git a/package/utils/busybox/Makefile b/package/utils/busybox/Makefile index d5253d60a7..cb26701a74 100644 --- a/package/utils/busybox/Makefile +++ b/package/utils/busybox/Makefile @@ -81,10 +81,6 @@ endef Package/busybox-selinux/conffiiles = $(Package/busybox/conffiles) endif -# don't create a version string containing the actual timestamp -export KCONFIG_NOTIMESTAMP=1 - - ifndef CONFIG_USE_MUSL LDLIBS:=m crypt endif diff --git a/package/utils/busybox/patches/530-use-SOURCE_DATE_EPOCH-for-timestamp-if-available.patch b/package/utils/busybox/patches/530-use-SOURCE_DATE_EPOCH-for-timestamp-if-available.patch new file mode 100644 index 0000000000..af473622ed --- /dev/null +++ b/package/utils/busybox/patches/530-use-SOURCE_DATE_EPOCH-for-timestamp-if-available.patch @@ -0,0 +1,80 @@ +From 59f773ee81a8945321f4aa20abc5e9577e6483e4 Mon Sep 17 00:00:00 2001 +From: Paul Spooren +Date: Thu, 13 May 2021 11:25:34 +0200 +Subject: [PATCH] use SOURCE_DATE_EPOCH for timestamp if available + +The SOURCE_DATE_EPOCH is an effort of the Reproducible Builds +organization to make timestamps/build dates in compiled tools +deterministic over several repetitive builds. + +Busybox shows by default the build date timestamp which changes whenever +compiled. To have a reasonable accurate build date while staying +reproducible, it's possible to use the *date of last source +modification* rather than the current time and date. + +Further information on SOURCE_DATE_EPOCH are available online [1]. + +This patch modifies `confdata.c` so that the content of the +SOURCE_DATE_EPOCH env variable is used as timestamp. + +To be independent of different timezones between builds, whenever +SOURCE_DATE_EPOCH is defined the GMT time is used. + +[1]: https://reproducible-builds.org/docs/source-date-epoch/ + +Signed-off-by: Paul Spooren +--- + scripts/kconfig/confdata.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c +index b05b96e45..73c25e3a8 100644 +--- a/scripts/kconfig/confdata.c ++++ b/scripts/kconfig/confdata.c +@@ -342,6 +342,8 @@ int conf_write(const char *name) + time_t now; + int use_timestamp = 1; + char *env; ++ char *source_date_epoch; ++ struct tm *build_time; + + dirname[0] = 0; + if (name && name[0]) { +@@ -378,7 +380,16 @@ int conf_write(const char *name) + } + sym = sym_lookup("KERNELVERSION", 0); + sym_calc_value(sym); +- time(&now); ++ ++ source_date_epoch = getenv("SOURCE_DATE_EPOCH"); ++ if (source_date_epoch && *source_date_epoch) { ++ now = strtoull(source_date_epoch, NULL, 10); ++ build_time = gmtime(&now); ++ } else { ++ time(&now); ++ build_time = localtime(&now); ++ } ++ + env = getenv("KCONFIG_NOTIMESTAMP"); + if (env && *env) + use_timestamp = 0; +@@ -398,14 +409,14 @@ int conf_write(const char *name) + if (use_timestamp) { + size_t ret = \ + strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP " +- "\"%Y-%m-%d %H:%M:%S %Z\"\n", localtime(&now)); ++ "\"%Y-%m-%d %H:%M:%S %Z\"\n", build_time); + /* if user has Factory timezone or some other odd install, the + * %Z above will overflow the string leaving us with undefined + * results ... so let's try again without the timezone. + */ + if (ret == 0) + strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP " +- "\"%Y-%m-%d %H:%M:%S\"\n", localtime(&now)); ++ "\"%Y-%m-%d %H:%M:%S\"\n", build_time); + } else { /* bbox */ + strcpy(buf, "#define AUTOCONF_TIMESTAMP \"\"\n"); + } +-- +2.30.2 + From ebeb7355f730df6c7c14753a556ada6c17b44c6d Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Wed, 12 May 2021 20:36:58 +0200 Subject: [PATCH 6/7] busybox: remove nslookup_lede/openwrt.patch The nslookup_lede/openwrt applet was introduced in de5b8e5. It was introduced because: Add a new LEDE nslookup applet which is compatible with musl libc and providing more features like ability to specify query type. In contrast to busybox' builtin nslookup applet, this variant does not rely on libc resolver internals but uses explicit send logic and the libresolv primitives to parse received DNS responses. In busybox this applet is added in 0dd3be8. In particular, this commit introduces the variable NSLOOKUP_BIG. We set the default to true and so nothing changes. Signed-off-by: Nick Hainke --- package/utils/busybox/Config-defaults.in | 10 +- package/utils/busybox/Makefile | 3 - .../utils/busybox/config/networking/Config.in | 12 - .../patches/230-add_nslookup_lede.patch | 971 ------------------ 4 files changed, 2 insertions(+), 994 deletions(-) delete mode 100644 package/utils/busybox/patches/230-add_nslookup_lede.patch diff --git a/package/utils/busybox/Config-defaults.in b/package/utils/busybox/Config-defaults.in index eb28bf6991..b6e3d7f35a 100644 --- a/package/utils/busybox/Config-defaults.in +++ b/package/utils/busybox/Config-defaults.in @@ -2459,17 +2459,11 @@ config BUSYBOX_DEFAULT_FEATURE_NETSTAT_PRG default y config BUSYBOX_DEFAULT_NSLOOKUP bool - default n + default y config BUSYBOX_DEFAULT_FEATURE_NSLOOKUP_BIG - bool - default n -config BUSYBOX_DEFAULT_FEATURE_NSLOOKUP_LONG_OPTIONS - bool - default n -config BUSYBOX_DEFAULT_NSLOOKUP_OPENWRT bool default y -config BUSYBOX_DEFAULT_FEATURE_NSLOOKUP_OPENWRT_LONG_OPTIONS +config BUSYBOX_DEFAULT_FEATURE_NSLOOKUP_LONG_OPTIONS bool default n config BUSYBOX_DEFAULT_NTPD diff --git a/package/utils/busybox/Makefile b/package/utils/busybox/Makefile index cb26701a74..be4a979350 100644 --- a/package/utils/busybox/Makefile +++ b/package/utils/busybox/Makefile @@ -86,9 +86,6 @@ LDLIBS:=m crypt endif LDLIBS += $(call BUSYBOX_IF_ENABLED,PAM,pam pam_misc pthread) -ifeq ($(CONFIG_USE_GLIBC),y) - LDLIBS += $(call BUSYBOX_IF_ENABLED,NSLOOKUP_OPENWRT,resolv) -endif ifeq ($(BUILD_VARIANT),selinux) LDLIBS += selinux sepol diff --git a/package/utils/busybox/config/networking/Config.in b/package/utils/busybox/config/networking/Config.in index 6608f5899d..3e1c4c4c04 100644 --- a/package/utils/busybox/config/networking/Config.in +++ b/package/utils/busybox/config/networking/Config.in @@ -774,19 +774,7 @@ config BUSYBOX_CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS bool "Enable long options" default BUSYBOX_DEFAULT_FEATURE_NSLOOKUP_LONG_OPTIONS depends on BUSYBOX_CONFIG_FEATURE_NSLOOKUP_BIG && BUSYBOX_CONFIG_LONG_OPTS -config BUSYBOX_CONFIG_NSLOOKUP_OPENWRT - bool "nslookup_openwrt" - depends on !BUSYBOX_CONFIG_NSLOOKUP - default BUSYBOX_DEFAULT_NSLOOKUP_OPENWRT - help - nslookup is a tool to query Internet name servers (LEDE flavor). -config BUSYBOX_CONFIG_FEATURE_NSLOOKUP_OPENWRT_LONG_OPTIONS - bool "Enable long options" - default BUSYBOX_DEFAULT_FEATURE_NSLOOKUP_OPENWRT_LONG_OPTIONS - depends on BUSYBOX_CONFIG_NSLOOKUP_OPENWRT && BUSYBOX_CONFIG_LONG_OPTS - help - Support long options for the nslookup applet. config BUSYBOX_CONFIG_NTPD bool "ntpd (22 kb)" default BUSYBOX_DEFAULT_NTPD diff --git a/package/utils/busybox/patches/230-add_nslookup_lede.patch b/package/utils/busybox/patches/230-add_nslookup_lede.patch deleted file mode 100644 index 280d4e238e..0000000000 --- a/package/utils/busybox/patches/230-add_nslookup_lede.patch +++ /dev/null @@ -1,971 +0,0 @@ -From ab0f8bb80527928f513297ab93e3ec8c8b48dd50 Mon Sep 17 00:00:00 2001 -From: Jo-Philipp Wich -Date: Tue, 14 Mar 2017 22:21:34 +0100 -Subject: [PATCH] networking: add LEDE nslookup applet - -Add a new LEDE nslookup applet which is compatible with musl libc -and providing more features like ability to specify query type. - -In contrast to busybox' builtin nslookup applet, this variant does -not rely on libc resolver internals but uses explicit send logic -and the libresolv primitives to parse received DNS responses. - -Signed-off-by: Jo-Philipp Wich ---- - Makefile.flags | 6 + - networking/nslookup_lede.c | 915 +++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 921 insertions(+) - create mode 100644 networking/nslookup_lede.c - ---- a/Makefile.flags -+++ b/Makefile.flags -@@ -158,6 +158,12 @@ endif - # libm may be needed for dc, awk, ntpd - # librt may be needed for clock_gettime() - -+# nslookup_lede might need the resolv library -+RESOLV_AVAILABLE := $(shell echo 'int main(void){res_init();return 0;}' >resolvtest.c; $(CC) $(CFLAGS) -include resolv.h -lresolv -o /dev/null resolvtest.c >/dev/null 2>&1 && echo "y"; rm resolvtest.c) -+ifeq ($(RESOLV_AVAILABLE),y) -+LDLIBS += resolv -+endif -+ - # libpam may use libpthread, libdl and/or libaudit. - # On some platforms that requires an explicit -lpthread, -ldl, -laudit. - # However, on *other platforms* it fails when some of those flags ---- /dev/null -+++ b/networking/nslookup_lede.c -@@ -0,0 +1,934 @@ -+/* -+ * nslookup_lede - musl compatible replacement for busybox nslookup -+ * -+ * Copyright (C) 2017 Jo-Philipp Wich -+ * -+ * Permission to use, copy, modify, and/or distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ */ -+ -+//config:config NSLOOKUP_OPENWRT -+//config: bool "nslookup_openwrt" -+//config: depends on !NSLOOKUP -+//config: default y -+//config: help -+//config: nslookup is a tool to query Internet name servers (LEDE flavor). -+//config: -+//config:config FEATURE_NSLOOKUP_OPENWRT_LONG_OPTIONS -+//config: bool "Enable long options" -+//config: default y -+//config: depends on NSLOOKUP_OPENWRT && LONG_OPTS -+//config: help -+//config: Support long options for the nslookup applet. -+ -+//applet:IF_NSLOOKUP_OPENWRT(APPLET(nslookup, BB_DIR_USR_BIN, BB_SUID_DROP)) -+ -+//kbuild:lib-$(CONFIG_NSLOOKUP_OPENWRT) += nslookup_lede.o -+ -+//usage:#define nslookup_lede_trivial_usage -+//usage: "[HOST] [SERVER]" -+//usage:#define nslookup_lede_full_usage "\n\n" -+//usage: "Query the nameserver for the IP address of the given HOST\n" -+//usage: "optionally using a specified DNS server" -+//usage: -+//usage:#define nslookup_lede_example_usage -+//usage: "$ nslookup localhost\n" -+//usage: "Server: default\n" -+//usage: "Address: default\n" -+//usage: "\n" -+//usage: "Name: debian\n" -+//usage: "Address: 127.0.0.1\n" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "libbb.h" -+ -+struct ns { -+ const char *name; -+ len_and_sockaddr addr; -+ int failures; -+ int replies; -+}; -+ -+struct query { -+ const char *name; -+ size_t qlen, rlen; -+ unsigned char query[512], reply[512]; -+ unsigned long latency; -+ int rcode, n_ns; -+}; -+ -+static struct { -+ int type; -+ const char *name; -+} qtypes[] = { -+ { ns_t_soa, "SOA" }, -+ { ns_t_ns, "NS" }, -+ { ns_t_a, "A" }, -+#if ENABLE_FEATURE_IPV6 -+ { ns_t_aaaa, "AAAA" }, -+#endif -+ { ns_t_cname, "CNAME" }, -+ { ns_t_mx, "MX" }, -+ { ns_t_txt, "TXT" }, -+ { ns_t_srv, "SRV" }, -+ { ns_t_ptr, "PTR" }, -+ { ns_t_any, "ANY" }, -+ { } -+}; -+ -+static const char *rcodes[] = { -+ "NOERROR", -+ "FORMERR", -+ "SERVFAIL", -+ "NXDOMAIN", -+ "NOTIMP", -+ "REFUSED", -+ "YXDOMAIN", -+ "YXRRSET", -+ "NXRRSET", -+ "NOTAUTH", -+ "NOTZONE", -+ "RESERVED11", -+ "RESERVED12", -+ "RESERVED13", -+ "RESERVED14", -+ "RESERVED15", -+ "BADVERS" -+}; -+ -+static unsigned int default_port = 53; -+static unsigned int default_retry = 2; -+static unsigned int default_timeout = 5; -+ -+ -+static int parse_reply(const unsigned char *msg, size_t len, int *bb_style_counter) -+{ -+ ns_msg handle; -+ ns_rr rr; -+ int i, n, rdlen; -+ const char *format = NULL; -+ char astr[INET6_ADDRSTRLEN], dname[MAXDNAME]; -+ const unsigned char *cp; -+ -+ if (ns_initparse(msg, len, &handle) != 0) { -+ //fprintf(stderr, "Unable to parse reply: %s\n", strerror(errno)); -+ return -1; -+ } -+ -+ for (i = 0; i < ns_msg_count(handle, ns_s_an); i++) { -+ if (ns_parserr(&handle, ns_s_an, i, &rr) != 0) { -+ //fprintf(stderr, "Unable to parse resource record: %s\n", strerror(errno)); -+ return -1; -+ } -+ -+ if (bb_style_counter && *bb_style_counter == 1) -+ printf("Name: %s\n", ns_rr_name(rr)); -+ -+ rdlen = ns_rr_rdlen(rr); -+ -+ switch (ns_rr_type(rr)) -+ { -+ case ns_t_a: -+ if (rdlen != 4) { -+ //fprintf(stderr, "Unexpected A record length\n"); -+ return -1; -+ } -+ inet_ntop(AF_INET, ns_rr_rdata(rr), astr, sizeof(astr)); -+ if (bb_style_counter) -+ printf("Address %d: %s\n", (*bb_style_counter)++, astr); -+ else -+ printf("Name:\t%s\nAddress: %s\n", ns_rr_name(rr), astr); -+ break; -+ -+#if ENABLE_FEATURE_IPV6 -+ case ns_t_aaaa: -+ if (rdlen != 16) { -+ //fprintf(stderr, "Unexpected AAAA record length\n"); -+ return -1; -+ } -+ inet_ntop(AF_INET6, ns_rr_rdata(rr), astr, sizeof(astr)); -+ if (bb_style_counter) -+ printf("Address %d: %s\n", (*bb_style_counter)++, astr); -+ else -+ printf("%s\thas AAAA address %s\n", ns_rr_name(rr), astr); -+ break; -+#endif -+ -+ case ns_t_ns: -+ if (!format) -+ format = "%s\tnameserver = %s\n"; -+ /* fall through */ -+ -+ case ns_t_cname: -+ if (!format) -+ format = "%s\tcanonical name = %s\n"; -+ /* fall through */ -+ -+ case ns_t_ptr: -+ if (!format) -+ format = "%s\tname = %s\n"; -+ if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), -+ ns_rr_rdata(rr), dname, sizeof(dname)) < 0) { -+ //fprintf(stderr, "Unable to uncompress domain: %s\n", strerror(errno)); -+ return -1; -+ } -+ printf(format, ns_rr_name(rr), dname); -+ break; -+ -+ case ns_t_mx: -+ if (rdlen < 2) { -+ fprintf(stderr, "MX record too short\n"); -+ return -1; -+ } -+ n = ns_get16(ns_rr_rdata(rr)); -+ if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), -+ ns_rr_rdata(rr) + 2, dname, sizeof(dname)) < 0) { -+ //fprintf(stderr, "Cannot uncompress MX domain: %s\n", strerror(errno)); -+ return -1; -+ } -+ printf("%s\tmail exchanger = %d %s\n", ns_rr_name(rr), n, dname); -+ break; -+ -+ case ns_t_txt: -+ if (rdlen < 1) { -+ //fprintf(stderr, "TXT record too short\n"); -+ return -1; -+ } -+ n = *(unsigned char *)ns_rr_rdata(rr); -+ if (n > 0) { -+ memset(dname, 0, sizeof(dname)); -+ memcpy(dname, ns_rr_rdata(rr) + 1, n); -+ printf("%s\ttext = \"%s\"\n", ns_rr_name(rr), dname); -+ } -+ break; -+ -+ case ns_t_srv: -+ if (rdlen < 6) { -+ //printf("SRV record too short\n"); -+ return -1; -+ } -+ -+ cp = ns_rr_rdata(rr); -+ n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), -+ cp + 6, dname, sizeof(dname)); -+ -+ if (n < 0) { -+ //printf("Unable to uncompress domain: %s\n", strerror(errno)); -+ return -1; -+ } -+ -+ printf("%s\tservice = %hu %hu %hu %s\n", ns_rr_name(rr), -+ ns_get16(cp), ns_get16(cp + 2), ns_get16(cp + 4), dname); -+ break; -+ -+ case ns_t_soa: -+ if (rdlen < 20) { -+ //fprintf(stderr, "SOA record too short\n"); -+ return -1; -+ } -+ -+ printf("%s\n", ns_rr_name(rr)); -+ -+ cp = ns_rr_rdata(rr); -+ n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), -+ cp, dname, sizeof(dname)); -+ -+ if (n < 0) { -+ //fprintf(stderr, "Unable to uncompress domain: %s\n", strerror(errno)); -+ return -1; -+ } -+ -+ printf("\torigin = %s\n", dname); -+ cp += n; -+ -+ n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), -+ cp, dname, sizeof(dname)); -+ -+ if (n < 0) { -+ //fprintf(stderr, "Unable to uncompress domain: %s\n", strerror(errno)); -+ return -1; -+ } -+ -+ printf("\tmail addr = %s\n", dname); -+ cp += n; -+ -+ printf("\tserial = %lu\n", ns_get32(cp)); -+ cp += 4; -+ -+ printf("\trefresh = %lu\n", ns_get32(cp)); -+ cp += 4; -+ -+ printf("\tretry = %lu\n", ns_get32(cp)); -+ cp += 4; -+ -+ printf("\texpire = %lu\n", ns_get32(cp)); -+ cp += 4; -+ -+ printf("\tminimum = %lu\n", ns_get32(cp)); -+ break; -+ -+ default: -+ break; -+ } -+ } -+ -+ return i; -+} -+ -+static int parse_nsaddr(const char *addrstr, len_and_sockaddr *lsa) -+{ -+ char *eptr, *hash, ifname[IFNAMSIZ]; -+ unsigned int port = default_port; -+ unsigned int scope = 0; -+ -+ hash = strchr(addrstr, '#'); -+ -+ if (hash) { -+ *hash++ = '\0'; -+ port = strtoul(hash, &eptr, 10); -+ -+ if (eptr == hash || *eptr != '\0' || port > 65535) { -+ errno = EINVAL; -+ return -1; -+ } -+ } -+ -+ hash = strchr(addrstr, '%'); -+ -+ if (hash) { -+ for (eptr = ++hash; *eptr != '\0' && *eptr != '#'; eptr++) { -+ if ((eptr - hash) >= IFNAMSIZ) { -+ errno = ENODEV; -+ return -1; -+ } -+ -+ ifname[eptr - hash] = *eptr; -+ } -+ -+ ifname[eptr - hash] = '\0'; -+ scope = if_nametoindex(ifname); -+ -+ if (scope == 0) { -+ errno = ENODEV; -+ return -1; -+ } -+ } -+ -+#if ENABLE_FEATURE_IPV6 -+ if (inet_pton(AF_INET6, addrstr, &lsa->u.sin6.sin6_addr)) { -+ lsa->u.sin6.sin6_family = AF_INET6; -+ lsa->u.sin6.sin6_port = htons(port); -+ lsa->u.sin6.sin6_scope_id = scope; -+ lsa->len = sizeof(lsa->u.sin6); -+ return 0; -+ } -+#endif -+ -+ if (!scope && inet_pton(AF_INET, addrstr, &lsa->u.sin.sin_addr)) { -+ lsa->u.sin.sin_family = AF_INET; -+ lsa->u.sin.sin_port = htons(port); -+ lsa->len = sizeof(lsa->u.sin); -+ return 0; -+ } -+ -+ errno = EINVAL; -+ return -1; -+} -+ -+static char *make_ptr(const char *addrstr) -+{ -+ const char *hexdigit = "0123456789abcdef"; -+ static char ptrstr[73]; -+ unsigned char addr[16]; -+ char *ptr = ptrstr; -+ int i; -+ -+ if (inet_pton(AF_INET6, addrstr, addr)) { -+ if (memcmp(addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12) != 0) { -+ for (i = 0; i < 16; i++) { -+ *ptr++ = hexdigit[(unsigned char)addr[15 - i] & 0xf]; -+ *ptr++ = '.'; -+ *ptr++ = hexdigit[(unsigned char)addr[15 - i] >> 4]; -+ *ptr++ = '.'; -+ } -+ strcpy(ptr, "ip6.arpa"); -+ } -+ else { -+ sprintf(ptr, "%u.%u.%u.%u.in-addr.arpa", -+ addr[15], addr[14], addr[13], addr[12]); -+ } -+ -+ return ptrstr; -+ } -+ -+ if (inet_pton(AF_INET, addrstr, addr)) { -+ sprintf(ptr, "%u.%u.%u.%u.in-addr.arpa", -+ addr[3], addr[2], addr[1], addr[0]); -+ return ptrstr; -+ } -+ -+ return NULL; -+} -+ -+static unsigned long mtime(void) -+{ -+ struct timespec ts; -+ clock_gettime(CLOCK_REALTIME, &ts); -+ return (unsigned long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; -+} -+ -+#if ENABLE_FEATURE_IPV6 -+static void to_v4_mapped(len_and_sockaddr *a) -+{ -+ if (a->u.sa.sa_family != AF_INET) -+ return; -+ -+ memcpy(a->u.sin6.sin6_addr.s6_addr + 12, -+ &a->u.sin.sin_addr, 4); -+ -+ memcpy(a->u.sin6.sin6_addr.s6_addr, -+ "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); -+ -+ a->u.sin6.sin6_family = AF_INET6; -+ a->u.sin6.sin6_flowinfo = 0; -+ a->u.sin6.sin6_scope_id = 0; -+ a->len = sizeof(a->u.sin6); -+} -+#endif -+ -+ -+/* -+ * Function logic borrowed & modified from musl libc, res_msend.c -+ */ -+ -+static int send_queries(struct ns *ns, int n_ns, struct query *queries, int n_queries) -+{ -+ int fd; -+ int timeout = default_timeout * 1000, retry_interval, servfail_retry = 0; -+ len_and_sockaddr from = { }; -+#if ENABLE_FEATURE_IPV6 -+ int one = 1; -+#endif -+ int recvlen = 0; -+ int n_replies = 0; -+ struct pollfd pfd; -+ unsigned long t0, t1, t2; -+ int nn, qn, next_query = 0; -+ -+ from.u.sa.sa_family = AF_INET; -+ from.len = sizeof(from.u.sin); -+ -+#if ENABLE_FEATURE_IPV6 -+ for (nn = 0; nn < n_ns; nn++) { -+ if (ns[nn].addr.u.sa.sa_family == AF_INET6) { -+ from.u.sa.sa_family = AF_INET6; -+ from.len = sizeof(from.u.sin6); -+ break; -+ } -+ } -+#endif -+ -+ /* Get local address and open/bind a socket */ -+ fd = socket(from.u.sa.sa_family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); -+ -+#if ENABLE_FEATURE_IPV6 -+ /* Handle case where system lacks IPv6 support */ -+ if (fd < 0 && from.u.sa.sa_family == AF_INET6 && errno == EAFNOSUPPORT) { -+ fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); -+ from.u.sa.sa_family = AF_INET; -+ } -+#endif -+ -+ if (fd < 0) -+ return -1; -+ -+ if (bind(fd, &from.u.sa, from.len) < 0) { -+ close(fd); -+ return -1; -+ } -+ -+#if ENABLE_FEATURE_IPV6 -+ /* Convert any IPv4 addresses in a mixed environment to v4-mapped */ -+ if (from.u.sa.sa_family == AF_INET6) { -+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); -+ -+ for (nn = 0; nn < n_ns; nn++) -+ to_v4_mapped(&ns[nn].addr); -+ } -+#endif -+ -+ pfd.fd = fd; -+ pfd.events = POLLIN; -+ retry_interval = timeout / default_retry; -+ t0 = t2 = mtime(); -+ t1 = t2 - retry_interval; -+ -+ for (; t2 - t0 < timeout; t2 = mtime()) { -+ if (t2 - t1 >= retry_interval) { -+ for (qn = 0; qn < n_queries; qn++) { -+ if (queries[qn].rlen) -+ continue; -+ -+ for (nn = 0; nn < n_ns; nn++) { -+ sendto(fd, queries[qn].query, queries[qn].qlen, -+ MSG_NOSIGNAL, &ns[nn].addr.u.sa, ns[nn].addr.len); -+ } -+ } -+ -+ t1 = t2; -+ servfail_retry = 2 * n_queries; -+ } -+ -+ /* Wait for a response, or until time to retry */ -+ if (poll(&pfd, 1, t1+retry_interval-t2) <= 0) -+ continue; -+ -+ while (1) { -+ recvlen = recvfrom(fd, queries[next_query].reply, -+ sizeof(queries[next_query].reply), 0, -+ &from.u.sa, &from.len); -+ -+ /* read error */ -+ if (recvlen < 0) -+ break; -+ -+ /* Ignore non-identifiable packets */ -+ if (recvlen < 4) -+ continue; -+ -+ /* Ignore replies from addresses we didn't send to */ -+ for (nn = 0; nn < n_ns; nn++) -+ if (memcmp(&from.u.sa, &ns[nn].addr.u.sa, from.len) == 0) -+ break; -+ -+ if (nn >= n_ns) -+ continue; -+ -+ /* Find which query this answer goes with, if any */ -+ for (qn = next_query; qn < n_queries; qn++) -+ if (!memcmp(queries[next_query].reply, queries[qn].query, 2)) -+ break; -+ -+ if (qn >= n_queries || queries[qn].rlen) -+ continue; -+ -+ queries[qn].rcode = queries[next_query].reply[3] & 15; -+ queries[qn].latency = mtime() - t0; -+ queries[qn].n_ns = nn; -+ -+ ns[nn].replies++; -+ -+ /* Only accept positive or negative responses; -+ * retry immediately on server failure, and ignore -+ * all other codes such as refusal. */ -+ switch (queries[qn].rcode) { -+ case 0: -+ case 3: -+ break; -+ -+ case 2: -+ if (servfail_retry && servfail_retry--) { -+ ns[nn].failures++; -+ sendto(fd, queries[qn].query, queries[qn].qlen, -+ MSG_NOSIGNAL, &ns[nn].addr.u.sa, ns[nn].addr.len); -+ } -+ /* fall through */ -+ -+ default: -+ continue; -+ } -+ -+ /* Store answer */ -+ n_replies++; -+ -+ queries[qn].rlen = recvlen; -+ -+ if (qn == next_query) { -+ while (next_query < n_queries) { -+ if (!queries[next_query].rlen) -+ break; -+ -+ next_query++; -+ } -+ } -+ else { -+ memcpy(queries[qn].reply, queries[next_query].reply, recvlen); -+ } -+ -+ if (next_query >= n_queries) -+ return n_replies; -+ } -+ } -+ -+ return n_replies; -+} -+ -+static struct ns *add_ns(struct ns **ns, int *n_ns, const char *addr) -+{ -+ char portstr[sizeof("65535")], *p; -+ len_and_sockaddr a = { }; -+ struct ns *tmp; -+ struct addrinfo *ai, *aip, hints = { -+ .ai_flags = AI_NUMERICSERV, -+ .ai_socktype = SOCK_DGRAM -+ }; -+ -+ if (parse_nsaddr(addr, &a)) { -+ /* Maybe we got a domain name, attempt to resolve it using the standard -+ * resolver routines */ -+ -+ p = strchr(addr, '#'); -+ snprintf(portstr, sizeof(portstr), "%hu", -+ (unsigned short)(p ? strtoul(p, NULL, 10) : default_port)); -+ -+ if (!getaddrinfo(addr, portstr, &hints, &ai)) { -+ for (aip = ai; aip; aip = aip->ai_next) { -+ if (aip->ai_addr->sa_family != AF_INET && -+ aip->ai_addr->sa_family != AF_INET6) -+ continue; -+ -+#if ! ENABLE_FEATURE_IPV6 -+ if (aip->ai_addr->sa_family != AF_INET) -+ continue; -+#endif -+ -+ tmp = realloc(*ns, sizeof(**ns) * (*n_ns + 1)); -+ -+ if (!tmp) -+ return NULL; -+ -+ *ns = tmp; -+ -+ (*ns)[*n_ns].name = addr; -+ (*ns)[*n_ns].replies = 0; -+ (*ns)[*n_ns].failures = 0; -+ (*ns)[*n_ns].addr.len = aip->ai_addrlen; -+ -+ memcpy(&(*ns)[*n_ns].addr.u.sa, aip->ai_addr, aip->ai_addrlen); -+ -+ (*n_ns)++; -+ } -+ -+ freeaddrinfo(ai); -+ -+ return &(*ns)[*n_ns]; -+ } -+ -+ return NULL; -+ } -+ -+ tmp = realloc(*ns, sizeof(**ns) * (*n_ns + 1)); -+ -+ if (!tmp) -+ return NULL; -+ -+ *ns = tmp; -+ -+ (*ns)[*n_ns].addr = a; -+ (*ns)[*n_ns].name = addr; -+ (*ns)[*n_ns].replies = 0; -+ (*ns)[*n_ns].failures = 0; -+ -+ return &(*ns)[(*n_ns)++]; -+} -+ -+static int parse_resolvconf(struct ns **ns, int *n_ns) -+{ -+ int prev_n_ns = *n_ns; -+ char line[128], *p; -+ FILE *resolv; -+ -+ if ((resolv = fopen("/etc/resolv.conf", "r")) != NULL) { -+ while (fgets(line, sizeof(line), resolv)) { -+ p = strtok(line, " \t\n"); -+ -+ if (!p || strcmp(p, "nameserver")) -+ continue; -+ -+ p = strtok(NULL, " \t\n"); -+ -+ if (!p) -+ continue; -+ -+ if (!add_ns(ns, n_ns, strdup(p))) { -+ free(p); -+ break; -+ } -+ } -+ -+ fclose(resolv); -+ } -+ -+ return *n_ns - prev_n_ns; -+} -+ -+static struct query *add_query(struct query **queries, int *n_queries, -+ int type, const char *dname) -+{ -+ struct query *tmp; -+ ssize_t qlen; -+ -+ tmp = realloc(*queries, sizeof(**queries) * (*n_queries + 1)); -+ -+ if (!tmp) -+ return NULL; -+ -+ memset(&tmp[*n_queries], 0, sizeof(*tmp)); -+ -+ qlen = res_mkquery(QUERY, dname, C_IN, type, NULL, 0, NULL, -+ tmp[*n_queries].query, sizeof(tmp[*n_queries].query)); -+ -+ tmp[*n_queries].qlen = qlen; -+ tmp[*n_queries].name = dname; -+ *queries = tmp; -+ -+ return &tmp[(*n_queries)++]; -+} -+ -+static char *sal2str(len_and_sockaddr *a) -+{ -+ static char buf[INET6_ADDRSTRLEN + 1 + IFNAMSIZ + 1 + 5 + 1]; -+ char *p = buf; -+ -+#if ENABLE_FEATURE_IPV6 -+ if (a->u.sa.sa_family == AF_INET6) { -+ inet_ntop(AF_INET6, &a->u.sin6.sin6_addr, buf, sizeof(buf)); -+ p += strlen(p); -+ -+ if (a->u.sin6.sin6_scope_id) { -+ if (if_indextoname(a->u.sin6.sin6_scope_id, p + 1)) { -+ *p++ = '%'; -+ p += strlen(p); -+ } -+ } -+ } -+ else -+#endif -+ { -+ inet_ntop(AF_INET, &a->u.sin.sin_addr, buf, sizeof(buf)); -+ p += strlen(p); -+ } -+ -+ sprintf(p, "#%hu", ntohs(a->u.sin.sin_port)); -+ -+ return buf; -+} -+ -+int nslookup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -+int nslookup_main(int argc, char **argv) -+{ -+ int rc = 1; -+ char *ptr, *chr; -+ struct ns *ns = NULL; -+ struct query *queries = NULL; -+ llist_t *type_strings = NULL; -+ int n_ns = 0, n_queries = 0; -+ int c, opts, option_index = 0; -+ int stats = 0, bb_style_counter = 0; -+ unsigned int types = 0; -+ HEADER *header; -+ -+#if ENABLE_FEATURE_NSLOOKUP_OPENWRT_LONG_OPTIONS -+ static const char nslookup_longopts[] ALIGN1 = -+ "type\0" Required_argument "q" -+ "querytype\0" Required_argument "q" -+ "port\0" Required_argument "p" -+ "retry\0" Required_argument "r" -+ "timeout\0" Required_argument "t" -+ "stats\0" No_argument "s" -+ ; -+ -+ opts = getopt32long(argv, "^" "+q:*p:+r:+t:+s" "\0" "q::", -+ nslookup_longopts, -+ &type_strings, &default_port, -+ &default_retry, &default_timeout); -+#else -+ opts = getopt32(argv, "^" "+q:*p:+r:+t:+s" "\0" "q::", -+ &type_strings, &default_port, -+ &default_retry, &default_timeout); -+#endif -+ -+ while (type_strings) { -+ ptr = llist_pop(&type_strings); -+ -+ /* skip leading text, e.g. when invoked with -querytype=AAAA */ -+ if ((chr = strchr(ptr, '=')) != NULL) -+ ptr = chr + 1; -+ -+ for (c = 0; qtypes[c].name; c++) -+ if (!strcmp(qtypes[c].name, ptr)) -+ break; -+ -+ if (!qtypes[c].name) { -+ fprintf(stderr, "Invalid query type \"%s\"\n", ptr); -+ goto out; -+ } -+ -+ types |= (1 << c); -+ } -+ -+ if (default_port > 65535) { -+ fprintf(stderr, "Invalid server port\n"); -+ goto out; -+ } -+ -+ if (!default_retry) { -+ fprintf(stderr, "Invalid retry value\n"); -+ goto out; -+ } -+ -+ if (!default_timeout) { -+ fprintf(stderr, "Invalid timeout value\n"); -+ goto out; -+ } -+ -+ stats = (opts & 16); -+ -+ if (optind >= argc) -+ bb_show_usage(); -+ -+ for (option_index = optind; -+ option_index < ((argc - optind) > 1 ? argc - 1 : argc); -+ option_index++) { -+ -+ /* No explicit type given, guess query type. -+ * If we can convert the domain argument into a ptr (means that -+ * inet_pton() could read it) we assume a PTR request, else -+ * we issue A+AAAA queries and switch to an output format -+ * mimicking the one of the traditional nslookup applet. */ -+ if (types == 0) { -+ ptr = make_ptr(argv[option_index]); -+ -+ if (ptr) { -+ add_query(&queries, &n_queries, T_PTR, ptr); -+ } -+ else { -+ bb_style_counter = 1; -+ add_query(&queries, &n_queries, T_A, argv[option_index]); -+#if ENABLE_FEATURE_IPV6 -+ add_query(&queries, &n_queries, T_AAAA, argv[option_index]); -+#endif -+ } -+ } -+ else { -+ for (c = 0; qtypes[c].name; c++) -+ if (types & (1 << c)) -+ add_query(&queries, &n_queries, qtypes[c].type, -+ argv[option_index]); -+ } -+ } -+ -+ /* Use given DNS server if present */ -+ if (option_index < argc) { -+ if (!add_ns(&ns, &n_ns, argv[option_index])) { -+ fprintf(stderr, "Invalid NS server address \"%s\": %s\n", -+ argv[option_index], strerror(errno)); -+ goto out; -+ } -+ } -+ else { -+ parse_resolvconf(&ns, &n_ns); -+ } -+ -+ /* Fall back to localhost if we could not find NS in resolv.conf */ -+ if (n_ns == 0) { -+ add_ns(&ns, &n_ns, "127.0.0.1"); -+ } -+ -+ for (c = 0; c < n_ns; c++) { -+ rc = send_queries(&ns[c], 1, queries, n_queries); -+ -+ if (rc < 0) { -+ fprintf(stderr, "Failed to send queries: %s\n", strerror(errno)); -+ goto out; -+ } else if (rc > 0) { -+ break; -+ } -+ } -+ -+ if (c >= n_ns) { -+ fprintf(stderr, -+ ";; connection timed out; no servers could be reached\n\n"); -+ -+ return 1; -+ } -+ -+ printf("Server:\t\t%s\n", ns[c].name); -+ printf("Address:\t%s\n", sal2str(&ns[c].addr)); -+ -+ if (stats) { -+ printf("Replies:\t%d\n", ns[c].replies); -+ printf("Failures:\t%d\n", ns[c].failures); -+ } -+ -+ printf("\n"); -+ -+ for (rc = 0; rc < n_queries; rc++) { -+ if (stats) { -+ printf("Query #%d completed in %lums:\n", rc, queries[rc].latency); -+ } -+ -+ if (queries[rc].rcode != 0) { -+ printf("** server can't find %s: %s\n", queries[rc].name, -+ rcodes[queries[rc].rcode]); -+ continue; -+ } -+ -+ c = 0; -+ -+ if (queries[rc].rlen) { -+ if (!bb_style_counter) { -+ header = (HEADER *)queries[rc].reply; -+ -+ if (!header->aa) -+ printf("Non-authoritative answer:\n"); -+ -+ c = parse_reply(queries[rc].reply, queries[rc].rlen, NULL); -+ } -+ else { -+ c = parse_reply(queries[rc].reply, queries[rc].rlen, -+ &bb_style_counter); -+ } -+ } -+ -+ if (c == 0) -+ printf("*** Can't find %s: No answer\n", queries[rc].name); -+ else if (c < 0) -+ printf("*** Can't find %s: Parse error\n", queries[rc].name); -+ -+ if (!bb_style_counter) -+ printf("\n"); -+ } -+ -+ rc = 0; -+ -+out: -+ if (n_ns) -+ free(ns); -+ -+ if (n_queries) -+ free(queries); -+ -+ return rc; -+} From 410922855493b40d8fc67f6f1e09cf7713d5dcea Mon Sep 17 00:00:00 2001 From: Philip Prindeville Date: Wed, 5 May 2021 17:43:55 -0600 Subject: [PATCH 7/7] busybox: preserve crontabs /etc/syslog.conf is used by sysklogd, and /etc/crontabs is used by crond, both features of busybox. Given this, ownership for these files should be bound to busybox, especially if one day there's a way to do an in-place opkg update of busybox. There's also the busybox provided syslogd which uses this file if CONFIG_BUSYBOX_FEATURE_SYSLOGD_CFG is set. Signed-off-by: Philip Prindeville --- package/base-files/Makefile | 1 - package/utils/busybox/Makefile | 23 +++++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/package/base-files/Makefile b/package/base-files/Makefile index 950931a605..89a8551ccd 100644 --- a/package/base-files/Makefile +++ b/package/base-files/Makefile @@ -47,7 +47,6 @@ define Package/base-files/conffiles /etc/config/ /etc/config/network /etc/config/system -/etc/crontabs/ /etc/dropbear/ /etc/ethers /etc/group diff --git a/package/utils/busybox/Makefile b/package/utils/busybox/Makefile index be4a979350..e5e318471d 100644 --- a/package/utils/busybox/Makefile +++ b/package/utils/busybox/Makefile @@ -73,14 +73,25 @@ define Package/busybox/config source "$(SOURCE)/Config.in" endef -ifdef CONFIG_BUSYBOX_CONFIG_FEATURE_SYSLOG -define Package/busybox/conffiles +ifneq ($(CONFIG_BUSYBOX_$(BUSYBOX_SYM)_FEATURE_SYSLOG)$(CONFIG_BUSYBOX_$(BUSYBOX_SYM)_FEATURE_SYSLOGD_CFG),) +define Package/busybox/conffiles/syslog /etc/syslog.conf endef - -Package/busybox-selinux/conffiiles = $(Package/busybox/conffiles) endif +ifneq ($(CONFIG_BUSYBOX_$(BUSYBOX_SYM)_CROND),) +define Package/busybox/conffiles/crond +/etc/crontabs/ +endef +endif + +define Package/busybox/conffiles +$(Package/busybox/conffiles/syslog) +$(Package/busybox/conffiles/crond) +endef + +Package/busybox-selinux/conffiles = $(Package/busybox/conffiles) + ifndef CONFIG_USE_MUSL LDLIBS:=m crypt endif @@ -129,8 +140,12 @@ define Package/busybox/install $(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_DIR) $(1)/usr/sbin $(CP) $(PKG_INSTALL_DIR)/* $(1)/ +ifneq ($(CONFIG_BUSYBOX_$(BUSYBOX_SYM)_FEATURE_SYSLOG)$(CONFIG_BUSYBOX_$(BUSYBOX_SYM)_FEATURE_SYSLOGD_CFG),) + touch $(1)/etc/syslog.conf +endif ifneq ($(CONFIG_BUSYBOX_$(BUSYBOX_SYM)_CROND),) $(INSTALL_BIN) ./files/cron $(1)/etc/init.d/cron + $(INSTALL_DIR) $(1)/etc/crontabs endif ifneq ($(CONFIG_BUSYBOX_$(BUSYBOX_SYM)_NTPD),) $(INSTALL_BIN) ./files/sysntpd $(1)/etc/init.d/sysntpd