mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 21:54:01 +00:00
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>
This commit is contained in:
parent
88ad3fd91c
commit
1a32bf4188
7 changed files with 401 additions and 3 deletions
|
@ -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 */
|
||||
|
||||
|
|
64
doc/README.dns
Normal file
64
doc/README.dns
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
211
net/dns.c
Normal file
211
net/dns.c
Normal file
|
@ -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();
|
||||
}
|
||||
|
39
net/dns.h
Normal file
39
net/dns.h
Normal file
|
@ -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
|
29
net/net.c
29
net/net.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -425,6 +431,11 @@ restart:
|
|||
case SNTP:
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue