|
@@ -24,9 +24,12 @@
|
24
|
24
|
#include <string.h>
|
25
|
25
|
#include <errno.h>
|
26
|
26
|
#include <byteswap.h>
|
27
|
|
-#include <gpxe/async.h>
|
28
|
|
-#include <gpxe/udp.h>
|
|
27
|
+#include <gpxe/refcnt.h>
|
|
28
|
+#include <gpxe/xfer.h>
|
|
29
|
+#include <gpxe/open.h>
|
29
|
30
|
#include <gpxe/resolv.h>
|
|
31
|
+#include <gpxe/retry.h>
|
|
32
|
+#include <gpxe/tcpip.h>
|
30
|
33
|
#include <gpxe/dns.h>
|
31
|
34
|
|
32
|
35
|
/** @file
|
|
@@ -35,8 +38,54 @@
|
35
|
38
|
*
|
36
|
39
|
*/
|
37
|
40
|
|
38
|
|
-/* The DNS server */
|
39
|
|
-struct in_addr nameserver = { INADDR_NONE };
|
|
41
|
+/** The DNS server */
|
|
42
|
+struct sockaddr_tcpip nameserver = {
|
|
43
|
+ .st_port = htons ( DNS_PORT ),
|
|
44
|
+};
|
|
45
|
+
|
|
46
|
+/** A DNS request */
|
|
47
|
+struct dns_request {
|
|
48
|
+ /** Reference counter */
|
|
49
|
+ struct refcnt refcnt;
|
|
50
|
+ /** Name resolution interface */
|
|
51
|
+ struct resolv_interface resolv;
|
|
52
|
+ /** Data transfer interface */
|
|
53
|
+ struct xfer_interface socket;
|
|
54
|
+ /** Retry timer */
|
|
55
|
+ struct retry_timer timer;
|
|
56
|
+
|
|
57
|
+ /** Socket address to fill in with resolved address */
|
|
58
|
+ struct sockaddr sa;
|
|
59
|
+ /** Current query packet */
|
|
60
|
+ struct dns_query query;
|
|
61
|
+ /** Location of query info structure within current packet
|
|
62
|
+ *
|
|
63
|
+ * The query info structure is located immediately after the
|
|
64
|
+ * compressed name.
|
|
65
|
+ */
|
|
66
|
+ struct dns_query_info *qinfo;
|
|
67
|
+ /** Recursion counter */
|
|
68
|
+ unsigned int recursion;
|
|
69
|
+};
|
|
70
|
+
|
|
71
|
+/**
|
|
72
|
+ * Mark DNS request as complete
|
|
73
|
+ *
|
|
74
|
+ * @v dns DNS request
|
|
75
|
+ * @v rc Return status code
|
|
76
|
+ */
|
|
77
|
+static void dns_done ( struct dns_request *dns, int rc ) {
|
|
78
|
+
|
|
79
|
+ /* Stop the retry timer */
|
|
80
|
+ stop_timer ( &dns->timer );
|
|
81
|
+
|
|
82
|
+ /* Close data transfer interface */
|
|
83
|
+ xfer_nullify ( &dns->socket );
|
|
84
|
+ xfer_close ( &dns->socket, rc );
|
|
85
|
+
|
|
86
|
+ /* Mark name resolution as complete */
|
|
87
|
+ resolv_done ( &dns->resolv, &dns->sa, rc );
|
|
88
|
+}
|
40
|
89
|
|
41
|
90
|
/**
|
42
|
91
|
* Compare DNS reply name against the query name from the original request
|
|
@@ -47,7 +96,8 @@ struct in_addr nameserver = { INADDR_NONE };
|
47
|
96
|
* @ret zero Names match
|
48
|
97
|
* @ret non-zero Names do not match
|
49
|
98
|
*/
|
50
|
|
-static int dns_name_cmp ( struct dns_request *dns, struct dns_header *reply,
|
|
99
|
+static int dns_name_cmp ( struct dns_request *dns,
|
|
100
|
+ const struct dns_header *reply,
|
51
|
101
|
const char *rname ) {
|
52
|
102
|
const char *qname = dns->query.payload;
|
53
|
103
|
int i;
|
|
@@ -101,7 +151,7 @@ static const char * dns_skip_name ( const char *name ) {
|
101
|
151
|
* @ret rr DNS RR, or NULL if not found
|
102
|
152
|
*/
|
103
|
153
|
static union dns_rr_info * dns_find_rr ( struct dns_request *dns,
|
104
|
|
- struct dns_header *reply ) {
|
|
154
|
+ const struct dns_header *reply ) {
|
105
|
155
|
int i, cmp;
|
106
|
156
|
const char *p = ( ( char * ) reply ) + sizeof ( struct dns_header );
|
107
|
157
|
union dns_rr_info *rr_info;
|
|
@@ -179,7 +229,7 @@ static inline char * dns_unmake_name ( char *name ) {
|
179
|
229
|
* @v buf Buffer into which to decompress DNS name
|
180
|
230
|
* @ret next Byte following decompressed DNS name
|
181
|
231
|
*/
|
182
|
|
-static char * dns_decompress_name ( struct dns_header *reply,
|
|
232
|
+static char * dns_decompress_name ( const struct dns_header *reply,
|
183
|
233
|
const char *name, char *buf ) {
|
184
|
234
|
int i, len;
|
185
|
235
|
|
|
@@ -198,31 +248,14 @@ static char * dns_decompress_name ( struct dns_header *reply,
|
198
|
248
|
return buf;
|
199
|
249
|
}
|
200
|
250
|
|
201
|
|
-/**
|
202
|
|
- * Mark DNS request as complete
|
203
|
|
- *
|
204
|
|
- * @v dns DNS request
|
205
|
|
- * @v rc Return status code
|
206
|
|
- */
|
207
|
|
-static void dns_done ( struct dns_request *dns, int rc ) {
|
208
|
|
-
|
209
|
|
- /* Stop the retry timer */
|
210
|
|
- stop_timer ( &dns->timer );
|
211
|
|
-
|
212
|
|
- /* Close UDP connection */
|
213
|
|
- udp_close ( &dns->udp );
|
214
|
|
-
|
215
|
|
- /* Mark async operation as complete */
|
216
|
|
- async_done ( &dns->async, rc );
|
217
|
|
-}
|
218
|
|
-
|
219
|
251
|
/**
|
220
|
252
|
* Send next packet in DNS request
|
221
|
253
|
*
|
222
|
254
|
* @v dns DNS request
|
223
|
255
|
*/
|
224
|
|
-static void dns_send_packet ( struct dns_request *dns ) {
|
|
256
|
+static int dns_send_packet ( struct dns_request *dns ) {
|
225
|
257
|
static unsigned int qid = 0;
|
|
258
|
+ size_t qlen;
|
226
|
259
|
|
227
|
260
|
/* Increment query ID */
|
228
|
261
|
dns->query.dns.id = htons ( ++qid );
|
|
@@ -233,9 +266,9 @@ static void dns_send_packet ( struct dns_request *dns ) {
|
233
|
266
|
start_timer ( &dns->timer );
|
234
|
267
|
|
235
|
268
|
/* Send the data */
|
236
|
|
- udp_send ( &dns->udp, &dns->query,
|
237
|
|
- ( ( ( void * ) dns->qinfo ) - ( ( void * ) &dns->query )
|
238
|
|
- + sizeof ( dns->qinfo ) ) );
|
|
269
|
+ qlen = ( ( ( void * ) dns->qinfo ) - ( ( void * ) &dns->query )
|
|
270
|
+ + sizeof ( dns->qinfo ) );
|
|
271
|
+ return xfer_deliver_raw ( &dns->socket, &dns->query, qlen );
|
239
|
272
|
}
|
240
|
273
|
|
241
|
274
|
/**
|
|
@@ -258,18 +291,16 @@ static void dns_timer_expired ( struct retry_timer *timer, int fail ) {
|
258
|
291
|
/**
|
259
|
292
|
* Receive new data
|
260
|
293
|
*
|
261
|
|
- * @v udp UDP connection
|
262
|
|
- * @v data Received data
|
263
|
|
- * @v len Length of received data
|
264
|
|
- * @v st_src Partially-filled source address
|
265
|
|
- * @v st_dest Partially-filled destination address
|
|
294
|
+ * @v socket UDP socket
|
|
295
|
+ * @v data DNS reply
|
|
296
|
+ * @v len Length of DNS reply
|
|
297
|
+ * @ret rc Return status code
|
266
|
298
|
*/
|
267
|
|
-static int dns_newdata ( struct udp_connection *conn, void *data, size_t len,
|
268
|
|
- struct sockaddr_tcpip *st_src __unused,
|
269
|
|
- struct sockaddr_tcpip *st_dest __unused ) {
|
|
299
|
+static int dns_xfer_deliver_raw ( struct xfer_interface *socket,
|
|
300
|
+ const void *data, size_t len ) {
|
270
|
301
|
struct dns_request *dns =
|
271
|
|
- container_of ( conn, struct dns_request, udp );
|
272
|
|
- struct dns_header *reply = data;
|
|
302
|
+ container_of ( socket, struct dns_request, socket );
|
|
303
|
+ const struct dns_header *reply = data;
|
273
|
304
|
union dns_rr_info *rr_info;
|
274
|
305
|
struct sockaddr_in *sin;
|
275
|
306
|
unsigned int qtype = dns->qinfo->qtype;
|
|
@@ -311,7 +342,7 @@ static int dns_newdata ( struct udp_connection *conn, void *data, size_t len,
|
311
|
342
|
/* Found the target A record */
|
312
|
343
|
DBGC ( dns, "DNS %p found address %s\n",
|
313
|
344
|
dns, inet_ntoa ( rr_info->a.in_addr ) );
|
314
|
|
- sin = ( struct sockaddr_in * ) dns->sa;
|
|
345
|
+ sin = ( struct sockaddr_in * ) &dns->sa;
|
315
|
346
|
sin->sin_family = AF_INET;
|
316
|
347
|
sin->sin_addr = rr_info->a.in_addr;
|
317
|
348
|
|
|
@@ -380,71 +411,62 @@ static int dns_newdata ( struct udp_connection *conn, void *data, size_t len,
|
380
|
411
|
}
|
381
|
412
|
}
|
382
|
413
|
|
383
|
|
-/** DNS UDP operations */
|
384
|
|
-struct udp_operations dns_udp_operations = {
|
385
|
|
- .newdata = dns_newdata,
|
386
|
|
-};
|
387
|
|
-
|
388
|
414
|
/**
|
389
|
|
- * Reap asynchronous operation
|
|
415
|
+ * Receive new data
|
390
|
416
|
*
|
391
|
|
- * @v async Asynchronous operation
|
|
417
|
+ * @v socket UDP socket
|
|
418
|
+ * @v rc Reason for close
|
392
|
419
|
*/
|
393
|
|
-static void dns_reap ( struct async *async ) {
|
|
420
|
+static void dns_xfer_close ( struct xfer_interface *socket, int rc ) {
|
394
|
421
|
struct dns_request *dns =
|
395
|
|
- container_of ( async, struct dns_request, async );
|
|
422
|
+ container_of ( socket, struct dns_request, socket );
|
396
|
423
|
|
397
|
|
- free ( dns );
|
398
|
|
-}
|
|
424
|
+ if ( ! rc )
|
|
425
|
+ rc = -ECONNABORTED;
|
399
|
426
|
|
400
|
|
-/**
|
401
|
|
- * Handle SIGKILL
|
402
|
|
- *
|
403
|
|
- * @v async Asynchronous operation
|
404
|
|
- */
|
405
|
|
-static void dns_sigkill ( struct async *async, enum signal signal __unused ) {
|
406
|
|
- struct dns_request *dns =
|
407
|
|
- container_of ( async, struct dns_request, async );
|
408
|
|
-
|
409
|
|
- dns_done ( dns, -ECANCELED );
|
|
427
|
+ dns_done ( dns, rc );
|
410
|
428
|
}
|
411
|
429
|
|
412
|
|
-/** DNS asynchronous operations */
|
413
|
|
-static struct async_operations dns_async_operations = {
|
414
|
|
- .reap = dns_reap,
|
415
|
|
- .signal = {
|
416
|
|
- [SIGKILL] = dns_sigkill,
|
417
|
|
- },
|
|
430
|
+/** DNS socket operations */
|
|
431
|
+static struct xfer_interface_operations dns_socket_operations = {
|
|
432
|
+ .close = dns_xfer_close,
|
|
433
|
+ .vredirect = xfer_vopen,
|
|
434
|
+ .request = ignore_xfer_request,
|
|
435
|
+ .seek = ignore_xfer_seek,
|
|
436
|
+ .alloc_iob = default_xfer_alloc_iob,
|
|
437
|
+ .deliver_iob = xfer_deliver_as_raw,
|
|
438
|
+ .deliver_raw = dns_xfer_deliver_raw,
|
418
|
439
|
};
|
419
|
440
|
|
420
|
441
|
/**
|
421
|
442
|
* Resolve name using DNS
|
422
|
443
|
*
|
423
|
|
- * @v name Host name to resolve
|
|
444
|
+ * @v resolv Name resolution interface
|
|
445
|
+ * @v name Name to resolve
|
424
|
446
|
* @v sa Socket address to fill in
|
425
|
|
- * @v parent Parent asynchronous operation
|
426
|
447
|
* @ret rc Return status code
|
427
|
448
|
*/
|
428
|
|
-int dns_resolv ( const char *name, struct sockaddr *sa,
|
429
|
|
- struct async *parent ) {
|
|
449
|
+static int dns_resolv ( struct resolv_interface *resolv,
|
|
450
|
+ const char *name, struct sockaddr *sa ) {
|
430
|
451
|
struct dns_request *dns;
|
431
|
|
- union {
|
432
|
|
- struct sockaddr_tcpip st;
|
433
|
|
- struct sockaddr_in sin;
|
434
|
|
- } server;
|
435
|
452
|
int rc;
|
436
|
453
|
|
|
454
|
+ /* Fail immediately if no DNS servers */
|
|
455
|
+ if ( ! nameserver.st_family ) {
|
|
456
|
+ DBG ( "DNS not attempting to resolve \"%s\": "
|
|
457
|
+ "no DNS servers\n", name );
|
|
458
|
+ return -ENXIO;
|
|
459
|
+ }
|
|
460
|
+
|
437
|
461
|
/* Allocate DNS structure */
|
438
|
462
|
dns = malloc ( sizeof ( *dns ) );
|
439
|
|
- if ( ! dns ) {
|
440
|
|
- rc = -ENOMEM;
|
441
|
|
- goto err;
|
442
|
|
- }
|
|
463
|
+ if ( ! dns )
|
|
464
|
+ return -ENOMEM;
|
443
|
465
|
memset ( dns, 0, sizeof ( *dns ) );
|
444
|
|
- dns->sa = sa;
|
|
466
|
+ resolv_init ( &dns->resolv, &null_resolv_ops, &dns->refcnt );
|
|
467
|
+ xfer_init ( &dns->socket, &dns_socket_operations, &dns->refcnt );
|
445
|
468
|
dns->timer.expired = dns_timer_expired;
|
446
|
|
- dns->udp.udp_op = &dns_udp_operations;
|
447
|
|
- async_init ( &dns->async, &dns_async_operations, parent );
|
|
469
|
+ memcpy ( &dns->sa, sa, sizeof ( dns->sa ) );
|
448
|
470
|
|
449
|
471
|
/* Create query */
|
450
|
472
|
dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
|
|
@@ -454,34 +476,25 @@ int dns_resolv ( const char *name, struct sockaddr *sa,
|
454
|
476
|
dns->qinfo->qtype = htons ( DNS_TYPE_A );
|
455
|
477
|
dns->qinfo->qclass = htons ( DNS_CLASS_IN );
|
456
|
478
|
|
457
|
|
- /* Identify nameserver */
|
458
|
|
- memset ( &server, 0, sizeof ( server ) );
|
459
|
|
- server.sin.sin_family = AF_INET;
|
460
|
|
- server.sin.sin_port = htons ( DNS_PORT );
|
461
|
|
- server.sin.sin_addr = nameserver;
|
462
|
|
- if ( server.sin.sin_addr.s_addr == INADDR_NONE ) {
|
463
|
|
- DBGC ( dns, "DNS %p no name servers\n", dns );
|
464
|
|
- rc = -ENXIO;
|
465
|
|
- goto err;
|
466
|
|
- }
|
467
|
|
-
|
468
|
479
|
/* Open UDP connection */
|
469
|
|
- DBGC ( dns, "DNS %p using nameserver %s\n", dns,
|
470
|
|
- inet_ntoa ( server.sin.sin_addr ) );
|
471
|
|
- udp_connect ( &dns->udp, &server.st );
|
472
|
|
- if ( ( rc = udp_open ( &dns->udp, 0 ) ) != 0 )
|
|
480
|
+ if ( ( rc = xfer_open_socket ( &dns->socket, SOCK_DGRAM,
|
|
481
|
+ ( struct sockaddr * ) &nameserver,
|
|
482
|
+ NULL ) ) != 0 ) {
|
|
483
|
+ DBGC ( dns, "DNS %p could not open socket: %s\n",
|
|
484
|
+ dns, strerror ( rc ) );
|
473
|
485
|
goto err;
|
|
486
|
+ }
|
474
|
487
|
|
475
|
488
|
/* Send first DNS packet */
|
476
|
489
|
dns_send_packet ( dns );
|
477
|
490
|
|
|
491
|
+ /* Attach parent interface, mortalise self, and return */
|
|
492
|
+ resolv_plug_plug ( &dns->resolv, resolv );
|
|
493
|
+ ref_put ( &dns->refcnt );
|
478
|
494
|
return 0;
|
479
|
495
|
|
480
|
496
|
err:
|
481
|
|
- DBGC ( dns, "DNS %p could not create request: %s\n",
|
482
|
|
- dns, strerror ( rc ) );
|
483
|
|
- async_uninit ( &dns->async );
|
484
|
|
- free ( dns );
|
|
497
|
+ ref_put ( &dns->refcnt );
|
485
|
498
|
return rc;
|
486
|
499
|
}
|
487
|
500
|
|