3
0

nslookup.c 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433
  1. /* vi: set sw=4 ts=4: */
  2. //config:config NSLOOKUP
  3. //config: bool "nslookup (10 kb)"
  4. //config: default y
  5. //config: help
  6. //config: nslookup is a tool to query Internet name servers.
  7. //config:
  8. //config:config FEATURE_NSLOOKUP_BIG
  9. //config: bool "Use internal resolver code instead of libc"
  10. //config: depends on NSLOOKUP
  11. //config: default y
  12. //config:
  13. //config:config FEATURE_NSLOOKUP_LONG_OPTIONS
  14. //config: bool "Enable long options"
  15. //config: default y
  16. //config: depends on FEATURE_NSLOOKUP_BIG && LONG_OPTS
  17. //applet:IF_NSLOOKUP(APPLET(nslookup, BB_DIR_USR_BIN, BB_SUID_DROP))
  18. //kbuild:lib-$(CONFIG_NSLOOKUP) += nslookup.o
  19. //usage:#define nslookup_trivial_usage
  20. //usage: IF_FEATURE_NSLOOKUP_BIG("[-type=QUERY_TYPE] [-debug] ") "HOST [DNS_SERVER]"
  21. //usage:#define nslookup_full_usage "\n\n"
  22. //usage: "Query DNS about HOST"
  23. //usage: IF_FEATURE_NSLOOKUP_BIG("\n")
  24. //usage: IF_FEATURE_NSLOOKUP_BIG("\nQUERY_TYPE: soa,ns,a,"IF_FEATURE_IPV6("aaaa,")"cname,mx,txt,ptr,srv,any")
  25. //usage:#define nslookup_example_usage
  26. //usage: "$ nslookup localhost\n"
  27. //usage: "Server: default\n"
  28. //usage: "Address: default\n"
  29. //usage: "\n"
  30. //usage: "Name: debian\n"
  31. //usage: "Address: 127.0.0.1\n"
  32. #if !ENABLE_FEATURE_NSLOOKUP_BIG
  33. #include <resolv.h>
  34. //#include <arpa/inet.h>
  35. //#include <netdb.h>
  36. #include "libbb.h"
  37. #include "common_bufsiz.h"
  38. /*
  39. * Mini nslookup implementation for busybox
  40. *
  41. * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu
  42. * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
  43. *
  44. * Correct default name server display and explicit name server option
  45. * added by Ben Zeckel <bzeckel@hmc.edu> June 2001
  46. *
  47. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  48. */
  49. /*
  50. * I'm only implementing non-interactive mode;
  51. * I totally forgot nslookup even had an interactive mode.
  52. *
  53. * This applet is the only user of res_init(). Without it,
  54. * you may avoid pulling in _res global from libc.
  55. */
  56. /* Examples of 'standard' nslookup output
  57. * $ nslookup yahoo.com
  58. * Server: 128.193.0.10
  59. * Address: 128.193.0.10#53
  60. *
  61. * Non-authoritative answer:
  62. * Name: yahoo.com
  63. * Address: 216.109.112.135
  64. * Name: yahoo.com
  65. * Address: 66.94.234.13
  66. *
  67. * $ nslookup 204.152.191.37
  68. * Server: 128.193.4.20
  69. * Address: 128.193.4.20#53
  70. *
  71. * Non-authoritative answer:
  72. * 37.191.152.204.in-addr.arpa canonical name = 37.32-27.191.152.204.in-addr.arpa.
  73. * 37.32-27.191.152.204.in-addr.arpa name = zeus-pub2.kernel.org.
  74. *
  75. * Authoritative answers can be found from:
  76. * 32-27.191.152.204.in-addr.arpa nameserver = ns1.kernel.org.
  77. * 32-27.191.152.204.in-addr.arpa nameserver = ns2.kernel.org.
  78. * 32-27.191.152.204.in-addr.arpa nameserver = ns3.kernel.org.
  79. * ns1.kernel.org internet address = 140.211.167.34
  80. * ns2.kernel.org internet address = 204.152.191.4
  81. * ns3.kernel.org internet address = 204.152.191.36
  82. */
  83. static int print_host(const char *hostname, const char *header)
  84. {
  85. /* We can't use xhost2sockaddr() - we want to get ALL addresses,
  86. * not just one */
  87. struct addrinfo *result = NULL;
  88. int rc;
  89. struct addrinfo hint;
  90. memset(&hint, 0 , sizeof(hint));
  91. /* hint.ai_family = AF_UNSPEC; - zero anyway */
  92. /* Needed. Or else we will get each address thrice (or more)
  93. * for each possible socket type (tcp,udp,raw...): */
  94. hint.ai_socktype = SOCK_STREAM;
  95. // hint.ai_flags = AI_CANONNAME;
  96. rc = getaddrinfo(hostname, NULL /*service*/, &hint, &result);
  97. if (rc == 0) {
  98. struct addrinfo *cur = result;
  99. unsigned cnt = 0;
  100. printf("%-10s %s\n", header, hostname);
  101. // puts(cur->ai_canonname); ?
  102. while (cur) {
  103. char *dotted, *revhost;
  104. dotted = xmalloc_sockaddr2dotted_noport(cur->ai_addr);
  105. revhost = xmalloc_sockaddr2hostonly_noport(cur->ai_addr);
  106. printf("Address %u: %s%c", ++cnt, dotted, revhost ? ' ' : '\n');
  107. if (revhost) {
  108. puts(revhost);
  109. if (ENABLE_FEATURE_CLEAN_UP)
  110. free(revhost);
  111. }
  112. if (ENABLE_FEATURE_CLEAN_UP)
  113. free(dotted);
  114. cur = cur->ai_next;
  115. }
  116. } else {
  117. #if ENABLE_VERBOSE_RESOLUTION_ERRORS
  118. bb_error_msg("can't resolve '%s': %s", hostname, gai_strerror(rc));
  119. #else
  120. bb_error_msg("can't resolve '%s'", hostname);
  121. #endif
  122. }
  123. if (ENABLE_FEATURE_CLEAN_UP && result)
  124. freeaddrinfo(result);
  125. return (rc != 0);
  126. }
  127. /* lookup the default nameserver and display it */
  128. static void server_print(void)
  129. {
  130. char *server;
  131. struct sockaddr *sa;
  132. #if ENABLE_FEATURE_IPV6
  133. sa = (struct sockaddr*)_res._u._ext.nsaddrs[0];
  134. if (!sa)
  135. #endif
  136. sa = (struct sockaddr*)&_res.nsaddr_list[0];
  137. server = xmalloc_sockaddr2dotted_noport(sa);
  138. print_host(server, "Server:");
  139. if (ENABLE_FEATURE_CLEAN_UP)
  140. free(server);
  141. bb_putchar('\n');
  142. }
  143. /* alter the global _res nameserver structure to use
  144. an explicit dns server instead of what is in /etc/resolv.conf */
  145. static void set_default_dns(const char *server)
  146. {
  147. len_and_sockaddr *lsa;
  148. if (!server)
  149. return;
  150. /* NB: this works even with, say, "[::1]:5353"! :) */
  151. lsa = xhost2sockaddr(server, 53);
  152. if (lsa->u.sa.sa_family == AF_INET) {
  153. _res.nscount = 1;
  154. /* struct copy */
  155. _res.nsaddr_list[0] = lsa->u.sin;
  156. }
  157. #if ENABLE_FEATURE_IPV6
  158. /* Hoped libc can cope with IPv4 address there too.
  159. * No such luck, glibc 2.4 segfaults even with IPv6,
  160. * maybe I misunderstand how to make glibc use IPv6 addr?
  161. * (uclibc 0.9.31+ should work) */
  162. if (lsa->u.sa.sa_family == AF_INET6) {
  163. // glibc neither SEGVs nor sends any dgrams with this
  164. // (strace shows no socket ops):
  165. //_res.nscount = 0;
  166. _res._u._ext.nscount = 1;
  167. /* store a pointer to part of malloc'ed lsa */
  168. _res._u._ext.nsaddrs[0] = &lsa->u.sin6;
  169. /* must not free(lsa)! */
  170. }
  171. #endif
  172. }
  173. int nslookup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  174. int nslookup_main(int argc, char **argv)
  175. {
  176. /* We allow 1 or 2 arguments.
  177. * The first is the name to be looked up and the second is an
  178. * optional DNS server with which to do the lookup.
  179. * More than 3 arguments is an error to follow the pattern of the
  180. * standard nslookup */
  181. if (!argv[1] || argv[1][0] == '-' || argc > 3)
  182. bb_show_usage();
  183. /* initialize DNS structure _res used in printing the default
  184. * name server and in the explicit name server option feature. */
  185. res_init();
  186. /* rfc2133 says this enables IPv6 lookups */
  187. /* (but it also says "may be enabled in /etc/resolv.conf") */
  188. /*_res.options |= RES_USE_INET6;*/
  189. set_default_dns(argv[2]);
  190. server_print();
  191. /* getaddrinfo and friends are free to request a resolver
  192. * reinitialization. Just in case, set_default_dns() again
  193. * after getaddrinfo (in server_print). This reportedly helps
  194. * with bug 675 "nslookup does not properly use second argument"
  195. * at least on Debian Wheezy and Openwrt AA (eglibc based).
  196. */
  197. set_default_dns(argv[2]);
  198. return print_host(argv[1], "Name:");
  199. }
  200. #else /****** A version from LEDE / OpenWRT ******/
  201. /*
  202. * musl compatible nslookup
  203. *
  204. * Copyright (C) 2017 Jo-Philipp Wich <jo@mein.io>
  205. *
  206. * Permission to use, copy, modify, and/or distribute this software for any
  207. * purpose with or without fee is hereby granted, provided that the above
  208. * copyright notice and this permission notice appear in all copies.
  209. *
  210. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  211. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  212. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  213. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  214. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  215. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  216. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  217. */
  218. #include "libbb.h"
  219. #include "common_bufsiz.h"
  220. #if 0
  221. # define dbg(...) fprintf(stderr, __VA_ARGS__)
  222. #else
  223. # define dbg(...) ((void)0)
  224. #endif
  225. /* Instead of using ancient libc DNS query support,
  226. * we can carry our own, independent code.
  227. * E.g. res_mkquery() loses
  228. * three of its paramemters (they are unused!).
  229. * Unfortunately, while it does eliminate
  230. * ns_get16
  231. * ns_get32
  232. * ns_name_uncompress
  233. * dn_skipname
  234. * ns_skiprr
  235. * ns_initparse
  236. * ns_parserr
  237. * libc functions from a static binary, libc versions of
  238. * dn_expand and res_mkquery are still linked in
  239. * - they are used by getnameinfo(). Each is ~230 bytes of code.
  240. * This makes USE_LIBC_RESOLV = 0 code _bigger_ (by about 27 bytes),
  241. * despite inlining and constant propagation.
  242. */
  243. #define USE_LIBC_RESOLV 1
  244. #if USE_LIBC_RESOLV
  245. #include <resolv.h>
  246. #else
  247. #define RESOLVFUNC /*nothing*/
  248. #define BIGRESOLVFUNC /*nothing*/
  249. #define TINYRESOLVFUNC ALWAYS_INLINE
  250. /* This one is taken from musl 1.2.4 */
  251. #define NS_MAXDNAME 1025
  252. #define NS_INT32SZ 4
  253. #define NS_INT16SZ 2
  254. #define MAXDNAME NS_MAXDNAME
  255. typedef enum __ns_opcode {
  256. ns_o_query = 0,
  257. } ns_opcode;
  258. typedef enum __ns_class {
  259. ns_c_in = 1,
  260. } ns_class;
  261. typedef enum __ns_sect {
  262. ns_s_qd = 0,
  263. ns_s_zn = 0,
  264. ns_s_an = 1,
  265. ns_s_pr = 1,
  266. ns_s_ns = 2,
  267. ns_s_ud = 2,
  268. ns_s_ar = 3,
  269. ns_s_max = 4
  270. } ns_sect;
  271. typedef enum __ns_type {
  272. ns_t_a = 1,
  273. ns_t_ns = 2,
  274. ns_t_cname = 5,
  275. ns_t_soa = 6,
  276. ns_t_ptr = 12,
  277. ns_t_mx = 15,
  278. ns_t_txt = 16,
  279. ns_t_aaaa = 28,
  280. ns_t_srv = 33,
  281. ns_t_any = 255,
  282. } ns_type;
  283. #define QUERY ns_o_query
  284. #define T_A ns_t_a
  285. #define T_PTR ns_t_ptr
  286. #define T_AAAA ns_t_aaaa
  287. #define C_IN ns_c_in
  288. typedef struct __ns_msg {
  289. const unsigned char *_msg, *_eom;
  290. uint16_t _id, _flags, _counts[ns_s_max];
  291. const unsigned char *_sections[ns_s_max];
  292. ns_sect _sect;
  293. int _rrnum;
  294. const unsigned char *_msg_ptr;
  295. } ns_msg;
  296. #define ns_msg_id(handle) ((handle)._id + 0)
  297. #define ns_msg_base(handle) ((handle)._msg + 0)
  298. #define ns_msg_end(handle) ((handle)._eom + 0)
  299. #define ns_msg_size(handle) ((handle)._eom - (handle)._msg)
  300. #define ns_msg_count(handle, section) ((handle)._counts[section] + 0)
  301. #define ns_msg_getflag(handle, flag) \
  302. (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift)
  303. typedef struct __ns_rr {
  304. char name[NS_MAXDNAME];
  305. uint16_t type;
  306. uint16_t rr_class;
  307. uint32_t ttl;
  308. uint16_t rdlength;
  309. const unsigned char *rdata;
  310. } ns_rr;
  311. #define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".")
  312. #define ns_rr_type(rr) ((ns_type)((rr).type + 0))
  313. #define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0))
  314. #define ns_rr_ttl(rr) ((rr).ttl + 0)
  315. #define ns_rr_rdlen(rr) ((rr).rdlength + 0)
  316. #define ns_rr_rdata(rr) ((rr).rdata + 0)
  317. typedef struct {
  318. unsigned id :16;
  319. #if __BYTE_ORDER == __BIG_ENDIAN
  320. unsigned qr: 1;
  321. unsigned opcode: 4;
  322. unsigned aa: 1;
  323. unsigned tc: 1;
  324. unsigned rd: 1;
  325. unsigned ra: 1;
  326. unsigned unused :1;
  327. unsigned ad: 1;
  328. unsigned cd: 1;
  329. unsigned rcode :4;
  330. #else
  331. unsigned rd :1;
  332. unsigned tc :1;
  333. unsigned aa :1;
  334. unsigned opcode :4;
  335. unsigned qr :1;
  336. unsigned rcode :4;
  337. unsigned cd: 1;
  338. unsigned ad: 1;
  339. unsigned unused :1;
  340. unsigned ra :1;
  341. #endif
  342. unsigned qdcount :16;
  343. unsigned ancount :16;
  344. unsigned nscount :16;
  345. unsigned arcount :16;
  346. } HEADER;
  347. #define dn_ns_get16 bb_ns_get16
  348. static unsigned TINYRESOLVFUNC ns_get16(const unsigned char *cp)
  349. {
  350. return cp[0]<<8 | cp[1];
  351. }
  352. #define ns_get32 bb_ns_get32
  353. static unsigned long TINYRESOLVFUNC ns_get32(const unsigned char *cp)
  354. {
  355. return (unsigned)cp[0]<<24 | cp[1]<<16 | cp[2]<<8 | cp[3];
  356. }
  357. #define NS_GET16(s, cp) (void)((s) = ns_get16(((cp)+=2)-2))
  358. #define NS_GET32(l, cp) (void)((l) = ns_get32(((cp)+=4)-4))
  359. #define dn_expand bb_dn_expand
  360. static int BIGRESOLVFUNC dn_expand(const unsigned char *base, const unsigned char *end, const unsigned char *src, char *dest, int space)
  361. {
  362. const unsigned char *p = src;
  363. char *dend, *dbegin = dest;
  364. int len = -1, i, j;
  365. if (p==end || space <= 0) return -1;
  366. dend = dest + (space > 254 ? 254 : space);
  367. /* detect reference loop using an iteration counter */
  368. for (i=0; i < end-base; i+=2) {
  369. /* loop invariants: p<end, dest<dend */
  370. if (*p & 0xc0) {
  371. if (p+1==end) return -1;
  372. j = ((p[0] & 0x3f) << 8) | p[1];
  373. if (len < 0) len = p+2-src;
  374. if (j >= end-base) return -1;
  375. p = base+j;
  376. } else if (*p) {
  377. if (dest != dbegin) *dest++ = '.';
  378. j = *p++;
  379. if (j >= end-p || j >= dend-dest) return -1;
  380. while (j--) *dest++ = *p++;
  381. } else {
  382. *dest = 0;
  383. if (len < 0) len = p+1-src;
  384. return len;
  385. }
  386. }
  387. return -1;
  388. }
  389. #define ns_name_uncompress bb_ns_name_uncompress
  390. static int RESOLVFUNC ns_name_uncompress(const unsigned char *msg, const unsigned char *eom,
  391. const unsigned char *src, char *dst, size_t dstsiz)
  392. {
  393. int r;
  394. r = dn_expand(msg, eom, src, dst, dstsiz);
  395. if (r < 0) errno = EMSGSIZE;
  396. return r;
  397. }
  398. #define dn_skipname bb_dn_skipname
  399. static int RESOLVFUNC dn_skipname(const unsigned char *s, const unsigned char *end)
  400. {
  401. const unsigned char *p = s;
  402. while (p < end)
  403. if (!*p) return p-s+1;
  404. else if (*p>=192)
  405. if (p+1<end) return p-s+2;
  406. else break;
  407. else
  408. if (end-p<*p+1) break;
  409. else p += *p + 1;
  410. return -1;
  411. }
  412. #define ns_skiprr bb_ns_skiprr
  413. static int BIGRESOLVFUNC ns_skiprr(const unsigned char *ptr, const unsigned char *eom, ns_sect section, int count)
  414. {
  415. const unsigned char *p = ptr;
  416. int r;
  417. while (count--) {
  418. r = dn_skipname(p, eom);
  419. if (r < 0) goto bad;
  420. if (r + 2 * NS_INT16SZ > eom - p) goto bad;
  421. p += r + 2 * NS_INT16SZ;
  422. if (section != ns_s_qd) {
  423. if (NS_INT32SZ + NS_INT16SZ > eom - p) goto bad;
  424. p += NS_INT32SZ;
  425. NS_GET16(r, p);
  426. if (r > eom - p) goto bad;
  427. p += r;
  428. }
  429. }
  430. return p - ptr;
  431. bad:
  432. errno = EMSGSIZE;
  433. return -1;
  434. }
  435. #define ns_parserr bb_ns_parserr
  436. static int BIGRESOLVFUNC ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr)
  437. {
  438. int r;
  439. if (section < 0 || section >= ns_s_max) goto bad;
  440. if (section != handle->_sect) {
  441. handle->_sect = section;
  442. handle->_rrnum = 0;
  443. handle->_msg_ptr = handle->_sections[section];
  444. }
  445. if (rrnum == -1) rrnum = handle->_rrnum;
  446. if (rrnum < 0 || rrnum >= handle->_counts[section]) goto bad;
  447. if (rrnum < handle->_rrnum) {
  448. handle->_rrnum = 0;
  449. handle->_msg_ptr = handle->_sections[section];
  450. }
  451. if (rrnum > handle->_rrnum) {
  452. r = ns_skiprr(handle->_msg_ptr, handle->_eom, section, rrnum - handle->_rrnum);
  453. if (r < 0) return -1;
  454. handle->_msg_ptr += r;
  455. handle->_rrnum = rrnum;
  456. }
  457. r = ns_name_uncompress(handle->_msg, handle->_eom, handle->_msg_ptr, rr->name, NS_MAXDNAME);
  458. if (r < 0) return -1;
  459. handle->_msg_ptr += r;
  460. if (2 * NS_INT16SZ > handle->_eom - handle->_msg_ptr) goto size;
  461. NS_GET16(rr->type, handle->_msg_ptr);
  462. NS_GET16(rr->rr_class, handle->_msg_ptr);
  463. if (section != ns_s_qd) {
  464. if (NS_INT32SZ + NS_INT16SZ > handle->_eom - handle->_msg_ptr) goto size;
  465. NS_GET32(rr->ttl, handle->_msg_ptr);
  466. NS_GET16(rr->rdlength, handle->_msg_ptr);
  467. if (rr->rdlength > handle->_eom - handle->_msg_ptr) goto size;
  468. rr->rdata = handle->_msg_ptr;
  469. handle->_msg_ptr += rr->rdlength;
  470. } else {
  471. rr->ttl = 0;
  472. rr->rdlength = 0;
  473. rr->rdata = NULL;
  474. }
  475. handle->_rrnum++;
  476. if (handle->_rrnum > handle->_counts[section]) {
  477. handle->_sect = section + 1;
  478. if (handle->_sect == ns_s_max) {
  479. handle->_rrnum = -1;
  480. handle->_msg_ptr = NULL;
  481. } else {
  482. handle->_rrnum = 0;
  483. }
  484. }
  485. return 0;
  486. bad:
  487. errno = ENODEV;
  488. return -1;
  489. size:
  490. errno = EMSGSIZE;
  491. return -1;
  492. }
  493. #define ns_initparse bb_ns_initparse
  494. static int BIGRESOLVFUNC ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle)
  495. {
  496. int i, r;
  497. handle->_msg = msg;
  498. handle->_eom = msg + msglen;
  499. if (msglen < (2 + ns_s_max) * NS_INT16SZ) goto bad;
  500. NS_GET16(handle->_id, msg);
  501. NS_GET16(handle->_flags, msg);
  502. for (i = 0; i < ns_s_max; i++) NS_GET16(handle->_counts[i], msg);
  503. for (i = 0; i < ns_s_max; i++) {
  504. if (handle->_counts[i]) {
  505. handle->_sections[i] = msg;
  506. r = ns_skiprr(msg, handle->_eom, i, handle->_counts[i]);
  507. if (r < 0) return -1;
  508. msg += r;
  509. } else {
  510. handle->_sections[i] = NULL;
  511. }
  512. }
  513. if (msg != handle->_eom) goto bad;
  514. handle->_sect = ns_s_max;
  515. handle->_rrnum = -1;
  516. handle->_msg_ptr = NULL;
  517. return 0;
  518. bad:
  519. errno = EMSGSIZE;
  520. return -1;
  521. }
  522. #define res_mkquery bb_res_mkquery
  523. static int RESOLVFUNC res_mkquery(int op, const char *dname, int class, int type,
  524. const unsigned char *data UNUSED_PARAM, int datalen UNUSED_PARAM,
  525. const unsigned char *newrr UNUSED_PARAM, unsigned char *buf, int buflen)
  526. {
  527. int i, j;
  528. unsigned char q[280];
  529. size_t l = strnlen(dname, 255);
  530. int n;
  531. if (l && dname[l-1]=='.') l--;
  532. if (l && dname[l-1]=='.') return -1;
  533. n = 17+l+!!l;
  534. if (l>253 || buflen<n || op>15u || class>255u || type>255u)
  535. return -1;
  536. //TODO: why do we even have the q[] array? Use buf[] directly!
  537. /* Construct query template - ID will be filled later */
  538. memset(q, 0, n);
  539. q[2] = op*8 + 1;
  540. q[3] = 32; /* AD */
  541. q[5] = 1;
  542. memcpy((char *)q+13, dname, l);
  543. for (i=13; q[i]; i=j+1) {
  544. for (j=i; q[j] && q[j] != '.'; j++);
  545. if (j-i-1u > 62u) return -1;
  546. q[i-1] = j-i;
  547. }
  548. q[i+1] = type;
  549. q[i+3] = class;
  550. #if 0
  551. //For some machines (here: a TP-Link RE200 powered by a MediaTek MT7620A)
  552. //the monotonic clock has a coarse resolution (here: 20us) and it can happen
  553. //that the requests for A and AAAA share the same transaction ID.
  554. //In that case the mapping from received responses to the sent queries
  555. //doesn't work and name resolution fails because the AAAA reply
  556. //is dropped as a duplicate reply to the A query.
  557. /* Make a reasonably unpredictable id */
  558. unsigned id;
  559. struct timespec ts;
  560. clock_gettime(CLOCK_REALTIME, &ts);
  561. id = ts.tv_nsec + ((uint32_t)(ts.tv_nsec) >> 16);
  562. q[0] = id/256;
  563. q[1] = id;
  564. #endif
  565. memcpy(buf, q, n);
  566. return n;
  567. }
  568. #endif /* !USE_LIBC_RESOLV */
  569. struct ns {
  570. const char *name;
  571. len_and_sockaddr *lsa;
  572. //UNUSED: int failures;
  573. int replies;
  574. };
  575. struct query {
  576. const char *name;
  577. unsigned qlen;
  578. // unsigned latency;
  579. // uint8_t rcode;
  580. /* res_mkquery() balks on names > 253 chars.
  581. * The formed query is 253+18 chars at max.
  582. * Real hostnames are nowhere near that long anyway.
  583. * Use of power-of-2 size means smaller code.
  584. */
  585. unsigned char query[512 - sizeof(int) - sizeof(char*)];
  586. // unsigned char reply[512];
  587. };
  588. static const struct {
  589. unsigned char type;
  590. char name[7];
  591. } qtypes[] ALIGN1 = {
  592. { ns_t_soa, "SOA" },
  593. { ns_t_ns, "NS" },
  594. { ns_t_a, "A" },
  595. #if ENABLE_FEATURE_IPV6
  596. { ns_t_aaaa, "AAAA" },
  597. #endif
  598. { ns_t_cname, "CNAME" },
  599. { ns_t_mx, "MX" },
  600. { ns_t_txt, "TXT" },
  601. { ns_t_srv, "SRV" },
  602. { ns_t_ptr, "PTR" },
  603. { ns_t_any, "ANY" },
  604. };
  605. static const char *const rcodes[] ALIGN_PTR = {
  606. "NOERROR", // 0
  607. "FORMERR", // 1
  608. "SERVFAIL", // 2
  609. "NXDOMAIN", // 3
  610. "NOTIMP", // 4
  611. "REFUSED", // 5
  612. "YXDOMAIN", // 6
  613. "YXRRSET", // 7
  614. "NXRRSET", // 8
  615. "NOTAUTH", // 9
  616. "NOTZONE", // 10
  617. "11", // 11 not assigned
  618. "12", // 12 not assigned
  619. "13", // 13 not assigned
  620. "14", // 14 not assigned
  621. "15", // 15 not assigned
  622. };
  623. #if ENABLE_FEATURE_IPV6
  624. static const char v4_mapped[12] = { 0,0,0,0, 0,0,0,0, 0,0,0xff,0xff };
  625. #endif
  626. struct globals {
  627. unsigned default_port;
  628. unsigned default_retry;
  629. unsigned default_timeout;
  630. unsigned query_count;
  631. unsigned serv_count;
  632. struct ns *server;
  633. struct query *query;
  634. char *search;
  635. smalluint have_search_directive;
  636. smalluint exitcode;
  637. } FIX_ALIASING;
  638. #define G (*(struct globals*)bb_common_bufsiz1)
  639. #define INIT_G() do { \
  640. setup_common_bufsiz(); \
  641. G.default_port = 53; \
  642. G.default_retry = 2; \
  643. G.default_timeout = 5; \
  644. } while (0)
  645. enum {
  646. OPT_debug = (1 << 0),
  647. };
  648. static NOINLINE int parse_reply(const unsigned char *msg, size_t len)
  649. {
  650. HEADER *header;
  651. ns_msg handle;
  652. ns_rr rr;
  653. int i, n, rdlen;
  654. const char *format = NULL;
  655. char astr[INET6_ADDRSTRLEN], dname[MAXDNAME];
  656. const unsigned char *cp;
  657. header = (HEADER *)msg;
  658. if (!header->aa)
  659. printf("Non-authoritative answer:\n");
  660. else if (option_mask32 & OPT_debug)
  661. printf("Non-authoritative answer:\n" + 4);
  662. if (ns_initparse(msg, len, &handle) != 0) {
  663. //printf("Unable to parse reply: %s\n", strerror(errno));
  664. return -1;
  665. }
  666. for (i = 0; i < ns_msg_count(handle, ns_s_an); i++) {
  667. if (ns_parserr(&handle, ns_s_an, i, &rr) != 0) {
  668. //printf("Unable to parse resource record: %s\n", strerror(errno));
  669. return -1;
  670. }
  671. rdlen = ns_rr_rdlen(rr);
  672. switch (ns_rr_type(rr))
  673. {
  674. case ns_t_a:
  675. if (rdlen != 4) {
  676. dbg("unexpected A record length %d\n", rdlen);
  677. return -1;
  678. }
  679. inet_ntop(AF_INET, ns_rr_rdata(rr), astr, sizeof(astr));
  680. printf("Name:\t%s\nAddress: %s\n", ns_rr_name(rr), astr);
  681. break;
  682. #if ENABLE_FEATURE_IPV6
  683. case ns_t_aaaa:
  684. if (rdlen != 16) {
  685. dbg("unexpected AAAA record length %d\n", rdlen);
  686. return -1;
  687. }
  688. inet_ntop(AF_INET6, ns_rr_rdata(rr), astr, sizeof(astr));
  689. /* bind-utils 9.11.3 uses the same format for A and AAAA answers */
  690. printf("Name:\t%s\nAddress: %s\n", ns_rr_name(rr), astr);
  691. break;
  692. #endif
  693. case ns_t_ns:
  694. if (!format)
  695. format = "%s\tnameserver = %s\n";
  696. /* fall through */
  697. case ns_t_cname:
  698. if (!format)
  699. format = "%s\tcanonical name = %s\n";
  700. /* fall through */
  701. case ns_t_ptr:
  702. if (!format)
  703. format = "%s\tname = %s\n";
  704. if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
  705. ns_rr_rdata(rr), dname, sizeof(dname)) < 0
  706. ) {
  707. //printf("Unable to uncompress domain: %s\n", strerror(errno));
  708. return -1;
  709. }
  710. printf(format, ns_rr_name(rr), dname);
  711. break;
  712. case ns_t_mx:
  713. if (rdlen < 2) {
  714. printf("MX record too short\n");
  715. return -1;
  716. }
  717. n = ns_get16(ns_rr_rdata(rr));
  718. if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
  719. ns_rr_rdata(rr) + 2, dname, sizeof(dname)) < 0
  720. ) {
  721. //printf("Cannot uncompress MX domain: %s\n", strerror(errno));
  722. return -1;
  723. }
  724. printf("%s\tmail exchanger = %d %s\n", ns_rr_name(rr), n, dname);
  725. break;
  726. case ns_t_txt:
  727. if (rdlen < 1) {
  728. //printf("TXT record too short\n");
  729. return -1;
  730. }
  731. n = *(unsigned char *)ns_rr_rdata(rr);
  732. if (n > 0) {
  733. memset(dname, 0, sizeof(dname));
  734. memcpy(dname, ns_rr_rdata(rr) + 1, n);
  735. printf("%s\ttext = \"%s\"\n", ns_rr_name(rr), dname);
  736. }
  737. break;
  738. case ns_t_srv:
  739. if (rdlen < 6) {
  740. //printf("SRV record too short\n");
  741. return -1;
  742. }
  743. cp = ns_rr_rdata(rr);
  744. n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
  745. cp + 6, dname, sizeof(dname));
  746. if (n < 0) {
  747. //printf("Unable to uncompress domain: %s\n", strerror(errno));
  748. return -1;
  749. }
  750. printf("%s\tservice = %u %u %u %s\n", ns_rr_name(rr),
  751. ns_get16(cp), ns_get16(cp + 2), ns_get16(cp + 4), dname);
  752. break;
  753. case ns_t_soa:
  754. if (rdlen < 20) {
  755. dbg("SOA record too short:%d\n", rdlen);
  756. return -1;
  757. }
  758. printf("%s\n", ns_rr_name(rr));
  759. cp = ns_rr_rdata(rr);
  760. n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
  761. cp, dname, sizeof(dname));
  762. if (n < 0) {
  763. //printf("Unable to uncompress domain: %s\n", strerror(errno));
  764. return -1;
  765. }
  766. printf("\torigin = %s\n", dname);
  767. cp += n;
  768. n = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle),
  769. cp, dname, sizeof(dname));
  770. if (n < 0) {
  771. //printf("Unable to uncompress domain: %s\n", strerror(errno));
  772. return -1;
  773. }
  774. printf("\tmail addr = %s\n", dname);
  775. cp += n;
  776. printf("\tserial = %lu\n", ns_get32(cp));
  777. cp += 4;
  778. printf("\trefresh = %lu\n", ns_get32(cp));
  779. cp += 4;
  780. printf("\tretry = %lu\n", ns_get32(cp));
  781. cp += 4;
  782. printf("\texpire = %lu\n", ns_get32(cp));
  783. cp += 4;
  784. printf("\tminimum = %lu\n", ns_get32(cp));
  785. break;
  786. default:
  787. break;
  788. }
  789. }
  790. return i;
  791. }
  792. /*
  793. * Function logic borrowed & modified from musl libc, res_msend.c
  794. * G.query_count is always > 0.
  795. */
  796. static int send_queries(struct ns *ns)
  797. {
  798. unsigned char reply[512];
  799. uint8_t rcode;
  800. len_and_sockaddr *local_lsa;
  801. struct pollfd pfd;
  802. int servfail_retry = 0;
  803. int n_replies = 0;
  804. // int save_idx = 0;
  805. unsigned retry_interval;
  806. unsigned timeout = G.default_timeout * 1000;
  807. unsigned tstart, tsent, tcur;
  808. pfd.events = POLLIN;
  809. pfd.fd = xsocket_type(&local_lsa, ns->lsa->u.sa.sa_family, SOCK_DGRAM);
  810. /*
  811. * local_lsa has "null" address and port 0 now.
  812. * bind() ensures we have a *particular port* selected by kernel
  813. * and remembered in fd, thus later recv(fd)
  814. * receives only packets sent to this port.
  815. */
  816. xbind(pfd.fd, &local_lsa->u.sa, local_lsa->len);
  817. free(local_lsa);
  818. /* Make read/writes know the destination */
  819. xconnect(pfd.fd, &ns->lsa->u.sa, ns->lsa->len);
  820. ndelay_on(pfd.fd);
  821. retry_interval = timeout / G.default_retry;
  822. tstart = tcur = monotonic_ms();
  823. goto send;
  824. while (tcur - tstart < timeout) {
  825. int qn;
  826. int recvlen;
  827. if (tcur - tsent >= retry_interval) {
  828. send:
  829. for (qn = 0; qn < G.query_count; qn++) {
  830. if (G.query[qn].qlen == 0)
  831. continue; /* this one was replied already */
  832. if (write(pfd.fd, G.query[qn].query, G.query[qn].qlen) < 0) {
  833. bb_perror_msg("write to '%s'", ns->name);
  834. n_replies = -1; /* "no go, try next server" */
  835. goto ret;
  836. }
  837. dbg("query %u sent\n", qn);
  838. }
  839. tsent = tcur;
  840. servfail_retry = 2 * G.query_count;
  841. }
  842. /* Wait for a response, or until time to retry */
  843. if (poll(&pfd, 1, retry_interval - (tcur - tsent)) <= 0)
  844. goto next;
  845. recvlen = read(pfd.fd, reply, sizeof(reply));
  846. if (recvlen < 0) {
  847. bb_simple_perror_msg("read");
  848. next:
  849. tcur = monotonic_ms();
  850. continue;
  851. }
  852. if (ns->replies++ == 0) {
  853. printf("Server:\t\t%s\n", ns->name);
  854. printf("Address:\t%s\n\n",
  855. auto_string(xmalloc_sockaddr2dotted(&ns->lsa->u.sa))
  856. );
  857. /* In "Address", bind-utils 9.11.3 show port after a hash: "1.2.3.4#53" */
  858. /* Should we do the same? */
  859. }
  860. /* Non-identifiable packet */
  861. if (recvlen < 4) {
  862. dbg("read is too short:%d\n", recvlen);
  863. goto next;
  864. }
  865. /* Find which query this answer goes with, if any */
  866. // qn = save_idx;
  867. qn = 0;
  868. for (;;) {
  869. if (memcmp(reply, G.query[qn].query, 2) == 0) {
  870. dbg("response matches query %u\n", qn);
  871. break;
  872. }
  873. if (++qn >= G.query_count) {
  874. dbg("response does not match any query\n");
  875. goto next;
  876. }
  877. }
  878. if (G.query[qn].qlen == 0) {
  879. dbg("dropped duplicate response to query %u\n", qn);
  880. goto next;
  881. }
  882. rcode = reply[3] & 0x0f;
  883. dbg("query %u rcode:%s\n", qn, rcodes[rcode]);
  884. /* Retry immediately on SERVFAIL */
  885. if (rcode == 2) {
  886. //UNUSED: ns->failures++;
  887. if (servfail_retry) {
  888. servfail_retry--;
  889. write(pfd.fd, G.query[qn].query, G.query[qn].qlen);
  890. dbg("query %u resent\n", qn);
  891. goto next;
  892. }
  893. }
  894. /* Process reply */
  895. G.query[qn].qlen = 0; /* flag: "reply received" */
  896. tcur = monotonic_ms();
  897. #if 1
  898. if (option_mask32 & OPT_debug) {
  899. printf("Query #%d completed in %ums:\n", qn, tcur - tstart);
  900. }
  901. if (rcode != 0) {
  902. printf("** server can't find %s: %s\n",
  903. G.query[qn].name, rcodes[rcode]);
  904. G.exitcode = EXIT_FAILURE;
  905. } else {
  906. switch (parse_reply(reply, recvlen)) {
  907. case -1:
  908. printf("*** Can't find %s: Parse error\n", G.query[qn].name);
  909. G.exitcode = EXIT_FAILURE;
  910. break;
  911. /* bind-utils 9.11.25 just says nothing in this case */
  912. //case 0:
  913. // break;
  914. }
  915. }
  916. /* NB: in case of authoritative, empty answer (NODATA), IOW: one with
  917. * ns_msg_count() == 0, bind-utils 9.11.25 shows no trace of this answer
  918. * (unless -debug, where it says:
  919. * ------------
  920. * QUESTIONS:
  921. * host.com, type = AAAA, class = IN
  922. * ANSWERS:
  923. * AUTHORITY RECORDS:
  924. * ADDITIONAL RECORDS:
  925. * ------------
  926. * ). Due to printing of below '\n', we do show an additional empty line.
  927. * This is better than not showing any indication of this reply at all,
  928. * yet maintains "compatibility". I wonder whether it's better to break compat
  929. * and emit something more meaningful, e.g. print "Empty answer (NODATA)"?
  930. */
  931. bb_putchar('\n');
  932. n_replies++;
  933. if (n_replies >= G.query_count)
  934. goto ret;
  935. #else
  936. //used to store replies and process them later
  937. G.query[qn].latency = tcur - tstart;
  938. n_replies++;
  939. if (qn != save_idx) {
  940. /* "wrong" receive buffer, move to correct one */
  941. memcpy(G.query[qn].reply, G.query[save_idx].reply, recvlen);
  942. continue;
  943. }
  944. /* G.query[0..save_idx] have replies, move to next one, if exists */
  945. for (;;) {
  946. save_idx++;
  947. if (save_idx >= G.query_count)
  948. goto ret; /* all are full: we have all results */
  949. if (!G.query[save_idx].rlen)
  950. break; /* this one is empty */
  951. }
  952. #endif
  953. } /* while() */
  954. ret:
  955. close(pfd.fd);
  956. return n_replies;
  957. }
  958. static void add_ns(const char *addr)
  959. {
  960. struct ns *ns;
  961. unsigned count;
  962. dbg("%s: addr:'%s'\n", __func__, addr);
  963. count = G.serv_count++;
  964. G.server = xrealloc_vector(G.server, /*8=2^3:*/ 3, count);
  965. ns = &G.server[count];
  966. ns->name = addr;
  967. ns->lsa = xhost2sockaddr(addr, G.default_port);
  968. /*ns->replies = 0; - already is */
  969. /*ns->failures = 0; - already is */
  970. }
  971. static void parse_resolvconf(void)
  972. {
  973. FILE *resolv;
  974. resolv = fopen_for_read("/etc/resolv.conf");
  975. if (resolv) {
  976. char line[512]; /* "search" is defined to be up to 256 chars */
  977. while (fgets(line, sizeof(line), resolv)) {
  978. char *p, *arg;
  979. char *tokstate;
  980. p = strtok_r(line, " \t\n", &tokstate);
  981. if (!p)
  982. continue;
  983. dbg("resolv_key:'%s'\n", p);
  984. arg = strtok_r(NULL, "\n", &tokstate);
  985. dbg("resolv_arg:'%s'\n", arg);
  986. if (!arg)
  987. continue;
  988. if (strcmp(p, "domain") == 0) {
  989. /* domain DOM */
  990. if (!G.have_search_directive)
  991. goto set_search;
  992. continue;
  993. }
  994. if (strcmp(p, "search") == 0) {
  995. /* search DOM1 DOM2... */
  996. G.have_search_directive = 1;
  997. set_search:
  998. free(G.search);
  999. G.search = xstrdup(arg);
  1000. dbg("search='%s'\n", G.search);
  1001. continue;
  1002. }
  1003. if (strcmp(p, "nameserver") != 0)
  1004. continue;
  1005. /* nameserver DNS */
  1006. add_ns(xstrdup(arg));
  1007. }
  1008. fclose(resolv);
  1009. }
  1010. if (!G.search) {
  1011. /* default search domain is domain part of hostname */
  1012. char *h = safe_gethostname();
  1013. char *d = strchr(h, '.');
  1014. if (d) {
  1015. G.search = d + 1;
  1016. dbg("search='%s' (from hostname)\n", G.search);
  1017. }
  1018. /* else free(h); */
  1019. }
  1020. /* Cater for case of "domain ." in resolv.conf */
  1021. if (G.search && LONE_CHAR(G.search, '.'))
  1022. G.search = NULL;
  1023. }
  1024. static void add_query(int type, const char *dname)
  1025. {
  1026. struct query *new_q;
  1027. unsigned count;
  1028. ssize_t qlen;
  1029. count = G.query_count++;
  1030. G.query = xrealloc_vector(G.query, /*4=2^2:*/ 2, count);
  1031. new_q = &G.query[count];
  1032. dbg("new query#%u type %u for '%s'\n", count, type, dname);
  1033. new_q->name = dname;
  1034. qlen = res_mkquery(QUERY, dname, C_IN, type,
  1035. /*data:*/ NULL, /*datalen:*/ 0,
  1036. /*newrr:*/ NULL,
  1037. new_q->query, sizeof(new_q->query)
  1038. );
  1039. new_q->qlen = qlen;
  1040. }
  1041. static void add_query_with_search(int type, const char *dname)
  1042. {
  1043. char *s;
  1044. if (type == T_PTR || !G.search || strchr(dname, '.')) {
  1045. add_query(type, dname);
  1046. return;
  1047. }
  1048. s = G.search;
  1049. for (;;) {
  1050. char *fullname, *e;
  1051. e = skip_non_whitespace(s);
  1052. fullname = xasprintf("%s.%.*s", dname, (int)(e - s), s);
  1053. add_query(type, fullname);
  1054. s = skip_whitespace(e);
  1055. if (!*s)
  1056. break;
  1057. }
  1058. }
  1059. static char *make_ptr(const char *addrstr)
  1060. {
  1061. unsigned char addr[16];
  1062. #if ENABLE_FEATURE_IPV6
  1063. if (inet_pton(AF_INET6, addrstr, addr)) {
  1064. if (memcmp(addr, v4_mapped, 12) != 0) {
  1065. int i;
  1066. char resbuf[80];
  1067. char *ptr = resbuf;
  1068. for (i = 0; i < 16; i++) {
  1069. *ptr++ = 0x20 | bb_hexdigits_upcase[(unsigned char)addr[15 - i] & 0xf];
  1070. *ptr++ = '.';
  1071. *ptr++ = 0x20 | bb_hexdigits_upcase[(unsigned char)addr[15 - i] >> 4];
  1072. *ptr++ = '.';
  1073. }
  1074. strcpy(ptr, "ip6.arpa");
  1075. return xstrdup(resbuf);
  1076. }
  1077. return xasprintf("%u.%u.%u.%u.in-addr.arpa",
  1078. addr[15], addr[14], addr[13], addr[12]);
  1079. }
  1080. #endif
  1081. if (inet_pton(AF_INET, addrstr, addr)) {
  1082. return xasprintf("%u.%u.%u.%u.in-addr.arpa",
  1083. addr[3], addr[2], addr[1], addr[0]);
  1084. }
  1085. return NULL;
  1086. }
  1087. int nslookup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  1088. int nslookup_main(int argc UNUSED_PARAM, char **argv)
  1089. {
  1090. unsigned types;
  1091. int rc;
  1092. int err;
  1093. INIT_G();
  1094. /* manpage: "Options can also be specified on the command line
  1095. * if they precede the arguments and are prefixed with a hyphen."
  1096. */
  1097. types = 0;
  1098. argv++;
  1099. for (;;) {
  1100. const char *options =
  1101. // bind-utils-9.11.3 accept these:
  1102. // class= cl=
  1103. // type= ty= querytype= query= qu= q=
  1104. // domain= do=
  1105. // port= po=
  1106. // timeout= t=
  1107. // retry= ret=
  1108. // ndots=
  1109. // recurse
  1110. // norecurse
  1111. // defname
  1112. // nodefname
  1113. // vc
  1114. // novc
  1115. // debug
  1116. // nodebug
  1117. // d2
  1118. // nod2
  1119. // search
  1120. // nosearch
  1121. // sil
  1122. // fail
  1123. // nofail
  1124. // ver (prints version and exits)
  1125. "type\0" /* 0 */
  1126. "querytype\0" /* 1 */
  1127. "port\0" /* 2 */
  1128. "retry\0" /* 3 */
  1129. "debug\0" /* 4 */
  1130. "t\0" /* disambiguate with "type": else -t=2 fails */
  1131. "timeout\0" /* 6 */
  1132. "";
  1133. int i;
  1134. char *arg;
  1135. char *val;
  1136. if (!*argv)
  1137. bb_show_usage();
  1138. if (argv[0][0] != '-')
  1139. break;
  1140. /* Separate out "=val" part */
  1141. arg = (*argv++) + 1;
  1142. val = strchrnul(arg, '=');
  1143. if (*val)
  1144. *val++ = '\0';
  1145. i = index_in_substrings(options, arg);
  1146. //bb_error_msg("i:%d arg:'%s' val:'%s'", i, arg, val);
  1147. if (i < 0)
  1148. bb_show_usage();
  1149. if (i <= 1) {
  1150. for (i = 0;; i++) {
  1151. if (i == ARRAY_SIZE(qtypes))
  1152. bb_error_msg_and_die("invalid query type \"%s\"", val);
  1153. if (strcasecmp(qtypes[i].name, val) == 0)
  1154. break;
  1155. }
  1156. types |= (1 << i);
  1157. continue;
  1158. }
  1159. if (i == 2) {
  1160. G.default_port = xatou_range(val, 1, 0xffff);
  1161. }
  1162. if (i == 3) {
  1163. G.default_retry = xatou_range(val, 1, INT_MAX);
  1164. }
  1165. if (i == 4) {
  1166. option_mask32 |= OPT_debug;
  1167. }
  1168. if (i > 4) {
  1169. G.default_timeout = xatou_range(val, 1, INT_MAX / 1000);
  1170. }
  1171. }
  1172. /* Use given DNS server if present */
  1173. if (argv[1]) {
  1174. if (argv[2])
  1175. bb_show_usage();
  1176. add_ns(argv[1]);
  1177. } else {
  1178. parse_resolvconf();
  1179. /* Fall back to localhost if we could not find NS in resolv.conf */
  1180. if (G.serv_count == 0)
  1181. add_ns("127.0.0.1");
  1182. }
  1183. if (types == 0) {
  1184. /* No explicit type given, guess query type.
  1185. * If we can convert the domain argument into a ptr (means that
  1186. * inet_pton() could read it) we assume a PTR request, else
  1187. * we issue A+AAAA queries and switch to an output format
  1188. * mimicking the one of the traditional nslookup applet.
  1189. */
  1190. char *ptr;
  1191. ptr = make_ptr(argv[0]);
  1192. if (ptr) {
  1193. add_query(T_PTR, ptr);
  1194. } else {
  1195. add_query_with_search(T_A, argv[0]);
  1196. #if ENABLE_FEATURE_IPV6
  1197. add_query_with_search(T_AAAA, argv[0]);
  1198. #endif
  1199. }
  1200. } else {
  1201. int c;
  1202. for (c = 0; c < ARRAY_SIZE(qtypes); c++) {
  1203. if (types & (1 << c))
  1204. add_query_with_search(qtypes[c].type, argv[0]);
  1205. }
  1206. }
  1207. /* Ensure the Transaction IDs are unique.
  1208. * See, for example, musl source of res_mkquery() where
  1209. * it risks using current time (same value!) for ALL queries.
  1210. */
  1211. {
  1212. struct timeval tv;
  1213. unsigned id;
  1214. xgettimeofday(&tv);
  1215. id = tv.tv_sec + tv.tv_usec;
  1216. for (rc = 0; rc < G.query_count; rc++) {
  1217. G.query[rc].query[0] = id >> 8;
  1218. G.query[rc].query[1] = id++;
  1219. }
  1220. }
  1221. for (rc = 0; rc < G.serv_count;) {
  1222. int c;
  1223. c = send_queries(&G.server[rc]);
  1224. if (c > 0) {
  1225. /* more than zero replies received */
  1226. #if 0 /* which version does this? */
  1227. if (option_mask32 & OPT_debug) {
  1228. printf("Replies:\t%d\n", G.server[rc].replies);
  1229. printf("Failures:\t%d\n\n", G.server[rc].failures);
  1230. }
  1231. #endif
  1232. break;
  1233. //FIXME: we "break" even though some queries may still be not answered, and other servers may know them?
  1234. }
  1235. /* c = 0: timed out waiting for replies */
  1236. /* c < 0: error (message already printed) */
  1237. rc++;
  1238. if (rc >= G.serv_count) {
  1239. //
  1240. // NB: bind-utils-9.11.3 behavior (all to stdout, not stderr):
  1241. //
  1242. // $ nslookup gmail.com 8.8.8.8
  1243. // ;; connection timed out; no servers could be reached
  1244. //
  1245. // Using TCP mode:
  1246. // $ nslookup -vc gmail.com 8.8.8.8; echo EXITCODE:$?
  1247. // <~10 sec>
  1248. // ;; Connection to 8.8.8.8#53(8.8.8.8) for gmail.com failed: timed out.
  1249. // <~10 sec>
  1250. // ;; Connection to 8.8.8.8#53(8.8.8.8) for gmail.com failed: timed out.
  1251. // <~10 sec>
  1252. // ;; connection timed out; no servers could be reached
  1253. // ;; Connection to 8.8.8.8#53(8.8.8.8) for gmail.com failed: timed out.
  1254. // <empty line>
  1255. // EXITCODE:1
  1256. // $ _
  1257. printf(";; connection timed out; no servers could be reached\n\n");
  1258. return EXIT_FAILURE;
  1259. }
  1260. }
  1261. err = 0;
  1262. for (rc = 0; rc < G.query_count; rc++) {
  1263. if (G.query[rc].qlen) {
  1264. printf("*** Can't find %s: No answer\n", G.query[rc].name);
  1265. err = 1;
  1266. }
  1267. }
  1268. if (err) /* should this affect exicode too? */
  1269. bb_putchar('\n');
  1270. if (ENABLE_FEATURE_CLEAN_UP) {
  1271. free(G.server);
  1272. free(G.query);
  1273. }
  1274. return G.exitcode;
  1275. }
  1276. #endif