diff options
| -rw-r--r-- | common/cmd_net.c | 49 | ||||
| -rw-r--r-- | doc/README.dns | 64 | ||||
| -rw-r--r-- | include/net.h | 5 | ||||
| -rw-r--r-- | net/Makefile | 7 | ||||
| -rw-r--r-- | net/dns.c | 211 | ||||
| -rw-r--r-- | net/dns.h | 39 | ||||
| -rw-r--r-- | net/net.c | 29 | 
7 files changed, 401 insertions, 3 deletions
| diff --git a/common/cmd_net.c b/common/cmd_net.c index 68183c49a..ac706ae8d 100644 --- a/common/cmd_net.c +++ b/common/cmd_net.c @@ -353,3 +353,52 @@ U_BOOT_CMD(  	"[NTP server IP]\n"  );  #endif + +#if defined(CONFIG_CMD_DNS) +int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	if (argc == 1) { +		cmd_usage(cmdtp); +		return -1; +	} + +	/* +	 * We should check for a valid hostname: +	 * - Each label must be between 1 and 63 characters long +	 * - the entire hostname has a maximum of 255 characters +	 * - only the ASCII letters 'a' through 'z' (case-insensitive), +	 *   the digits '0' through '9', and the hyphen +	 * - cannot begin or end with a hyphen +	 * - no other symbols, punctuation characters, or blank spaces are +	 *   permitted +	 * but hey - this is a minimalist implmentation, so only check length +	 * and let the name server deal with things. +	 */ +	if (strlen(argv[1]) >= 255) { +		printf("dns error: hostname too long\n"); +		return 1; +	} + +	NetDNSResolve = argv[1]; + +	if (argc == 3) +		NetDNSenvvar = argv[2]; +	else +		NetDNSenvvar = NULL; + +	if (NetLoop(DNS) < 0) { +		printf("dns lookup of %s failed, check setup\n", argv[1]); +		return 1; +	} + +	return 0; +} + +U_BOOT_CMD( +	dns,	3,	1,	do_dns, +	"lookup the IP of a hostname", +	"hostname [envvar]" +); + +#endif	/* CONFIG_CMD_DNS */ + diff --git a/doc/README.dns b/doc/README.dns new file mode 100644 index 000000000..deeccd772 --- /dev/null +++ b/doc/README.dns @@ -0,0 +1,64 @@ +Domain Name System +------------------------------------------- + +The Domain Name System (DNS) is a hierarchical naming system for computers, +services, or any resource participating in the Internet. It associates various +information with domain names assigned to each of the participants. Most +importantly, it translates domain names meaningful to humans into the numerical +(binary) identifiers associated with networking equipment for the purpose of +locating and addressing these devices world-wide. An often used analogy to +explain the Domain Name System is that it serves as the "phone book" for the +Internet by translating human-friendly computer hostnames into IP addresses. +For example, www.example.com translates to 208.77.188.166. + +For more information on DNS - http://en.wikipedia.org/wiki/Domain_Name_System + + + +U-Boot and DNS +------------------------------------------ + +CONFIG_CMD_DNS - controls if the 'dns' command is compiled in. If it is, it +                 will send name lookups to the dns server (env var 'dnsip') +                 Turning this option on will about abou 1k to U-Boot's size. + +                 Example: + +bfin> print dnsip +dnsip=192.168.0.1 + +bfin> dns www.google.com +66.102.1.104 + +                 By default, dns does nothing except print the IP number on +                 the default console - which by itself, would be pretty +                 useless. Adding a third argument to the dns command will +                 use that as the environment variable to be set. + +                 Example: + +bfin> print googleip +## Error: "googleip" not defined +bfin> dns www.google.com googleip +64.233.161.104 +bfin> print googleip +googleip=64.233.161.104 +bfin> ping ${googleip} +Using Blackfin EMAC device +host 64.233.161.104 is alive + +                 In this way, you can lookup, and set many more meaningful +                 things. + +bfin> sntp +ntpserverip not set +bfin> dns pool.ntp.org ntpserverip +72.18.205.156 +bfin> sntp +Date: 2009-07-18 Time:  4:06:57 + +                 For some helpful things that can be related to DNS in U-Boot, +                 look at the top level README for these config options: +                    CONFIG_CMD_DHCP +                    CONFIG_BOOTP_DNS +                    CONFIG_BOOTP_DNS2 diff --git a/include/net.h b/include/net.h index 88a951357..4a03717ae 100644 --- a/include/net.h +++ b/include/net.h @@ -361,6 +361,11 @@ typedef enum { BOOTP, RARP, ARP, TFTP, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP  /* from net/net.c */  extern char	BootFile[128];			/* Boot File name		*/ +#if defined(CONFIG_CMD_DNS) +extern char *NetDNSResolve;		/* The host to resolve  */ +extern char *NetDNSenvvar;		/* the env var to put the ip into */ +#endif +  #if defined(CONFIG_CMD_PING)  extern IPaddr_t	NetPingIP;			/* the ip address to ping		*/  #endif diff --git a/net/Makefile b/net/Makefile index d34187425..835a04af4 100644 --- a/net/Makefile +++ b/net/Makefile @@ -27,13 +27,14 @@ include $(TOPDIR)/config.mk  LIB	= $(obj)libnet.a -COBJS-y += net.o -COBJS-y += tftp.o  COBJS-y += bootp.o -COBJS-y += rarp.o +COBJS-$(CONFIG_CMD_DNS)  += dns.o  COBJS-y += eth.o +COBJS-y += net.o  COBJS-y += nfs.o +COBJS-y += rarp.o  COBJS-$(CONFIG_CMD_SNTP) += sntp.o +COBJS-y += tftp.o  COBJS	:= $(COBJS-y)  SRCS	:= $(COBJS:.o=.c) diff --git a/net/dns.c b/net/dns.c new file mode 100644 index 000000000..f25c3f8c2 --- /dev/null +++ b/net/dns.c @@ -0,0 +1,211 @@ +/* + * DNS support driver + * + * Copyright (c) 2008 Pieter Voorthuijsen <pieter.voorthuijsen@prodrive.nl> + * Copyright (c) 2009 Robin Getz <rgetz@blackfin.uclinux.org> + * + * This is a simple DNS implementation for U-Boot. It will use the first IP + * in the DNS response as NetServerIP. This can then be used for any other + * network related activities. + * + * The packet handling is partly based on TADNS, original copyrights + * follow below. + * + */ + +/* + * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> + * + * "THE BEER-WARE LICENSE" (Revision 42): + * Sergey Lyubka wrote this file.  As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. + */ + +#include <common.h> +#include <command.h> +#include <net.h> + +#include "dns.h" + +char *NetDNSResolve;	/* The host to resolve  */ +char *NetDNSenvvar;	/* The envvar to store the answer in */ + +static int DnsOurPort; + +static void +DnsSend(void) +{ +	struct header *header; +	int n, name_len; +	uchar *p, *pkt; +	const char *s; +	const char *name; +	enum dns_query_type qtype = DNS_A_RECORD; + +	name = NetDNSResolve; +	pkt = p = (uchar *)(NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE); + +	/* Prepare DNS packet header */ +	header           = (struct header *) pkt; +	header->tid      = 1; +	header->flags    = htons(0x100);	/* standard query */ +	header->nqueries = htons(1);		/* Just one query */ +	header->nanswers = 0; +	header->nauth    = 0; +	header->nother   = 0; + +	/* Encode DNS name */ +	name_len = strlen(name); +	p = (uchar *) &header->data;	/* For encoding host name into packet */ + +	do { +		s = strchr(name, '.'); +		if (!s) +			s = name + name_len; + +		n = s - name;			/* Chunk length */ +		*p++ = n;			/* Copy length  */ +		memcpy(p, name, n);		/* Copy chunk   */ +		p += n; + +		if (*s == '.') +			n++; + +		name += n; +		name_len -= n; +	} while (*s != '\0'); + +	*p++ = 0;			/* Mark end of host name */ +	*p++ = 0;			/* Some servers require double null */ +	*p++ = (unsigned char) qtype;	/* Query Type */ + +	*p++ = 0; +	*p++ = 1;				/* Class: inet, 0x0001 */ + +	n = p - pkt;				/* Total packet length */ +	debug("Packet size %d\n", n); + +	DnsOurPort = random_port(); + +	NetSendUDPPacket(NetServerEther, NetOurDNSIP, DNS_SERVICE_PORT, +		DnsOurPort, n); +	debug("DNS packet sent\n"); +} + +static void +DnsTimeout(void) +{ +	puts("Timeout\n"); +	NetState = NETLOOP_FAIL; +} + +static void +DnsHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len) +{ +	struct header *header; +	const unsigned char *p, *e, *s; +	u16 type, i; +	int found, stop, dlen; +	char IPStr[22]; +	IPaddr_t IPAddress; +	short tmp; + + +	debug("%s\n", __func__); +	if (dest != DnsOurPort) +		return; + +	for (i = 0; i < len; i += 4) +		debug("0x%p - 0x%.2x  0x%.2x  0x%.2x  0x%.2x\n", +			pkt+i, pkt[i], pkt[i+1], pkt[i+2], pkt[i+3]); + +	/* We sent 1 query. We want to see more that 1 answer. */ +	header = (struct header *) pkt; +	if (ntohs(header->nqueries) != 1) +		return; + +	/* Received 0 answers */ +	if (header->nanswers == 0) { +		puts("DNS server returned no answers\n"); +		NetState = NETLOOP_SUCCESS; +		return; +	} + +	/* Skip host name */ +	s = &header->data[0]; +	e = pkt + len; +	for (p = s; p < e && *p != '\0'; p++) +		continue; + +	/* We sent query class 1, query type 1 */ +	tmp = p[1] | (p[2] << 8); +	if (&p[5] > e || ntohs(tmp) != DNS_A_RECORD) { +		puts("DNS response was not A record\n"); +		NetState = NETLOOP_SUCCESS; +		return; +	} + +	/* Go to the first answer section */ +	p += 5; + +	/* Loop through the answers, we want A type answer */ +	for (found = stop = 0; !stop && &p[12] < e; ) { + +		/* Skip possible name in CNAME answer */ +		if (*p != 0xc0) { +			while (*p && &p[12] < e) +				p++; +			p--; +		} +		debug("Name (Offset in header): %d\n", p[1]); + +		tmp = p[2] | (p[3] << 8); +		type = ntohs(tmp); +		debug("type = %d\n", type); +		if (type == DNS_CNAME_RECORD) { +			/* CNAME answer. shift to the next section */ +			debug("Found canonical name\n"); +			tmp = p[10] | (p[11] << 8); +			dlen = ntohs(tmp); +			debug("dlen = %d\n", dlen); +			p += 12 + dlen; +		} else if (type == DNS_A_RECORD) { +			debug("Found A-record\n"); +			found = stop = 1; +		} else { +			debug("Unknown type\n"); +			stop = 1; +		} +	} + +	if (found && &p[12] < e) { + +		tmp = p[10] | (p[11] << 8); +		dlen = ntohs(tmp); +		p += 12; +		memcpy(&IPAddress, p, 4); + +		if (p + dlen <= e) { +			ip_to_string(IPAddress, IPStr); +			printf("%s\n", IPStr); +			if (NetDNSenvvar) +				setenv(NetDNSenvvar, IPStr); +		} else +			puts("server responded with invalid IP number\n"); +	} + +	NetState = NETLOOP_SUCCESS; +} + +void +DnsStart(void) +{ +	debug("%s\n", __func__); + +	NetSetTimeout(DNS_TIMEOUT, DnsTimeout); +	NetSetHandler(DnsHandler); + +	DnsSend(); +} + diff --git a/net/dns.h b/net/dns.h new file mode 100644 index 000000000..277c093ed --- /dev/null +++ b/net/dns.h @@ -0,0 +1,39 @@ +/* + * (C) Masami Komiya <mkomiya@sonare.it> 2005 + *  Copyright 2009, Robin Getz <rgetz@blackfin.uclinux.org> + * + * This program 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. + */ + +#ifndef __DNS_H__ +#define __DNS_H__ + +#define DNS_SERVICE_PORT 53 +#define DNS_TIMEOUT      10000UL + +/* http://en.wikipedia.org/wiki/List_of_DNS_record_types */ +enum dns_query_type { +	DNS_A_RECORD = 0x01, +	DNS_CNAME_RECORD = 0x05, +	DNS_MX_RECORD = 0x0f, +}; + +/* + * DNS network packet + */ +struct header { +	uint16_t	tid;		/* Transaction ID */ +	uint16_t	flags;		/* Flags */ +	uint16_t	nqueries;	/* Questions */ +	uint16_t	nanswers;	/* Answers */ +	uint16_t	nauth;		/* Authority PRs */ +	uint16_t	nother;		/* Other PRs */ +	unsigned char	data[1];	/* Data, variable length */ +}; + +extern void DnsStart(void);		/* Begin DNS */ + +#endif @@ -92,6 +92,9 @@  #if defined(CONFIG_CDP_VERSION)  #include <timestamp.h>  #endif +#if defined(CONFIG_CMD_DNS) +#include "dns.h" +#endif  #if defined(CONFIG_CMD_NET) @@ -291,6 +294,9 @@ NetInitLoop(proto_t protocol)  		NetServerIP = getenv_IPaddr ("serverip");  		NetOurNativeVLAN = getenv_VLAN("nvlan");  		NetOurVLAN = getenv_VLAN("vlan"); +#if defined(CONFIG_CMD_DNS) +		NetOurDNSIP = getenv_IPaddr("dnsip"); +#endif  		env_changed_id = env_id;  	} @@ -426,6 +432,11 @@ restart:  			SntpStart();  			break;  #endif +#if defined(CONFIG_CMD_DNS) +		case DNS: +			DnsStart(); +			break; +#endif  		default:  			break;  		} @@ -1518,6 +1529,14 @@ static int net_check_prereq (proto_t protocol)  		}  		goto common;  #endif +#if defined(CONFIG_CMD_DNS) +	case DNS: +		if (NetOurDNSIP == 0) { +			puts("*** ERROR: DNS server address not given\n"); +			return 1; +		} +		goto common; +#endif  #if defined(CONFIG_CMD_NFS)  	case NFS:  #endif @@ -1681,6 +1700,16 @@ void copy_filename (char *dst, char *src, int size)  #endif +#if defined(CONFIG_CMD_NFS) || defined(CONFIG_CMD_SNTP) || defined(CONFIG_CMD_DNS) +/* + * make port a little random, but use something trivial to compute + */ +unsigned int random_port(void) +{ +	return 1024 + (get_timer(0) % 0x8000);; +} +#endif +  void ip_to_string (IPaddr_t x, char *s)  {  	x = ntohl (x); |