-From 8c1440a0934dd8b3ad6aae48d6653b5ba6fce8a1 Mon Sep 17 00:00:00 2001
+From ab0f8bb80527928f513297ab93e3ec8c8b48dd50 Mon Sep 17 00:00:00 2001
From: Jo-Philipp Wich <jo@mein.io>
Date: Tue, 14 Mar 2017 22:21:34 +0100
Subject: [PATCH] networking: add LEDE nslookup applet
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
---
- networking/nslookup_lede.c | 869 +++++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 875 insertions(+)
+ Makefile.flags | 6 +
+ networking/nslookup_lede.c | 915 +++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 921 insertions(+)
create mode 100644 networking/nslookup_lede.c
-diff --git a/networking/nslookup_lede.c b/networking/nslookup_lede.c
-new file mode 100644
-index 0000000..fe927ad
+--- a/Makefile.flags
++++ b/Makefile.flags
+@@ -134,6 +134,12 @@ else
+ LDLIBS += m
+ endif
+
++# 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,869 @@
+@@ -0,0 +1,914 @@
+/*
+ * nslookup_lede - musl compatible replacement for busybox nslookup
+ *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
-+//config:config NSLOOKUP_LEDE
-+//config: bool "nslookup_lede"
++//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_LEDE_LONG_OPTIONS
++//config:config FEATURE_NSLOOKUP_OPENWRT_LONG_OPTIONS
+//config: bool "Enable long options"
+//config: default y
-+//config: depends on NSLOOKUP_LEDE && LONG_OPTS
++//config: depends on NSLOOKUP_OPENWRT && LONG_OPTS
+//config: help
+//config: Support long options for the nslookup applet.
+
-+//applet:IF_NSLOOKUP_LEDE(APPLET(nslookup, BB_DIR_USR_BIN, BB_SUID_DROP))
++//applet:IF_NSLOOKUP_OPENWRT(APPLET(nslookup, BB_DIR_USR_BIN, BB_SUID_DROP))
+
-+//kbuild:lib-$(CONFIG_NSLOOKUP_LEDE) += nslookup_lede.o
++//kbuild:lib-$(CONFIG_NSLOOKUP_OPENWRT) += nslookup_lede.o
+
+//usage:#define nslookup_lede_trivial_usage
+//usage: "[HOST] [SERVER]"
+ { 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" },
+static unsigned int default_timeout = 5;
+
+
-+static int parse_reply(const unsigned char *msg, size_t len)
++static int parse_reply(const unsigned char *msg, size_t len, int *bb_style_counter)
+{
+ ns_msg handle;
+ ns_rr rr;
+ 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))
+ return -1;
+ }
+ inet_ntop(AF_INET, ns_rr_rdata(rr), astr, sizeof(astr));
-+ printf("Name:\t%s\nAddress: %s\n", ns_rr_name(rr), 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));
-+ printf("%s\thas AAAA address %s\n", ns_rr_name(rr), 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)
+ }
+ }
+
++#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->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;
+ 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)
+ a->u.sin6.sin6_scope_id = 0;
+ a->len = sizeof(a->u.sin6);
+}
++#endif
+
+
+/*
+ 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;
+ 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;
+ 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;
+ 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;
+ for (aip = ai; aip; aip = aip->ai_next) {
+ if (aip->ai_addr->sa_family != AF_INET &&
+ aip->ai_addr->sa_family != AF_INET6)
-+ continue;
++ continue;
++
++#if ! ENABLE_FEATURE_IPV6
++ if (aip->ai_addr->sa_family != AF_INET)
++ continue;
++#endif
+
+ tmp = realloc(*ns, sizeof(**ns) * (*n_ns + 1));
+
+ 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);
+ }
+ }
+ }
-+ else {
++ else
++#endif
++ {
+ inet_ntop(AF_INET, &a->u.sin.sin_addr, buf, sizeof(buf));
+ p += strlen(p);
+ }
+
-+ sprintf(p, "#%hu", ntohs(a->u.sin6.sin6_port));
++ sprintf(p, "#%hu", ntohs(a->u.sin.sin_port));
+
+ return buf;
+}
+
-+
-+#if ENABLE_FEATURE_NSLOOKUP_LEDE_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" Required_argument "s"
-+ ;
-+#endif
-+
+int nslookup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int nslookup_main(int argc, char **argv)
+{
+ llist_t *type_strings = NULL;
+ int n_ns = 0, n_queries = 0;
+ int c, opts, option_index = 0;
-+ int stats = 0;
++ int stats = 0, bb_style_counter = 0;
+ unsigned int types = 0;
+ HEADER *header;
+
-+#if ENABLE_FEATURE_NSLOOKUP_LEDE_LONG_OPTIONS
-+ applet_long_options = nslookup_longopts;
-+#endif
++#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 = getopt32(argv, "+q:*p:+r:+t:+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;
-+ *ptr++ = 0;
-+ }
++ if ((chr = strchr(ptr, '=')) != NULL)
++ ptr = chr + 1;
+
+ for (c = 0; qtypes[c].name; c++)
+ if (!strcmp(qtypes[c].name, ptr))
+ /* 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 queries. */
++ * 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)
++ if (ptr) {
+ add_query(&queries, &n_queries, T_PTR, ptr);
-+ else
++ }
++ 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++)
+ c = 0;
+
+ if (queries[rc].rlen) {
-+ header = (HEADER *)queries[rc].reply;
++ if (!bb_style_counter) {
++ header = (HEADER *)queries[rc].reply;
+
-+ if (!header->aa)
-+ printf("Non-authoritative answer:\n");
++ if (!header->aa)
++ printf("Non-authoritative answer:\n");
+
-+ c = parse_reply(queries[rc].reply, queries[rc].rlen);
++ 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)
+ else if (c < 0)
+ printf("*** Can't find %s: Parse error\n", queries[rc].name);
+
-+ printf("\n");
++ if (!bb_style_counter)
++ printf("\n");
+ }
+
+ rc = 0;
+
+ return rc;
+}
---
-2.1.4
-