00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 FILE_LICENCE ( GPL2_OR_LATER );
00023
00024 #include <stdint.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <stdio.h>
00028 #include <errno.h>
00029 #include <byteswap.h>
00030 #include <gpxe/refcnt.h>
00031 #include <gpxe/xfer.h>
00032 #include <gpxe/open.h>
00033 #include <gpxe/resolv.h>
00034 #include <gpxe/retry.h>
00035 #include <gpxe/tcpip.h>
00036 #include <gpxe/settings.h>
00037 #include <gpxe/features.h>
00038 #include <gpxe/dns.h>
00039
00040
00041
00042
00043
00044
00045
00046 FEATURE ( FEATURE_PROTOCOL, "DNS", DHCP_EB_FEATURE_DNS, 1 );
00047
00048
00049 static struct sockaddr_tcpip nameserver = {
00050 .st_port = htons ( DNS_PORT ),
00051 };
00052
00053
00054 static char *localdomain;
00055
00056
00057 struct dns_request {
00058
00059 struct refcnt refcnt;
00060
00061 struct resolv_interface resolv;
00062
00063 struct xfer_interface socket;
00064
00065 struct retry_timer timer;
00066
00067
00068 struct sockaddr sa;
00069
00070 struct dns_query query;
00071
00072
00073
00074
00075
00076 struct dns_query_info *qinfo;
00077
00078 unsigned int recursion;
00079 };
00080
00081
00082
00083
00084
00085
00086
00087 static void dns_done ( struct dns_request *dns, int rc ) {
00088
00089
00090 stop_timer ( &dns->timer );
00091
00092
00093 xfer_nullify ( &dns->socket );
00094 xfer_close ( &dns->socket, rc );
00095
00096
00097 resolv_done ( &dns->resolv, &dns->sa, rc );
00098 }
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109 static int dns_name_cmp ( struct dns_request *dns,
00110 const struct dns_header *reply,
00111 const char *rname ) {
00112 const char *qname = dns->query.payload;
00113 int i;
00114
00115 while ( 1 ) {
00116
00117 while ( ( *rname ) & 0xc0 ) {
00118 rname = ( ( ( char * ) reply ) +
00119 ( ntohs( *((uint16_t *)rname) ) & ~0xc000 ));
00120 }
00121
00122 if ( *rname != *qname )
00123 return -1;
00124
00125 if ( ! *qname )
00126 return 0;
00127
00128 for ( i = *qname + 1; i > 0 ; i-- ) {
00129 if ( *(rname++) != *(qname++) )
00130 return -1;
00131 }
00132 }
00133 }
00134
00135
00136
00137
00138
00139
00140
00141 static const char * dns_skip_name ( const char *name ) {
00142 while ( 1 ) {
00143 if ( ! *name ) {
00144
00145 return ( name + 1);
00146 }
00147 if ( *name & 0xc0 ) {
00148
00149 return ( name + 2 );
00150 }
00151
00152 name += *name + 1;
00153 }
00154 }
00155
00156
00157
00158
00159
00160
00161
00162
00163 static union dns_rr_info * dns_find_rr ( struct dns_request *dns,
00164 const struct dns_header *reply ) {
00165 int i, cmp;
00166 const char *p = ( ( char * ) reply ) + sizeof ( struct dns_header );
00167 union dns_rr_info *rr_info;
00168
00169
00170 for ( i = ntohs ( reply->qdcount ) ; i > 0 ; i-- ) {
00171 p = dns_skip_name ( p ) + sizeof ( struct dns_query_info );
00172 }
00173
00174
00175 for ( i = ntohs ( reply->ancount ) ; i > 0 ; i-- ) {
00176 cmp = dns_name_cmp ( dns, reply, p );
00177 p = dns_skip_name ( p );
00178 rr_info = ( ( union dns_rr_info * ) p );
00179 if ( cmp == 0 )
00180 return rr_info;
00181 p += ( sizeof ( rr_info->common ) +
00182 ntohs ( rr_info->common.rdlength ) );
00183 }
00184
00185 return NULL;
00186 }
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 static char * dns_qualify_name ( const char *string ) {
00198 char *fqdn;
00199
00200
00201 if ( ( ! localdomain ) || ( strchr ( string, '.' ) != 0 ) )
00202 return strdup ( string );
00203
00204
00205 asprintf ( &fqdn, "%s.%s", string, localdomain );
00206 return fqdn;
00207 }
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 static char * dns_make_name ( const char *string, char *buf ) {
00219 char *length_byte = buf++;
00220 char c;
00221
00222 while ( ( c = *(string++) ) ) {
00223 if ( c == '.' ) {
00224 *length_byte = buf - length_byte - 1;
00225 length_byte = buf;
00226 }
00227 *(buf++) = c;
00228 }
00229 *length_byte = buf - length_byte - 1;
00230 *(buf++) = '\0';
00231 return buf;
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242 static inline char * dns_unmake_name ( char *name ) {
00243 char *p;
00244 unsigned int len;
00245
00246 p = name;
00247 while ( ( len = *p ) ) {
00248 *(p++) = '.';
00249 p += len;
00250 }
00251
00252 return name + 1;
00253 }
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 static char * dns_decompress_name ( const struct dns_header *reply,
00264 const char *name, char *buf ) {
00265 int i, len;
00266
00267 do {
00268
00269 while ( ( *name ) & 0xc0 ) {
00270 name = ( ( char * ) reply +
00271 ( ntohs ( *((uint16_t *)name) ) & ~0xc000 ) );
00272 }
00273
00274 len = *name;
00275 for ( i = len + 1 ; i > 0 ; i-- ) {
00276 *(buf++) = *(name++);
00277 }
00278 } while ( len );
00279 return buf;
00280 }
00281
00282
00283
00284
00285
00286
00287 static int dns_send_packet ( struct dns_request *dns ) {
00288 static unsigned int qid = 0;
00289 size_t qlen;
00290
00291
00292 dns->query.dns.id = htons ( ++qid );
00293
00294 DBGC ( dns, "DNS %p sending query ID %d\n", dns, qid );
00295
00296
00297 start_timer ( &dns->timer );
00298
00299
00300 qlen = ( ( ( void * ) dns->qinfo ) - ( ( void * ) &dns->query )
00301 + sizeof ( dns->qinfo ) );
00302 return xfer_deliver_raw ( &dns->socket, &dns->query, qlen );
00303 }
00304
00305
00306
00307
00308
00309
00310
00311 static void dns_timer_expired ( struct retry_timer *timer, int fail ) {
00312 struct dns_request *dns =
00313 container_of ( timer, struct dns_request, timer );
00314
00315 if ( fail ) {
00316 dns_done ( dns, -ETIMEDOUT );
00317 } else {
00318 dns_send_packet ( dns );
00319 }
00320 }
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 static int dns_xfer_deliver_raw ( struct xfer_interface *socket,
00331 const void *data, size_t len ) {
00332 struct dns_request *dns =
00333 container_of ( socket, struct dns_request, socket );
00334 const struct dns_header *reply = data;
00335 union dns_rr_info *rr_info;
00336 struct sockaddr_in *sin;
00337 unsigned int qtype = dns->qinfo->qtype;
00338
00339
00340 if ( len < sizeof ( *reply ) ) {
00341 DBGC ( dns, "DNS %p received underlength packet length %zd\n",
00342 dns, len );
00343 return -EINVAL;
00344 }
00345
00346
00347 if ( reply->id != dns->query.dns.id ) {
00348 DBGC ( dns, "DNS %p received unexpected reply ID %d "
00349 "(wanted %d)\n", dns, ntohs ( reply->id ),
00350 ntohs ( dns->query.dns.id ) );
00351 return -EINVAL;
00352 }
00353
00354 DBGC ( dns, "DNS %p received reply ID %d\n", dns, ntohs ( reply->id ));
00355
00356
00357
00358
00359
00360
00361 stop_timer ( &dns->timer );
00362
00363
00364
00365
00366
00367
00368 while ( ( rr_info = dns_find_rr ( dns, reply ) ) ) {
00369 switch ( rr_info->common.type ) {
00370
00371 case htons ( DNS_TYPE_A ):
00372
00373
00374 DBGC ( dns, "DNS %p found address %s\n",
00375 dns, inet_ntoa ( rr_info->a.in_addr ) );
00376 sin = ( struct sockaddr_in * ) &dns->sa;
00377 sin->sin_family = AF_INET;
00378 sin->sin_addr = rr_info->a.in_addr;
00379
00380
00381 dns_done ( dns, 0 );
00382 return 0;
00383
00384 case htons ( DNS_TYPE_CNAME ):
00385
00386
00387 DBGC ( dns, "DNS %p found CNAME\n", dns );
00388 dns->qinfo = ( void * ) dns_decompress_name ( reply,
00389 rr_info->cname.cname,
00390 dns->query.payload );
00391 dns->qinfo->qtype = htons ( DNS_TYPE_A );
00392 dns->qinfo->qclass = htons ( DNS_CLASS_IN );
00393
00394
00395 if ( ++dns->recursion > DNS_MAX_CNAME_RECURSION ) {
00396 DBGC ( dns, "DNS %p recursion exceeded\n",
00397 dns );
00398 dns_done ( dns, -ELOOP );
00399 return 0;
00400 }
00401 break;
00402
00403 default:
00404 DBGC ( dns, "DNS %p got unknown record type %d\n",
00405 dns, ntohs ( rr_info->common.type ) );
00406 break;
00407 }
00408 }
00409
00410
00411
00412
00413 switch ( qtype ) {
00414
00415 case htons ( DNS_TYPE_A ):
00416
00417
00418
00419 DBGC ( dns, "DNS %p found no A record; trying CNAME\n", dns );
00420 dns->qinfo->qtype = htons ( DNS_TYPE_CNAME );
00421 dns_send_packet ( dns );
00422 return 0;
00423
00424 case htons ( DNS_TYPE_CNAME ):
00425
00426
00427
00428
00429 if ( dns->qinfo->qtype == htons ( DNS_TYPE_A ) ) {
00430 dns_send_packet ( dns );
00431 return 0;
00432 } else {
00433 DBGC ( dns, "DNS %p found no CNAME record\n", dns );
00434 dns_done ( dns, -ENXIO );
00435 return 0;
00436 }
00437
00438 default:
00439 assert ( 0 );
00440 dns_done ( dns, -EINVAL );
00441 return 0;
00442 }
00443 }
00444
00445
00446
00447
00448
00449
00450
00451 static void dns_xfer_close ( struct xfer_interface *socket, int rc ) {
00452 struct dns_request *dns =
00453 container_of ( socket, struct dns_request, socket );
00454
00455 if ( ! rc )
00456 rc = -ECONNABORTED;
00457
00458 dns_done ( dns, rc );
00459 }
00460
00461
00462 static struct xfer_interface_operations dns_socket_operations = {
00463 .close = dns_xfer_close,
00464 .vredirect = xfer_vreopen,
00465 .window = unlimited_xfer_window,
00466 .alloc_iob = default_xfer_alloc_iob,
00467 .deliver_iob = xfer_deliver_as_raw,
00468 .deliver_raw = dns_xfer_deliver_raw,
00469 };
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479 static int dns_resolv ( struct resolv_interface *resolv,
00480 const char *name, struct sockaddr *sa ) {
00481 struct dns_request *dns;
00482 char *fqdn;
00483 int rc;
00484
00485
00486 if ( ! nameserver.st_family ) {
00487 DBG ( "DNS not attempting to resolve \"%s\": "
00488 "no DNS servers\n", name );
00489 rc = -ENXIO;
00490 goto err_no_nameserver;
00491 }
00492
00493
00494 fqdn = dns_qualify_name ( name );
00495 if ( ! fqdn ) {
00496 rc = -ENOMEM;
00497 goto err_qualify_name;
00498 }
00499
00500
00501 dns = zalloc ( sizeof ( *dns ) );
00502 if ( ! dns ) {
00503 rc = -ENOMEM;
00504 goto err_alloc_dns;
00505 }
00506 resolv_init ( &dns->resolv, &null_resolv_ops, &dns->refcnt );
00507 xfer_init ( &dns->socket, &dns_socket_operations, &dns->refcnt );
00508 dns->timer.expired = dns_timer_expired;
00509 memcpy ( &dns->sa, sa, sizeof ( dns->sa ) );
00510
00511
00512 dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
00513 DNS_FLAG_RD );
00514 dns->query.dns.qdcount = htons ( 1 );
00515 dns->qinfo = ( void * ) dns_make_name ( fqdn, dns->query.payload );
00516 dns->qinfo->qtype = htons ( DNS_TYPE_A );
00517 dns->qinfo->qclass = htons ( DNS_CLASS_IN );
00518
00519
00520 if ( ( rc = xfer_open_socket ( &dns->socket, SOCK_DGRAM,
00521 ( struct sockaddr * ) &nameserver,
00522 NULL ) ) != 0 ) {
00523 DBGC ( dns, "DNS %p could not open socket: %s\n",
00524 dns, strerror ( rc ) );
00525 goto err_open_socket;
00526 }
00527
00528
00529 dns_send_packet ( dns );
00530
00531
00532 resolv_plug_plug ( &dns->resolv, resolv );
00533 ref_put ( &dns->refcnt );
00534 free ( fqdn );
00535 return 0;
00536
00537 err_open_socket:
00538 err_alloc_dns:
00539 ref_put ( &dns->refcnt );
00540 err_qualify_name:
00541 free ( fqdn );
00542 err_no_nameserver:
00543 return rc;
00544 }
00545
00546
00547 struct resolver dns_resolver __resolver ( RESOLV_NORMAL ) = {
00548 .name = "DNS",
00549 .resolv = dns_resolv,
00550 };
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560 struct setting dns_setting __setting = {
00561 .name = "dns",
00562 .description = "DNS server",
00563 .tag = DHCP_DNS_SERVERS,
00564 .type = &setting_type_ipv4,
00565 };
00566
00567
00568 struct setting domain_setting __setting = {
00569 .name = "domain",
00570 .description = "Local domain",
00571 .tag = DHCP_DOMAIN_NAME,
00572 .type = &setting_type_string,
00573 };
00574
00575
00576
00577
00578
00579
00580 static int apply_dns_settings ( void ) {
00581 struct sockaddr_in *sin_nameserver =
00582 ( struct sockaddr_in * ) &nameserver;
00583 int len;
00584
00585 if ( ( len = fetch_ipv4_setting ( NULL, &dns_setting,
00586 &sin_nameserver->sin_addr ) ) >= 0 ){
00587 sin_nameserver->sin_family = AF_INET;
00588 DBG ( "DNS using nameserver %s\n",
00589 inet_ntoa ( sin_nameserver->sin_addr ) );
00590 }
00591
00592
00593 if ( ( len = fetch_string_setting_copy ( NULL, &domain_setting,
00594 &localdomain ) ) >= 0 )
00595 DBG ( "DNS local domain %s\n", localdomain );
00596
00597 return 0;
00598 }
00599
00600
00601 struct settings_applicator dns_applicator __settings_applicator = {
00602 .apply = apply_dns_settings,
00603 };