diff options
Diffstat (limited to 'cfe/cfe/net/net_dns.c')
-rwxr-xr-x | cfe/cfe/net/net_dns.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/cfe/cfe/net/net_dns.c b/cfe/cfe/net/net_dns.c new file mode 100755 index 0000000..89b50b1 --- /dev/null +++ b/cfe/cfe/net/net_dns.c @@ -0,0 +1,354 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Domain Name System Resolver File: net_dns.c + * + * This module provides minimal support for looking up IP addresses + * from DNS name servers (RFCxxxx) + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_timer.h" +#include "cfe_error.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "cfe.h" + +#include "net_api.h" + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define ip_addriszero(a) (((a)[0]|(a)[1]|(a)[2]|(a)[3]) == 0) + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define UDP_PORT_DNS 53 + +#define DNS_FLG_QUERY 0x0000 +#define DNS_FLG_RESPONSE 0x8000 +#define DNS_OPCODE_QUERY 0x0000 +#define DNS_FLG_AA 0x0400 +#define DNS_FLG_TC 0x0200 +#define DNS_FLG_RD 0x0100 +#define DNS_FLG_RA 0x0080 +#define DNS_RCODE_MASK 0x000F +#define DNS_RCODE_OK 0x0000 +#define DNS_RCODE_NAMEERR 0x0003 + + +#define QTYPE_HOSTADDR 1 +#define QCLASS_INTERNET 1 + +#define DNS_QUERY_TIMEOUT 1 /* seconds */ +#define DNS_RETRY_COUNT 8 + + +/* ********************************************************************* + * dns_dolookup(s,hostname,ipaddr) + * + * Look up a host name and return its IP address. + * + * Input parameters: + * s - udp socket + * server - name server to query + * hostname - host name to find + * ipaddr - buffer to place IP address + * + * Return value: + * 0 if no responses found + * >0 to indicate number of response records (usually 1) + * else error code + ********************************************************************* */ + +static int dns_dolookup(int s,uint8_t *server,char *hostname,uint8_t *ipaddr) +{ + ebuf_t *buf; + uint16_t id; + uint16_t tmp; + char *tok; + char *ptr; + int64_t timer; + int nres = 0; + uint16_t nqr,nar,nns,nxr; + uint8_t tmpb; + int expired; + + + /* + * Use the current time for our request ID + */ + + id = (uint16_t) cfe_ticks; + + /* + * Get a buffer and fill it in. + */ + + buf = udp_alloc(); + + ebuf_append_u16_be(buf,id); + ebuf_append_u16_be(buf,(DNS_FLG_QUERY | DNS_OPCODE_QUERY | DNS_FLG_RD)); + ebuf_append_u16_be(buf,1); /* one question */ + ebuf_append_u16_be(buf,0); /* no answers */ + ebuf_append_u16_be(buf,0); /* no server resource records */ + ebuf_append_u16_be(buf,0); /* no additional records */ + + /* + * Chop up the hostname into pieces, basically replacing + * the dots with length indicators. + */ + + ptr = hostname; + + while ((tok = strchr(ptr,'.'))) { + ebuf_append_u8(buf,(tok-ptr)); + ebuf_append_bytes(buf,ptr,(tok-ptr)); + ptr = tok + 1; + } + + ebuf_append_u8(buf,strlen(ptr)); + ebuf_append_bytes(buf,ptr,strlen(ptr)); + ebuf_append_u8(buf,0); + ebuf_append_u16_be(buf,QTYPE_HOSTADDR); + ebuf_append_u16_be(buf,QCLASS_INTERNET); + + /* + * Send the request to the name server + */ + + udp_send(s,buf,server); + + /* + * Set a timer for the response + */ + + TIMER_SET(timer,DNS_QUERY_TIMEOUT*CFE_HZ); + + /* + * Start waiting... + */ + + while (!(expired = TIMER_EXPIRED(timer))) { + POLL(); + + buf = udp_recv(s); + if (!buf) continue; + + /* IDs must match */ + + ebuf_get_u16_be(buf,tmp); + if (id != tmp) goto drop; + + /* It must be a response */ + + ebuf_get_u16_be(buf,tmp); + + if ((tmp & DNS_FLG_RESPONSE) == 0) goto drop; + + if ((tmp & DNS_RCODE_MASK) != DNS_RCODE_OK) { + udp_free(buf); + /* name error */ + break; + } + + ebuf_get_u16_be(buf,nqr); + ebuf_get_u16_be(buf,nar); + ebuf_get_u16_be(buf,nns); + ebuf_get_u16_be(buf,nxr); + + if (nar == 0) { + goto drop; + } + + while (nqr > 0) { + if (ebuf_length(buf) <= 0) { + goto drop; + } + for (;;) { + ebuf_get_u8(buf,tmpb); + if (tmpb == 0) break; + ebuf_skip(buf,tmpb); + if (ebuf_length(buf) <= 0) { + goto drop; + } + } + ebuf_skip(buf,2); /* skip QTYPE */ + ebuf_skip(buf,2); /* skip QCLASS */ + nqr--; /* next question record */ + } + + /* + * Loop through the answer records to find + * a HOSTADDR record. Ignore any other records + * we find. + */ + + while (nar > 0) { + uint16_t rname,rtype,rclass,dlen; + + ebuf_get_u16_be(buf,rname); /* resource name */ + + ebuf_get_u16_be(buf,rtype); /* resource type */ + + ebuf_get_u16_be(buf,rclass); /* resource class */ + + ebuf_skip(buf,4); /* time to live */ + + ebuf_get_u16_be(buf,dlen); /* length of data */ + + if (rtype != QTYPE_HOSTADDR) { + ebuf_skip(buf,dlen); + nar--; + continue; + } + if (rclass != QCLASS_INTERNET) { + ebuf_skip(buf,dlen); + nar--; + continue; + } + + if (dlen != IP_ADDR_LEN) { + ebuf_skip(buf,dlen); + nar--; + continue; + } + + ebuf_get_bytes(buf,ipaddr,IP_ADDR_LEN); + break; + } + + if (nar == 0) goto drop; + + udp_free(buf); + nres++; + break; + + drop: + udp_free(buf); + } + + if (expired) return CFE_ERR_TIMEOUT; + if (nres == 0) return CFE_ERR_HOSTUNKNOWN; + return nres; +} + + +/* ********************************************************************* + * dns_lookup(hostname,ipaddr) + * + * Look up a host name and return its IP address. + * + * Input parameters: + * hostname - host name to find + * ipaddr - buffer to place IP address + * + * Return value: + * 0 if no responses found + * >0 to indicate number of response records (usually 1) + * else error code + ********************************************************************* */ + +int dns_lookup(char *hostname,uint8_t *ipaddr) +{ + int s; + int nres = 0; + int retries; + char temphostname[100]; + uint8_t *server; + uint8_t *tok; + + /* + * If it's a valid IP address, don't look it up. + */ + + if (parseipaddr(hostname,ipaddr) == 0) return 1; + + /* + * Add default domain if no domain was specified + */ + + if (strchr(hostname,'.') == NULL) { + tok = net_getparam(NET_DOMAIN); + if (tok) { + xsprintf(temphostname,"%s.%s",hostname,tok); + hostname = temphostname; + } + } + + /* + * Figure out who the name server is + */ + + server = net_getparam(NET_NAMESERVER); + + if (!server) return CFE_ERR_NETDOWN; + if (ip_addriszero(server)) return CFE_ERR_NONAMESERVER; + + /* + * Go do the name server lookup + */ + + s = udp_socket(UDP_PORT_DNS); + if (s < 0) return CFE_ERR_NOHANDLES; + + for (retries = 0; retries < DNS_RETRY_COUNT; retries++) { + nres = dns_dolookup(s,server,hostname,ipaddr); + if (nres == CFE_ERR_TIMEOUT) continue; + if (nres >= 0) break; + } + + udp_close(s); + + return nres; + +} |