support cname
This commit is contained in:
parent
34feab6f21
commit
3729fcfc1a
1 changed files with 133 additions and 34 deletions
|
@ -66,21 +66,33 @@ struct recv_data
|
||||||
int cache;
|
int cache;
|
||||||
grub_uint16_t id;
|
grub_uint16_t id;
|
||||||
int dns_err;
|
int dns_err;
|
||||||
const char *name;
|
char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
check_name (const grub_uint8_t *name_at, const grub_uint8_t *head,
|
check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
|
||||||
const grub_uint8_t *tail, const char *check_with)
|
const grub_uint8_t *tail, const char *check_with,
|
||||||
|
int *length, char *set)
|
||||||
{
|
{
|
||||||
const char *readable_ptr = check_with;
|
const char *readable_ptr = check_with;
|
||||||
const grub_uint8_t *ptr;
|
const grub_uint8_t *ptr;
|
||||||
|
char *optr = set;
|
||||||
int bytes_processed = 0;
|
int bytes_processed = 0;
|
||||||
|
if (length)
|
||||||
|
*length = 0;
|
||||||
for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; )
|
for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; )
|
||||||
{
|
{
|
||||||
/* End marker. */
|
/* End marker. */
|
||||||
if (!*ptr)
|
if (!*ptr)
|
||||||
return (*readable_ptr == 0);
|
{
|
||||||
|
if (length && *length)
|
||||||
|
(*length)--;
|
||||||
|
if (optr && optr != set)
|
||||||
|
optr--;
|
||||||
|
if (optr)
|
||||||
|
*optr = 0;
|
||||||
|
return !readable_ptr || (*readable_ptr == 0);
|
||||||
|
}
|
||||||
if (*ptr & 0xc0)
|
if (*ptr & 0xc0)
|
||||||
{
|
{
|
||||||
bytes_processed += 2;
|
bytes_processed += 2;
|
||||||
|
@ -89,22 +101,66 @@ check_name (const grub_uint8_t *name_at, const grub_uint8_t *head,
|
||||||
ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]);
|
ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)
|
if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (grub_memchr (ptr + 1, 0, *ptr)
|
if (grub_memchr (ptr + 1, 0, *ptr)
|
||||||
|| grub_memchr (ptr + 1, '.', *ptr))
|
|| grub_memchr (ptr + 1, '.', *ptr))
|
||||||
return 0;
|
return 0;
|
||||||
if (readable_ptr[*ptr] != '.' && readable_ptr[*ptr] != 0)
|
if (readable_ptr)
|
||||||
|
readable_ptr += *ptr;
|
||||||
|
if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0)
|
||||||
return 0;
|
return 0;
|
||||||
bytes_processed += *ptr + 1;
|
bytes_processed += *ptr + 1;
|
||||||
readable_ptr += *ptr;
|
if (length)
|
||||||
if (*readable_ptr)
|
*length += *ptr + 1;
|
||||||
|
if (optr)
|
||||||
|
{
|
||||||
|
grub_memcpy (optr, ptr + 1, *ptr);
|
||||||
|
optr += *ptr;
|
||||||
|
}
|
||||||
|
if (optr)
|
||||||
|
*optr++ = '.';
|
||||||
|
if (readable_ptr && *readable_ptr)
|
||||||
readable_ptr++;
|
readable_ptr++;
|
||||||
ptr += *ptr + 1;
|
ptr += *ptr + 1;
|
||||||
}
|
}
|
||||||
return 0;
|
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
|
static grub_err_t
|
||||||
recv_hook (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
recv_hook (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
||||||
struct grub_net_buff *nb,
|
struct grub_net_buff *nb,
|
||||||
|
@ -113,7 +169,9 @@ recv_hook (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
||||||
struct dns_header *head;
|
struct dns_header *head;
|
||||||
struct recv_data *data = data_;
|
struct recv_data *data = data_;
|
||||||
int i, j;
|
int i, j;
|
||||||
grub_uint8_t *ptr;
|
grub_uint8_t *ptr, *reparse_ptr;
|
||||||
|
int redirect_cnt = 0;
|
||||||
|
char *redirect_save = NULL;
|
||||||
|
|
||||||
head = (struct dns_header *) nb->data;
|
head = (struct dns_header *) nb->data;
|
||||||
ptr = (grub_uint8_t *) (head + 1);
|
ptr = (grub_uint8_t *) (head + 1);
|
||||||
|
@ -161,10 +219,12 @@ recv_hook (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
||||||
grub_netbuff_free (nb);
|
grub_netbuff_free (nb);
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
for (i = 0; i < grub_cpu_to_be16 (head->ancount); i++)
|
reparse_ptr = ptr;
|
||||||
|
reparse:
|
||||||
|
for (i = 0, ptr = reparse_ptr; i < grub_cpu_to_be16 (head->ancount); i++)
|
||||||
{
|
{
|
||||||
int ignored = 0;
|
int ignored = 0;
|
||||||
int is_ipv6 = 0;
|
grub_uint8_t class;
|
||||||
grub_uint32_t ttl = 0;
|
grub_uint32_t ttl = 0;
|
||||||
grub_uint16_t length;
|
grub_uint16_t length;
|
||||||
if (ptr >= nb->tail)
|
if (ptr >= nb->tail)
|
||||||
|
@ -188,11 +248,7 @@ recv_hook (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
||||||
}
|
}
|
||||||
if (*ptr++ != 0)
|
if (*ptr++ != 0)
|
||||||
ignored = 1;
|
ignored = 1;
|
||||||
if (*ptr != 1 && *ptr != 28)
|
class = *ptr++;
|
||||||
ignored = 1;
|
|
||||||
if (*ptr == 28)
|
|
||||||
is_ipv6 = 1;
|
|
||||||
ptr++;
|
|
||||||
if (*ptr++ != 0)
|
if (*ptr++ != 0)
|
||||||
ignored = 1;
|
ignored = 1;
|
||||||
if (*ptr++ != 1)
|
if (*ptr++ != 1)
|
||||||
|
@ -211,25 +267,56 @@ recv_hook (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
||||||
grub_netbuff_free (nb);
|
grub_netbuff_free (nb);
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
if (!ignored && !is_ipv6 && length == 4)
|
if (!ignored)
|
||||||
{
|
switch (class)
|
||||||
(*data->addresses)[*data->naddresses].type
|
{
|
||||||
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
case DNS_CLASS_A:
|
||||||
grub_memcpy (&(*data->addresses)[*data->naddresses].ipv4,
|
if (length != 4)
|
||||||
ptr, 4);
|
break;
|
||||||
(*data->naddresses)++;
|
(*data->addresses)[*data->naddresses].type
|
||||||
}
|
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||||
if (!ignored && is_ipv6 && length == 16)
|
grub_memcpy (&(*data->addresses)[*data->naddresses].ipv4,
|
||||||
{
|
ptr, 4);
|
||||||
(*data->addresses)[*data->naddresses].type
|
(*data->naddresses)++;
|
||||||
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
|
break;
|
||||||
grub_memcpy (&(*data->addresses)[*data->naddresses].ipv6,
|
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);
|
ptr, 16);
|
||||||
(*data->naddresses)++;
|
(*data->naddresses)++;
|
||||||
|
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;
|
ptr += length;
|
||||||
}
|
}
|
||||||
grub_netbuff_free (nb);
|
grub_netbuff_free (nb);
|
||||||
|
grub_free (redirect_save);
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,10 +338,14 @@ grub_net_dns_lookup (const char *name,
|
||||||
static grub_uint16_t id = 1;
|
static grub_uint16_t id = 1;
|
||||||
grub_err_t err = GRUB_ERR_NONE;
|
grub_err_t err = GRUB_ERR_NONE;
|
||||||
struct recv_data data = {naddresses, addresses, cache,
|
struct recv_data data = {naddresses, addresses, cache,
|
||||||
grub_cpu_to_be16 (id++), 0, name};
|
grub_cpu_to_be16 (id++), 0, 0};
|
||||||
grub_uint8_t *nbd;
|
grub_uint8_t *nbd;
|
||||||
int have_server = 0;
|
int have_server = 0;
|
||||||
|
|
||||||
|
data.name = grub_strdup (name);
|
||||||
|
if (!data.name)
|
||||||
|
return grub_errno;
|
||||||
|
|
||||||
*naddresses = 0;
|
*naddresses = 0;
|
||||||
/* if (cache && cache_lookup (name, servers, n_servers, addresses))
|
/* if (cache && cache_lookup (name, servers, n_servers, addresses))
|
||||||
return GRUB_ERR_NONE;*/
|
return GRUB_ERR_NONE;*/
|
||||||
|
@ -266,7 +357,10 @@ grub_net_dns_lookup (const char *name,
|
||||||
+ grub_strlen (name) + 2 + 4
|
+ grub_strlen (name) + 2 + 4
|
||||||
+ 2 + 4);
|
+ 2 + 4);
|
||||||
if (!nb)
|
if (!nb)
|
||||||
return grub_errno;
|
{
|
||||||
|
grub_free (data.name);
|
||||||
|
return grub_errno;
|
||||||
|
}
|
||||||
grub_netbuff_reserve (nb, GRUB_NET_OUR_MAX_IP_HEADER_SIZE
|
grub_netbuff_reserve (nb, GRUB_NET_OUR_MAX_IP_HEADER_SIZE
|
||||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE
|
+ GRUB_NET_MAX_LINK_HEADER_SIZE
|
||||||
+ GRUB_NET_UDP_HEADER_SIZE);
|
+ GRUB_NET_UDP_HEADER_SIZE);
|
||||||
|
@ -281,8 +375,11 @@ grub_net_dns_lookup (const char *name,
|
||||||
if (!dot)
|
if (!dot)
|
||||||
dot = iptr + grub_strlen (iptr);
|
dot = iptr + grub_strlen (iptr);
|
||||||
if ((dot - iptr) >= 64)
|
if ((dot - iptr) >= 64)
|
||||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
{
|
||||||
"domain component is too long");
|
grub_free (data.name);
|
||||||
|
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||||
|
"domain component is too long");
|
||||||
|
}
|
||||||
*optr = (dot - iptr);
|
*optr = (dot - iptr);
|
||||||
optr++;
|
optr++;
|
||||||
grub_memcpy (optr, iptr, dot - iptr);
|
grub_memcpy (optr, iptr, dot - iptr);
|
||||||
|
@ -365,9 +462,11 @@ grub_net_dns_lookup (const char *name,
|
||||||
grub_net_poll_cards (200);
|
grub_net_poll_cards (200);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
grub_free (data.name);
|
||||||
grub_netbuff_free (nb);
|
grub_netbuff_free (nb);
|
||||||
for (j = 0; j < send_servers; j++)
|
for (j = 0; j < send_servers; j++)
|
||||||
grub_net_udp_close (sockets[j]);
|
grub_net_udp_close (sockets[j]);
|
||||||
|
|
||||||
if (*data.naddresses)
|
if (*data.naddresses)
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
if (data.dns_err)
|
if (data.dns_err)
|
||||||
|
|
Loading…
Reference in a new issue