123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770 |
- /*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2010,2011 Free Software Foundation, Inc.
- *
- * GRUB is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GRUB is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <grub/net.h>
- #include <grub/net/udp.h>
- #include <grub/command.h>
- #include <grub/i18n.h>
- #include <grub/err.h>
- #include <grub/time.h>
- struct dns_cache_element
- {
- char *name;
- grub_size_t naddresses;
- struct grub_net_network_level_address *addresses;
- grub_uint64_t limit_time;
- };
- #define DNS_CACHE_SIZE 1021
- #define DNS_HASH_BASE 423
- typedef enum grub_dns_qtype_id
- {
- GRUB_DNS_QTYPE_A = 1,
- GRUB_DNS_QTYPE_AAAA = 28
- } grub_dns_qtype_id_t;
- static struct dns_cache_element dns_cache[DNS_CACHE_SIZE];
- static struct grub_net_network_level_address *dns_servers;
- static grub_size_t dns_nservers, dns_servers_alloc;
- grub_err_t
- grub_net_add_dns_server (const struct grub_net_network_level_address *s)
- {
- if (dns_servers_alloc <= dns_nservers)
- {
- int na = dns_servers_alloc * 2;
- struct grub_net_network_level_address *ns;
- if (na < 8)
- na = 8;
- ns = grub_realloc (dns_servers, na * sizeof (ns[0]));
- if (!ns)
- return grub_errno;
- dns_servers_alloc = na;
- dns_servers = ns;
- }
- dns_servers[dns_nservers++] = *s;
- return GRUB_ERR_NONE;
- }
- void
- grub_net_remove_dns_server (const struct grub_net_network_level_address *s)
- {
- grub_size_t i;
- for (i = 0; i < dns_nservers; i++)
- if (grub_net_addr_cmp (s, &dns_servers[i]) == 0)
- break;
- if (i < dns_nservers)
- {
- dns_servers[i] = dns_servers[dns_nservers - 1];
- dns_nservers--;
- }
- }
- struct dns_header
- {
- grub_uint16_t id;
- grub_uint8_t flags;
- grub_uint8_t ra_z_r_code;
- grub_uint16_t qdcount;
- grub_uint16_t ancount;
- grub_uint16_t nscount;
- grub_uint16_t arcount;
- } GRUB_PACKED;
- enum
- {
- FLAGS_RESPONSE = 0x80,
- FLAGS_OPCODE = 0x78,
- FLAGS_RD = 0x01
- };
- enum
- {
- ERRCODE_MASK = 0x0f
- };
- enum
- {
- DNS_PORT = 53
- };
- struct recv_data
- {
- grub_size_t *naddresses;
- struct grub_net_network_level_address **addresses;
- int cache;
- grub_uint16_t id;
- int dns_err;
- char *name;
- const char *oname;
- int stop;
- };
- static inline int
- hash (const char *str)
- {
- unsigned v = 0, xn = 1;
- const char *ptr;
- for (ptr = str; *ptr; )
- {
- v = (v + xn * *ptr);
- xn = (DNS_HASH_BASE * xn) % DNS_CACHE_SIZE;
- ptr++;
- if (((ptr - str) & 0x3ff) == 0)
- v %= DNS_CACHE_SIZE;
- }
- return v % DNS_CACHE_SIZE;
- }
- static int
- check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
- const grub_uint8_t *tail, const char *check_with,
- int *length, char *set)
- {
- const char *readable_ptr = check_with;
- const grub_uint8_t *ptr;
- char *optr = set;
- int bytes_processed = 0;
- if (length)
- *length = 0;
- for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; )
- {
- /* End marker. */
- if (!*ptr)
- {
- if (length && *length)
- (*length)--;
- if (optr && optr != set)
- optr--;
- if (optr)
- *optr = 0;
- return !readable_ptr || (*readable_ptr == 0);
- }
- if (*ptr & 0xc0)
- {
- bytes_processed += 2;
- if (ptr + 1 >= tail)
- return 0;
- ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]);
- continue;
- }
- if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)
- return 0;
- if (grub_memchr (ptr + 1, 0, *ptr)
- || grub_memchr (ptr + 1, '.', *ptr))
- return 0;
- if (readable_ptr)
- readable_ptr += *ptr;
- if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0)
- return 0;
- bytes_processed += *ptr + 1;
- if (length)
- *length += *ptr + 1;
- if (optr)
- {
- grub_memcpy (optr, ptr + 1, *ptr);
- optr += *ptr;
- }
- if (optr)
- *optr++ = '.';
- if (readable_ptr && *readable_ptr)
- readable_ptr++;
- ptr += *ptr + 1;
- }
- return 0;
- }
- static int
- check_name (const grub_uint8_t *name_at, const grub_uint8_t *head,
- const grub_uint8_t *tail, const char *check_with)
- {
- return check_name_real (name_at, head, tail, check_with, NULL, NULL);
- }
- static char *
- get_name (const grub_uint8_t *name_at, const grub_uint8_t *head,
- const grub_uint8_t *tail)
- {
- int length;
- char *ret;
- if (!check_name_real (name_at, head, tail, NULL, &length, NULL))
- return NULL;
- ret = grub_malloc (length + 1);
- if (!ret)
- return NULL;
- if (!check_name_real (name_at, head, tail, NULL, NULL, ret))
- {
- grub_free (ret);
- return NULL;
- }
- return ret;
- }
- enum
- {
- DNS_CLASS_A = 1,
- DNS_CLASS_CNAME = 5,
- DNS_CLASS_AAAA = 28
- };
- static grub_err_t
- recv_hook (grub_net_udp_socket_t sock __attribute__ ((unused)),
- struct grub_net_buff *nb,
- void *data_)
- {
- struct dns_header *head;
- struct recv_data *data = data_;
- int i, j;
- grub_uint8_t *ptr, *reparse_ptr;
- int redirect_cnt = 0;
- char *redirect_save = NULL;
- grub_uint32_t ttl_all = ~0U;
- head = (struct dns_header *) nb->data;
- ptr = (grub_uint8_t *) (head + 1);
- if (ptr >= nb->tail)
- {
- grub_netbuff_free (nb);
- return GRUB_ERR_NONE;
- }
-
- if (head->id != data->id)
- {
- grub_netbuff_free (nb);
- return GRUB_ERR_NONE;
- }
- if (!(head->flags & FLAGS_RESPONSE) || (head->flags & FLAGS_OPCODE))
- {
- grub_netbuff_free (nb);
- return GRUB_ERR_NONE;
- }
- if (head->ra_z_r_code & ERRCODE_MASK)
- {
- data->dns_err = 1;
- grub_netbuff_free (nb);
- return GRUB_ERR_NONE;
- }
- for (i = 0; i < grub_be_to_cpu16 (head->qdcount); i++)
- {
- if (ptr >= nb->tail)
- {
- grub_netbuff_free (nb);
- return GRUB_ERR_NONE;
- }
- while (ptr < nb->tail && !((*ptr & 0xc0) || *ptr == 0))
- ptr += *ptr + 1;
- if (ptr < nb->tail && (*ptr & 0xc0))
- ptr++;
- ptr++;
- ptr += 4;
- }
- *data->addresses = grub_malloc (sizeof ((*data->addresses)[0])
- * grub_be_to_cpu16 (head->ancount));
- if (!*data->addresses)
- {
- grub_errno = GRUB_ERR_NONE;
- grub_netbuff_free (nb);
- return GRUB_ERR_NONE;
- }
- reparse_ptr = ptr;
- reparse:
- for (i = 0, ptr = reparse_ptr; i < grub_be_to_cpu16 (head->ancount); i++)
- {
- int ignored = 0;
- grub_uint8_t class;
- grub_uint32_t ttl = 0;
- grub_uint16_t length;
- if (ptr >= nb->tail)
- {
- if (!*data->naddresses)
- grub_free (*data->addresses);
- return GRUB_ERR_NONE;
- }
- ignored = !check_name (ptr, nb->data, nb->tail, data->name);
- while (ptr < nb->tail && !((*ptr & 0xc0) || *ptr == 0))
- ptr += *ptr + 1;
- if (ptr < nb->tail && (*ptr & 0xc0))
- ptr++;
- ptr++;
- if (ptr + 10 >= nb->tail)
- {
- if (!*data->naddresses)
- grub_free (*data->addresses);
- grub_netbuff_free (nb);
- return GRUB_ERR_NONE;
- }
- if (*ptr++ != 0)
- ignored = 1;
- class = *ptr++;
- if (*ptr++ != 0)
- ignored = 1;
- if (*ptr++ != 1)
- ignored = 1;
- for (j = 0; j < 4; j++)
- {
- ttl <<= 8;
- ttl |= *ptr++;
- }
- length = *ptr++ << 8;
- length |= *ptr++;
- if (ptr + length > nb->tail)
- {
- if (!*data->naddresses)
- grub_free (*data->addresses);
- grub_netbuff_free (nb);
- return GRUB_ERR_NONE;
- }
- if (!ignored)
- {
- if (ttl_all > ttl)
- ttl_all = ttl;
- switch (class)
- {
- case DNS_CLASS_A:
- if (length != 4)
- break;
- (*data->addresses)[*data->naddresses].type
- = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
- grub_memcpy (&(*data->addresses)[*data->naddresses].ipv4,
- ptr, 4);
- (*data->naddresses)++;
- data->stop = 1;
- break;
- case DNS_CLASS_AAAA:
- if (length != 16)
- break;
- (*data->addresses)[*data->naddresses].type
- = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
- grub_memcpy (&(*data->addresses)[*data->naddresses].ipv6,
- ptr, 16);
- (*data->naddresses)++;
- data->stop = 1;
- break;
- case DNS_CLASS_CNAME:
- if (!(redirect_cnt & (redirect_cnt - 1)))
- {
- grub_free (redirect_save);
- redirect_save = data->name;
- }
- else
- grub_free (data->name);
- redirect_cnt++;
- data->name = get_name (ptr, nb->data, nb->tail);
- if (!data->name)
- {
- data->dns_err = 1;
- grub_errno = 0;
- return GRUB_ERR_NONE;
- }
- grub_dprintf ("dns", "CNAME %s\n", data->name);
- if (grub_strcmp (redirect_save, data->name) == 0)
- {
- data->dns_err = 1;
- grub_free (redirect_save);
- return GRUB_ERR_NONE;
- }
- goto reparse;
- }
- }
- ptr += length;
- }
- if (ttl_all && *data->naddresses && data->cache)
- {
- int h;
- grub_dprintf ("dns", "caching for %d seconds\n", ttl_all);
- h = hash (data->oname);
- grub_free (dns_cache[h].name);
- dns_cache[h].name = 0;
- grub_free (dns_cache[h].addresses);
- dns_cache[h].addresses = 0;
- dns_cache[h].name = grub_strdup (data->oname);
- dns_cache[h].naddresses = *data->naddresses;
- dns_cache[h].addresses = grub_malloc (*data->naddresses
- * sizeof (dns_cache[h].addresses[0]));
- dns_cache[h].limit_time = grub_get_time_ms () + 1000 * ttl_all;
- if (!dns_cache[h].addresses || !dns_cache[h].name)
- {
- grub_free (dns_cache[h].name);
- dns_cache[h].name = 0;
- grub_free (dns_cache[h].addresses);
- dns_cache[h].addresses = 0;
- }
- grub_memcpy (dns_cache[h].addresses, *data->addresses,
- *data->naddresses
- * sizeof (dns_cache[h].addresses[0]));
- }
- grub_netbuff_free (nb);
- grub_free (redirect_save);
- return GRUB_ERR_NONE;
- }
- grub_err_t
- grub_net_dns_lookup (const char *name,
- const struct grub_net_network_level_address *servers,
- grub_size_t n_servers,
- grub_size_t *naddresses,
- struct grub_net_network_level_address **addresses,
- int cache)
- {
- grub_size_t send_servers = 0;
- grub_size_t i, j;
- struct grub_net_buff *nb;
- grub_net_udp_socket_t *sockets;
- grub_uint8_t *optr;
- const char *iptr;
- struct dns_header *head;
- static grub_uint16_t id = 1;
- grub_uint8_t *qtypeptr;
- grub_err_t err = GRUB_ERR_NONE;
- struct recv_data data = {naddresses, addresses, cache,
- grub_cpu_to_be16 (id++), 0, 0, name, 0};
- grub_uint8_t *nbd;
- grub_size_t try_server = 0;
- if (!servers)
- {
- servers = dns_servers;
- n_servers = dns_nservers;
- }
- if (!n_servers)
- return grub_error (GRUB_ERR_BAD_ARGUMENT,
- N_("no DNS servers configured"));
- *naddresses = 0;
- if (cache)
- {
- int h;
- h = hash (name);
- if (dns_cache[h].name && grub_strcmp (dns_cache[h].name, name) == 0
- && grub_get_time_ms () < dns_cache[h].limit_time)
- {
- grub_dprintf ("dns", "retrieved from cache\n");
- *addresses = grub_malloc (dns_cache[h].naddresses
- * sizeof ((*addresses)[0]));
- if (!*addresses)
- return grub_errno;
- *naddresses = dns_cache[h].naddresses;
- grub_memcpy (*addresses, dns_cache[h].addresses,
- dns_cache[h].naddresses
- * sizeof ((*addresses)[0]));
- return GRUB_ERR_NONE;
- }
- }
- sockets = grub_malloc (sizeof (sockets[0]) * n_servers);
- if (!sockets)
- return grub_errno;
- data.name = grub_strdup (name);
- if (!data.name)
- {
- grub_free (sockets);
- return grub_errno;
- }
- nb = grub_netbuff_alloc (GRUB_NET_OUR_MAX_IP_HEADER_SIZE
- + GRUB_NET_MAX_LINK_HEADER_SIZE
- + GRUB_NET_UDP_HEADER_SIZE
- + sizeof (struct dns_header)
- + grub_strlen (name) + 2 + 4);
- if (!nb)
- {
- grub_free (sockets);
- grub_free (data.name);
- return grub_errno;
- }
- grub_netbuff_reserve (nb, GRUB_NET_OUR_MAX_IP_HEADER_SIZE
- + GRUB_NET_MAX_LINK_HEADER_SIZE
- + GRUB_NET_UDP_HEADER_SIZE);
- grub_netbuff_put (nb, sizeof (struct dns_header)
- + grub_strlen (name) + 2 + 4);
- head = (struct dns_header *) nb->data;
- optr = (grub_uint8_t *) (head + 1);
- for (iptr = name; *iptr; )
- {
- const char *dot;
- dot = grub_strchr (iptr, '.');
- if (!dot)
- dot = iptr + grub_strlen (iptr);
- if ((dot - iptr) >= 64)
- {
- grub_free (sockets);
- grub_free (data.name);
- return grub_error (GRUB_ERR_BAD_ARGUMENT,
- N_("domain name component is too long"));
- }
- *optr = (dot - iptr);
- optr++;
- grub_memcpy (optr, iptr, dot - iptr);
- optr += dot - iptr;
- iptr = dot;
- if (*iptr)
- iptr++;
- }
- *optr++ = 0;
- /* Type. */
- *optr++ = 0;
- qtypeptr = optr++;
- /* Class. */
- *optr++ = 0;
- *optr++ = 1;
- head->id = data.id;
- head->flags = FLAGS_RD;
- head->ra_z_r_code = 0;
- head->qdcount = grub_cpu_to_be16_compile_time (1);
- head->ancount = grub_cpu_to_be16_compile_time (0);
- head->nscount = grub_cpu_to_be16_compile_time (0);
- head->arcount = grub_cpu_to_be16_compile_time (0);
- nbd = nb->data;
- for (i = 0; i < n_servers * 4; i++)
- {
- /* Connect to a next server. */
- while (!(i & 1) && try_server < n_servers)
- {
- sockets[send_servers] = grub_net_udp_open (servers[try_server++],
- DNS_PORT,
- recv_hook,
- &data);
- if (!sockets[send_servers])
- {
- err = grub_errno;
- grub_errno = GRUB_ERR_NONE;
- }
- else
- {
- send_servers++;
- break;
- }
- }
- if (!send_servers)
- goto out;
- if (*data.naddresses)
- goto out;
- for (j = 0; j < send_servers; j++)
- {
- grub_err_t err2;
- grub_size_t t = 0;
- do
- {
- nb->data = nbd;
- if (servers[j].option == DNS_OPTION_IPV4 ||
- ((servers[j].option == DNS_OPTION_PREFER_IPV4) && (t++ == 0)) ||
- ((servers[j].option == DNS_OPTION_PREFER_IPV6) && (t++ == 1)))
- *qtypeptr = GRUB_DNS_QTYPE_A;
- else
- *qtypeptr = GRUB_DNS_QTYPE_AAAA;
- grub_dprintf ("dns", "QTYPE: %u QNAME: %s\n", *qtypeptr, name);
- err2 = grub_net_send_udp_packet (sockets[j], nb);
- if (err2)
- {
- grub_errno = GRUB_ERR_NONE;
- err = err2;
- }
- if (*data.naddresses)
- goto out;
- }
- while (t == 1);
- }
- grub_net_poll_cards (200, &data.stop);
- }
- out:
- grub_free (data.name);
- grub_netbuff_free (nb);
- for (j = 0; j < send_servers; j++)
- grub_net_udp_close (sockets[j]);
-
- grub_free (sockets);
- if (*data.naddresses)
- return GRUB_ERR_NONE;
- if (data.dns_err)
- return grub_error (GRUB_ERR_NET_NO_DOMAIN,
- N_("no DNS record found"));
-
- if (err)
- {
- grub_errno = err;
- return err;
- }
- return grub_error (GRUB_ERR_TIMEOUT,
- N_("no DNS reply received"));
- }
- static grub_err_t
- grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)),
- int argc, char **args)
- {
- grub_err_t err;
- struct grub_net_network_level_address cmd_server;
- struct grub_net_network_level_address *servers;
- grub_size_t nservers, i, naddresses = 0;
- struct grub_net_network_level_address *addresses = 0;
- if (argc != 2 && argc != 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
- if (argc == 2)
- {
- err = grub_net_resolve_address (args[1], &cmd_server);
- if (err)
- return err;
- servers = &cmd_server;
- nservers = 1;
- }
- else
- {
- servers = dns_servers;
- nservers = dns_nservers;
- }
- grub_net_dns_lookup (args[0], servers, nservers, &naddresses,
- &addresses, 0);
- for (i = 0; i < naddresses; i++)
- {
- char buf[GRUB_NET_MAX_STR_ADDR_LEN];
- grub_net_addr_to_str (&addresses[i], buf);
- grub_printf ("%s\n", buf);
- }
- grub_free (addresses);
- if (naddresses)
- return GRUB_ERR_NONE;
- return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found"));
- }
- static grub_err_t
- grub_cmd_list_dns (struct grub_command *cmd __attribute__ ((unused)),
- int argc __attribute__ ((unused)),
- char **args __attribute__ ((unused)))
- {
- grub_size_t i;
- const char *strtype = "";
- for (i = 0; i < dns_nservers; i++)
- {
- switch (dns_servers[i].option)
- {
- case DNS_OPTION_IPV4:
- strtype = _("only ipv4");
- break;
- case DNS_OPTION_IPV6:
- strtype = _("only ipv6");
- break;
- case DNS_OPTION_PREFER_IPV4:
- strtype = _("prefer ipv4");
- break;
- case DNS_OPTION_PREFER_IPV6:
- strtype = _("prefer ipv6");
- break;
- }
- char buf[GRUB_NET_MAX_STR_ADDR_LEN];
- grub_net_addr_to_str (&dns_servers[i], buf);
- grub_printf ("%s (%s)\n", buf, strtype);
- }
- return GRUB_ERR_NONE;
- }
- static grub_err_t
- grub_cmd_add_dns (struct grub_command *cmd __attribute__ ((unused)),
- int argc, char **args)
- {
- grub_err_t err;
- struct grub_net_network_level_address server;
- if ((argc < 1) || (argc > 2))
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
- else if (argc == 1)
- server.option = DNS_OPTION_PREFER_IPV4;
- else
- {
- if (grub_strcmp (args[1], "--only-ipv4") == 0)
- server.option = DNS_OPTION_IPV4;
- else if (grub_strcmp (args[1], "--only-ipv6") == 0)
- server.option = DNS_OPTION_IPV6;
- else if (grub_strcmp (args[1], "--prefer-ipv4") == 0)
- server.option = DNS_OPTION_PREFER_IPV4;
- else if (grub_strcmp (args[1], "--prefer-ipv6") == 0)
- server.option = DNS_OPTION_PREFER_IPV6;
- else
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid argument"));
- }
- err = grub_net_resolve_address (args[0], &server);
- if (err)
- return err;
- return grub_net_add_dns_server (&server);
- }
- static grub_err_t
- grub_cmd_del_dns (struct grub_command *cmd __attribute__ ((unused)),
- int argc, char **args)
- {
- grub_err_t err;
- struct grub_net_network_level_address server;
- if (argc != 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
- err = grub_net_resolve_address (args[1], &server);
- if (err)
- return err;
- return grub_net_add_dns_server (&server);
- }
- static grub_command_t cmd, cmd_add, cmd_del, cmd_list;
- void
- grub_dns_init (void)
- {
- cmd = grub_register_command ("net_nslookup", grub_cmd_nslookup,
- N_("ADDRESS DNSSERVER"),
- N_("Perform a DNS lookup"));
- cmd_add = grub_register_command ("net_add_dns", grub_cmd_add_dns,
- N_("DNSSERVER"),
- N_("Add a DNS server"));
- cmd_del = grub_register_command ("net_del_dns", grub_cmd_del_dns,
- N_("DNSSERVER"),
- N_("Remove a DNS server"));
- cmd_list = grub_register_command ("net_ls_dns", grub_cmd_list_dns,
- NULL, N_("List DNS servers"));
- }
- void
- grub_dns_fini (void)
- {
- grub_unregister_command (cmd);
- grub_unregister_command (cmd_add);
- grub_unregister_command (cmd_del);
- grub_unregister_command (cmd_list);
- }
|