📄 dns_impl.inl
字号:
#ifndef CYGONCE_NS_DNS_DNS_IMPL_H
#define CYGONCE_NS_DNS_DNS_IMPL_H
//=============================================================================
//
// dns_impl.inl
//
// DNS client code implementation.
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos 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 2 or (at your option) any later version.
//
// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): andrew.lunn
// Contributors:andrew.lunn, jskov
// Date: 2001-09-18
// Description: The code is kept in this separate file to allow it to be
// used from RedBoot.
//
//####DESCRIPTIONEND####
//
//=============================================================================
#include <cyg/ns/dns/dns_priv.h>
/* Validate a hostname is legal as defined in RFC 1035 */
static int
valid_hostname(const char *hostname)
{
const char * label;
const char * label_end;
if (!hostname) {
return false;
}
label = hostname;
while (*label) {
if (!isalpha(*label))
return false;
label_end = strchr(label, (int)'.') - 1;
if (label_end == (char *)-1) {
label_end = strchr(label, (int)'\0') - 1;
}
while (label != label_end) {
if (!isalnum(*label) && (*label != '-')) {
return false;
}
label++;
}
label = label_end+1; /* Move onto the . or the null. */
if (*label == '.') { /* Move over the . if there is one */
label++;
}
}
return true;
}
/* Build a qname structure. The structure consists of pairs of
<len><label> where <label> is eg ma in tux.ma.tech.ascom.ch. len is
the length of the label. */
static int
build_qname(char *ptr, const char *hostname)
{
const char *label = hostname;
char *end_label;
int total_len = 0;
int len;
while (*label) {
end_label = strchr(label, (int)'.') - 1;
if (end_label == (char *)-1) {
end_label = strchr(label, (int)'\0') - 1;
}
len = end_label - label + 1;
if (len > 63) {
return -1;
}
*ptr++ = (char) len; /* Put the length of the label */
memcpy(ptr, label, len); /* and now the label */
ptr += len;
total_len += len +1;
label = end_label+1; /* Move onto the . or the null. */
if (*label == '.') { /* Move over the . if there is one */
label++;
}
}
*ptr = 0; /* Add the last length of zero
to mark the end */
return (total_len+1);
}
/* Given a pointer to a qname, find the length of the qname. This is
the number of bytes needed to represent the qname, not the length
of the name. A qname is terminated by either a 00, or a pointer
into another qname. This pointer has the top two bits set. */
static int
qname_len(unsigned char * qname)
{
unsigned char * ptr = qname;
while ((*ptr != 0) && ((*ptr & 0xc0) != 0xc0)) {
ptr += *ptr + 1;
}
/* Pointers are two bytes */
if ((*ptr & 0xc0) == 0xc0) {
ptr++;
}
ptr++; /* Skip over the trailing byte */
return (ptr - qname);
}
/* Build a real name from a qname. Alloc the memory needed and return
it. Return NULL on error */
char *
real_name(char *msg, unsigned char *qname)
{
unsigned char * ptr = qname;
char * name;
char * label;
int len = 0;
int offset;
/* First pass works out the length of the name */
while (*ptr != 0) {
if ((*ptr & 0xc0) == 0xc0) {
/* pointer to somewhere else. Follow the pointer */
offset = ((*ptr & 0x3f) << 8) | *(ptr+1);
ptr = msg + offset;
} else {
len += *ptr + 1;
ptr += *ptr + 1;
}
}
/* Now allocate the memory needed and copy the host name into it */
name = alloc_string(len+1);
if (name) {
label = name;
ptr = qname;
while (*ptr != 0) {
if ((*ptr & 0xc0) == 0xc0) {
/* pointer to somewhere else. Follow the pointer */
offset = ((*ptr & 0x3f) << 8) | *(ptr+1);
ptr = msg + offset;
} else {
len = *ptr;
memcpy(label, (ptr+1), len);
label += len;
*label++ = '.';
ptr += *ptr + 1;
}
}
*label = '\0';
}
return name;
}
/* Build a query message which can be sent to the server. If something
goes wrong return -1, otherwise the length of the query message */
static int
build_query(char * msg, const char * hostname, short rr_type)
{
struct dns_header *dns_hdr;
char *ptr;
int len;
/* Fill out the header */
dns_hdr = (struct dns_header *) msg;
dns_hdr->id = htons(id++);
dns_hdr->rd = true;
dns_hdr->opcode = DNS_QUERY;
dns_hdr->qdcount = htons(1);
/* Now the question we want to ask */
ptr = (char *)&dns_hdr[1];
len = build_qname(ptr, hostname);
if (len < 0) {
h_errno = NO_RECOVERY;
return -1;
}
ptr += len;
/* Set the type and class fields */
*ptr++ = (rr_type >> 8) & 0xff;
*ptr++ = rr_type & 0xff;
*ptr++ = (DNS_CLASS_IN >> 8) & 0xff;
*ptr++ = DNS_CLASS_IN & 0xff;
len = ptr - msg;
return len;
}
/* Check if the hostname is actually of dot format. If so convert it
and return host entity structure. If not, return NULL. */
static struct hostent *
dot_hostname(const char *hostname)
{
struct hostent *hent = NULL;
struct in_addr addr;
if (inet_aton(hostname, &addr)) {
hent = alloc_hent();
if (hent) {
memcpy(hent->h_addr_list[0], &addr, sizeof(struct in_addr));
hent->h_addrtype = AF_INET;
hent->h_length = sizeof(struct in_addr);
hent->h_name = alloc_string(strlen(hostname)+1);
if (!hent->h_name) {
free_hent(hent);
return NULL;
}
strcpy(hent->h_name, hostname);
}
}
return hent;
}
/* Decode the answer from the server. Returns NULL if failed, or
a hostent structure containing different data depending on the
query type:
DNS_TYPE_A:
h_name: a pointer to the hostname
h_addr_list[0]: a pointer to in_addr structure
DNS_TYPE_PTR:
h_name: a pointer to the hostname
h_addr_list[0]: a pointer to an empty in_addr structure. Caller
must fill out!
*/
static struct hostent *
parse_answer(char * msg, short rr_type)
{
static struct hostent *hent;
struct dns_header *dns_hdr;
struct resource_record rr, *rr_p = NULL;
char *qname = NULL;
char *ptr;
dns_hdr = (struct dns_header *)msg;
if (DNS_REPLY_NAME_ERROR == dns_hdr->rcode) {
h_errno = HOST_NOT_FOUND;
return NULL;
}
if ((dns_hdr->qr != 1) ||
(dns_hdr->opcode != DNS_QUERY) ||
(dns_hdr->rcode != DNS_REPLY_NOERR)) {
h_errno = NO_RECOVERY;
return NULL;
}
dns_hdr->ancount = ntohs(dns_hdr->ancount);
dns_hdr->qdcount = ntohs(dns_hdr->qdcount);
ptr = (char *)&dns_hdr[1];
/* Skip over the query section */
if (dns_hdr->qdcount > 0) {
while (dns_hdr->qdcount) {
ptr += qname_len(ptr);
ptr += 4; /* skip type & class */
dns_hdr->qdcount--;
}
}
/* Skip over the answers resource records to find an answer of the
correct type. */
while (dns_hdr->ancount) {
qname = ptr;
ptr += qname_len(ptr);
rr_p = (struct resource_record *)ptr;
memcpy(&rr, ptr, sizeof(rr));
if ((rr.rr_type == htons(rr_type)) &&
(rr.class == htons(DNS_CLASS_IN))) {
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -