diff options
| author | Robin Getz <rgetz@blackfin.uclinux.org> | 2009-07-20 14:53:54 -0400 | 
|---|---|---|
| committer | Ben Warren <biggerbadderben@gmail.com> | 2009-07-22 22:53:44 -0700 | 
| commit | 1a32bf41881b5dbe3119cb77a33572b4d462cabf (patch) | |
| tree | dda370cbcb7a6614e111ad2399661392322bab0b /net/dns.c | |
| parent | 88ad3fd91c83a4343b25385fd78fd8e29ebb723f (diff) | |
| download | olio-uboot-2014.01-1a32bf41881b5dbe3119cb77a33572b4d462cabf.tar.xz olio-uboot-2014.01-1a32bf41881b5dbe3119cb77a33572b4d462cabf.zip | |
Add DNS support
On 04 Oct 2008 Pieter posted a dns implementation for U-Boot.
http://www.mail-archive.com/u-boot-users@lists.sourceforge.net/msg10216.html
>
> DNS can be enabled by setting CFG_CMD_DNS. After performing a query,
> the serverip environment var is updated.
>
> Probably there are some cosmetic issues with the patch. Unfortunatly I
> do not have the time to correct these. So if anybody else likes DNS
> support in U-Boot and has the time, feel free to patch it in the main tree.
Here it is again - slightly modified & smaller:
  - update to 2009-06 (Pieter's patch was for U-Boot 1.2.0)
  - README.dns is added
  - syntax is changed (now takes a third option, the env var to store
    the result in)
  - add a random port() function in net.c
  - sort Makefile in ./net/Makefile
  - dns just returns unless a env var is given
  - run through checkpatch, and clean up style issues
  - remove packet from stack
  - cleaned up some comments
  - failure returns much faster (if server responds, don't wait for
    timeout)
  - use built in functions (memcpy) rather than byte copy.
Signed-off-by: Robin Getz <rgetz@blackfin.uclinux.org>
Signed-off-by: Pieter Voorthuijsen <pieter.voorthuijsen@prodrive.nl>
Signed-off-by: Ben Warren <biggerbadderben@gmail.com>
Diffstat (limited to 'net/dns.c')
| -rw-r--r-- | net/dns.c | 211 | 
1 files changed, 211 insertions, 0 deletions
| 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(); +} + |