Blame view

net/dns.c 4.55 KB
1a32bf418   Robin Getz   Add DNS support
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  /*
   * 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>
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
28
  #include <asm/unaligned.h>
1a32bf418   Robin Getz   Add DNS support
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  
  #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;
594c26f8a   Joe Hershberger   net: cosmetic: Un...
48
  	pkt = p = (uchar *)(NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE);
1a32bf418   Robin Getz   Add DNS support
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  
  	/* 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);
  
  	DnsOurPort = random_port();
  
  	NetSendUDPPacket(NetServerEther, NetOurDNSIP, DNS_SERVICE_PORT,
  		DnsOurPort, n);
  	debug("DNS packet sent
  ");
  }
  
  static void
  DnsTimeout(void)
  {
  	puts("Timeout
  ");
22f6e99d5   Joe Hershberger   net: Refactor to ...
104
  	net_set_state(NETLOOP_FAIL);
1a32bf418   Robin Getz   Add DNS support
105
106
107
  }
  
  static void
03eb129f8   Luca Ceresoli   NET: pass source ...
108
  DnsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
1a32bf418   Robin Getz   Add DNS support
109
110
111
112
113
114
115
  {
  	struct header *header;
  	const unsigned char *p, *e, *s;
  	u16 type, i;
  	int found, stop, dlen;
  	char IPStr[22];
  	IPaddr_t IPAddress;
1a32bf418   Robin Getz   Add DNS support
116
117
118
119
120
121
122
123
124
125
126
  
  
  	debug("%s
  ", __func__);
  	if (dest != DnsOurPort)
  		return;
  
  	for (i = 0; i < len; i += 4)
  		debug("0x%p - 0x%.2x  0x%.2x  0x%.2x  0x%.2x
  ",
  			pkt+i, pkt[i], pkt[i+1], pkt[i+2], pkt[i+3]);
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
127
  	/* We sent one query. We want to have a single answer: */
1a32bf418   Robin Getz   Add DNS support
128
129
130
131
132
133
  	header = (struct header *) pkt;
  	if (ntohs(header->nqueries) != 1)
  		return;
  
  	/* Received 0 answers */
  	if (header->nanswers == 0) {
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
134
135
  		puts("DNS: host not found
  ");
22f6e99d5   Joe Hershberger   net: Refactor to ...
136
  		net_set_state(NETLOOP_SUCCESS);
1a32bf418   Robin Getz   Add DNS support
137
138
139
140
141
142
143
144
145
146
  		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 */
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
147
148
149
  	if (&p[5] > e || get_unaligned_be16(p+1) != DNS_A_RECORD) {
  		puts("DNS: response was not an A record
  ");
22f6e99d5   Joe Hershberger   net: Refactor to ...
150
  		net_set_state(NETLOOP_SUCCESS);
1a32bf418   Robin Getz   Add DNS support
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  		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
  ", p[1]);
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
168
  		type = get_unaligned_be16(p+2);
1a32bf418   Robin Getz   Add DNS support
169
170
171
172
173
174
  		debug("type = %d
  ", type);
  		if (type == DNS_CNAME_RECORD) {
  			/* CNAME answer. shift to the next section */
  			debug("Found canonical name
  ");
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
175
  			dlen = get_unaligned_be16(p+10);
1a32bf418   Robin Getz   Add DNS support
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  			debug("dlen = %d
  ", dlen);
  			p += 12 + dlen;
  		} else if (type == DNS_A_RECORD) {
  			debug("Found A-record
  ");
  			found = stop = 1;
  		} else {
  			debug("Unknown type
  ");
  			stop = 1;
  		}
  	}
  
  	if (found && &p[12] < e) {
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
191
  		dlen = get_unaligned_be16(p+10);
1a32bf418   Robin Getz   Add DNS support
192
193
194
195
196
197
198
199
200
201
202
203
204
  		p += 12;
  		memcpy(&IPAddress, p, 4);
  
  		if (p + dlen <= e) {
  			ip_to_string(IPAddress, IPStr);
  			printf("%s
  ", IPStr);
  			if (NetDNSenvvar)
  				setenv(NetDNSenvvar, IPStr);
  		} else
  			puts("server responded with invalid IP number
  ");
  	}
22f6e99d5   Joe Hershberger   net: Refactor to ...
205
  	net_set_state(NETLOOP_SUCCESS);
1a32bf418   Robin Getz   Add DNS support
206
207
208
209
210
211
212
213
214
  }
  
  void
  DnsStart(void)
  {
  	debug("%s
  ", __func__);
  
  	NetSetTimeout(DNS_TIMEOUT, DnsTimeout);
ece223b52   Joe Hershberger   net: Refactor to ...
215
  	net_set_udp_handler(DnsHandler);
1a32bf418   Robin Getz   Add DNS support
216
217
218
  
  	DnsSend();
  }