#ifndef CYGONCE_NS_DNS_DNS_IMPL_H
|
#ifndef CYGONCE_NS_DNS_DNS_IMPL_H
|
#define CYGONCE_NS_DNS_DNS_IMPL_H
|
#define CYGONCE_NS_DNS_DNS_IMPL_H
|
//=============================================================================
|
//=============================================================================
|
//
|
//
|
// dns_impl.inl
|
// dns_impl.inl
|
//
|
//
|
// DNS client code implementation.
|
// DNS client code implementation.
|
//
|
//
|
//=============================================================================
|
//=============================================================================
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
// -------------------------------------------
|
// -------------------------------------------
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
//
|
//
|
// eCos is free software; you can redistribute it and/or modify it under
|
// 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
|
// 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.
|
// 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
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// for more details.
|
// for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License along
|
// You should have received a copy of the GNU General Public License along
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
//
|
//
|
// As a special exception, if other files instantiate templates or use macros
|
// 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
|
// 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
|
// 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
|
// 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
|
// License. However the source code for this file must still be made available
|
// in accordance with section (3) of the GNU General Public License.
|
// 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 exception does not invalidate any other reasons why a work based on
|
// this file might be covered by the GNU General Public License.
|
// this file might be covered by the GNU General Public License.
|
//
|
//
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
// at http://sources.redhat.com/ecos/ecos-license/
|
// at http://sources.redhat.com/ecos/ecos-license/
|
// -------------------------------------------
|
// -------------------------------------------
|
//####ECOSGPLCOPYRIGHTEND####
|
//####ECOSGPLCOPYRIGHTEND####
|
//=============================================================================
|
//=============================================================================
|
//#####DESCRIPTIONBEGIN####
|
//#####DESCRIPTIONBEGIN####
|
//
|
//
|
// Author(s): andrew.lunn
|
// Author(s): andrew.lunn
|
// Contributors:andrew.lunn, jskov
|
// Contributors:andrew.lunn, jskov
|
// Date: 2001-09-18
|
// Date: 2001-09-18
|
// Description: The code is kept in this separate file to allow it to be
|
// Description: The code is kept in this separate file to allow it to be
|
// used from RedBoot.
|
// used from RedBoot.
|
//
|
//
|
//####DESCRIPTIONEND####
|
//####DESCRIPTIONEND####
|
//
|
//
|
//=============================================================================
|
//=============================================================================
|
|
|
#include
|
#include
|
|
|
/* Validate a hostname is legal as defined in RFC 1035 */
|
/* Validate a hostname is legal as defined in RFC 1035 */
|
static int
|
static int
|
valid_hostname(const char *hostname)
|
valid_hostname(const char *hostname)
|
{
|
{
|
const char * label;
|
const char * label;
|
const char * label_end;
|
const char * label_end;
|
|
|
if (!hostname) {
|
if (!hostname) {
|
return false;
|
return false;
|
}
|
}
|
label = hostname;
|
label = hostname;
|
while (*label) {
|
while (*label) {
|
if (!isalpha(*label))
|
if (!isalpha(*label))
|
return false;
|
return false;
|
label_end = strchr(label, (int)'.') - 1;
|
label_end = strchr(label, (int)'.') - 1;
|
if (label_end == (char *)-1) {
|
if (label_end == (char *)-1) {
|
label_end = strchr(label, (int)'\0') - 1;
|
label_end = strchr(label, (int)'\0') - 1;
|
}
|
}
|
while (label != label_end) {
|
while (label != label_end) {
|
if (!isalnum(*label) && (*label != '-')) {
|
if (!isalnum(*label) && (*label != '-')) {
|
return false;
|
return false;
|
}
|
}
|
label++;
|
label++;
|
}
|
}
|
label = label_end+1; /* Move onto the . or the null. */
|
label = label_end+1; /* Move onto the . or the null. */
|
if (*label == '.') { /* Move over the . if there is one */
|
if (*label == '.') { /* Move over the . if there is one */
|
label++;
|
label++;
|
}
|
}
|
}
|
}
|
return true;
|
return true;
|
}
|
}
|
|
|
/* Build a qname structure. The structure consists of pairs of
|
/* Build a qname structure. The structure consists of pairs of
|
|
where is eg ma in tux.ma.tech.ascom.ch. len is
|
the length of the label. */
|
the length of the label. */
|
static int
|
static int
|
build_qname(char *ptr, const char *hostname)
|
build_qname(char *ptr, const char *hostname)
|
{
|
{
|
const char *label = hostname;
|
const char *label = hostname;
|
char *end_label;
|
char *end_label;
|
int total_len = 0;
|
int total_len = 0;
|
int len;
|
int len;
|
|
|
while (*label) {
|
while (*label) {
|
end_label = strchr(label, (int)'.') - 1;
|
end_label = strchr(label, (int)'.') - 1;
|
if (end_label == (char *)-1) {
|
if (end_label == (char *)-1) {
|
end_label = strchr(label, (int)'\0') - 1;
|
end_label = strchr(label, (int)'\0') - 1;
|
}
|
}
|
len = end_label - label + 1;
|
len = end_label - label + 1;
|
if (len > 63) {
|
if (len > 63) {
|
return -1;
|
return -1;
|
}
|
}
|
*ptr++ = (char) len; /* Put the length of the label */
|
*ptr++ = (char) len; /* Put the length of the label */
|
memcpy(ptr, label, len); /* and now the label */
|
memcpy(ptr, label, len); /* and now the label */
|
ptr += len;
|
ptr += len;
|
|
|
total_len += len +1;
|
total_len += len +1;
|
label = end_label+1; /* Move onto the . or the null. */
|
label = end_label+1; /* Move onto the . or the null. */
|
if (*label == '.') { /* Move over the . if there is one */
|
if (*label == '.') { /* Move over the . if there is one */
|
label++;
|
label++;
|
}
|
}
|
}
|
}
|
*ptr = 0; /* Add the last length of zero
|
*ptr = 0; /* Add the last length of zero
|
to mark the end */
|
to mark the end */
|
return (total_len+1);
|
return (total_len+1);
|
}
|
}
|
|
|
/* Given a pointer to a qname, find the length of the qname. This is
|
/* 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
|
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
|
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. */
|
into another qname. This pointer has the top two bits set. */
|
static int
|
static int
|
qname_len(unsigned char * qname)
|
qname_len(unsigned char * qname)
|
{
|
{
|
unsigned char * ptr = qname;
|
unsigned char * ptr = qname;
|
|
|
while ((*ptr != 0) && ((*ptr & 0xc0) != 0xc0)) {
|
while ((*ptr != 0) && ((*ptr & 0xc0) != 0xc0)) {
|
ptr += *ptr + 1;
|
ptr += *ptr + 1;
|
}
|
}
|
/* Pointers are two bytes */
|
/* Pointers are two bytes */
|
if ((*ptr & 0xc0) == 0xc0) {
|
if ((*ptr & 0xc0) == 0xc0) {
|
ptr++;
|
ptr++;
|
}
|
}
|
ptr++; /* Skip over the trailing byte */
|
ptr++; /* Skip over the trailing byte */
|
|
|
return (ptr - qname);
|
return (ptr - qname);
|
}
|
}
|
|
|
/* Build a real name from a qname. Alloc the memory needed and return
|
/* Build a real name from a qname. Alloc the memory needed and return
|
it. Return NULL on error */
|
it. Return NULL on error */
|
char *
|
char *
|
real_name(char *msg, unsigned char *qname)
|
real_name(char *msg, unsigned char *qname)
|
{
|
{
|
unsigned char * ptr = qname;
|
unsigned char * ptr = qname;
|
char * name;
|
char * name;
|
char * label;
|
char * label;
|
int len = 0;
|
int len = 0;
|
int offset;
|
int offset;
|
|
|
/* First pass works out the length of the name */
|
/* First pass works out the length of the name */
|
while (*ptr != 0) {
|
while (*ptr != 0) {
|
if ((*ptr & 0xc0) == 0xc0) {
|
if ((*ptr & 0xc0) == 0xc0) {
|
/* pointer to somewhere else. Follow the pointer */
|
/* pointer to somewhere else. Follow the pointer */
|
offset = ((*ptr & 0x3f) << 8) | *(ptr+1);
|
offset = ((*ptr & 0x3f) << 8) | *(ptr+1);
|
ptr = msg + offset;
|
ptr = msg + offset;
|
} else {
|
} else {
|
len += *ptr + 1;
|
len += *ptr + 1;
|
ptr += *ptr + 1;
|
ptr += *ptr + 1;
|
}
|
}
|
}
|
}
|
|
|
/* Now allocate the memory needed and copy the host name into it */
|
/* Now allocate the memory needed and copy the host name into it */
|
name = alloc_string(len+1);
|
name = alloc_string(len+1);
|
if (name) {
|
if (name) {
|
label = name;
|
label = name;
|
ptr = qname;
|
ptr = qname;
|
while (*ptr != 0) {
|
while (*ptr != 0) {
|
if ((*ptr & 0xc0) == 0xc0) {
|
if ((*ptr & 0xc0) == 0xc0) {
|
/* pointer to somewhere else. Follow the pointer */
|
/* pointer to somewhere else. Follow the pointer */
|
offset = ((*ptr & 0x3f) << 8) | *(ptr+1);
|
offset = ((*ptr & 0x3f) << 8) | *(ptr+1);
|
ptr = msg + offset;
|
ptr = msg + offset;
|
} else {
|
} else {
|
len = *ptr;
|
len = *ptr;
|
memcpy(label, (ptr+1), len);
|
memcpy(label, (ptr+1), len);
|
label += len;
|
label += len;
|
*label++ = '.';
|
*label++ = '.';
|
ptr += *ptr + 1;
|
ptr += *ptr + 1;
|
}
|
}
|
}
|
}
|
*label = '\0';
|
*label = '\0';
|
}
|
}
|
return name;
|
return name;
|
}
|
}
|
|
|
/* Build a query message which can be sent to the server. If something
|
/* Build a query message which can be sent to the server. If something
|
goes wrong return -1, otherwise the length of the query message */
|
goes wrong return -1, otherwise the length of the query message */
|
static int
|
static int
|
build_query(char * msg, const char * hostname, short rr_type)
|
build_query(char * msg, const char * hostname, short rr_type)
|
{
|
{
|
struct dns_header *dns_hdr;
|
struct dns_header *dns_hdr;
|
char *ptr;
|
char *ptr;
|
int len;
|
int len;
|
|
|
/* Fill out the header */
|
/* Fill out the header */
|
dns_hdr = (struct dns_header *) msg;
|
dns_hdr = (struct dns_header *) msg;
|
dns_hdr->id = htons(id++);
|
dns_hdr->id = htons(id++);
|
dns_hdr->rd = true;
|
dns_hdr->rd = true;
|
dns_hdr->opcode = DNS_QUERY;
|
dns_hdr->opcode = DNS_QUERY;
|
dns_hdr->qdcount = htons(1);
|
dns_hdr->qdcount = htons(1);
|
|
|
/* Now the question we want to ask */
|
/* Now the question we want to ask */
|
ptr = (char *)&dns_hdr[1];
|
ptr = (char *)&dns_hdr[1];
|
|
|
len = build_qname(ptr, hostname);
|
len = build_qname(ptr, hostname);
|
|
|
if (len < 0) {
|
if (len < 0) {
|
h_errno = NO_RECOVERY;
|
h_errno = NO_RECOVERY;
|
return -1;
|
return -1;
|
}
|
}
|
ptr += len;
|
ptr += len;
|
|
|
/* Set the type and class fields */
|
/* Set the type and class fields */
|
*ptr++ = (rr_type >> 8) & 0xff;
|
*ptr++ = (rr_type >> 8) & 0xff;
|
*ptr++ = rr_type & 0xff;
|
*ptr++ = rr_type & 0xff;
|
*ptr++ = (DNS_CLASS_IN >> 8) & 0xff;
|
*ptr++ = (DNS_CLASS_IN >> 8) & 0xff;
|
*ptr++ = DNS_CLASS_IN & 0xff;
|
*ptr++ = DNS_CLASS_IN & 0xff;
|
|
|
len = ptr - msg;
|
len = ptr - msg;
|
|
|
return len;
|
return len;
|
}
|
}
|
|
|
/* Check if the hostname is actually of dot format. If so convert it
|
/* Check if the hostname is actually of dot format. If so convert it
|
and return host entity structure. If not, return NULL. */
|
and return host entity structure. If not, return NULL. */
|
static struct hostent *
|
static struct hostent *
|
dot_hostname(const char *hostname)
|
dot_hostname(const char *hostname)
|
{
|
{
|
struct hostent *hent = NULL;
|
struct hostent *hent = NULL;
|
struct in_addr addr;
|
struct in_addr addr;
|
|
|
if (inet_aton(hostname, &addr)) {
|
if (inet_aton(hostname, &addr)) {
|
hent = alloc_hent();
|
hent = alloc_hent();
|
if (hent) {
|
if (hent) {
|
memcpy(hent->h_addr_list[0], &addr, sizeof(struct in_addr));
|
memcpy(hent->h_addr_list[0], &addr, sizeof(struct in_addr));
|
hent->h_addrtype = AF_INET;
|
hent->h_addrtype = AF_INET;
|
hent->h_length = sizeof(struct in_addr);
|
hent->h_length = sizeof(struct in_addr);
|
hent->h_name = alloc_string(strlen(hostname)+1);
|
hent->h_name = alloc_string(strlen(hostname)+1);
|
if (!hent->h_name) {
|
if (!hent->h_name) {
|
free_hent(hent);
|
free_hent(hent);
|
return NULL;
|
return NULL;
|
}
|
}
|
strcpy(hent->h_name, hostname);
|
strcpy(hent->h_name, hostname);
|
}
|
}
|
}
|
}
|
return hent;
|
return hent;
|
}
|
}
|
|
|
/* Decode the answer from the server. Returns NULL if failed, or
|
/* Decode the answer from the server. Returns NULL if failed, or
|
a hostent structure containing different data depending on the
|
a hostent structure containing different data depending on the
|
query type:
|
query type:
|
DNS_TYPE_A:
|
DNS_TYPE_A:
|
h_name: a pointer to the hostname
|
h_name: a pointer to the hostname
|
h_addr_list[0]: a pointer to in_addr structure
|
h_addr_list[0]: a pointer to in_addr structure
|
DNS_TYPE_PTR:
|
DNS_TYPE_PTR:
|
h_name: a pointer to the hostname
|
h_name: a pointer to the hostname
|
h_addr_list[0]: a pointer to an empty in_addr structure. Caller
|
h_addr_list[0]: a pointer to an empty in_addr structure. Caller
|
must fill out!
|
must fill out!
|
*/
|
*/
|
static struct hostent *
|
static struct hostent *
|
parse_answer(char * msg, short rr_type)
|
parse_answer(char * msg, short rr_type)
|
{
|
{
|
static struct hostent *hent;
|
static struct hostent *hent;
|
struct dns_header *dns_hdr;
|
struct dns_header *dns_hdr;
|
struct resource_record rr, *rr_p = NULL;
|
struct resource_record rr, *rr_p = NULL;
|
char *qname = NULL;
|
char *qname = NULL;
|
char *ptr;
|
char *ptr;
|
|
|
dns_hdr = (struct dns_header *)msg;
|
dns_hdr = (struct dns_header *)msg;
|
|
|
if (DNS_REPLY_NAME_ERROR == dns_hdr->rcode) {
|
if (DNS_REPLY_NAME_ERROR == dns_hdr->rcode) {
|
h_errno = HOST_NOT_FOUND;
|
h_errno = HOST_NOT_FOUND;
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
if ((dns_hdr->qr != 1) ||
|
if ((dns_hdr->qr != 1) ||
|
(dns_hdr->opcode != DNS_QUERY) ||
|
(dns_hdr->opcode != DNS_QUERY) ||
|
(dns_hdr->rcode != DNS_REPLY_NOERR)) {
|
(dns_hdr->rcode != DNS_REPLY_NOERR)) {
|
h_errno = NO_RECOVERY;
|
h_errno = NO_RECOVERY;
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
dns_hdr->ancount = ntohs(dns_hdr->ancount);
|
dns_hdr->ancount = ntohs(dns_hdr->ancount);
|
dns_hdr->qdcount = ntohs(dns_hdr->qdcount);
|
dns_hdr->qdcount = ntohs(dns_hdr->qdcount);
|
ptr = (char *)&dns_hdr[1];
|
ptr = (char *)&dns_hdr[1];
|
|
|
/* Skip over the query section */
|
/* Skip over the query section */
|
if (dns_hdr->qdcount > 0) {
|
if (dns_hdr->qdcount > 0) {
|
while (dns_hdr->qdcount) {
|
while (dns_hdr->qdcount) {
|
ptr += qname_len(ptr);
|
ptr += qname_len(ptr);
|
ptr += 4; /* skip type & class */
|
ptr += 4; /* skip type & class */
|
dns_hdr->qdcount--;
|
dns_hdr->qdcount--;
|
}
|
}
|
}
|
}
|
/* Skip over the answers resource records to find an answer of the
|
/* Skip over the answers resource records to find an answer of the
|
correct type. */
|
correct type. */
|
while (dns_hdr->ancount) {
|
while (dns_hdr->ancount) {
|
qname = ptr;
|
qname = ptr;
|
ptr += qname_len(ptr);
|
ptr += qname_len(ptr);
|
rr_p = (struct resource_record *)ptr;
|
rr_p = (struct resource_record *)ptr;
|
memcpy(&rr, ptr, sizeof(rr));
|
memcpy(&rr, ptr, sizeof(rr));
|
if ((rr.rr_type == htons(rr_type)) &&
|
if ((rr.rr_type == htons(rr_type)) &&
|
(rr.class == htons(DNS_CLASS_IN))) {
|
(rr.class == htons(DNS_CLASS_IN))) {
|
break;
|
break;
|
}
|
}
|
ptr += sizeof(struct resource_record) - sizeof(rr.rdata) + ntohs(rr.rdlength);
|
ptr += sizeof(struct resource_record) - sizeof(rr.rdata) + ntohs(rr.rdlength);
|
dns_hdr->ancount--;
|
dns_hdr->ancount--;
|
}
|
}
|
|
|
/* If we found one. decode it */
|
/* If we found one. decode it */
|
if (dns_hdr->ancount > 0) {
|
if (dns_hdr->ancount > 0) {
|
hent = alloc_hent();
|
hent = alloc_hent();
|
if (!hent)
|
if (!hent)
|
return NULL;
|
return NULL;
|
switch (rr_type) {
|
switch (rr_type) {
|
case DNS_TYPE_A:
|
case DNS_TYPE_A:
|
hent->h_name = real_name(msg, qname);
|
hent->h_name = real_name(msg, qname);
|
if (!hent->h_name) {
|
if (!hent->h_name) {
|
free_hent(hent);
|
free_hent(hent);
|
return NULL;
|
return NULL;
|
}
|
}
|
memcpy(hent->h_addr_list[0], rr_p->rdata, sizeof(struct in_addr));
|
memcpy(hent->h_addr_list[0], rr_p->rdata, sizeof(struct in_addr));
|
hent->h_addrtype = AF_INET;
|
hent->h_addrtype = AF_INET;
|
hent->h_length = sizeof(struct in_addr);
|
hent->h_length = sizeof(struct in_addr);
|
return hent;
|
return hent;
|
case DNS_TYPE_PTR:
|
case DNS_TYPE_PTR:
|
hent->h_name = real_name(msg, rr_p->rdata);
|
hent->h_name = real_name(msg, rr_p->rdata);
|
if (!hent->h_name) {
|
if (!hent->h_name) {
|
free_hent(hent);
|
free_hent(hent);
|
return NULL;
|
return NULL;
|
}
|
}
|
hent->h_addrtype = AF_INET;
|
hent->h_addrtype = AF_INET;
|
hent->h_length = sizeof(struct in_addr);
|
hent->h_length = sizeof(struct in_addr);
|
return hent;
|
return hent;
|
default:
|
default:
|
free_hent(hent);
|
free_hent(hent);
|
}
|
}
|
}
|
}
|
h_errno = NO_DATA;
|
h_errno = NO_DATA;
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
/* Given an address, find out the hostname. */
|
/* Given an address, find out the hostname. */
|
struct hostent *
|
struct hostent *
|
gethostbyaddr(const char *addr, int len, int type)
|
gethostbyaddr(const char *addr, int len, int type)
|
{
|
{
|
unsigned char msg[MAXDNSMSGSIZE];
|
unsigned char msg[MAXDNSMSGSIZE];
|
char hostname[40];
|
char hostname[40];
|
struct hostent * hent;
|
struct hostent * hent;
|
|
|
CYG_REPORT_FUNCNAMETYPE( "gethostbyaddr", "returning %08x" );
|
CYG_REPORT_FUNCNAMETYPE( "gethostbyaddr", "returning %08x" );
|
CYG_REPORT_FUNCARG3( "addr=%08x, len=%d, type=%d", addr, len, type );
|
CYG_REPORT_FUNCARG3( "addr=%08x, len=%d, type=%d", addr, len, type );
|
|
|
if ( !addr || 0 == len) {
|
if ( !addr || 0 == len) {
|
CYG_REPORT_RETVAL( NULL );
|
CYG_REPORT_RETVAL( NULL );
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
CYG_CHECK_DATA_PTR( addr, "addr is not a valid pointer!" );
|
CYG_CHECK_DATA_PTR( addr, "addr is not a valid pointer!" );
|
|
|
/* Has the socket to the DNS server been opened? */
|
/* Has the socket to the DNS server been opened? */
|
if (s < 0) {
|
if (s < 0) {
|
CYG_REPORT_RETVAL( NULL );
|
CYG_REPORT_RETVAL( NULL );
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
/* See if there is an answer to an old query. If so free the memory
|
/* See if there is an answer to an old query. If so free the memory
|
it uses. */
|
it uses. */
|
free_stored_hent();
|
free_stored_hent();
|
|
|
/* Only IPv4 addresses accepted */
|
/* Only IPv4 addresses accepted */
|
if ((type != AF_INET) || (len != sizeof(struct in_addr))) {
|
if ((type != AF_INET) || (len != sizeof(struct in_addr))) {
|
CYG_REPORT_RETVAL( NULL );
|
CYG_REPORT_RETVAL( NULL );
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
cyg_drv_mutex_lock(&dns_mutex);
|
cyg_drv_mutex_lock(&dns_mutex);
|
|
|
/* Build the 'hostname' we want to lookup. */
|
/* Build the 'hostname' we want to lookup. */
|
sprintf(hostname, "%d.%d.%d.%d.IN-ADDR.ARPA.",
|
sprintf(hostname, "%d.%d.%d.%d.IN-ADDR.ARPA.",
|
(unsigned char)addr[3],
|
(unsigned char)addr[3],
|
(unsigned char)addr[2],
|
(unsigned char)addr[2],
|
(unsigned char)addr[1],
|
(unsigned char)addr[1],
|
(unsigned char)addr[0]);
|
(unsigned char)addr[0]);
|
|
|
memset(msg, 0, sizeof(msg));
|
memset(msg, 0, sizeof(msg));
|
|
|
/* Build a PTR type request using the hostname */
|
/* Build a PTR type request using the hostname */
|
len = build_query(msg, hostname, DNS_TYPE_PTR);
|
len = build_query(msg, hostname, DNS_TYPE_PTR);
|
if (len < 0) {
|
if (len < 0) {
|
cyg_drv_mutex_unlock(&dns_mutex);
|
cyg_drv_mutex_unlock(&dns_mutex);
|
CYG_REPORT_RETVAL( NULL );
|
CYG_REPORT_RETVAL( NULL );
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
/* Send the request and wait for an answer */
|
/* Send the request and wait for an answer */
|
len = send_recv(msg, len, sizeof(msg));
|
len = send_recv(msg, len, sizeof(msg));
|
if (len < 0) {
|
if (len < 0) {
|
cyg_drv_mutex_unlock(&dns_mutex);
|
cyg_drv_mutex_unlock(&dns_mutex);
|
CYG_REPORT_RETVAL( NULL );
|
CYG_REPORT_RETVAL( NULL );
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
/* Fill in the missing address */
|
/* Fill in the missing address */
|
hent = parse_answer(msg, DNS_TYPE_PTR);
|
hent = parse_answer(msg, DNS_TYPE_PTR);
|
if (hent) {
|
if (hent) {
|
memcpy(hent->h_addr_list[0], addr, sizeof(struct in_addr));
|
memcpy(hent->h_addr_list[0], addr, sizeof(struct in_addr));
|
store_hent(hent);
|
store_hent(hent);
|
}
|
}
|
cyg_drv_mutex_unlock(&dns_mutex);
|
cyg_drv_mutex_unlock(&dns_mutex);
|
|
|
CYG_REPORT_RETVAL( hent );
|
CYG_REPORT_RETVAL( hent );
|
return hent;
|
return hent;
|
}
|
}
|
|
|
/* Given a hostname find out the IP address */
|
/* Given a hostname find out the IP address */
|
struct hostent *
|
struct hostent *
|
gethostbyname(const char * hostname)
|
gethostbyname(const char * hostname)
|
{
|
{
|
unsigned char msg[MAXDNSMSGSIZE];
|
unsigned char msg[MAXDNSMSGSIZE];
|
char name[256];
|
char name[256];
|
struct hostent *hent;
|
struct hostent *hent;
|
int len;
|
int len;
|
|
|
CYG_REPORT_FUNCNAMETYPE( "gethostbyname", "returning %08x" );
|
CYG_REPORT_FUNCNAMETYPE( "gethostbyname", "returning %08x" );
|
CYG_REPORT_FUNCARG1( "hostname=%08x", hostname );
|
CYG_REPORT_FUNCARG1( "hostname=%08x", hostname );
|
|
|
if ( !hostname ) {
|
if ( !hostname ) {
|
CYG_REPORT_RETVAL( NULL );
|
CYG_REPORT_RETVAL( NULL );
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
CYG_CHECK_DATA_PTR( hostname, "hostname is not a valid pointer!" );
|
CYG_CHECK_DATA_PTR( hostname, "hostname is not a valid pointer!" );
|
|
|
/* Has the socket to the DNS server been opened? */
|
/* Has the socket to the DNS server been opened? */
|
if (s < 0) {
|
if (s < 0) {
|
CYG_REPORT_RETVAL( NULL );
|
CYG_REPORT_RETVAL( NULL );
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
/* See if there is an answer to an old query. If so free the memory
|
/* See if there is an answer to an old query. If so free the memory
|
it uses */
|
it uses */
|
free_stored_hent();
|
free_stored_hent();
|
|
|
if (!valid_hostname(hostname)) {
|
if (!valid_hostname(hostname)) {
|
/* It could be a dot address */
|
/* It could be a dot address */
|
hent = dot_hostname(hostname);
|
hent = dot_hostname(hostname);
|
store_hent(hent);
|
store_hent(hent);
|
CYG_REPORT_RETVAL( hent );
|
CYG_REPORT_RETVAL( hent );
|
return hent;
|
return hent;
|
}
|
}
|
|
|
cyg_drv_mutex_lock(&dns_mutex);
|
cyg_drv_mutex_lock(&dns_mutex);
|
|
|
/* First try the name as passed in */
|
/* First try the name as passed in */
|
memset(msg, 0, sizeof(msg));
|
memset(msg, 0, sizeof(msg));
|
len = build_query(msg, hostname, DNS_TYPE_A);
|
len = build_query(msg, hostname, DNS_TYPE_A);
|
if (len < 0) {
|
if (len < 0) {
|
cyg_drv_mutex_unlock(&dns_mutex);
|
cyg_drv_mutex_unlock(&dns_mutex);
|
CYG_REPORT_RETVAL( NULL );
|
CYG_REPORT_RETVAL( NULL );
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
/* Send the query and wait for an answer */
|
/* Send the query and wait for an answer */
|
len = send_recv(msg, len, sizeof(msg));
|
len = send_recv(msg, len, sizeof(msg));
|
if (len < 0) {
|
if (len < 0) {
|
cyg_drv_mutex_unlock(&dns_mutex);
|
cyg_drv_mutex_unlock(&dns_mutex);
|
CYG_REPORT_RETVAL( NULL );
|
CYG_REPORT_RETVAL( NULL );
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
/* Decode the answer */
|
/* Decode the answer */
|
hent = parse_answer(msg, DNS_TYPE_A);
|
hent = parse_answer(msg, DNS_TYPE_A);
|
if (hent) {
|
if (hent) {
|
cyg_drv_mutex_unlock(&dns_mutex);
|
cyg_drv_mutex_unlock(&dns_mutex);
|
store_hent(hent);
|
store_hent(hent);
|
CYG_REPORT_RETVAL( hent );
|
CYG_REPORT_RETVAL( hent );
|
return hent;
|
return hent;
|
}
|
}
|
|
|
/* If no match, try appending the domainname if we have one */
|
/* If no match, try appending the domainname if we have one */
|
if (domainname) {
|
if (domainname) {
|
if ((strlen(hostname) + strlen(domainname)) > 254) {
|
if ((strlen(hostname) + strlen(domainname)) > 254) {
|
h_errno = NO_RECOVERY;
|
h_errno = NO_RECOVERY;
|
cyg_drv_mutex_unlock(&dns_mutex);
|
cyg_drv_mutex_unlock(&dns_mutex);
|
CYG_REPORT_RETVAL( NULL );
|
CYG_REPORT_RETVAL( NULL );
|
return NULL;
|
return NULL;
|
}
|
}
|
strcpy(name, hostname);
|
strcpy(name, hostname);
|
strcat(name, ".");
|
strcat(name, ".");
|
strcat(name, domainname);
|
strcat(name, domainname);
|
|
|
memset(msg, 0, sizeof(msg));
|
memset(msg, 0, sizeof(msg));
|
len = build_query(msg, name, DNS_TYPE_A);
|
len = build_query(msg, name, DNS_TYPE_A);
|
if (len < 0) {
|
if (len < 0) {
|
cyg_drv_mutex_unlock(&dns_mutex);
|
cyg_drv_mutex_unlock(&dns_mutex);
|
CYG_REPORT_RETVAL( NULL );
|
CYG_REPORT_RETVAL( NULL );
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
/* Send the query and wait for an answer */
|
/* Send the query and wait for an answer */
|
len = send_recv(msg, len, sizeof(msg));
|
len = send_recv(msg, len, sizeof(msg));
|
if (len < 0) {
|
if (len < 0) {
|
cyg_drv_mutex_unlock(&dns_mutex);
|
cyg_drv_mutex_unlock(&dns_mutex);
|
CYG_REPORT_RETVAL( NULL );
|
CYG_REPORT_RETVAL( NULL );
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
/* Decode the answer */
|
/* Decode the answer */
|
hent = parse_answer(msg, DNS_TYPE_A);
|
hent = parse_answer(msg, DNS_TYPE_A);
|
}
|
}
|
|
|
cyg_drv_mutex_unlock(&dns_mutex);
|
cyg_drv_mutex_unlock(&dns_mutex);
|
store_hent(hent);
|
store_hent(hent);
|
CYG_REPORT_RETVAL( hent );
|
CYG_REPORT_RETVAL( hent );
|
return hent;
|
return hent;
|
}
|
}
|
|
|
/* Set the domain names, as used by the DNS server */
|
/* Set the domain names, as used by the DNS server */
|
int
|
int
|
setdomainname(const char *name, size_t len)
|
setdomainname(const char *name, size_t len)
|
{
|
{
|
char * ptr;
|
char * ptr;
|
|
|
CYG_REPORT_FUNCNAMETYPE( "setdomainname", "returning %d" );
|
CYG_REPORT_FUNCNAMETYPE( "setdomainname", "returning %d" );
|
CYG_REPORT_FUNCARG2( "name=%08x, len=%d", name, len );
|
CYG_REPORT_FUNCARG2( "name=%08x, len=%d", name, len );
|
|
|
if ((len < 0) || (len > 255)) {
|
if ((len < 0) || (len > 255)) {
|
h_errno = NO_RECOVERY;
|
h_errno = NO_RECOVERY;
|
CYG_REPORT_RETVAL( -1 );
|
CYG_REPORT_RETVAL( -1 );
|
return -1;
|
return -1;
|
}
|
}
|
if (len != 0) {
|
if (len != 0) {
|
CYG_CHECK_DATA_PTR( name, "name is not a valid pointer!" );
|
CYG_CHECK_DATA_PTR( name, "name is not a valid pointer!" );
|
ptr = alloc_string(len+1);
|
ptr = alloc_string(len+1);
|
if (!ptr) {
|
if (!ptr) {
|
CYG_REPORT_RETVAL( -1 );
|
CYG_REPORT_RETVAL( -1 );
|
return -1;
|
return -1;
|
}
|
}
|
memcpy(ptr, name, len);
|
memcpy(ptr, name, len);
|
ptr[len]=0;
|
ptr[len]=0;
|
} else {
|
} else {
|
ptr = NULL;
|
ptr = NULL;
|
}
|
}
|
|
|
if (domainname) {
|
if (domainname) {
|
free_string(domainname);
|
free_string(domainname);
|
}
|
}
|
domainname = ptr;
|
domainname = ptr;
|
CYG_REPORT_RETVAL( 0 );
|
CYG_REPORT_RETVAL( 0 );
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Return the domain name as used by the DNS server */
|
/* Return the domain name as used by the DNS server */
|
int
|
int
|
getdomainname(char *name, size_t len)
|
getdomainname(char *name, size_t len)
|
{
|
{
|
CYG_REPORT_FUNCNAMETYPE( "getdomainname", "returning %d" );
|
CYG_REPORT_FUNCNAMETYPE( "getdomainname", "returning %d" );
|
CYG_REPORT_FUNCARG2( "name=%08x, len=%d", name, len );
|
CYG_REPORT_FUNCARG2( "name=%08x, len=%d", name, len );
|
|
|
if ( !name || 0 == len) {
|
if ( !name || 0 == len) {
|
CYG_REPORT_RETVAL( -1 );
|
CYG_REPORT_RETVAL( -1 );
|
return -1;
|
return -1;
|
}
|
}
|
|
|
CYG_CHECK_DATA_PTR( name, "name is not a valid pointer!" );
|
CYG_CHECK_DATA_PTR( name, "name is not a valid pointer!" );
|
|
|
/* No domainname set, return a 0 */
|
/* No domainname set, return a 0 */
|
if (!domainname) {
|
if (!domainname) {
|
if (len == 0) {
|
if (len == 0) {
|
h_errno = HOST_NOT_FOUND;
|
h_errno = HOST_NOT_FOUND;
|
CYG_REPORT_RETVAL( -1 );
|
CYG_REPORT_RETVAL( -1 );
|
return -1;
|
return -1;
|
}
|
}
|
name[0]='\0';
|
name[0]='\0';
|
} else {
|
} else {
|
if ((strlen(domainname) + 1) > len) {
|
if ((strlen(domainname) + 1) > len) {
|
h_errno = NO_RECOVERY;
|
h_errno = NO_RECOVERY;
|
CYG_REPORT_RETVAL( -1 );
|
CYG_REPORT_RETVAL( -1 );
|
return -1;
|
return -1;
|
}
|
}
|
strncpy(name, domainname, len);
|
strncpy(name, domainname, len);
|
}
|
}
|
CYG_REPORT_RETVAL( 0 );
|
CYG_REPORT_RETVAL( 0 );
|
return 0;
|
return 0;
|
}
|
}
|
|
|
int h_errno = DNS_SUCCESS;
|
int h_errno = DNS_SUCCESS;
|
|
|
const char*
|
const char*
|
hstrerror(int err)
|
hstrerror(int err)
|
{
|
{
|
CYG_REPORT_FUNCNAMETYPE( "hstrerror", "returning %08x" );
|
CYG_REPORT_FUNCNAMETYPE( "hstrerror", "returning %08x" );
|
CYG_REPORT_FUNCARG1( "err=%d", err );
|
CYG_REPORT_FUNCARG1( "err=%d", err );
|
|
|
switch (err) {
|
switch (err) {
|
case DNS_SUCCESS:
|
case DNS_SUCCESS:
|
return "No error";
|
return "No error";
|
case HOST_NOT_FOUND:
|
case HOST_NOT_FOUND:
|
return "No such host is known";
|
return "No such host is known";
|
case TRY_AGAIN:
|
case TRY_AGAIN:
|
return "Timeout";
|
return "Timeout";
|
case NO_RECOVERY:
|
case NO_RECOVERY:
|
return "Server failure or invalid input";
|
return "Server failure or invalid input";
|
case NO_DATA:
|
case NO_DATA:
|
return "No data for type";
|
return "No data for type";
|
default:
|
default:
|
return "Uknown error";
|
return "Uknown error";
|
}
|
}
|
}
|
}
|
|
|
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
#endif // CYGONCE_NS_DNS_DNS_IMPL_H
|
#endif // CYGONCE_NS_DNS_DNS_IMPL_H
|
// End of dns_impl.h
|
// End of dns_impl.h
|
|
|