dns.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  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. head = (struct dns_header *) nb->data;
  222. ptr = (grub_uint8_t *) (head + 1);
  223. if (ptr >= nb->tail)
  224. {
  225. grub_netbuff_free (nb);
  226. return GRUB_ERR_NONE;
  227. }
  228. if (head->id != data->id)
  229. {
  230. grub_netbuff_free (nb);
  231. return GRUB_ERR_NONE;
  232. }
  233. if (!(head->flags & FLAGS_RESPONSE) || (head->flags & FLAGS_OPCODE))
  234. {
  235. grub_netbuff_free (nb);
  236. return GRUB_ERR_NONE;
  237. }
  238. if (head->ra_z_r_code & ERRCODE_MASK)
  239. {
  240. data->dns_err = 1;
  241. grub_netbuff_free (nb);
  242. return GRUB_ERR_NONE;
  243. }
  244. for (i = 0; i < grub_be_to_cpu16 (head->qdcount); i++)
  245. {
  246. if (ptr >= nb->tail)
  247. {
  248. grub_netbuff_free (nb);
  249. return GRUB_ERR_NONE;
  250. }
  251. while (ptr < nb->tail && !((*ptr & 0xc0) || *ptr == 0))
  252. ptr += *ptr + 1;
  253. if (ptr < nb->tail && (*ptr & 0xc0))
  254. ptr++;
  255. ptr++;
  256. ptr += 4;
  257. }
  258. *data->addresses = grub_malloc (sizeof ((*data->addresses)[0])
  259. * grub_be_to_cpu16 (head->ancount));
  260. if (!*data->addresses)
  261. {
  262. grub_errno = GRUB_ERR_NONE;
  263. grub_netbuff_free (nb);
  264. return GRUB_ERR_NONE;
  265. }
  266. reparse_ptr = ptr;
  267. reparse:
  268. for (i = 0, ptr = reparse_ptr; i < grub_be_to_cpu16 (head->ancount); i++)
  269. {
  270. int ignored = 0;
  271. grub_uint8_t class;
  272. grub_uint32_t ttl = 0;
  273. grub_uint16_t length;
  274. if (ptr >= nb->tail)
  275. {
  276. if (!*data->naddresses)
  277. grub_free (*data->addresses);
  278. return GRUB_ERR_NONE;
  279. }
  280. ignored = !check_name (ptr, nb->data, nb->tail, data->name);
  281. while (ptr < nb->tail && !((*ptr & 0xc0) || *ptr == 0))
  282. ptr += *ptr + 1;
  283. if (ptr < nb->tail && (*ptr & 0xc0))
  284. ptr++;
  285. ptr++;
  286. if (ptr + 10 >= nb->tail)
  287. {
  288. if (!*data->naddresses)
  289. grub_free (*data->addresses);
  290. grub_netbuff_free (nb);
  291. return GRUB_ERR_NONE;
  292. }
  293. if (*ptr++ != 0)
  294. ignored = 1;
  295. class = *ptr++;
  296. if (*ptr++ != 0)
  297. ignored = 1;
  298. if (*ptr++ != 1)
  299. ignored = 1;
  300. for (j = 0; j < 4; j++)
  301. {
  302. ttl <<= 8;
  303. ttl |= *ptr++;
  304. }
  305. length = *ptr++ << 8;
  306. length |= *ptr++;
  307. if (ptr + length > nb->tail)
  308. {
  309. if (!*data->naddresses)
  310. grub_free (*data->addresses);
  311. grub_netbuff_free (nb);
  312. return GRUB_ERR_NONE;
  313. }
  314. if (!ignored)
  315. {
  316. if (ttl_all > ttl)
  317. ttl_all = ttl;
  318. switch (class)
  319. {
  320. case DNS_CLASS_A:
  321. if (length != 4)
  322. break;
  323. (*data->addresses)[*data->naddresses].type
  324. = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
  325. grub_memcpy (&(*data->addresses)[*data->naddresses].ipv4,
  326. ptr, 4);
  327. (*data->naddresses)++;
  328. data->stop = 1;
  329. break;
  330. case DNS_CLASS_AAAA:
  331. if (length != 16)
  332. break;
  333. (*data->addresses)[*data->naddresses].type
  334. = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
  335. grub_memcpy (&(*data->addresses)[*data->naddresses].ipv6,
  336. ptr, 16);
  337. (*data->naddresses)++;
  338. data->stop = 1;
  339. break;
  340. case DNS_CLASS_CNAME:
  341. if (!(redirect_cnt & (redirect_cnt - 1)))
  342. {
  343. grub_free (redirect_save);
  344. redirect_save = data->name;
  345. }
  346. else
  347. grub_free (data->name);
  348. redirect_cnt++;
  349. data->name = get_name (ptr, nb->data, nb->tail);
  350. if (!data->name)
  351. {
  352. data->dns_err = 1;
  353. grub_errno = 0;
  354. return GRUB_ERR_NONE;
  355. }
  356. grub_dprintf ("dns", "CNAME %s\n", data->name);
  357. if (grub_strcmp (redirect_save, data->name) == 0)
  358. {
  359. data->dns_err = 1;
  360. grub_free (redirect_save);
  361. return GRUB_ERR_NONE;
  362. }
  363. goto reparse;
  364. }
  365. }
  366. ptr += length;
  367. }
  368. if (ttl_all && *data->naddresses && data->cache)
  369. {
  370. int h;
  371. grub_dprintf ("dns", "caching for %d seconds\n", ttl_all);
  372. h = hash (data->oname);
  373. grub_free (dns_cache[h].name);
  374. dns_cache[h].name = 0;
  375. grub_free (dns_cache[h].addresses);
  376. dns_cache[h].addresses = 0;
  377. dns_cache[h].name = grub_strdup (data->oname);
  378. dns_cache[h].naddresses = *data->naddresses;
  379. dns_cache[h].addresses = grub_malloc (*data->naddresses
  380. * sizeof (dns_cache[h].addresses[0]));
  381. dns_cache[h].limit_time = grub_get_time_ms () + 1000 * ttl_all;
  382. if (!dns_cache[h].addresses || !dns_cache[h].name)
  383. {
  384. grub_free (dns_cache[h].name);
  385. dns_cache[h].name = 0;
  386. grub_free (dns_cache[h].addresses);
  387. dns_cache[h].addresses = 0;
  388. }
  389. grub_memcpy (dns_cache[h].addresses, *data->addresses,
  390. *data->naddresses
  391. * sizeof (dns_cache[h].addresses[0]));
  392. }
  393. grub_netbuff_free (nb);
  394. grub_free (redirect_save);
  395. return GRUB_ERR_NONE;
  396. }
  397. grub_err_t
  398. grub_net_dns_lookup (const char *name,
  399. const struct grub_net_network_level_address *servers,
  400. grub_size_t n_servers,
  401. grub_size_t *naddresses,
  402. struct grub_net_network_level_address **addresses,
  403. int cache)
  404. {
  405. grub_size_t send_servers = 0;
  406. grub_size_t i, j;
  407. struct grub_net_buff *nb;
  408. grub_net_udp_socket_t *sockets;
  409. grub_uint8_t *optr;
  410. const char *iptr;
  411. struct dns_header *head;
  412. static grub_uint16_t id = 1;
  413. grub_uint8_t *qtypeptr;
  414. grub_err_t err = GRUB_ERR_NONE;
  415. struct recv_data data = {naddresses, addresses, cache,
  416. grub_cpu_to_be16 (id++), 0, 0, name, 0};
  417. grub_uint8_t *nbd;
  418. grub_size_t try_server = 0;
  419. if (!servers)
  420. {
  421. servers = dns_servers;
  422. n_servers = dns_nservers;
  423. }
  424. if (!n_servers)
  425. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  426. N_("no DNS servers configured"));
  427. *naddresses = 0;
  428. if (cache)
  429. {
  430. int h;
  431. h = hash (name);
  432. if (dns_cache[h].name && grub_strcmp (dns_cache[h].name, name) == 0
  433. && grub_get_time_ms () < dns_cache[h].limit_time)
  434. {
  435. grub_dprintf ("dns", "retrieved from cache\n");
  436. *addresses = grub_malloc (dns_cache[h].naddresses
  437. * sizeof ((*addresses)[0]));
  438. if (!*addresses)
  439. return grub_errno;
  440. *naddresses = dns_cache[h].naddresses;
  441. grub_memcpy (*addresses, dns_cache[h].addresses,
  442. dns_cache[h].naddresses
  443. * sizeof ((*addresses)[0]));
  444. return GRUB_ERR_NONE;
  445. }
  446. }
  447. sockets = grub_malloc (sizeof (sockets[0]) * n_servers);
  448. if (!sockets)
  449. return grub_errno;
  450. data.name = grub_strdup (name);
  451. if (!data.name)
  452. {
  453. grub_free (sockets);
  454. return grub_errno;
  455. }
  456. nb = grub_netbuff_alloc (GRUB_NET_OUR_MAX_IP_HEADER_SIZE
  457. + GRUB_NET_MAX_LINK_HEADER_SIZE
  458. + GRUB_NET_UDP_HEADER_SIZE
  459. + sizeof (struct dns_header)
  460. + grub_strlen (name) + 2 + 4);
  461. if (!nb)
  462. {
  463. grub_free (sockets);
  464. grub_free (data.name);
  465. return grub_errno;
  466. }
  467. grub_netbuff_reserve (nb, GRUB_NET_OUR_MAX_IP_HEADER_SIZE
  468. + GRUB_NET_MAX_LINK_HEADER_SIZE
  469. + GRUB_NET_UDP_HEADER_SIZE);
  470. grub_netbuff_put (nb, sizeof (struct dns_header)
  471. + grub_strlen (name) + 2 + 4);
  472. head = (struct dns_header *) nb->data;
  473. optr = (grub_uint8_t *) (head + 1);
  474. for (iptr = name; *iptr; )
  475. {
  476. const char *dot;
  477. dot = grub_strchr (iptr, '.');
  478. if (!dot)
  479. dot = iptr + grub_strlen (iptr);
  480. if ((dot - iptr) >= 64)
  481. {
  482. grub_free (sockets);
  483. grub_free (data.name);
  484. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  485. N_("domain name component is too long"));
  486. }
  487. *optr = (dot - iptr);
  488. optr++;
  489. grub_memcpy (optr, iptr, dot - iptr);
  490. optr += dot - iptr;
  491. iptr = dot;
  492. if (*iptr)
  493. iptr++;
  494. }
  495. *optr++ = 0;
  496. /* Type. */
  497. *optr++ = 0;
  498. qtypeptr = optr++;
  499. /* Class. */
  500. *optr++ = 0;
  501. *optr++ = 1;
  502. head->id = data.id;
  503. head->flags = FLAGS_RD;
  504. head->ra_z_r_code = 0;
  505. head->qdcount = grub_cpu_to_be16_compile_time (1);
  506. head->ancount = grub_cpu_to_be16_compile_time (0);
  507. head->nscount = grub_cpu_to_be16_compile_time (0);
  508. head->arcount = grub_cpu_to_be16_compile_time (0);
  509. nbd = nb->data;
  510. for (i = 0; i < n_servers * 4; i++)
  511. {
  512. /* Connect to a next server. */
  513. while (!(i & 1) && try_server < n_servers)
  514. {
  515. sockets[send_servers] = grub_net_udp_open (servers[try_server++],
  516. DNS_PORT,
  517. recv_hook,
  518. &data);
  519. if (!sockets[send_servers])
  520. {
  521. err = grub_errno;
  522. grub_errno = GRUB_ERR_NONE;
  523. }
  524. else
  525. {
  526. send_servers++;
  527. break;
  528. }
  529. }
  530. if (!send_servers)
  531. goto out;
  532. if (*data.naddresses)
  533. goto out;
  534. for (j = 0; j < send_servers; j++)
  535. {
  536. grub_err_t err2;
  537. grub_size_t t = 0;
  538. do
  539. {
  540. nb->data = nbd;
  541. if (servers[j].option == DNS_OPTION_IPV4 ||
  542. ((servers[j].option == DNS_OPTION_PREFER_IPV4) && (t++ == 0)) ||
  543. ((servers[j].option == DNS_OPTION_PREFER_IPV6) && (t++ == 1)))
  544. *qtypeptr = GRUB_DNS_QTYPE_A;
  545. else
  546. *qtypeptr = GRUB_DNS_QTYPE_AAAA;
  547. grub_dprintf ("dns", "QTYPE: %u QNAME: %s\n", *qtypeptr, name);
  548. err2 = grub_net_send_udp_packet (sockets[j], nb);
  549. if (err2)
  550. {
  551. grub_errno = GRUB_ERR_NONE;
  552. err = err2;
  553. }
  554. if (*data.naddresses)
  555. goto out;
  556. }
  557. while (t == 1);
  558. }
  559. grub_net_poll_cards (200, &data.stop);
  560. }
  561. out:
  562. grub_free (data.name);
  563. grub_netbuff_free (nb);
  564. for (j = 0; j < send_servers; j++)
  565. grub_net_udp_close (sockets[j]);
  566. grub_free (sockets);
  567. if (*data.naddresses)
  568. return GRUB_ERR_NONE;
  569. if (data.dns_err)
  570. return grub_error (GRUB_ERR_NET_NO_DOMAIN,
  571. N_("no DNS record found"));
  572. if (err)
  573. {
  574. grub_errno = err;
  575. return err;
  576. }
  577. return grub_error (GRUB_ERR_TIMEOUT,
  578. N_("no DNS reply received"));
  579. }
  580. static grub_err_t
  581. grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)),
  582. int argc, char **args)
  583. {
  584. grub_err_t err;
  585. struct grub_net_network_level_address cmd_server;
  586. struct grub_net_network_level_address *servers;
  587. grub_size_t nservers, i, naddresses = 0;
  588. struct grub_net_network_level_address *addresses = 0;
  589. if (argc != 2 && argc != 1)
  590. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
  591. if (argc == 2)
  592. {
  593. err = grub_net_resolve_address (args[1], &cmd_server);
  594. if (err)
  595. return err;
  596. servers = &cmd_server;
  597. nservers = 1;
  598. }
  599. else
  600. {
  601. servers = dns_servers;
  602. nservers = dns_nservers;
  603. }
  604. grub_net_dns_lookup (args[0], servers, nservers, &naddresses,
  605. &addresses, 0);
  606. for (i = 0; i < naddresses; i++)
  607. {
  608. char buf[GRUB_NET_MAX_STR_ADDR_LEN];
  609. grub_net_addr_to_str (&addresses[i], buf);
  610. grub_printf ("%s\n", buf);
  611. }
  612. grub_free (addresses);
  613. if (naddresses)
  614. return GRUB_ERR_NONE;
  615. return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found"));
  616. }
  617. static grub_err_t
  618. grub_cmd_list_dns (struct grub_command *cmd __attribute__ ((unused)),
  619. int argc __attribute__ ((unused)),
  620. char **args __attribute__ ((unused)))
  621. {
  622. grub_size_t i;
  623. const char *strtype = "";
  624. for (i = 0; i < dns_nservers; i++)
  625. {
  626. switch (dns_servers[i].option)
  627. {
  628. case DNS_OPTION_IPV4:
  629. strtype = _("only ipv4");
  630. break;
  631. case DNS_OPTION_IPV6:
  632. strtype = _("only ipv6");
  633. break;
  634. case DNS_OPTION_PREFER_IPV4:
  635. strtype = _("prefer ipv4");
  636. break;
  637. case DNS_OPTION_PREFER_IPV6:
  638. strtype = _("prefer ipv6");
  639. break;
  640. }
  641. char buf[GRUB_NET_MAX_STR_ADDR_LEN];
  642. grub_net_addr_to_str (&dns_servers[i], buf);
  643. grub_printf ("%s (%s)\n", buf, strtype);
  644. }
  645. return GRUB_ERR_NONE;
  646. }
  647. static grub_err_t
  648. grub_cmd_add_dns (struct grub_command *cmd __attribute__ ((unused)),
  649. int argc, char **args)
  650. {
  651. grub_err_t err;
  652. struct grub_net_network_level_address server;
  653. if ((argc < 1) || (argc > 2))
  654. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
  655. else if (argc == 1)
  656. server.option = DNS_OPTION_PREFER_IPV4;
  657. else
  658. {
  659. if (grub_strcmp (args[1], "--only-ipv4") == 0)
  660. server.option = DNS_OPTION_IPV4;
  661. else if (grub_strcmp (args[1], "--only-ipv6") == 0)
  662. server.option = DNS_OPTION_IPV6;
  663. else if (grub_strcmp (args[1], "--prefer-ipv4") == 0)
  664. server.option = DNS_OPTION_PREFER_IPV4;
  665. else if (grub_strcmp (args[1], "--prefer-ipv6") == 0)
  666. server.option = DNS_OPTION_PREFER_IPV6;
  667. else
  668. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid argument"));
  669. }
  670. err = grub_net_resolve_address (args[0], &server);
  671. if (err)
  672. return err;
  673. return grub_net_add_dns_server (&server);
  674. }
  675. static grub_err_t
  676. grub_cmd_del_dns (struct grub_command *cmd __attribute__ ((unused)),
  677. int argc, char **args)
  678. {
  679. grub_err_t err;
  680. struct grub_net_network_level_address server;
  681. if (argc != 1)
  682. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
  683. err = grub_net_resolve_address (args[1], &server);
  684. if (err)
  685. return err;
  686. return grub_net_add_dns_server (&server);
  687. }
  688. static grub_command_t cmd, cmd_add, cmd_del, cmd_list;
  689. void
  690. grub_dns_init (void)
  691. {
  692. cmd = grub_register_command ("net_nslookup", grub_cmd_nslookup,
  693. N_("ADDRESS DNSSERVER"),
  694. N_("Perform a DNS lookup"));
  695. cmd_add = grub_register_command ("net_add_dns", grub_cmd_add_dns,
  696. N_("DNSSERVER"),
  697. N_("Add a DNS server"));
  698. cmd_del = grub_register_command ("net_del_dns", grub_cmd_del_dns,
  699. N_("DNSSERVER"),
  700. N_("Remove a DNS server"));
  701. cmd_list = grub_register_command ("net_ls_dns", grub_cmd_list_dns,
  702. NULL, N_("List DNS servers"));
  703. }
  704. void
  705. grub_dns_fini (void)
  706. {
  707. grub_unregister_command (cmd);
  708. grub_unregister_command (cmd_add);
  709. grub_unregister_command (cmd_del);
  710. grub_unregister_command (cmd_list);
  711. }