getrrsetbyname.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. /* $OpenBSD: getrrsetbyname.c,v 1.11 2007/10/11 18:36:41 jakob Exp $ */
  2. /*
  3. * Copyright (c) 2001 Jakob Schlyter. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  22. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. /*
  28. * Portions Copyright (c) 1999-2001 Internet Software Consortium.
  29. *
  30. * Permission to use, copy, modify, and distribute this software for any
  31. * purpose with or without fee is hereby granted, provided that the above
  32. * copyright notice and this permission notice appear in all copies.
  33. *
  34. * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
  35. * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  36. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  37. * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
  38. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  39. * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  40. * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  41. * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  42. */
  43. /* OPENBSD ORIGINAL: lib/libc/net/getrrsetbyname.c */
  44. #include "includes.h"
  45. #if !defined (HAVE_GETRRSETBYNAME) && !defined (HAVE_LDNS)
  46. #include <stdlib.h>
  47. #include <string.h>
  48. #include <netinet/in.h>
  49. #include <arpa/inet.h>
  50. #include "getrrsetbyname.h"
  51. #if defined(HAVE_DECL_H_ERRNO) && !HAVE_DECL_H_ERRNO
  52. extern int h_errno;
  53. #endif
  54. /* We don't need multithread support here */
  55. #ifdef _THREAD_PRIVATE
  56. # undef _THREAD_PRIVATE
  57. #endif
  58. #define _THREAD_PRIVATE(a,b,c) (c)
  59. #ifndef HAVE__RES_EXTERN
  60. struct __res_state _res;
  61. #endif
  62. /* Necessary functions and macros */
  63. /*
  64. * Inline versions of get/put short/long. Pointer is advanced.
  65. *
  66. * These macros demonstrate the property of C whereby it can be
  67. * portable or it can be elegant but rarely both.
  68. */
  69. #ifndef INT32SZ
  70. # define INT32SZ 4
  71. #endif
  72. #ifndef INT16SZ
  73. # define INT16SZ 2
  74. #endif
  75. #ifndef GETSHORT
  76. #define GETSHORT(s, cp) { \
  77. register u_char *t_cp = (u_char *)(cp); \
  78. (s) = ((u_int16_t)t_cp[0] << 8) \
  79. | ((u_int16_t)t_cp[1]) \
  80. ; \
  81. (cp) += INT16SZ; \
  82. }
  83. #endif
  84. #ifndef GETLONG
  85. #define GETLONG(l, cp) { \
  86. register u_char *t_cp = (u_char *)(cp); \
  87. (l) = ((u_int32_t)t_cp[0] << 24) \
  88. | ((u_int32_t)t_cp[1] << 16) \
  89. | ((u_int32_t)t_cp[2] << 8) \
  90. | ((u_int32_t)t_cp[3]) \
  91. ; \
  92. (cp) += INT32SZ; \
  93. }
  94. #endif
  95. /*
  96. * Routines to insert/extract short/long's.
  97. */
  98. #ifndef HAVE__GETSHORT
  99. static u_int16_t
  100. _getshort(msgp)
  101. register const u_char *msgp;
  102. {
  103. register u_int16_t u;
  104. GETSHORT(u, msgp);
  105. return (u);
  106. }
  107. #elif defined(HAVE_DECL__GETSHORT) && (HAVE_DECL__GETSHORT == 0)
  108. u_int16_t _getshort(register const u_char *);
  109. #endif
  110. #ifndef HAVE__GETLONG
  111. static u_int32_t
  112. _getlong(msgp)
  113. register const u_char *msgp;
  114. {
  115. register u_int32_t u;
  116. GETLONG(u, msgp);
  117. return (u);
  118. }
  119. #elif defined(HAVE_DECL__GETLONG) && (HAVE_DECL__GETLONG == 0)
  120. u_int32_t _getlong(register const u_char *);
  121. #endif
  122. /* ************** */
  123. #define ANSWER_BUFFER_SIZE 0xffff
  124. struct dns_query {
  125. char *name;
  126. u_int16_t type;
  127. u_int16_t class;
  128. struct dns_query *next;
  129. };
  130. struct dns_rr {
  131. char *name;
  132. u_int16_t type;
  133. u_int16_t class;
  134. u_int16_t ttl;
  135. u_int16_t size;
  136. void *rdata;
  137. struct dns_rr *next;
  138. };
  139. struct dns_response {
  140. HEADER header;
  141. struct dns_query *query;
  142. struct dns_rr *answer;
  143. struct dns_rr *authority;
  144. struct dns_rr *additional;
  145. };
  146. static struct dns_response *parse_dns_response(const u_char *, int);
  147. static struct dns_query *parse_dns_qsection(const u_char *, int,
  148. const u_char **, int);
  149. static struct dns_rr *parse_dns_rrsection(const u_char *, int, const u_char **,
  150. int);
  151. static void free_dns_query(struct dns_query *);
  152. static void free_dns_rr(struct dns_rr *);
  153. static void free_dns_response(struct dns_response *);
  154. static int count_dns_rr(struct dns_rr *, u_int16_t, u_int16_t);
  155. int
  156. getrrsetbyname(const char *hostname, unsigned int rdclass,
  157. unsigned int rdtype, unsigned int flags,
  158. struct rrsetinfo **res)
  159. {
  160. struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
  161. int result;
  162. struct rrsetinfo *rrset = NULL;
  163. struct dns_response *response = NULL;
  164. struct dns_rr *rr;
  165. struct rdatainfo *rdata;
  166. int length;
  167. unsigned int index_ans, index_sig;
  168. int rri_flags = 0;
  169. u_char answer[ANSWER_BUFFER_SIZE];
  170. /* check for invalid class and type */
  171. if (rdclass > 0xffff || rdtype > 0xffff) {
  172. result = ERRSET_INVAL;
  173. goto fail;
  174. }
  175. /* don't allow queries of class or type ANY */
  176. if (rdclass == 0xff || rdtype == 0xff) {
  177. result = ERRSET_INVAL;
  178. goto fail;
  179. }
  180. /* Allow RRSET_FORCE_EDNS0 flag only. */
  181. if ((flags & !RRSET_FORCE_EDNS0) != 0) {
  182. result = ERRSET_INVAL;
  183. goto fail;
  184. }
  185. /* initialize resolver */
  186. if ((_resp->options & RES_INIT) == 0 && res_init() == -1) {
  187. result = ERRSET_FAIL;
  188. goto fail;
  189. }
  190. #ifdef DEBUG
  191. _resp->options |= RES_DEBUG;
  192. #endif /* DEBUG */
  193. #ifdef RES_USE_DNSSEC
  194. /* turn on DNSSEC if required */
  195. // if (_resp->options & RES_USE_EDNS0)
  196. // _resp->options |= RES_USE_DNSSEC;
  197. // if (flags & RRSET_FORCE_EDNS0)
  198. // resp->options |= (RES_USE_EDNS0|RES_USE_DNSSEC);
  199. // else
  200. rri_flags |= RRSET_SECURE_UNSUPPORTED;
  201. #endif /* RES_USE_DNSEC */
  202. /* make query */
  203. length = res_query(hostname, (signed int) rdclass, (signed int) rdtype,
  204. answer, sizeof(answer));
  205. if (length < 0) {
  206. switch(h_errno) {
  207. case HOST_NOT_FOUND:
  208. result = ERRSET_NONAME;
  209. goto fail;
  210. case NO_DATA:
  211. result = ERRSET_NODATA;
  212. goto fail;
  213. default:
  214. result = ERRSET_FAIL;
  215. goto fail;
  216. }
  217. }
  218. /* parse result */
  219. response = parse_dns_response(answer, length);
  220. if (response == NULL) {
  221. result = ERRSET_FAIL;
  222. goto fail;
  223. }
  224. if (response->header.qdcount != 1) {
  225. result = ERRSET_FAIL;
  226. goto fail;
  227. }
  228. /* initialize rrset */
  229. rrset = calloc(1, sizeof(struct rrsetinfo));
  230. if (rrset == NULL) {
  231. result = ERRSET_NOMEMORY;
  232. goto fail;
  233. }
  234. rrset->rri_rdclass = response->query->class;
  235. rrset->rri_rdtype = response->query->type;
  236. rrset->rri_ttl = response->answer->ttl;
  237. rrset->rri_nrdatas = response->header.ancount;
  238. rrset->rri_flags = rri_flags;
  239. #ifdef HAVE_HEADER_AD
  240. /* check for authenticated data */
  241. if (response->header.ad == 1)
  242. rrset->rri_flags |= RRSET_VALIDATED;
  243. #else
  244. rrset->rri_flags |= RRSET_SECURE_UNSUPPORTED;
  245. #endif
  246. /* copy name from answer section */
  247. rrset->rri_name = strdup(response->answer->name);
  248. if (rrset->rri_name == NULL) {
  249. result = ERRSET_NOMEMORY;
  250. goto fail;
  251. }
  252. /* count answers */
  253. rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass,
  254. rrset->rri_rdtype);
  255. rrset->rri_nsigs = count_dns_rr(response->answer, rrset->rri_rdclass,
  256. T_RRSIG);
  257. /* allocate memory for answers */
  258. rrset->rri_rdatas = calloc(rrset->rri_nrdatas,
  259. sizeof(struct rdatainfo));
  260. if (rrset->rri_rdatas == NULL) {
  261. result = ERRSET_NOMEMORY;
  262. goto fail;
  263. }
  264. /* allocate memory for signatures */
  265. if (rrset->rri_nsigs > 0) {
  266. rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo));
  267. if (rrset->rri_sigs == NULL) {
  268. result = ERRSET_NOMEMORY;
  269. goto fail;
  270. }
  271. }
  272. /* copy answers & signatures */
  273. for (rr = response->answer, index_ans = 0, index_sig = 0;
  274. rr; rr = rr->next) {
  275. rdata = NULL;
  276. if (rr->class == rrset->rri_rdclass &&
  277. rr->type == rrset->rri_rdtype)
  278. rdata = &rrset->rri_rdatas[index_ans++];
  279. if (rr->class == rrset->rri_rdclass &&
  280. rr->type == T_RRSIG)
  281. rdata = &rrset->rri_sigs[index_sig++];
  282. if (rdata) {
  283. rdata->rdi_length = rr->size;
  284. rdata->rdi_data = malloc(rr->size);
  285. if (rdata->rdi_data == NULL) {
  286. result = ERRSET_NOMEMORY;
  287. goto fail;
  288. }
  289. memcpy(rdata->rdi_data, rr->rdata, rr->size);
  290. }
  291. }
  292. free_dns_response(response);
  293. *res = rrset;
  294. return (ERRSET_SUCCESS);
  295. fail:
  296. if (rrset != NULL)
  297. freerrset(rrset);
  298. if (response != NULL)
  299. free_dns_response(response);
  300. return (result);
  301. }
  302. void
  303. freerrset(struct rrsetinfo *rrset)
  304. {
  305. u_int16_t i;
  306. if (rrset == NULL)
  307. return;
  308. if (rrset->rri_rdatas) {
  309. for (i = 0; i < rrset->rri_nrdatas; i++) {
  310. if (rrset->rri_rdatas[i].rdi_data == NULL)
  311. break;
  312. free(rrset->rri_rdatas[i].rdi_data);
  313. }
  314. free(rrset->rri_rdatas);
  315. }
  316. if (rrset->rri_sigs) {
  317. for (i = 0; i < rrset->rri_nsigs; i++) {
  318. if (rrset->rri_sigs[i].rdi_data == NULL)
  319. break;
  320. free(rrset->rri_sigs[i].rdi_data);
  321. }
  322. free(rrset->rri_sigs);
  323. }
  324. if (rrset->rri_name)
  325. free(rrset->rri_name);
  326. free(rrset);
  327. }
  328. /*
  329. * DNS response parsing routines
  330. */
  331. static struct dns_response *
  332. parse_dns_response(const u_char *answer, int size)
  333. {
  334. struct dns_response *resp;
  335. const u_char *cp;
  336. /* allocate memory for the response */
  337. resp = calloc(1, sizeof(*resp));
  338. if (resp == NULL)
  339. return (NULL);
  340. /* initialize current pointer */
  341. cp = answer;
  342. /* copy header */
  343. memcpy(&resp->header, cp, HFIXEDSZ);
  344. cp += HFIXEDSZ;
  345. /* fix header byte order */
  346. resp->header.qdcount = ntohs(resp->header.qdcount);
  347. resp->header.ancount = ntohs(resp->header.ancount);
  348. resp->header.nscount = ntohs(resp->header.nscount);
  349. resp->header.arcount = ntohs(resp->header.arcount);
  350. /* there must be at least one query */
  351. if (resp->header.qdcount < 1) {
  352. free_dns_response(resp);
  353. return (NULL);
  354. }
  355. /* parse query section */
  356. resp->query = parse_dns_qsection(answer, size, &cp,
  357. resp->header.qdcount);
  358. if (resp->header.qdcount && resp->query == NULL) {
  359. free_dns_response(resp);
  360. return (NULL);
  361. }
  362. /* parse answer section */
  363. resp->answer = parse_dns_rrsection(answer, size, &cp,
  364. resp->header.ancount);
  365. if (resp->header.ancount && resp->answer == NULL) {
  366. free_dns_response(resp);
  367. return (NULL);
  368. }
  369. /* parse authority section */
  370. resp->authority = parse_dns_rrsection(answer, size, &cp,
  371. resp->header.nscount);
  372. if (resp->header.nscount && resp->authority == NULL) {
  373. free_dns_response(resp);
  374. return (NULL);
  375. }
  376. /* parse additional section */
  377. resp->additional = parse_dns_rrsection(answer, size, &cp,
  378. resp->header.arcount);
  379. if (resp->header.arcount && resp->additional == NULL) {
  380. free_dns_response(resp);
  381. return (NULL);
  382. }
  383. return (resp);
  384. }
  385. static struct dns_query *
  386. parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count)
  387. {
  388. struct dns_query *head, *curr, *prev;
  389. int i, length;
  390. char name[MAXDNAME];
  391. for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
  392. /* allocate and initialize struct */
  393. curr = calloc(1, sizeof(struct dns_query));
  394. if (curr == NULL) {
  395. free_dns_query(head);
  396. return (NULL);
  397. }
  398. if (head == NULL)
  399. head = curr;
  400. if (prev != NULL)
  401. prev->next = curr;
  402. /* name */
  403. length = dn_expand(answer, answer + size, *cp, name,
  404. sizeof(name));
  405. if (length < 0) {
  406. free_dns_query(head);
  407. return (NULL);
  408. }
  409. curr->name = strdup(name);
  410. if (curr->name == NULL) {
  411. free_dns_query(head);
  412. return (NULL);
  413. }
  414. *cp += length;
  415. /* type */
  416. curr->type = _getshort(*cp);
  417. *cp += INT16SZ;
  418. /* class */
  419. curr->class = _getshort(*cp);
  420. *cp += INT16SZ;
  421. }
  422. return (head);
  423. }
  424. static struct dns_rr *
  425. parse_dns_rrsection(const u_char *answer, int size, const u_char **cp,
  426. int count)
  427. {
  428. struct dns_rr *head, *curr, *prev;
  429. int i, length;
  430. char name[MAXDNAME];
  431. for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
  432. /* allocate and initialize struct */
  433. curr = calloc(1, sizeof(struct dns_rr));
  434. if (curr == NULL) {
  435. free_dns_rr(head);
  436. return (NULL);
  437. }
  438. if (head == NULL)
  439. head = curr;
  440. if (prev != NULL)
  441. prev->next = curr;
  442. /* name */
  443. length = dn_expand(answer, answer + size, *cp, name,
  444. sizeof(name));
  445. if (length < 0) {
  446. free_dns_rr(head);
  447. return (NULL);
  448. }
  449. curr->name = strdup(name);
  450. if (curr->name == NULL) {
  451. free_dns_rr(head);
  452. return (NULL);
  453. }
  454. *cp += length;
  455. /* type */
  456. curr->type = _getshort(*cp);
  457. *cp += INT16SZ;
  458. /* class */
  459. curr->class = _getshort(*cp);
  460. *cp += INT16SZ;
  461. /* ttl */
  462. curr->ttl = _getlong(*cp);
  463. *cp += INT32SZ;
  464. /* rdata size */
  465. curr->size = _getshort(*cp);
  466. *cp += INT16SZ;
  467. /* rdata itself */
  468. curr->rdata = malloc(curr->size);
  469. if (curr->rdata == NULL) {
  470. free_dns_rr(head);
  471. return (NULL);
  472. }
  473. memcpy(curr->rdata, *cp, curr->size);
  474. *cp += curr->size;
  475. }
  476. return (head);
  477. }
  478. static void
  479. free_dns_query(struct dns_query *p)
  480. {
  481. if (p == NULL)
  482. return;
  483. if (p->name)
  484. free(p->name);
  485. free_dns_query(p->next);
  486. free(p);
  487. }
  488. static void
  489. free_dns_rr(struct dns_rr *p)
  490. {
  491. if (p == NULL)
  492. return;
  493. if (p->name)
  494. free(p->name);
  495. if (p->rdata)
  496. free(p->rdata);
  497. free_dns_rr(p->next);
  498. free(p);
  499. }
  500. static void
  501. free_dns_response(struct dns_response *p)
  502. {
  503. if (p == NULL)
  504. return;
  505. free_dns_query(p->query);
  506. free_dns_rr(p->answer);
  507. free_dns_rr(p->authority);
  508. free_dns_rr(p->additional);
  509. free(p);
  510. }
  511. static int
  512. count_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type)
  513. {
  514. int n = 0;
  515. while(p) {
  516. if (p->class == class && p->type == type)
  517. n++;
  518. p = p->next;
  519. }
  520. return (n);
  521. }
  522. #endif /* !defined (HAVE_GETRRSETBYNAME) && !defined (HAVE_LDNS) */