Преглед изворни кода

A working DNS resolver (not yet tied in to anything)

tags/v0.9.3
Michael Brown пре 18 година
родитељ
комит
9af12d5fba
6 измењених фајлова са 509 додато и 385 уклоњено
  1. 1
    0
      src/include/errno.h
  2. 39
    22
      src/include/gpxe/dns.h
  3. 1
    1
      src/include/nmb.h
  4. 463
    0
      src/net/udp/dns.c
  5. 0
    361
      src/proto/dns.c
  6. 5
    1
      src/proto/nmb.c

+ 1
- 0
src/include/errno.h Прегледај датотеку

@@ -137,6 +137,7 @@
137 137
 #define EINVAL		0xdd	/**< Invalid argument */
138 138
 #define EIO		0xde	/**< Input/output error */
139 139
 #define EISCONN		0xdf	/**< Transport endpoint is already connected */
140
+#define ELOOP		0xf8	/**< Too many symbolic links */
140 141
 #define EMFILE		0xe0	/**< Too many open files */
141 142
 #define EMSGSIZE	0xe1	/**< Message too long */
142 143
 #define ENAMETOOLONG	0xe2	/**< File name too long */

src/include/dns.h → src/include/gpxe/dns.h Прегледај датотеку

@@ -1,10 +1,16 @@
1
-#ifndef DNS_RESOLVER_H
2
-#define DNS_RESOLVER_H
1
+#ifndef _GPXE_DNS_H
2
+#define _GPXE_DNS_H
3 3
 
4
-#include "stdint.h"
4
+/** @file
5
+ *
6
+ * DNS protocol
7
+ *
8
+ */
9
+
10
+#include <stdint.h>
5 11
 #include <gpxe/in.h>
6
-#include "ip.h"
7
-#include "udp.h"
12
+#include <gpxe/async.h>
13
+#include <gpxe/retry.h>
8 14
 
9 15
 /*
10 16
  * Constants
@@ -33,7 +39,7 @@
33 39
 #define DNS_FLAG_RCODE_NX	( 0x03 << 0 )
34 40
 #define DNS_FLAG_RCODE(flags)	( (flags) & ( 0x0f << 0 ) )
35 41
 
36
-#define	DNS_UDP_PORT		53
42
+#define	DNS_PORT		53
37 43
 #define	DNS_MAX_RETRIES		3
38 44
 #define	DNS_MAX_CNAME_RECURSION	0x30
39 45
 
@@ -56,13 +62,11 @@ struct dns_query_info {
56 62
 } __attribute__ (( packed ));
57 63
 
58 64
 struct dns_query {
59
-	struct iphdr	ip;
60
-	struct udphdr	udp;
61 65
 	struct dns_header dns;
62 66
 	char		payload[ 256 + sizeof ( struct dns_query_info ) ];
63 67
 } __attribute__ (( packed ));
64 68
 
65
-struct dns_rr_info {
69
+struct dns_rr_info_common {
66 70
 	uint16_t	type;
67 71
 	uint16_t	class;
68 72
 	uint32_t	ttl;
@@ -70,23 +74,36 @@ struct dns_rr_info {
70 74
 } __attribute__ (( packed ));
71 75
 
72 76
 struct dns_rr_info_a {
73
-	struct dns_rr_info info;
77
+	struct dns_rr_info_common common;
74 78
 	struct in_addr in_addr;
75 79
 } __attribute__ (( packed ));
76 80
 
77 81
 struct dns_rr_info_cname {
78
-	struct dns_rr_info info;
79
-	char		cname[0];
82
+	struct dns_rr_info_common common;
83
+	char cname[0];
80 84
 } __attribute__ (( packed ));
81 85
 
82
-/*
83
- * Functions in dns.c (used by nmb.c)
84
- *
85
- */
86
-extern struct dns_header * dns_query ( struct dns_query *query,
87
-				       unsigned int query_len, 
88
-				       struct sockaddr_in *nameserver );
89
-extern struct dns_rr_info * dns_find_rr ( struct dns_query *query,
90
-					  struct dns_header *reply );
86
+union dns_rr_info {
87
+	struct dns_rr_info_common common;
88
+	struct dns_rr_info_a a;
89
+	struct dns_rr_info_cname cname;
90
+};
91
+
92
+struct dns_request {
93
+
94
+	struct sockaddr_tcpip *st;
95
+
96
+	struct async async;
97
+	struct dns_query query;
98
+	struct dns_query_info *qinfo;
99
+
100
+	unsigned int recursion;
101
+
102
+	struct udp_connection udp;
103
+	struct retry_timer timer;
104
+};
105
+
106
+extern int dns_resolv ( const char *name, struct sockaddr_tcpip *st,
107
+			struct async *parent );
91 108
 
92
-#endif /* DNS_RESOLVER_H */
109
+#endif /* _GPXE_DNS_H */

+ 1
- 1
src/include/nmb.h Прегледај датотеку

@@ -1,7 +1,7 @@
1 1
 #ifndef NMB_H
2 2
 #define NMB_H
3 3
 
4
-#include "dns.h"
4
+#include <gpxe/dns.h>
5 5
 
6 6
 /*
7 7
  * NetBIOS name query packets are basically the same as DNS packets,

+ 463
- 0
src/net/udp/dns.c Прегледај датотеку

@@ -0,0 +1,463 @@
1
+/*
2
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * Portions copyright (C) 2004 Anselm M. Hoffmeister
5
+ * <stockholm@users.sourceforge.net>.
6
+ *
7
+ * This program is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU General Public License as
9
+ * published by the Free Software Foundation; either version 2 of the
10
+ * License, or any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful, but
13
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
+ */
21
+
22
+#include <stdint.h>
23
+#include <stdlib.h>
24
+#include <string.h>
25
+#include <errno.h>
26
+#include <byteswap.h>
27
+#include <gpxe/async.h>
28
+#include <gpxe/udp.h>
29
+#include <gpxe/dhcp.h>
30
+#include <gpxe/dns.h>
31
+
32
+/** @file
33
+ *
34
+ * DNS protocol
35
+ *
36
+ */
37
+
38
+/**
39
+ * Compare DNS reply name against the query name from the original request
40
+ *
41
+ * @v dns		DNS request
42
+ * @v reply		DNS reply
43
+ * @v rname		Reply name
44
+ * @ret	zero		Names match
45
+ * @ret non-zero	Names do not match
46
+ */
47
+static int dns_name_cmp ( struct dns_request *dns, struct dns_header *reply, 
48
+			  const char *rname ) {
49
+	const char *qname = dns->query.payload;
50
+	int i;
51
+
52
+	while ( 1 ) {
53
+		/* Obtain next section of rname */
54
+		while ( ( *rname ) & 0xc0 ) {			
55
+			rname = ( ( ( char * ) reply ) +
56
+				  ( ntohs( *((uint16_t *)rname) ) & ~0xc000 ));
57
+		}
58
+		/* Check that lengths match */
59
+		if ( *rname != *qname )
60
+			return -1;
61
+		/* If length is zero, we have reached the end */
62
+		if ( ! *qname )
63
+			return 0;
64
+		/* Check that data matches */
65
+		for ( i = *qname + 1; i > 0 ; i-- ) {
66
+			if ( *(rname++) != *(qname++) )
67
+				return -1;
68
+		}
69
+	}
70
+}
71
+
72
+/**
73
+ * Skip over a (possibly compressed) DNS name
74
+ *
75
+ * @v name		DNS name
76
+ * @ret name		Next DNS name
77
+ */
78
+static const char * dns_skip_name ( const char *name ) {
79
+	while ( 1 ) {
80
+		if ( ! *name ) {
81
+			/* End of name */
82
+			return ( name + 1);
83
+		}
84
+		if ( *name & 0xc0 ) {
85
+			/* Start of a compressed name */
86
+			return ( name + 2 );
87
+		}
88
+		/* Uncompressed name portion */
89
+		name += *name + 1;
90
+	}
91
+}
92
+
93
+/**
94
+ * Find an RR in a reply packet corresponding to our query
95
+ *
96
+ * @v dns		DNS request
97
+ * @v reply		DNS reply
98
+ * @ret rr		DNS RR, or NULL if not found
99
+ */
100
+static union dns_rr_info * dns_find_rr ( struct dns_request *dns,
101
+					 struct dns_header *reply ) {
102
+	int i, cmp;
103
+	const char *p = ( ( char * ) reply ) + sizeof ( struct dns_header );
104
+	union dns_rr_info *rr_info;
105
+
106
+	/* Skip over the questions section */
107
+	for ( i = ntohs ( reply->qdcount ) ; i > 0 ; i-- ) {
108
+		p = dns_skip_name ( p ) + sizeof ( struct dns_query_info );
109
+	}
110
+
111
+	/* Process the answers section */
112
+	for ( i = ntohs ( reply->ancount ) ; i > 0 ; i-- ) {
113
+		cmp = dns_name_cmp ( dns, reply, p );
114
+		p = dns_skip_name ( p );
115
+		rr_info = ( ( union dns_rr_info * ) p );
116
+		if ( cmp == 0 )
117
+			return rr_info;
118
+		p += ( sizeof ( rr_info->common ) +
119
+		       ntohs ( rr_info->common.rdlength ) );
120
+	}
121
+
122
+	return NULL;
123
+}
124
+
125
+/**
126
+ * Convert a standard NUL-terminated string to a DNS name
127
+ *
128
+ * @v string		Name as a NUL-terminated string
129
+ * @v buf		Buffer in which to place DNS name
130
+ * @ret next		Byte following constructed DNS name
131
+ *
132
+ * DNS names consist of "<length>element" pairs.
133
+ */
134
+static char * dns_make_name ( const char *string, char *buf ) {
135
+	char *length_byte = buf++;
136
+	char c;
137
+
138
+	while ( ( c = *(string++) ) ) {
139
+		if ( c == '.' ) {
140
+			*length_byte = buf - length_byte - 1;
141
+			length_byte = buf;
142
+		}
143
+		*(buf++) = c;
144
+	}
145
+	*length_byte = buf - length_byte - 1;
146
+	*(buf++) = '\0';
147
+	return buf;
148
+}
149
+
150
+/**
151
+ * Convert an uncompressed DNS name to a NUL-terminated string
152
+ *
153
+ * @v name		DNS name
154
+ * @ret string		NUL-terminated string
155
+ *
156
+ * Produce a printable version of a DNS name.  Used only for debugging.
157
+ */
158
+static inline char * dns_unmake_name ( char *name ) {
159
+	char *p;
160
+	unsigned int len;
161
+
162
+	p = name;
163
+	while ( ( len = *p ) ) {
164
+		*(p++) = '.';
165
+		p += len;
166
+	}
167
+
168
+	return name + 1;
169
+}
170
+
171
+/**
172
+ * Decompress a DNS name
173
+ *
174
+ * @v reply		DNS replay
175
+ * @v name		DNS name
176
+ * @v buf		Buffer into which to decompress DNS name
177
+ * @ret next		Byte following decompressed DNS name
178
+ */
179
+static char * dns_decompress_name ( struct dns_header *reply,
180
+				    const char *name, char *buf ) {
181
+	int i, len;
182
+
183
+	do {
184
+		/* Obtain next section of name */
185
+		while ( ( *name ) & 0xc0 ) {
186
+			name = ( ( char * ) reply +
187
+				 ( ntohs ( *((uint16_t *)name) ) & ~0xc000 ) );
188
+		}
189
+		/* Copy data */
190
+		len = *name;
191
+		for ( i = len + 1 ; i > 0 ; i-- ) {
192
+			*(buf++) = *(name++);
193
+		}
194
+	} while ( len );
195
+	return buf;
196
+}
197
+
198
+/**
199
+ * Mark DNS request as complete
200
+ *
201
+ * @v dns		DNS request
202
+ * @v rc		Return status code
203
+ */
204
+static void dns_done ( struct dns_request *dns, int rc ) {
205
+
206
+	/* Stop the retry timer */
207
+	stop_timer ( &dns->timer );
208
+
209
+	/* Close UDP connection */
210
+	udp_close ( &dns->udp );
211
+
212
+	/* Mark async operation as complete */
213
+	async_done ( &dns->async, rc );
214
+}
215
+
216
+/**
217
+ * Send next packet in DNS request
218
+ *
219
+ * @v dns		DNS request
220
+ */
221
+static void dns_send_packet ( struct dns_request *dns ) {
222
+	static unsigned int qid = 0;
223
+
224
+	/* Increment query ID */
225
+	dns->query.dns.id = htons ( ++qid );
226
+
227
+	DBGC ( dns, "DNS %p sending query ID %d\n", dns, qid );
228
+
229
+	/* Start retransmission timer */
230
+	start_timer ( &dns->timer );
231
+
232
+	/* Send the data */
233
+	udp_send ( &dns->udp, &dns->query,
234
+		   ( ( ( void * ) dns->qinfo ) - ( ( void * ) &dns->query )
235
+		     + sizeof ( dns->qinfo ) ) );
236
+}
237
+
238
+/**
239
+ * Handle DNS retransmission timer expiry
240
+ *
241
+ * @v timer		Retry timer
242
+ * @v fail		Failure indicator
243
+ */
244
+static void dns_timer_expired ( struct retry_timer *timer, int fail ) {
245
+	struct dns_request *dns =
246
+		container_of ( timer, struct dns_request, timer );
247
+
248
+	if ( fail ) {
249
+		dns_done ( dns, -ETIMEDOUT );
250
+	} else {
251
+		dns_send_packet ( dns );
252
+	}
253
+}
254
+
255
+/**
256
+ * Receive new data
257
+ *
258
+ * @v udp		UDP connection
259
+ * @v data		Received data
260
+ * @v len		Length of received data
261
+ * @v st_src		Partially-filled source address
262
+ * @v st_dest		Partially-filled destination address
263
+ */
264
+static int dns_newdata ( struct udp_connection *conn, void *data, size_t len,
265
+			 struct sockaddr_tcpip *st_src __unused,
266
+			 struct sockaddr_tcpip *st_dest __unused ) {
267
+	struct dns_request *dns =
268
+		container_of ( conn, struct dns_request, udp );
269
+	struct dns_header *reply = data;
270
+	union dns_rr_info *rr_info;
271
+	struct sockaddr_in *sin;
272
+	unsigned int qtype = dns->qinfo->qtype;
273
+
274
+	/* Sanity check */
275
+	if ( len < sizeof ( *reply ) ) {
276
+		DBGC ( dns, "DNS %p received underlength packet length %zd\n",
277
+		       dns, len );
278
+		return -EINVAL;
279
+	}
280
+
281
+	/* Check reply ID matches query ID */
282
+	if ( reply->id != dns->query.dns.id ) {
283
+		DBGC ( dns, "DNS %p received unexpected reply ID %d "
284
+		       "(wanted %d)\n", dns, ntohs ( reply->id ),
285
+		       ntohs ( dns->query.dns.id ) );
286
+		return -EINVAL;
287
+	}
288
+
289
+	DBGC ( dns, "DNS %p received reply ID %d\n", dns, ntohs ( reply->id ));
290
+
291
+	/* Stop the retry timer.  After this point, each code path
292
+	 * must either restart the timer by calling dns_send_packet(),
293
+	 * or mark the DNS operation as complete by calling
294
+	 * dns_done()
295
+	 */
296
+	stop_timer ( &dns->timer );
297
+
298
+	/* Search through response for useful answers.  Do this
299
+	 * multiple times, to take advantage of useful nameservers
300
+	 * which send us e.g. the CNAME *and* the A record for the
301
+	 * pointed-to name.
302
+	 */
303
+	while ( ( rr_info = dns_find_rr ( dns, reply ) ) ) {
304
+		switch ( rr_info->common.type ) {
305
+
306
+		case htons ( DNS_TYPE_A ):
307
+
308
+			/* Found the target A record */
309
+			DBGC ( dns, "DNS %p found address %s\n",
310
+			       dns, inet_ntoa ( rr_info->a.in_addr ) );
311
+			sin = ( struct sockaddr_in * ) dns->st;
312
+			sin->sin_family = AF_INET;
313
+			sin->sin_addr = rr_info->a.in_addr;
314
+
315
+			/* Mark operation as complete */
316
+			dns_done ( dns, 0 );
317
+			return 0;
318
+
319
+		case htons ( DNS_TYPE_CNAME ):
320
+
321
+			/* Found a CNAME record; update query and recurse */
322
+			DBGC ( dns, "DNS %p found CNAME\n", dns );
323
+			dns->qinfo = ( void * ) dns_decompress_name ( reply,
324
+							 rr_info->cname.cname,
325
+							 dns->query.payload );
326
+			dns->qinfo->qtype = htons ( DNS_TYPE_A );
327
+			dns->qinfo->qclass = htons ( DNS_CLASS_IN );
328
+			
329
+			/* Terminate the operation if we recurse too far */
330
+			if ( ++dns->recursion > DNS_MAX_CNAME_RECURSION ) {
331
+				DBGC ( dns, "DNS %p recursion exceeded\n",
332
+				       dns );
333
+				dns_done ( dns, -ELOOP );
334
+				return 0;
335
+			}
336
+			break;
337
+
338
+		default:
339
+			DBGC ( dns, "DNS %p got unknown record type %d\n",
340
+			       dns, ntohs ( rr_info->common.type ) );
341
+			break;
342
+		}
343
+	}
344
+	
345
+	/* Determine what to do next based on the type of query we
346
+	 * issued and the reponse we received
347
+	 */
348
+	switch ( qtype ) {
349
+
350
+	case htons ( DNS_TYPE_A ):
351
+		/* We asked for an A record and got nothing;
352
+		 * try the CNAME.
353
+		 */
354
+		DBGC ( dns, "DNS %p found no A record; trying CNAME\n", dns );
355
+		dns->qinfo->qtype = htons ( DNS_TYPE_CNAME );
356
+		dns_send_packet ( dns );
357
+		return 0;
358
+
359
+	case htons ( DNS_TYPE_CNAME ):
360
+		/* We asked for a CNAME record.  If we got a response
361
+		 * (i.e. if the next A query is already set up), then
362
+		 * issue it, otherwise abort.
363
+		 */
364
+		if ( dns->qinfo->qtype == htons ( DNS_TYPE_A ) ) {
365
+			dns_send_packet ( dns );
366
+			return 0;
367
+		} else {
368
+			DBGC ( dns, "DNS %p found no CNAME record\n", dns );
369
+			dns_done ( dns, -ENXIO );
370
+			return 0;
371
+		}
372
+
373
+	default:
374
+		assert ( 0 );
375
+		dns_done ( dns, -EINVAL );
376
+		return 0;
377
+	}
378
+}
379
+
380
+/** DNS UDP operations */
381
+struct udp_operations dns_udp_operations = {
382
+	.newdata = dns_newdata,
383
+};
384
+
385
+/**
386
+ * Reap asynchronous operation
387
+ *
388
+ * @v async		Asynchronous operation
389
+ */
390
+static void dns_reap ( struct async *async ) {
391
+	struct dns_request *dns =
392
+		container_of ( async, struct dns_request, async );
393
+
394
+	free ( dns );
395
+}
396
+
397
+/** DNS asynchronous operations */
398
+static struct async_operations dns_async_operations = {
399
+	.reap = dns_reap,
400
+};
401
+
402
+/**
403
+ * Resolve name using DNS
404
+ *
405
+ */
406
+int dns_resolv ( const char *name, struct sockaddr_tcpip *st,
407
+		 struct async *parent ) {
408
+	struct dns_request *dns;
409
+	union {
410
+		struct sockaddr_tcpip st;
411
+		struct sockaddr_in sin;
412
+	} nameserver;
413
+	int rc;
414
+
415
+	/* Allocate DNS structure */
416
+	dns = malloc ( sizeof ( *dns ) );
417
+	if ( ! dns ) {
418
+		rc = -ENOMEM;
419
+		goto err;
420
+	}
421
+	memset ( dns, 0, sizeof ( *dns ) );
422
+	dns->st = st;
423
+	dns->timer.expired = dns_timer_expired;
424
+	dns->udp.udp_op = &dns_udp_operations;
425
+
426
+	/* Create query */
427
+	dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
428
+				       DNS_FLAG_RD );
429
+	dns->query.dns.qdcount = htons ( 1 );
430
+	dns->qinfo = ( void * ) dns_make_name ( name, dns->query.payload );
431
+	dns->qinfo->qtype = htons ( DNS_TYPE_A );
432
+	dns->qinfo->qclass = htons ( DNS_CLASS_IN );
433
+
434
+	/* Open UDP connection */
435
+	memset ( &nameserver, 0, sizeof ( nameserver ) );
436
+	nameserver.sin.sin_family = AF_INET;
437
+	nameserver.sin.sin_port = htons ( DNS_PORT );
438
+#warning "DHCP-DNS hack"
439
+	struct dhcp_option *option =
440
+		find_global_dhcp_option ( DHCP_DNS_SERVERS );
441
+	if ( ! option ) {
442
+		DBGC ( dns, "DNS %p no name servers\n", dns );
443
+		rc = -ENXIO;
444
+		goto err;
445
+	}
446
+	dhcp_ipv4_option ( option, &nameserver.sin.sin_addr );
447
+	DBGC ( dns, "DNS %p using nameserver %s\n", dns, 
448
+	       inet_ntoa ( nameserver.sin.sin_addr ) );
449
+	udp_connect ( &dns->udp, &nameserver.st );
450
+	if ( ( rc = udp_open ( &dns->udp, 0 ) ) != 0 )
451
+		goto err;
452
+
453
+	dns_send_packet ( dns );
454
+
455
+	async_init ( &dns->async, &dns_async_operations, parent );
456
+	return 0;	
457
+
458
+ err:
459
+	DBGC ( dns, "DNS %p could not create request: %s\n", 
460
+	       dns, strerror ( rc ) );
461
+	free ( dns );
462
+	return rc;
463
+}

+ 0
- 361
src/proto/dns.c Прегледај датотеку

@@ -1,361 +0,0 @@
1
-/**************************************************************************
2
-*
3
-*    dns_resolver.c: Etherboot support for resolution of host/domain
4
-*    names in filename parameters
5
-*    Written 2004 by Anselm M. Hoffmeister
6
-*    <stockholm@users.sourceforge.net>
7
-*
8
-*    This program is free software; you can redistribute it and/or modify
9
-*    it under the terms of the GNU General Public License as published by
10
-*    the Free Software Foundation; either version 2 of the License, or
11
-*    (at your option) any later version.
12
-*
13
-*    This program is distributed in the hope that it will be useful,
14
-*    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
-*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
-*    GNU General Public License for more details.
17
-*
18
-*    You should have received a copy of the GNU General Public License
19
-*    along with this program; if not, write to the Free Software
20
-*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
-*
22
-*    This code is using nuts and bolts from throughout etherboot.
23
-*    It is a fresh implementation according to the DNS RFC, #1035
24
-*    
25
-*    REVISION HISTORY:
26
-*    ================
27
-*    2004-05-10 File created
28
-*    2004-05-19 First release to CVS
29
-*    2004-05-22 CNAME support first stage finished
30
-*    2004-05-24 First "stable" release to CVS
31
-*    2004-08-28 Improve readability, set recursion flag
32
-*    2005-04-30 Tidied up to the point of being a complete rewrite (mcb30)
33
-***************************************************************************/
34
-
35
-#include "etherboot.h"
36
-#include "nic.h"
37
-#include "resolv.h"
38
-#include "dns.h"
39
-
40
-/*
41
- *	await_dns
42
- *	Shall be called on any incoming packet during the resolution process
43
- *	(as is the case with all the other await_ functions in etherboot)
44
- *	Param:	as any await functions
45
- *
46
- */
47
-static int await_dns ( int ival, void *ptr,
48
-		       unsigned short ptype __unused,
49
-		       struct iphdr *ip __unused,
50
-		       struct udphdr *udp, struct tcphdr *tcp __unused ) {
51
-	struct dns_header **header = ptr;
52
-
53
-	if ( ! udp )
54
-		return 0;
55
-	if ( ntohs ( udp->dest ) != ival )
56
-		return 0;
57
-	*header = ( struct dns_header * ) ( udp + 1 );
58
-	return 1;
59
-}
60
-
61
-/*
62
- * Send a name server query and wait for a response.  Query is retried
63
- * up to DNS_MAX_RETRIES times.  Returns a pointer to the answer
64
- * packet, or NULL if no answer was received.
65
- *
66
- */
67
-struct dns_header * dns_query ( struct dns_query *query,
68
-				unsigned int query_len, 
69
-				struct sockaddr_in *nameserver ) {
70
-	long timeout;
71
-	int retry;
72
-	struct dns_header *reply;
73
-
74
-	for ( retry = 0 ; retry < DNS_MAX_RETRIES ; retry++ ) {
75
-		udp_transmit ( nameserver->sin_addr.s_addr,
76
-			       nameserver->sin_port, nameserver->sin_port,
77
-			       query_len, query );
78
-		timeout = rfc2131_sleep_interval ( TIMEOUT, retry );
79
-		if ( ! await_reply ( await_dns, nameserver->sin_port,
80
-				     &reply, timeout ) )
81
-			continue;
82
-		if ( reply->id != query->dns.id ) {
83
-			DBG ( "DNS received unexpected reply ID %d "
84
-			      "(wanted %d)\n",
85
-			      ntohs ( reply->id ), ntohs ( query->dns.id ) );
86
-			continue;
87
-		}
88
-		/* We have a valid reply! */
89
-		return reply;
90
-	}
91
-	return NULL;
92
-}
93
-
94
-/*
95
- * Compare two DNS names to see if they are the same.  Takes
96
- * compressed names in the reply into account (though the query name
97
- * must be uncompressed).  Returns 0 for a match (for consistency with
98
- * strcmp et al).
99
- *
100
- */
101
-static inline int dns_name_cmp ( const char *qname, const char *rname,
102
-				 struct dns_header *reply ) {
103
-	int i;
104
-	while ( 1 ) {
105
-		/* Obtain next section of rname */
106
-		while ( ( *rname ) & 0xc0 ) {
107
-			rname = ( ( char * ) reply +
108
-				  ( ntohs( *((uint16_t *)rname) ) & ~0xc000 ));
109
-		}
110
-		/* Check that lengths match */
111
-		if ( *rname != *qname )
112
-			return 1;
113
-		/* If length is zero, we have reached the end */
114
-		if ( ! *qname )
115
-			return 0;
116
-		/* Check that data matches */
117
-		for ( i = *qname + 1; i > 0 ; i-- ) {
118
-			if ( *(rname++) != *(qname++) )
119
-				return 1;
120
-		}
121
-	}
122
-}
123
-
124
-/*
125
- * Skip over a DNS name, which may be compressed
126
- *
127
- */
128
-static inline const char * dns_skip_name ( const char *name ) {
129
-	while ( 1 ) {
130
-		if ( ! *name ) {
131
-			/* End of name */
132
-			return ( name + 1);
133
-		}
134
-		if ( *name & 0xc0 ) {
135
-			/* Start of a compressed name */
136
-			return ( name + 2 );
137
-		}
138
-		/* Uncompressed name portion */
139
-		name += *name + 1;
140
-	}
141
-}
142
-
143
-/*
144
- * Find a Resource Record in a reply packet corresponding to our
145
- * query.  Returns a pointer to the RR, or NULL if no answer found.
146
- *
147
- */
148
-struct dns_rr_info * dns_find_rr ( struct dns_query *query,
149
-				   struct dns_header *reply ) {
150
-	int i, cmp;
151
-	const char *p = ( ( char * ) reply ) + sizeof ( struct dns_header );
152
-
153
-	/* Skip over the questions section */
154
-	for ( i = ntohs ( reply->qdcount ) ; i > 0 ; i-- ) {
155
-		p = dns_skip_name ( p ) + sizeof ( struct dns_query_info );
156
-	}
157
-
158
-	/* Process the answers section */
159
-	for ( i = ntohs ( reply->ancount ) ; i > 0 ; i-- ) {
160
-		cmp = dns_name_cmp ( query->payload, p, reply );
161
-		p = dns_skip_name ( p );
162
-		if ( cmp == 0 )
163
-			return ( ( struct dns_rr_info * ) p );
164
-		p += ( sizeof ( struct dns_rr_info ) +
165
-		       ntohs ( ( ( struct dns_rr_info * ) p )->rdlength ) );
166
-	}
167
-
168
-	return NULL;
169
-}
170
-
171
-/*
172
- * Convert a standard NUL-terminated string to a DNS query name,
173
- * consisting of "<length>element" pairs.
174
- *
175
- * Returns a pointer to the character following the constructed DNS
176
- * query name.
177
- *
178
- */
179
-static inline char * dns_make_name ( char *dest, const char *name ) {
180
-	char *length_byte = dest++;
181
-	char c;
182
-
183
-	while ( ( c = *(name++) ) ) {
184
-		if ( c == '.' ) {
185
-			*length_byte = dest - length_byte - 1;
186
-			length_byte = dest;
187
-		}
188
-		*(dest++) = c;
189
-	}
190
-	*length_byte = dest - length_byte - 1;
191
-	*(dest++) = '\0';
192
-	return dest;
193
-}
194
-
195
-/*
196
- * Produce a printable version of a DNS name.  Used only for debugging.
197
- *
198
- */
199
-static inline char * dns_unmake_name ( char *name ) {
200
-	char *p;
201
-	unsigned int len;
202
-
203
-	p = name;
204
-	while ( ( len = *p ) ) {
205
-		*(p++) = '.';
206
-		p += len;
207
-	}
208
-	
209
-	return name + 1;
210
-}
211
-
212
-/*
213
- * Decompress a DNS name.
214
- *
215
- * Returns a pointer to the character following the decompressed DNS
216
- * name.
217
- *
218
- */
219
-static inline char * dns_decompress_name ( char *dest, const char *name,
220
-					   struct dns_header *header ) {
221
-	int i, len;
222
-
223
-	do {
224
-		/* Obtain next section of name */
225
-		while ( ( *name ) & 0xc0 ) {
226
-			name = ( ( char * ) header +
227
-				 ( ntohs ( *((uint16_t *)name) ) & ~0xc000 ) );
228
-		}
229
-		/* Copy data */
230
-		len = *name;
231
-		for ( i = len + 1 ; i > 0 ; i-- ) {
232
-			*(dest++) = *(name++);
233
-		}
234
-	} while ( len );
235
-	return dest;
236
-}
237
-
238
-/*
239
- * Resolve a name using DNS
240
- *
241
- */
242
-static int dns_resolv ( struct in_addr *addr, const char *name ) {
243
-	struct dns_query query;
244
-	struct dns_query_info *query_info;
245
-	struct dns_header *reply;
246
-	struct dns_rr_info *rr_info;
247
-	struct sockaddr_in nameserver;
248
-	uint16_t qtype;
249
-	unsigned int recursion = 0;
250
-	unsigned int id = 1;
251
-
252
-	/* Fail immediately if we have no name server */
253
-	if ( ! arptable[ARP_NAMESERVER].ipaddr.s_addr ) {
254
-		DBG ( "DNS has no nameserver\n" );
255
-		return 0;
256
-	}
257
-
258
-	DBG ( "DNS resolving %s\n", name );
259
-
260
-	/* Set up the query data */
261
-	nameserver.sin_addr = arptable[ARP_NAMESERVER].ipaddr;
262
-	nameserver.sin_port = DNS_UDP_PORT;
263
-	memset ( &query, 0, sizeof ( query ) );
264
-	query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
265
-				  DNS_FLAG_RD );
266
-	query.dns.qdcount = htons ( 1 );
267
-	query_info = ( void * )	dns_make_name ( query.payload, name );
268
-	query_info->qtype = htons ( DNS_TYPE_A );
269
-	query_info->qclass = htons ( DNS_CLASS_IN );
270
-
271
-	while ( 1 ) {
272
-		/* Transmit current query, wait for reply */
273
-		query.dns.id = htons ( id++ );
274
-		qtype = ntohs ( query_info->qtype );
275
-		reply = dns_query ( &query,
276
-				    ( ( ( char * ) query_info )
277
-				      + sizeof ( *query_info )
278
-				      - ( ( char * ) &query ) ),
279
-				    &nameserver );
280
-		if ( ! reply ) {
281
-			DBG ( "DNS got no response from server %@ (port %d)\n",
282
-			      nameserver.sin_addr.s_addr,
283
-			      nameserver.sin_port );
284
-			return 0;
285
-		}
286
-
287
-		/* Search through response for useful answers.  Do
288
-		 * this multiple times, to take advantage of useful
289
-		 * nameservers which send us e.g. the CNAME *and* the
290
-		 * A record for the pointed-to name.
291
-		 */
292
-		while ( ( rr_info = dns_find_rr ( &query, reply ) ) ) {
293
-			switch ( ntohs ( rr_info->type ) ) {
294
-			case DNS_TYPE_A: {
295
-				/* Found the target A record */
296
-				struct dns_rr_info_a *rr_info_a =
297
-					( struct dns_rr_info_a * ) rr_info;
298
-				*addr = rr_info_a->in_addr;
299
-				DBG ( "DNS found address %@\n", addr->s_addr );
300
-				return 1; }
301
-			case DNS_TYPE_CNAME: {
302
-				/* Found a CNAME record - update the query */
303
-				struct dns_rr_info_cname *rr_info_cname =
304
-					( struct dns_rr_info_cname * ) rr_info;
305
-				char *cname = rr_info_cname->cname;
306
-
307
-				query_info = ( void * )
308
-					dns_decompress_name ( query.payload,
309
-							      cname, reply );
310
-				DBG ( "DNS found CNAME %s\n",
311
-				      dns_unmake_name ( query.payload ) );
312
-				DBG ( "", /* Reconstruct name */
313
-				      dns_make_name ( query.payload,
314
-						      query.payload + 1 ) );
315
-				
316
-				query_info->qtype = htons ( DNS_TYPE_A );
317
-				query_info->qclass = htons ( DNS_CLASS_IN );
318
-
319
-				if ( ++recursion > DNS_MAX_CNAME_RECURSION ) {
320
-					DBG ( "DNS recursion exceeded\n" );
321
-					return 0;
322
-				}
323
-				break; }
324
-			default:
325
-				DBG ( "DNS got unknown record type %d\n",
326
-				      ntohs ( rr_info->type ) );
327
-				return 0;
328
-			}
329
-		}
330
-		
331
-		/* Determine what to do next based on the type of
332
-		 * query we issued and the reponse we received
333
-		 */
334
-		switch ( qtype ) {
335
-		case DNS_TYPE_A :
336
-			/* We asked for an A record and got nothing;
337
-			 * try the CNAME.
338
-			 */
339
-			DBG ( "DNS found no A record; trying CNAME\n" );
340
-			query_info->qtype = htons ( DNS_TYPE_CNAME );
341
-			break;
342
-		case DNS_TYPE_CNAME :
343
-			/* We asked for a CNAME record.  If we didn't
344
-			 * get any response (i.e. the next A query
345
-			 * isn't already set up), then abort.
346
-			 */
347
-			if ( query_info->qtype != htons ( DNS_TYPE_A ) ) {
348
-				DBG ( "DNS found no CNAME record\n" );
349
-				return 0;
350
-			}
351
-			break;
352
-		default:
353
-			DBG ( "DNS internal error - inconsistent state\n" );
354
-		}
355
-	}
356
-}
357
-
358
-struct resolver dns_resolver __resolver = {
359
-	.name = "DNS",
360
-	.resolv = dns_resolv,
361
-};

+ 5
- 1
src/proto/nmb.c Прегледај датотеку

@@ -1,6 +1,8 @@
1
+#if 0
2
+
1 3
 #include "resolv.h"
2 4
 #include "string.h"
3
-#include "dns.h"
5
+#include <gpxe/dns.h>
4 6
 #include "nic.h"
5 7
 #include "nmb.h"
6 8
 
@@ -104,3 +106,5 @@ struct resolver nmb_resolver __resolver = {
104 106
 	.name = "NMB",
105 107
 	.resolv = nmb_resolv,
106 108
 };
109
+
110
+#endif

Loading…
Откажи
Сачувај