[tcp] Ignore duplicate ACKs in TCP ESTABLISHED state
[people/oremanj/gpxe.git] / src / net / udp / dns.c
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 FILE_LICENCE ( GPL2_OR_LATER );
23
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <byteswap.h>
30 #include <gpxe/refcnt.h>
31 #include <gpxe/xfer.h>
32 #include <gpxe/open.h>
33 #include <gpxe/resolv.h>
34 #include <gpxe/retry.h>
35 #include <gpxe/tcpip.h>
36 #include <gpxe/settings.h>
37 #include <gpxe/features.h>
38 #include <gpxe/dns.h>
39
40 /** @file
41  *
42  * DNS protocol
43  *
44  */
45
46 FEATURE ( FEATURE_PROTOCOL, "DNS", DHCP_EB_FEATURE_DNS, 1 );
47
48 /** The DNS server */
49 static struct sockaddr_tcpip nameserver = {
50         .st_port = htons ( DNS_PORT ),
51 };
52
53 /** The local domain */
54 static char *localdomain;
55
56 /** A DNS request */
57 struct dns_request {
58         /** Reference counter */
59         struct refcnt refcnt;
60         /** Name resolution interface */
61         struct resolv_interface resolv;
62         /** Data transfer interface */
63         struct xfer_interface socket;
64         /** Retry timer */
65         struct retry_timer timer;
66
67         /** Socket address to fill in with resolved address */
68         struct sockaddr sa;
69         /** Current query packet */
70         struct dns_query query;
71         /** Location of query info structure within current packet
72          *
73          * The query info structure is located immediately after the
74          * compressed name.
75          */
76         struct dns_query_info *qinfo;
77         /** Recursion counter */
78         unsigned int recursion;
79 };
80
81 /**
82  * Mark DNS request as complete
83  *
84  * @v dns               DNS request
85  * @v rc                Return status code
86  */
87 static void dns_done ( struct dns_request *dns, int rc ) {
88
89         /* Stop the retry timer */
90         stop_timer ( &dns->timer );
91
92         /* Close data transfer interface */
93         xfer_nullify ( &dns->socket );
94         xfer_close ( &dns->socket, rc );
95
96         /* Mark name resolution as complete */
97         resolv_done ( &dns->resolv, &dns->sa, rc );
98 }
99
100 /**
101  * Compare DNS reply name against the query name from the original request
102  *
103  * @v dns               DNS request
104  * @v reply             DNS reply
105  * @v rname             Reply name
106  * @ret zero            Names match
107  * @ret non-zero        Names do not match
108  */
109 static int dns_name_cmp ( struct dns_request *dns,
110                           const struct dns_header *reply, 
111                           const char *rname ) {
112         const char *qname = dns->query.payload;
113         int i;
114
115         while ( 1 ) {
116                 /* Obtain next section of rname */
117                 while ( ( *rname ) & 0xc0 ) {
118                         rname = ( ( ( char * ) reply ) +
119                                   ( ntohs( *((uint16_t *)rname) ) & ~0xc000 ));
120                 }
121                 /* Check that lengths match */
122                 if ( *rname != *qname )
123                         return -1;
124                 /* If length is zero, we have reached the end */
125                 if ( ! *qname )
126                         return 0;
127                 /* Check that data matches */
128                 for ( i = *qname + 1; i > 0 ; i-- ) {
129                         if ( *(rname++) != *(qname++) )
130                                 return -1;
131                 }
132         }
133 }
134
135 /**
136  * Skip over a (possibly compressed) DNS name
137  *
138  * @v name              DNS name
139  * @ret name            Next DNS name
140  */
141 static const char * dns_skip_name ( const char *name ) {
142         while ( 1 ) {
143                 if ( ! *name ) {
144                         /* End of name */
145                         return ( name + 1);
146                 }
147                 if ( *name & 0xc0 ) {
148                         /* Start of a compressed name */
149                         return ( name + 2 );
150                 }
151                 /* Uncompressed name portion */
152                 name += *name + 1;
153         }
154 }
155
156 /**
157  * Find an RR in a reply packet corresponding to our query
158  *
159  * @v dns               DNS request
160  * @v reply             DNS reply
161  * @ret rr              DNS RR, or NULL if not found
162  */
163 static union dns_rr_info * dns_find_rr ( struct dns_request *dns,
164                                          const struct dns_header *reply ) {
165         int i, cmp;
166         const char *p = ( ( char * ) reply ) + sizeof ( struct dns_header );
167         union dns_rr_info *rr_info;
168
169         /* Skip over the questions section */
170         for ( i = ntohs ( reply->qdcount ) ; i > 0 ; i-- ) {
171                 p = dns_skip_name ( p ) + sizeof ( struct dns_query_info );
172         }
173
174         /* Process the answers section */
175         for ( i = ntohs ( reply->ancount ) ; i > 0 ; i-- ) {
176                 cmp = dns_name_cmp ( dns, reply, p );
177                 p = dns_skip_name ( p );
178                 rr_info = ( ( union dns_rr_info * ) p );
179                 if ( cmp == 0 )
180                         return rr_info;
181                 p += ( sizeof ( rr_info->common ) +
182                        ntohs ( rr_info->common.rdlength ) );
183         }
184
185         return NULL;
186 }
187
188 /**
189  * Append DHCP domain name if available and name is not fully qualified
190  *
191  * @v string            Name as a NUL-terminated string
192  * @ret fqdn            Fully-qualified domain name, malloc'd copy
193  *
194  * The caller must free fqdn which is allocated even if the name is already
195  * fully qualified.
196  */
197 static char * dns_qualify_name ( const char *string ) {
198         char *fqdn;
199
200         /* Leave unchanged if already fully-qualified or no local domain */
201         if ( ( ! localdomain ) || ( strchr ( string, '.' ) != 0 ) )
202                 return strdup ( string );
203
204         /* Append local domain to name */
205         asprintf ( &fqdn, "%s.%s", string, localdomain );
206         return fqdn;
207 }
208
209 /**
210  * Convert a standard NUL-terminated string to a DNS name
211  *
212  * @v string            Name as a NUL-terminated string
213  * @v buf               Buffer in which to place DNS name
214  * @ret next            Byte following constructed DNS name
215  *
216  * DNS names consist of "<length>element" pairs.
217  */
218 static char * dns_make_name ( const char *string, char *buf ) {
219         char *length_byte = buf++;
220         char c;
221
222         while ( ( c = *(string++) ) ) {
223                 if ( c == '.' ) {
224                         *length_byte = buf - length_byte - 1;
225                         length_byte = buf;
226                 }
227                 *(buf++) = c;
228         }
229         *length_byte = buf - length_byte - 1;
230         *(buf++) = '\0';
231         return buf;
232 }
233
234 /**
235  * Convert an uncompressed DNS name to a NUL-terminated string
236  *
237  * @v name              DNS name
238  * @ret string          NUL-terminated string
239  *
240  * Produce a printable version of a DNS name.  Used only for debugging.
241  */
242 static inline char * dns_unmake_name ( char *name ) {
243         char *p;
244         unsigned int len;
245
246         p = name;
247         while ( ( len = *p ) ) {
248                 *(p++) = '.';
249                 p += len;
250         }
251
252         return name + 1;
253 }
254
255 /**
256  * Decompress a DNS name
257  *
258  * @v reply             DNS replay
259  * @v name              DNS name
260  * @v buf               Buffer into which to decompress DNS name
261  * @ret next            Byte following decompressed DNS name
262  */
263 static char * dns_decompress_name ( const struct dns_header *reply,
264                                     const char *name, char *buf ) {
265         int i, len;
266
267         do {
268                 /* Obtain next section of name */
269                 while ( ( *name ) & 0xc0 ) {
270                         name = ( ( char * ) reply +
271                                  ( ntohs ( *((uint16_t *)name) ) & ~0xc000 ) );
272                 }
273                 /* Copy data */
274                 len = *name;
275                 for ( i = len + 1 ; i > 0 ; i-- ) {
276                         *(buf++) = *(name++);
277                 }
278         } while ( len );
279         return buf;
280 }
281
282 /**
283  * Send next packet in DNS request
284  *
285  * @v dns               DNS request
286  */
287 static int dns_send_packet ( struct dns_request *dns ) {
288         static unsigned int qid = 0;
289         size_t qlen;
290
291         /* Increment query ID */
292         dns->query.dns.id = htons ( ++qid );
293
294         DBGC ( dns, "DNS %p sending query ID %d\n", dns, qid );
295
296         /* Start retransmission timer */
297         start_timer ( &dns->timer );
298
299         /* Send the data */
300         qlen = ( ( ( void * ) dns->qinfo ) - ( ( void * ) &dns->query )
301                  + sizeof ( dns->qinfo ) );
302         return xfer_deliver_raw ( &dns->socket, &dns->query, qlen );
303 }
304
305 /**
306  * Handle DNS retransmission timer expiry
307  *
308  * @v timer             Retry timer
309  * @v fail              Failure indicator
310  */
311 static void dns_timer_expired ( struct retry_timer *timer, int fail ) {
312         struct dns_request *dns =
313                 container_of ( timer, struct dns_request, timer );
314
315         if ( fail ) {
316                 dns_done ( dns, -ETIMEDOUT );
317         } else {
318                 dns_send_packet ( dns );
319         }
320 }
321
322 /**
323  * Receive new data
324  *
325  * @v socket            UDP socket
326  * @v data              DNS reply
327  * @v len               Length of DNS reply
328  * @ret rc              Return status code
329  */
330 static int dns_xfer_deliver_raw ( struct xfer_interface *socket,
331                                   const void *data, size_t len ) {
332         struct dns_request *dns =
333                 container_of ( socket, struct dns_request, socket );
334         const struct dns_header *reply = data;
335         union dns_rr_info *rr_info;
336         struct sockaddr_in *sin;
337         unsigned int qtype = dns->qinfo->qtype;
338
339         /* Sanity check */
340         if ( len < sizeof ( *reply ) ) {
341                 DBGC ( dns, "DNS %p received underlength packet length %zd\n",
342                        dns, len );
343                 return -EINVAL;
344         }
345
346         /* Check reply ID matches query ID */
347         if ( reply->id != dns->query.dns.id ) {
348                 DBGC ( dns, "DNS %p received unexpected reply ID %d "
349                        "(wanted %d)\n", dns, ntohs ( reply->id ),
350                        ntohs ( dns->query.dns.id ) );
351                 return -EINVAL;
352         }
353
354         DBGC ( dns, "DNS %p received reply ID %d\n", dns, ntohs ( reply->id ));
355
356         /* Stop the retry timer.  After this point, each code path
357          * must either restart the timer by calling dns_send_packet(),
358          * or mark the DNS operation as complete by calling
359          * dns_done()
360          */
361         stop_timer ( &dns->timer );
362
363         /* Search through response for useful answers.  Do this
364          * multiple times, to take advantage of useful nameservers
365          * which send us e.g. the CNAME *and* the A record for the
366          * pointed-to name.
367          */
368         while ( ( rr_info = dns_find_rr ( dns, reply ) ) ) {
369                 switch ( rr_info->common.type ) {
370
371                 case htons ( DNS_TYPE_A ):
372
373                         /* Found the target A record */
374                         DBGC ( dns, "DNS %p found address %s\n",
375                                dns, inet_ntoa ( rr_info->a.in_addr ) );
376                         sin = ( struct sockaddr_in * ) &dns->sa;
377                         sin->sin_family = AF_INET;
378                         sin->sin_addr = rr_info->a.in_addr;
379
380                         /* Mark operation as complete */
381                         dns_done ( dns, 0 );
382                         return 0;
383
384                 case htons ( DNS_TYPE_CNAME ):
385
386                         /* Found a CNAME record; update query and recurse */
387                         DBGC ( dns, "DNS %p found CNAME\n", dns );
388                         dns->qinfo = ( void * ) dns_decompress_name ( reply,
389                                                          rr_info->cname.cname,
390                                                          dns->query.payload );
391                         dns->qinfo->qtype = htons ( DNS_TYPE_A );
392                         dns->qinfo->qclass = htons ( DNS_CLASS_IN );
393                         
394                         /* Terminate the operation if we recurse too far */
395                         if ( ++dns->recursion > DNS_MAX_CNAME_RECURSION ) {
396                                 DBGC ( dns, "DNS %p recursion exceeded\n",
397                                        dns );
398                                 dns_done ( dns, -ELOOP );
399                                 return 0;
400                         }
401                         break;
402
403                 default:
404                         DBGC ( dns, "DNS %p got unknown record type %d\n",
405                                dns, ntohs ( rr_info->common.type ) );
406                         break;
407                 }
408         }
409         
410         /* Determine what to do next based on the type of query we
411          * issued and the reponse we received
412          */
413         switch ( qtype ) {
414
415         case htons ( DNS_TYPE_A ):
416                 /* We asked for an A record and got nothing;
417                  * try the CNAME.
418                  */
419                 DBGC ( dns, "DNS %p found no A record; trying CNAME\n", dns );
420                 dns->qinfo->qtype = htons ( DNS_TYPE_CNAME );
421                 dns_send_packet ( dns );
422                 return 0;
423
424         case htons ( DNS_TYPE_CNAME ):
425                 /* We asked for a CNAME record.  If we got a response
426                  * (i.e. if the next A query is already set up), then
427                  * issue it, otherwise abort.
428                  */
429                 if ( dns->qinfo->qtype == htons ( DNS_TYPE_A ) ) {
430                         dns_send_packet ( dns );
431                         return 0;
432                 } else {
433                         DBGC ( dns, "DNS %p found no CNAME record\n", dns );
434                         dns_done ( dns, -ENXIO );
435                         return 0;
436                 }
437
438         default:
439                 assert ( 0 );
440                 dns_done ( dns, -EINVAL );
441                 return 0;
442         }
443 }
444
445 /**
446  * Receive new data
447  *
448  * @v socket            UDP socket
449  * @v rc                Reason for close
450  */
451 static void dns_xfer_close ( struct xfer_interface *socket, int rc ) {
452         struct dns_request *dns =
453                 container_of ( socket, struct dns_request, socket );
454
455         if ( ! rc )
456                 rc = -ECONNABORTED;
457
458         dns_done ( dns, rc );
459 }
460
461 /** DNS socket operations */
462 static struct xfer_interface_operations dns_socket_operations = {
463         .close          = dns_xfer_close,
464         .vredirect      = xfer_vreopen,
465         .window         = unlimited_xfer_window,
466         .alloc_iob      = default_xfer_alloc_iob,
467         .deliver_iob    = xfer_deliver_as_raw,
468         .deliver_raw    = dns_xfer_deliver_raw,
469 };
470
471 /**
472  * Resolve name using DNS
473  *
474  * @v resolv            Name resolution interface
475  * @v name              Name to resolve
476  * @v sa                Socket address to fill in
477  * @ret rc              Return status code
478  */
479 static int dns_resolv ( struct resolv_interface *resolv,
480                         const char *name, struct sockaddr *sa ) {
481         struct dns_request *dns;
482         char *fqdn;
483         int rc;
484
485         /* Fail immediately if no DNS servers */
486         if ( ! nameserver.st_family ) {
487                 DBG ( "DNS not attempting to resolve \"%s\": "
488                       "no DNS servers\n", name );
489                 rc = -ENXIO;
490                 goto err_no_nameserver;
491         }
492
493         /* Ensure fully-qualified domain name if DHCP option was given */
494         fqdn = dns_qualify_name ( name );
495         if ( ! fqdn ) {
496                 rc = -ENOMEM;
497                 goto err_qualify_name;
498         }
499
500         /* Allocate DNS structure */
501         dns = zalloc ( sizeof ( *dns ) );
502         if ( ! dns ) {
503                 rc = -ENOMEM;
504                 goto err_alloc_dns;
505         }
506         resolv_init ( &dns->resolv, &null_resolv_ops, &dns->refcnt );
507         xfer_init ( &dns->socket, &dns_socket_operations, &dns->refcnt );
508         dns->timer.expired = dns_timer_expired;
509         memcpy ( &dns->sa, sa, sizeof ( dns->sa ) );
510
511         /* Create query */
512         dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
513                                        DNS_FLAG_RD );
514         dns->query.dns.qdcount = htons ( 1 );
515         dns->qinfo = ( void * ) dns_make_name ( fqdn, dns->query.payload );
516         dns->qinfo->qtype = htons ( DNS_TYPE_A );
517         dns->qinfo->qclass = htons ( DNS_CLASS_IN );
518
519         /* Open UDP connection */
520         if ( ( rc = xfer_open_socket ( &dns->socket, SOCK_DGRAM,
521                                        ( struct sockaddr * ) &nameserver,
522                                        NULL ) ) != 0 ) {
523                 DBGC ( dns, "DNS %p could not open socket: %s\n",
524                        dns, strerror ( rc ) );
525                 goto err_open_socket;
526         }
527
528         /* Send first DNS packet */
529         dns_send_packet ( dns );
530
531         /* Attach parent interface, mortalise self, and return */
532         resolv_plug_plug ( &dns->resolv, resolv );
533         ref_put ( &dns->refcnt );
534         free ( fqdn );
535         return 0;       
536
537  err_open_socket:
538  err_alloc_dns:
539         ref_put ( &dns->refcnt );
540  err_qualify_name:
541         free ( fqdn );
542  err_no_nameserver:
543         return rc;
544 }
545
546 /** DNS name resolver */
547 struct resolver dns_resolver __resolver ( RESOLV_NORMAL ) = {
548         .name = "DNS",
549         .resolv = dns_resolv,
550 };
551
552 /******************************************************************************
553  *
554  * Settings
555  *
556  ******************************************************************************
557  */
558
559 /** DNS server setting */
560 struct setting dns_setting __setting = {
561         .name = "dns",
562         .description = "DNS server",
563         .tag = DHCP_DNS_SERVERS,
564         .type = &setting_type_ipv4,
565 };
566
567 /** Domain name setting */
568 struct setting domain_setting __setting = {
569         .name = "domain",
570         .description = "Local domain",
571         .tag = DHCP_DOMAIN_NAME,
572         .type = &setting_type_string,
573 };
574
575 /**
576  * Apply DNS settings
577  *
578  * @ret rc              Return status code
579  */
580 static int apply_dns_settings ( void ) {
581         struct sockaddr_in *sin_nameserver =
582                 ( struct sockaddr_in * ) &nameserver;
583         int len;
584
585         if ( ( len = fetch_ipv4_setting ( NULL, &dns_setting,
586                                           &sin_nameserver->sin_addr ) ) >= 0 ){
587                 sin_nameserver->sin_family = AF_INET;
588                 DBG ( "DNS using nameserver %s\n",
589                       inet_ntoa ( sin_nameserver->sin_addr ) );
590         }
591
592         /* Get local domain DHCP option */
593         if ( ( len = fetch_string_setting_copy ( NULL, &domain_setting,
594                                                  &localdomain ) ) >= 0 )
595                 DBG ( "DNS local domain %s\n", localdomain );
596
597         return 0;
598 }
599
600 /** DNS settings applicator */
601 struct settings_applicator dns_applicator __settings_applicator = {
602         .apply = apply_dns_settings,
603 };