dns.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2010,2011 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/net.h>
  19. #include <grub/net/udp.h>
  20. #include <grub/command.h>
  21. #include <grub/i18n.h>
  22. #include <grub/err.h>
  23. #include <grub/time.h>
  24. struct dns_cache_element
  25. {
  26. char *name;
  27. grub_size_t naddresses;
  28. struct grub_net_network_level_address *addresses;
  29. grub_uint64_t limit_time;
  30. };
  31. #define DNS_CACHE_SIZE 1021
  32. #define DNS_HASH_BASE 423
  33. typedef enum grub_dns_qtype_id
  34. {
  35. GRUB_DNS_QTYPE_A = 1,
  36. GRUB_DNS_QTYPE_AAAA = 28
  37. } grub_dns_qtype_id_t;
  38. static struct dns_cache_element dns_cache[DNS_CACHE_SIZE];
  39. static struct grub_net_network_level_address *dns_servers;
  40. static grub_size_t dns_nservers, dns_servers_alloc;
  41. grub_err_t
  42. grub_net_add_dns_server (const struct grub_net_network_level_address *s)
  43. {
  44. if (dns_servers_alloc <= dns_nservers)
  45. {
  46. int na = dns_servers_alloc * 2;
  47. struct grub_net_network_level_address *ns;
  48. if (na < 8)
  49. na = 8;
  50. ns = grub_realloc (dns_servers, na * sizeof (ns[0]));
  51. if (!ns)
  52. return grub_errno;
  53. dns_servers_alloc = na;
  54. dns_servers = ns;
  55. }
  56. dns_servers[dns_nservers++] = *s;
  57. return GRUB_ERR_NONE;
  58. }
  59. void
  60. grub_net_remove_dns_server (const struct grub_net_network_level_address *s)
  61. {
  62. grub_size_t i;
  63. for (i = 0; i < dns_nservers; i++)
  64. if (grub_net_addr_cmp (s, &dns_servers[i]) == 0)
  65. break;
  66. if (i < dns_nservers)
  67. {
  68. dns_servers[i] = dns_servers[dns_nservers - 1];
  69. dns_nservers--;
  70. }
  71. }
  72. struct dns_header
  73. {
  74. grub_uint16_t id;
  75. grub_uint8_t flags;
  76. grub_uint8_t ra_z_r_code;
  77. grub_uint16_t qdcount;
  78. grub_uint16_t ancount;
  79. grub_uint16_t nscount;
  80. grub_uint16_t arcount;
  81. } GRUB_PACKED;
  82. enum
  83. {
  84. FLAGS_RESPONSE = 0x80,
  85. FLAGS_OPCODE = 0x78,
  86. FLAGS_RD = 0x01
  87. };
  88. enum
  89. {
  90. ERRCODE_MASK = 0x0f
  91. };
  92. enum
  93. {
  94. DNS_PORT = 53
  95. };
  96. struct recv_data
  97. {
  98. grub_size_t *naddresses;
  99. struct grub_net_network_level_address **addresses;
  100. int cache;
  101. grub_uint16_t id;
  102. int dns_err;
  103. char *name;
  104. const char *oname;
  105. int stop;
  106. };
  107. static inline int
  108. hash (const char *str)
  109. {
  110. unsigned v = 0, xn = 1;
  111. const char *ptr;
  112. for (ptr = str; *ptr; )
  113. {
  114. v = (v + xn * *ptr);
  115. xn = (DNS_HASH_BASE * xn) % DNS_CACHE_SIZE;
  116. ptr++;
  117. if (((ptr - str) & 0x3ff) == 0)
  118. v %= DNS_CACHE_SIZE;
  119. }
  120. return v % DNS_CACHE_SIZE;
  121. }
  122. static int
  123. check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
  124. const grub_uint8_t *tail, const char *check_with,
  125. int *length, char *set)
  126. {
  127. const char *readable_ptr = check_with;
  128. const grub_uint8_t *ptr;
  129. char *optr = set;
  130. int bytes_processed = 0;
  131. if (length)
  132. *length = 0;
  133. for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; )
  134. {
  135. /* End marker. */
  136. if (!*ptr)
  137. {
  138. if (length && *length)
  139. (*length)--;
  140. if (optr && optr != set)
  141. optr--;
  142. if (optr)
  143. *optr = 0;
  144. return !readable_ptr || (*readable_ptr == 0);
  145. }
  146. if (*ptr & 0xc0)
  147. {
  148. bytes_processed += 2;
  149. if (ptr + 1 >= tail)
  150. return 0;
  151. ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]);
  152. continue;
  153. }
  154. if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)
  155. return 0;
  156. if (grub_memchr (ptr + 1, 0, *ptr)
  157. || grub_memchr (ptr + 1, '.', *ptr))
  158. return 0;
  159. if (readable_ptr)
  160. readable_ptr += *ptr;
  161. if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0)
  162. return 0;
  163. bytes_processed += *ptr + 1;
  164. if (length)
  165. *length += *ptr + 1;
  166. if (optr)
  167. {
  168. grub_memcpy (optr, ptr + 1, *ptr);
  169. optr += *ptr;
  170. }
  171. if (optr)
  172. *optr++ = '.';
  173. if (readable_ptr && *readable_ptr)
  174. readable_ptr++;
  175. ptr += *ptr + 1;
  176. }
  177. return 0;
  178. }
  179. static int
  180. check_name (const grub_uint8_t *name_at, const grub_uint8_t *head,
  181. const grub_uint8_t *tail, const char *check_with)
  182. {
  183. return check_name_real (name_at, head, tail, check_with, NULL, NULL);
  184. }
  185. static char *
  186. get_name (const grub_uint8_t *name_at, const grub_uint8_t *head,
  187. const grub_uint8_t *tail)
  188. {
  189. int length;
  190. char *ret;
  191. if (!check_name_real (name_at, head, tail, NULL, &length, NULL))
  192. return NULL;
  193. ret = grub_malloc (length + 1);
  194. if (!ret)
  195. return NULL;
  196. if (!check_name_real (name_at, head, tail, NULL, NULL, ret))
  197. {
  198. grub_free (ret);
  199. return NULL;
  200. }
  201. return ret;
  202. }
  203. enum
  204. {
  205. DNS_CLASS_A = 1,
  206. DNS_CLASS_CNAME = 5,
  207. DNS_CLASS_AAAA = 28
  208. };
  209. static grub_err_t
  210. recv_hook (grub_net_udp_socket_t sock __attribute__ ((unused)),
  211. struct grub_net_buff *nb,
  212. void *data_)
  213. {
  214. struct dns_header *head;
  215. struct recv_data *data = data_;
  216. int i, j;
  217. grub_uint8_t *ptr, *reparse_ptr;
  218. int redirect_cnt = 0;
  219. char *redirect_save = NULL;
  220. grub_uint32_t ttl_all = ~0U;
  221. /* Code apparently assumed that only one packet is received as response.
  222. We may get multiple responses due to network condition, so check here
  223. and quit early. */
  224. if (*data->addresses)
  225. {
  226. grub_netbuff_free (nb);
  227. return GRUB_ERR_NONE;
  228. }
  229. head = (struct dns_header *) nb->data;
  230. ptr = (grub_uint8_t *) (head + 1);
  231. if (ptr >= nb->tail)
  232. {
  233. grub_netbuff_free (nb);
  234. return GRUB_ERR_NONE;
  235. }
  236. if (head->id != data->id)
  237. {
  238. grub_netbuff_free (nb);
  239. return GRUB_ERR_NONE;
  240. }
  241. if (!(head->flags & FLAGS_RESPONSE) || (head->flags & FLAGS_OPCODE))
  242. {
  243. grub_netbuff_free (nb);
  244. return GRUB_ERR_NONE;
  245. }
  246. if (head->ra_z_r_code & ERRCODE_MASK)
  247. {
  248. data->dns_err = 1;
  249. grub_netbuff_free (nb);
  250. return GRUB_ERR_NONE;
  251. }
  252. for (i = 0; i < grub_be_to_cpu16 (head->qdcount); i++)
  253. {
  254. if (ptr >= nb->tail)
  255. {
  256. grub_netbuff_free (nb);
  257. return GRUB_ERR_NONE;
  258. }
  259. while (ptr < nb->tail && !((*ptr & 0xc0) || *ptr == 0))
  260. ptr += *ptr + 1;
  261. if (ptr < nb->tail && (*ptr & 0xc0))
  262. ptr++;
  263. ptr++;
  264. ptr += 4;
  265. }
  266. *data->addresses = grub_malloc (sizeof ((*data->addresses)[0])
  267. * grub_be_to_cpu16 (head->ancount));
  268. if (!*data->addresses)
  269. {
  270. grub_errno = GRUB_ERR_NONE;
  271. grub_netbuff_free (nb);
  272. return GRUB_ERR_NONE;
  273. }
  274. reparse_ptr = ptr;
  275. reparse:
  276. for (i = 0, ptr = reparse_ptr; i < grub_be_to_cpu16 (head->ancount); i++)
  277. {
  278. int ignored = 0;
  279. grub_uint8_t class;
  280. grub_uint32_t ttl = 0;
  281. grub_uint16_t length;
  282. if (ptr >= nb->tail)
  283. {
  284. if (!*data->naddresses)
  285. grub_free (*data->addresses);
  286. return GRUB_ERR_NONE;
  287. }
  288. ignored = !check_name (ptr, nb->data, nb->tail, data->name);
  289. while (ptr < nb->tail && !((*ptr & 0xc0) || *ptr == 0))
  290. ptr += *ptr + 1;
  291. if (ptr < nb->tail && (*ptr & 0xc0))
  292. ptr++;
  293. ptr++;
  294. if (ptr + 10 >= nb->tail)
  295. {
  296. if (!*data->naddresses)
  297. grub_free (*data->addresses);
  298. grub_netbuff_free (nb);
  299. return GRUB_ERR_NONE;
  300. }
  301. if (*ptr++ != 0)
  302. ignored = 1;
  303. class = *ptr++;
  304. if (*ptr++ != 0)
  305. ignored = 1;
  306. if (*ptr++ != 1)
  307. ignored = 1;
  308. for (j = 0; j < 4; j++)
  309. {
  310. ttl <<= 8;
  311. ttl |= *ptr++;
  312. }
  313. length = *ptr++ << 8;
  314. length |= *ptr++;
  315. if (ptr + length > nb->tail)
  316. {
  317. if (!*data->naddresses)
  318. grub_free (*data->addresses);
  319. grub_netbuff_free (nb);
  320. return GRUB_ERR_NONE;
  321. }
  322. if (!ignored)
  323. {
  324. if (ttl_all > ttl)
  325. ttl_all = ttl;
  326. switch (class)
  327. {
  328. case DNS_CLASS_A:
  329. if (length != 4)
  330. break;
  331. (*data->addresses)[*data->naddresses].type
  332. = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  333. grub_memcpy (&(*data->addresses)[*data->naddresses].ipv4,
  334. ptr, 4);
  335. (*data->naddresses)++;
  336. data->stop = 1;
  337. break;
  338. case DNS_CLASS_AAAA:
  339. if (length != 16)
  340. break;
  341. (*data->addresses)[*data->naddresses].type
  342. = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
  343. grub_memcpy (&(*data->addresses)[*data->naddresses].ipv6,
  344. ptr, 16);
  345. (*data->naddresses)++;
  346. data->stop = 1;
  347. break;
  348. case DNS_CLASS_CNAME:
  349. if (!(redirect_cnt & (redirect_cnt - 1)))
  350. {
  351. grub_free (redirect_save);
  352. redirect_save = data->name;
  353. }
  354. else
  355. grub_free (data->name);
  356. redirect_cnt++;
  357. data->name = get_name (ptr, nb->data, nb->tail);
  358. if (!data->name)
  359. {
  360. data->dns_err = 1;
  361. grub_errno = 0;
  362. return GRUB_ERR_NONE;
  363. }
  364. grub_dprintf ("dns", "CNAME %s\n", data->name);
  365. if (grub_strcmp (redirect_save, data->name) == 0)
  366. {
  367. data->dns_err = 1;
  368. grub_free (redirect_save);
  369. return GRUB_ERR_NONE;
  370. }
  371. goto reparse;
  372. }
  373. }
  374. ptr += length;
  375. }
  376. if (ttl_all && *data->naddresses && data->cache)
  377. {
  378. int h;
  379. grub_dprintf ("dns", "caching for %d seconds\n", ttl_all);
  380. h = hash (data->oname);
  381. grub_free (dns_cache[h].name);
  382. dns_cache[h].name = 0;
  383. grub_free (dns_cache[h].addresses);
  384. dns_cache[h].addresses = 0;
  385. dns_cache[h].name = grub_strdup (data->oname);
  386. dns_cache[h].naddresses = *data->naddresses;
  387. dns_cache[h].addresses = grub_malloc (*data->naddresses
  388. * sizeof (dns_cache[h].addresses[0]));
  389. dns_cache[h].limit_time = grub_get_time_ms () + 1000 * ttl_all;
  390. if (!dns_cache[h].addresses || !dns_cache[h].name)
  391. {
  392. grub_free (dns_cache[h].name);
  393. dns_cache[h].name = 0;
  394. grub_free (dns_cache[h].addresses);
  395. dns_cache[h].addresses = 0;
  396. }
  397. grub_memcpy (dns_cache[h].addresses, *data->addresses,
  398. *data->naddresses
  399. * sizeof (dns_cache[h].addresses[0]));
  400. }
  401. grub_netbuff_free (nb);
  402. grub_free (redirect_save);
  403. return GRUB_ERR_NONE;
  404. }
  405. grub_err_t
  406. grub_net_dns_lookup (const char *name,
  407. const struct grub_net_network_level_address *servers,
  408. grub_size_t n_servers,
  409. grub_size_t *naddresses,
  410. struct grub_net_network_level_address **addresses,
  411. int cache)
  412. {
  413. grub_size_t send_servers = 0;
  414. grub_size_t i, j;
  415. struct grub_net_buff *nb;
  416. grub_net_udp_socket_t *sockets;
  417. grub_uint8_t *optr;
  418. const char *iptr;
  419. struct dns_header *head;
  420. static grub_uint16_t id = 1;
  421. grub_uint8_t *qtypeptr;
  422. grub_err_t err = GRUB_ERR_NONE;
  423. struct recv_data data = {naddresses, addresses, cache,
  424. grub_cpu_to_be16 (id++), 0, 0, name, 0};
  425. grub_uint8_t *nbd;
  426. grub_size_t try_server = 0;
  427. if (!servers)
  428. {
  429. servers = dns_servers;
  430. n_servers = dns_nservers;
  431. }
  432. if (!n_servers)
  433. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  434. N_("no DNS servers configured"));
  435. *naddresses = 0;
  436. if (cache)
  437. {
  438. int h;
  439. h = hash (name);
  440. if (dns_cache[h].name && grub_strcmp (dns_cache[h].name, name) == 0
  441. && grub_get_time_ms () < dns_cache[h].limit_time)
  442. {
  443. grub_dprintf ("dns", "retrieved from cache\n");
  444. *addresses = grub_malloc (dns_cache[h].naddresses
  445. * sizeof ((*addresses)[0]));
  446. if (!*addresses)
  447. return grub_errno;
  448. *naddresses = dns_cache[h].naddresses;
  449. grub_memcpy (*addresses, dns_cache[h].addresses,
  450. dns_cache[h].naddresses
  451. * sizeof ((*addresses)[0]));
  452. return GRUB_ERR_NONE;
  453. }
  454. }
  455. sockets = grub_malloc (sizeof (sockets[0]) * n_servers);
  456. if (!sockets)
  457. return grub_errno;
  458. data.name = grub_strdup (name);
  459. if (!data.name)
  460. {
  461. grub_free (sockets);
  462. return grub_errno;
  463. }
  464. nb = grub_netbuff_alloc (GRUB_NET_OUR_MAX_IP_HEADER_SIZE
  465. + GRUB_NET_MAX_LINK_HEADER_SIZE
  466. + GRUB_NET_UDP_HEADER_SIZE
  467. + sizeof (struct dns_header)
  468. + grub_strlen (name) + 2 + 4);
  469. if (!nb)
  470. {
  471. grub_free (sockets);
  472. grub_free (data.name);
  473. return grub_errno;
  474. }
  475. grub_netbuff_reserve (nb, GRUB_NET_OUR_MAX_IP_HEADER_SIZE
  476. + GRUB_NET_MAX_LINK_HEADER_SIZE
  477. + GRUB_NET_UDP_HEADER_SIZE);
  478. grub_netbuff_put (nb, sizeof (struct dns_header)
  479. + grub_strlen (name) + 2 + 4);
  480. head = (struct dns_header *) nb->data;
  481. optr = (grub_uint8_t *) (head + 1);
  482. for (iptr = name; *iptr; )
  483. {
  484. const char *dot;
  485. dot = grub_strchr (iptr, '.');
  486. if (!dot)
  487. dot = iptr + grub_strlen (iptr);
  488. if ((dot - iptr) >= 64)
  489. {
  490. grub_free (sockets);
  491. grub_free (data.name);
  492. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  493. N_("domain name component is too long"));
  494. }
  495. *optr = (dot - iptr);
  496. optr++;
  497. grub_memcpy (optr, iptr, dot - iptr);
  498. optr += dot - iptr;
  499. iptr = dot;
  500. if (*iptr)
  501. iptr++;
  502. }
  503. *optr++ = 0;
  504. /* Type. */
  505. *optr++ = 0;
  506. qtypeptr = optr++;
  507. /* Class. */
  508. *optr++ = 0;
  509. *optr++ = 1;
  510. head->id = data.id;
  511. head->flags = FLAGS_RD;
  512. head->ra_z_r_code = 0;
  513. head->qdcount = grub_cpu_to_be16_compile_time (1);
  514. head->ancount = grub_cpu_to_be16_compile_time (0);
  515. head->nscount = grub_cpu_to_be16_compile_time (0);
  516. head->arcount = grub_cpu_to_be16_compile_time (0);
  517. nbd = nb->data;
  518. for (i = 0; i < n_servers * 4; i++)
  519. {
  520. /* Connect to a next server. */
  521. while (!(i & 1) && try_server < n_servers)
  522. {
  523. sockets[send_servers] = grub_net_udp_open (servers[try_server++],
  524. DNS_PORT,
  525. recv_hook,
  526. &data);
  527. if (!sockets[send_servers])
  528. {
  529. err = grub_errno;
  530. grub_errno = GRUB_ERR_NONE;
  531. }
  532. else
  533. {
  534. send_servers++;
  535. break;
  536. }
  537. }
  538. if (!send_servers)
  539. goto out;
  540. if (*data.naddresses)
  541. goto out;
  542. for (j = 0; j < send_servers; j++)
  543. {
  544. grub_err_t err2;
  545. grub_size_t t = 0;
  546. do
  547. {
  548. nb->data = nbd;
  549. if (servers[j].option == DNS_OPTION_IPV4 ||
  550. ((servers[j].option == DNS_OPTION_PREFER_IPV4) && (t++ == 0)) ||
  551. ((servers[j].option == DNS_OPTION_PREFER_IPV6) && (t++ == 1)))
  552. *qtypeptr = GRUB_DNS_QTYPE_A;
  553. else
  554. *qtypeptr = GRUB_DNS_QTYPE_AAAA;
  555. grub_dprintf ("dns", "QTYPE: %u QNAME: %s\n", *qtypeptr, name);
  556. err2 = grub_net_send_udp_packet (sockets[j], nb);
  557. if (err2)
  558. {
  559. grub_errno = GRUB_ERR_NONE;
  560. err = err2;
  561. }
  562. if (*data.naddresses)
  563. goto out;
  564. }
  565. while (t == 1);
  566. }
  567. grub_net_poll_cards (200, &data.stop);
  568. }
  569. out:
  570. grub_free (data.name);
  571. grub_netbuff_free (nb);
  572. for (j = 0; j < send_servers; j++)
  573. grub_net_udp_close (sockets[j]);
  574. grub_free (sockets);
  575. if (*data.naddresses)
  576. return GRUB_ERR_NONE;
  577. if (data.dns_err)
  578. return grub_error (GRUB_ERR_NET_NO_DOMAIN,
  579. N_("no DNS record found"));
  580. if (err)
  581. {
  582. grub_errno = err;
  583. return err;
  584. }
  585. return grub_error (GRUB_ERR_TIMEOUT,
  586. N_("no DNS reply received"));
  587. }
  588. static grub_err_t
  589. grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)),
  590. int argc, char **args)
  591. {
  592. grub_err_t err;
  593. struct grub_net_network_level_address cmd_server;
  594. struct grub_net_network_level_address *servers;
  595. grub_size_t nservers, i, naddresses = 0;
  596. struct grub_net_network_level_address *addresses = 0;
  597. if (argc != 2 && argc != 1)
  598. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
  599. if (argc == 2)
  600. {
  601. err = grub_net_resolve_address (args[1], &cmd_server);
  602. if (err)
  603. return err;
  604. servers = &cmd_server;
  605. nservers = 1;
  606. }
  607. else
  608. {
  609. servers = dns_servers;
  610. nservers = dns_nservers;
  611. }
  612. grub_net_dns_lookup (args[0], servers, nservers, &naddresses,
  613. &addresses, 0);
  614. for (i = 0; i < naddresses; i++)
  615. {
  616. char buf[GRUB_NET_MAX_STR_ADDR_LEN];
  617. grub_net_addr_to_str (&addresses[i], buf);
  618. grub_printf ("%s\n", buf);
  619. }
  620. grub_free (addresses);
  621. if (naddresses)
  622. return GRUB_ERR_NONE;
  623. return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found"));
  624. }
  625. static grub_err_t
  626. grub_cmd_list_dns (struct grub_command *cmd __attribute__ ((unused)),
  627. int argc __attribute__ ((unused)),
  628. char **args __attribute__ ((unused)))
  629. {
  630. grub_size_t i;
  631. const char *strtype = "";
  632. for (i = 0; i < dns_nservers; i++)
  633. {
  634. switch (dns_servers[i].option)
  635. {
  636. case DNS_OPTION_IPV4:
  637. strtype = _("only ipv4");
  638. break;
  639. case DNS_OPTION_IPV6:
  640. strtype = _("only ipv6");
  641. break;
  642. case DNS_OPTION_PREFER_IPV4:
  643. strtype = _("prefer ipv4");
  644. break;
  645. case DNS_OPTION_PREFER_IPV6:
  646. strtype = _("prefer ipv6");
  647. break;
  648. }
  649. char buf[GRUB_NET_MAX_STR_ADDR_LEN];
  650. grub_net_addr_to_str (&dns_servers[i], buf);
  651. grub_printf ("%s (%s)\n", buf, strtype);
  652. }
  653. return GRUB_ERR_NONE;
  654. }
  655. static grub_err_t
  656. grub_cmd_add_dns (struct grub_command *cmd __attribute__ ((unused)),
  657. int argc, char **args)
  658. {
  659. grub_err_t err;
  660. struct grub_net_network_level_address server;
  661. if ((argc < 1) || (argc > 2))
  662. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
  663. else if (argc == 1)
  664. server.option = DNS_OPTION_PREFER_IPV4;
  665. else
  666. {
  667. if (grub_strcmp (args[1], "--only-ipv4") == 0)
  668. server.option = DNS_OPTION_IPV4;
  669. else if (grub_strcmp (args[1], "--only-ipv6") == 0)
  670. server.option = DNS_OPTION_IPV6;
  671. else if (grub_strcmp (args[1], "--prefer-ipv4") == 0)
  672. server.option = DNS_OPTION_PREFER_IPV4;
  673. else if (grub_strcmp (args[1], "--prefer-ipv6") == 0)
  674. server.option = DNS_OPTION_PREFER_IPV6;
  675. else
  676. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid argument"));
  677. }
  678. err = grub_net_resolve_address (args[0], &server);
  679. if (err)
  680. return err;
  681. return grub_net_add_dns_server (&server);
  682. }
  683. static grub_err_t
  684. grub_cmd_del_dns (struct grub_command *cmd __attribute__ ((unused)),
  685. int argc, char **args)
  686. {
  687. grub_err_t err;
  688. struct grub_net_network_level_address server;
  689. if (argc != 1)
  690. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
  691. err = grub_net_resolve_address (args[1], &server);
  692. if (err)
  693. return err;
  694. return grub_net_add_dns_server (&server);
  695. }
  696. static grub_command_t cmd, cmd_add, cmd_del, cmd_list;
  697. void
  698. grub_dns_init (void)
  699. {
  700. cmd = grub_register_command ("net_nslookup", grub_cmd_nslookup,
  701. N_("ADDRESS DNSSERVER"),
  702. N_("Perform a DNS lookup"));
  703. cmd_add = grub_register_command ("net_add_dns", grub_cmd_add_dns,
  704. N_("DNSSERVER"),
  705. N_("Add a DNS server"));
  706. cmd_del = grub_register_command ("net_del_dns", grub_cmd_del_dns,
  707. N_("DNSSERVER"),
  708. N_("Remove a DNS server"));
  709. cmd_list = grub_register_command ("net_ls_dns", grub_cmd_list_dns,
  710. NULL, N_("List DNS servers"));
  711. }
  712. void
  713. grub_dns_fini (void)
  714. {
  715. grub_unregister_command (cmd);
  716. grub_unregister_command (cmd_add);
  717. grub_unregister_command (cmd_del);
  718. grub_unregister_command (cmd_list);
  719. }