A working DNS resolver (not yet tied in to anything)
authorMichael Brown <mcb30@etherboot.org>
Mon, 15 Jan 2007 17:31:35 +0000 (17:31 +0000)
committerMichael Brown <mcb30@etherboot.org>
Mon, 15 Jan 2007 17:31:35 +0000 (17:31 +0000)
src/include/errno.h
src/include/gpxe/dns.h [moved from src/include/dns.h with 67% similarity]
src/include/nmb.h
src/net/udp/dns.c [new file with mode: 0644]
src/proto/dns.c [deleted file]
src/proto/nmb.c

index 3025fa9..541d9cb 100644 (file)
 #define EINVAL         0xdd    /**< Invalid argument */
 #define EIO            0xde    /**< Input/output error */
 #define EISCONN                0xdf    /**< Transport endpoint is already connected */
+#define ELOOP          0xf8    /**< Too many symbolic links */
 #define EMFILE         0xe0    /**< Too many open files */
 #define EMSGSIZE       0xe1    /**< Message too long */
 #define ENAMETOOLONG   0xe2    /**< File name too long */
similarity index 67%
rename from src/include/dns.h
rename to src/include/gpxe/dns.h
index c72c690..49292d5 100644 (file)
@@ -1,10 +1,16 @@
-#ifndef DNS_RESOLVER_H
-#define DNS_RESOLVER_H
+#ifndef _GPXE_DNS_H
+#define _GPXE_DNS_H
 
-#include "stdint.h"
+/** @file
+ *
+ * DNS protocol
+ *
+ */
+
+#include <stdint.h>
 #include <gpxe/in.h>
-#include "ip.h"
-#include "udp.h"
+#include <gpxe/async.h>
+#include <gpxe/retry.h>
 
 /*
  * Constants
@@ -33,7 +39,7 @@
 #define DNS_FLAG_RCODE_NX      ( 0x03 << 0 )
 #define DNS_FLAG_RCODE(flags)  ( (flags) & ( 0x0f << 0 ) )
 
-#define        DNS_UDP_PORT            53
+#define        DNS_PORT                53
 #define        DNS_MAX_RETRIES         3
 #define        DNS_MAX_CNAME_RECURSION 0x30
 
@@ -56,13 +62,11 @@ struct dns_query_info {
 } __attribute__ (( packed ));
 
 struct dns_query {
-       struct iphdr    ip;
-       struct udphdr   udp;
        struct dns_header dns;
        char            payload[ 256 + sizeof ( struct dns_query_info ) ];
 } __attribute__ (( packed ));
 
-struct dns_rr_info {
+struct dns_rr_info_common {
        uint16_t        type;
        uint16_t        class;
        uint32_t        ttl;
@@ -70,23 +74,36 @@ struct dns_rr_info {
 } __attribute__ (( packed ));
 
 struct dns_rr_info_a {
-       struct dns_rr_info info;
+       struct dns_rr_info_common common;
        struct in_addr in_addr;
 } __attribute__ (( packed ));
 
 struct dns_rr_info_cname {
-       struct dns_rr_info info;
-       char            cname[0];
+       struct dns_rr_info_common common;
+       char cname[0];
 } __attribute__ (( packed ));
 
-/*
- * Functions in dns.c (used by nmb.c)
- *
- */
-extern struct dns_header * dns_query ( struct dns_query *query,
-                                      unsigned int query_len, 
-                                      struct sockaddr_in *nameserver );
-extern struct dns_rr_info * dns_find_rr ( struct dns_query *query,
-                                         struct dns_header *reply );
+union dns_rr_info {
+       struct dns_rr_info_common common;
+       struct dns_rr_info_a a;
+       struct dns_rr_info_cname cname;
+};
+
+struct dns_request {
+
+       struct sockaddr_tcpip *st;
+
+       struct async async;
+       struct dns_query query;
+       struct dns_query_info *qinfo;
+
+       unsigned int recursion;
+
+       struct udp_connection udp;
+       struct retry_timer timer;
+};
+
+extern int dns_resolv ( const char *name, struct sockaddr_tcpip *st,
+                       struct async *parent );
 
-#endif /* DNS_RESOLVER_H */
+#endif /* _GPXE_DNS_H */
index 7948d9e..3e551ff 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef NMB_H
 #define NMB_H
 
-#include "dns.h"
+#include <gpxe/dns.h>
 
 /*
  * NetBIOS name query packets are basically the same as DNS packets,
diff --git a/src/net/udp/dns.c b/src/net/udp/dns.c
new file mode 100644 (file)
index 0000000..17075d6
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * Portions copyright (C) 2004 Anselm M. Hoffmeister
+ * <stockholm@users.sourceforge.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <gpxe/async.h>
+#include <gpxe/udp.h>
+#include <gpxe/dhcp.h>
+#include <gpxe/dns.h>
+
+/** @file
+ *
+ * DNS protocol
+ *
+ */
+
+/**
+ * Compare DNS reply name against the query name from the original request
+ *
+ * @v dns              DNS request
+ * @v reply            DNS reply
+ * @v rname            Reply name
+ * @ret        zero            Names match
+ * @ret non-zero       Names do not match
+ */
+static int dns_name_cmp ( struct dns_request *dns, struct dns_header *reply, 
+                         const char *rname ) {
+       const char *qname = dns->query.payload;
+       int i;
+
+       while ( 1 ) {
+               /* Obtain next section of rname */
+               while ( ( *rname ) & 0xc0 ) {                   
+                       rname = ( ( ( char * ) reply ) +
+                                 ( ntohs( *((uint16_t *)rname) ) & ~0xc000 ));
+               }
+               /* Check that lengths match */
+               if ( *rname != *qname )
+                       return -1;
+               /* If length is zero, we have reached the end */
+               if ( ! *qname )
+                       return 0;
+               /* Check that data matches */
+               for ( i = *qname + 1; i > 0 ; i-- ) {
+                       if ( *(rname++) != *(qname++) )
+                               return -1;
+               }
+       }
+}
+
+/**
+ * Skip over a (possibly compressed) DNS name
+ *
+ * @v name             DNS name
+ * @ret name           Next DNS name
+ */
+static const char * dns_skip_name ( const char *name ) {
+       while ( 1 ) {
+               if ( ! *name ) {
+                       /* End of name */
+                       return ( name + 1);
+               }
+               if ( *name & 0xc0 ) {
+                       /* Start of a compressed name */
+                       return ( name + 2 );
+               }
+               /* Uncompressed name portion */
+               name += *name + 1;
+       }
+}
+
+/**
+ * Find an RR in a reply packet corresponding to our query
+ *
+ * @v dns              DNS request
+ * @v reply            DNS reply
+ * @ret rr             DNS RR, or NULL if not found
+ */
+static union dns_rr_info * dns_find_rr ( struct dns_request *dns,
+                                        struct dns_header *reply ) {
+       int i, cmp;
+       const char *p = ( ( char * ) reply ) + sizeof ( struct dns_header );
+       union dns_rr_info *rr_info;
+
+       /* Skip over the questions section */
+       for ( i = ntohs ( reply->qdcount ) ; i > 0 ; i-- ) {
+               p = dns_skip_name ( p ) + sizeof ( struct dns_query_info );
+       }
+
+       /* Process the answers section */
+       for ( i = ntohs ( reply->ancount ) ; i > 0 ; i-- ) {
+               cmp = dns_name_cmp ( dns, reply, p );
+               p = dns_skip_name ( p );
+               rr_info = ( ( union dns_rr_info * ) p );
+               if ( cmp == 0 )
+                       return rr_info;
+               p += ( sizeof ( rr_info->common ) +
+                      ntohs ( rr_info->common.rdlength ) );
+       }
+
+       return NULL;
+}
+
+/**
+ * Convert a standard NUL-terminated string to a DNS name
+ *
+ * @v string           Name as a NUL-terminated string
+ * @v buf              Buffer in which to place DNS name
+ * @ret next           Byte following constructed DNS name
+ *
+ * DNS names consist of "<length>element" pairs.
+ */
+static char * dns_make_name ( const char *string, char *buf ) {
+       char *length_byte = buf++;
+       char c;
+
+       while ( ( c = *(string++) ) ) {
+               if ( c == '.' ) {
+                       *length_byte = buf - length_byte - 1;
+                       length_byte = buf;
+               }
+               *(buf++) = c;
+       }
+       *length_byte = buf - length_byte - 1;
+       *(buf++) = '\0';
+       return buf;
+}
+
+/**
+ * Convert an uncompressed DNS name to a NUL-terminated string
+ *
+ * @v name             DNS name
+ * @ret string         NUL-terminated string
+ *
+ * Produce a printable version of a DNS name.  Used only for debugging.
+ */
+static inline char * dns_unmake_name ( char *name ) {
+       char *p;
+       unsigned int len;
+
+       p = name;
+       while ( ( len = *p ) ) {
+               *(p++) = '.';
+               p += len;
+       }
+
+       return name + 1;
+}
+
+/**
+ * Decompress a DNS name
+ *
+ * @v reply            DNS replay
+ * @v name             DNS name
+ * @v buf              Buffer into which to decompress DNS name
+ * @ret next           Byte following decompressed DNS name
+ */
+static char * dns_decompress_name ( struct dns_header *reply,
+                                   const char *name, char *buf ) {
+       int i, len;
+
+       do {
+               /* Obtain next section of name */
+               while ( ( *name ) & 0xc0 ) {
+                       name = ( ( char * ) reply +
+                                ( ntohs ( *((uint16_t *)name) ) & ~0xc000 ) );
+               }
+               /* Copy data */
+               len = *name;
+               for ( i = len + 1 ; i > 0 ; i-- ) {
+                       *(buf++) = *(name++);
+               }
+       } while ( len );
+       return buf;
+}
+
+/**
+ * Mark DNS request as complete
+ *
+ * @v dns              DNS request
+ * @v rc               Return status code
+ */
+static void dns_done ( struct dns_request *dns, int rc ) {
+
+       /* Stop the retry timer */
+       stop_timer ( &dns->timer );
+
+       /* Close UDP connection */
+       udp_close ( &dns->udp );
+
+       /* Mark async operation as complete */
+       async_done ( &dns->async, rc );
+}
+
+/**
+ * Send next packet in DNS request
+ *
+ * @v dns              DNS request
+ */
+static void dns_send_packet ( struct dns_request *dns ) {
+       static unsigned int qid = 0;
+
+       /* Increment query ID */
+       dns->query.dns.id = htons ( ++qid );
+
+       DBGC ( dns, "DNS %p sending query ID %d\n", dns, qid );
+
+       /* Start retransmission timer */
+       start_timer ( &dns->timer );
+
+       /* Send the data */
+       udp_send ( &dns->udp, &dns->query,
+                  ( ( ( void * ) dns->qinfo ) - ( ( void * ) &dns->query )
+                    + sizeof ( dns->qinfo ) ) );
+}
+
+/**
+ * Handle DNS retransmission timer expiry
+ *
+ * @v timer            Retry timer
+ * @v fail             Failure indicator
+ */
+static void dns_timer_expired ( struct retry_timer *timer, int fail ) {
+       struct dns_request *dns =
+               container_of ( timer, struct dns_request, timer );
+
+       if ( fail ) {
+               dns_done ( dns, -ETIMEDOUT );
+       } else {
+               dns_send_packet ( dns );
+       }
+}
+
+/**
+ * Receive new data
+ *
+ * @v udp              UDP connection
+ * @v data             Received data
+ * @v len              Length of received data
+ * @v st_src           Partially-filled source address
+ * @v st_dest          Partially-filled destination address
+ */
+static int dns_newdata ( struct udp_connection *conn, void *data, size_t len,
+                        struct sockaddr_tcpip *st_src __unused,
+                        struct sockaddr_tcpip *st_dest __unused ) {
+       struct dns_request *dns =
+               container_of ( conn, struct dns_request, udp );
+       struct dns_header *reply = data;
+       union dns_rr_info *rr_info;
+       struct sockaddr_in *sin;
+       unsigned int qtype = dns->qinfo->qtype;
+
+       /* Sanity check */
+       if ( len < sizeof ( *reply ) ) {
+               DBGC ( dns, "DNS %p received underlength packet length %zd\n",
+                      dns, len );
+               return -EINVAL;
+       }
+
+       /* Check reply ID matches query ID */
+       if ( reply->id != dns->query.dns.id ) {
+               DBGC ( dns, "DNS %p received unexpected reply ID %d "
+                      "(wanted %d)\n", dns, ntohs ( reply->id ),
+                      ntohs ( dns->query.dns.id ) );
+               return -EINVAL;
+       }
+
+       DBGC ( dns, "DNS %p received reply ID %d\n", dns, ntohs ( reply->id ));
+
+       /* Stop the retry timer.  After this point, each code path
+        * must either restart the timer by calling dns_send_packet(),
+        * or mark the DNS operation as complete by calling
+        * dns_done()
+        */
+       stop_timer ( &dns->timer );
+
+       /* Search through response for useful answers.  Do this
+        * multiple times, to take advantage of useful nameservers
+        * which send us e.g. the CNAME *and* the A record for the
+        * pointed-to name.
+        */
+       while ( ( rr_info = dns_find_rr ( dns, reply ) ) ) {
+               switch ( rr_info->common.type ) {
+
+               case htons ( DNS_TYPE_A ):
+
+                       /* Found the target A record */
+                       DBGC ( dns, "DNS %p found address %s\n",
+                              dns, inet_ntoa ( rr_info->a.in_addr ) );
+                       sin = ( struct sockaddr_in * ) dns->st;
+                       sin->sin_family = AF_INET;
+                       sin->sin_addr = rr_info->a.in_addr;
+
+                       /* Mark operation as complete */
+                       dns_done ( dns, 0 );
+                       return 0;
+
+               case htons ( DNS_TYPE_CNAME ):
+
+                       /* Found a CNAME record; update query and recurse */
+                       DBGC ( dns, "DNS %p found CNAME\n", dns );
+                       dns->qinfo = ( void * ) dns_decompress_name ( reply,
+                                                        rr_info->cname.cname,
+                                                        dns->query.payload );
+                       dns->qinfo->qtype = htons ( DNS_TYPE_A );
+                       dns->qinfo->qclass = htons ( DNS_CLASS_IN );
+                       
+                       /* Terminate the operation if we recurse too far */
+                       if ( ++dns->recursion > DNS_MAX_CNAME_RECURSION ) {
+                               DBGC ( dns, "DNS %p recursion exceeded\n",
+                                      dns );
+                               dns_done ( dns, -ELOOP );
+                               return 0;
+                       }
+                       break;
+
+               default:
+                       DBGC ( dns, "DNS %p got unknown record type %d\n",
+                              dns, ntohs ( rr_info->common.type ) );
+                       break;
+               }
+       }
+       
+       /* Determine what to do next based on the type of query we
+        * issued and the reponse we received
+        */
+       switch ( qtype ) {
+
+       case htons ( DNS_TYPE_A ):
+               /* We asked for an A record and got nothing;
+                * try the CNAME.
+                */
+               DBGC ( dns, "DNS %p found no A record; trying CNAME\n", dns );
+               dns->qinfo->qtype = htons ( DNS_TYPE_CNAME );
+               dns_send_packet ( dns );
+               return 0;
+
+       case htons ( DNS_TYPE_CNAME ):
+               /* We asked for a CNAME record.  If we got a response
+                * (i.e. if the next A query is already set up), then
+                * issue it, otherwise abort.
+                */
+               if ( dns->qinfo->qtype == htons ( DNS_TYPE_A ) ) {
+                       dns_send_packet ( dns );
+                       return 0;
+               } else {
+                       DBGC ( dns, "DNS %p found no CNAME record\n", dns );
+                       dns_done ( dns, -ENXIO );
+                       return 0;
+               }
+
+       default:
+               assert ( 0 );
+               dns_done ( dns, -EINVAL );
+               return 0;
+       }
+}
+
+/** DNS UDP operations */
+struct udp_operations dns_udp_operations = {
+       .newdata = dns_newdata,
+};
+
+/**
+ * Reap asynchronous operation
+ *
+ * @v async            Asynchronous operation
+ */
+static void dns_reap ( struct async *async ) {
+       struct dns_request *dns =
+               container_of ( async, struct dns_request, async );
+
+       free ( dns );
+}
+
+/** DNS asynchronous operations */
+static struct async_operations dns_async_operations = {
+       .reap = dns_reap,
+};
+
+/**
+ * Resolve name using DNS
+ *
+ */
+int dns_resolv ( const char *name, struct sockaddr_tcpip *st,
+                struct async *parent ) {
+       struct dns_request *dns;
+       union {
+               struct sockaddr_tcpip st;
+               struct sockaddr_in sin;
+       } nameserver;
+       int rc;
+
+       /* Allocate DNS structure */
+       dns = malloc ( sizeof ( *dns ) );
+       if ( ! dns ) {
+               rc = -ENOMEM;
+               goto err;
+       }
+       memset ( dns, 0, sizeof ( *dns ) );
+       dns->st = st;
+       dns->timer.expired = dns_timer_expired;
+       dns->udp.udp_op = &dns_udp_operations;
+
+       /* Create query */
+       dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
+                                      DNS_FLAG_RD );
+       dns->query.dns.qdcount = htons ( 1 );
+       dns->qinfo = ( void * ) dns_make_name ( name, dns->query.payload );
+       dns->qinfo->qtype = htons ( DNS_TYPE_A );
+       dns->qinfo->qclass = htons ( DNS_CLASS_IN );
+
+       /* Open UDP connection */
+       memset ( &nameserver, 0, sizeof ( nameserver ) );
+       nameserver.sin.sin_family = AF_INET;
+       nameserver.sin.sin_port = htons ( DNS_PORT );
+#warning "DHCP-DNS hack"
+       struct dhcp_option *option =
+               find_global_dhcp_option ( DHCP_DNS_SERVERS );
+       if ( ! option ) {
+               DBGC ( dns, "DNS %p no name servers\n", dns );
+               rc = -ENXIO;
+               goto err;
+       }
+       dhcp_ipv4_option ( option, &nameserver.sin.sin_addr );
+       DBGC ( dns, "DNS %p using nameserver %s\n", dns, 
+              inet_ntoa ( nameserver.sin.sin_addr ) );
+       udp_connect ( &dns->udp, &nameserver.st );
+       if ( ( rc = udp_open ( &dns->udp, 0 ) ) != 0 )
+               goto err;
+
+       dns_send_packet ( dns );
+
+       async_init ( &dns->async, &dns_async_operations, parent );
+       return 0;       
+
+ err:
+       DBGC ( dns, "DNS %p could not create request: %s\n", 
+              dns, strerror ( rc ) );
+       free ( dns );
+       return rc;
+}
diff --git a/src/proto/dns.c b/src/proto/dns.c
deleted file mode 100644 (file)
index 60ea04a..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-/**************************************************************************
-*
-*    dns_resolver.c: Etherboot support for resolution of host/domain
-*    names in filename parameters
-*    Written 2004 by Anselm M. Hoffmeister
-*    <stockholm@users.sourceforge.net>
-*
-*    This program is free software; you can redistribute it and/or modify
-*    it under the terms of the GNU General Public License as published by
-*    the Free Software Foundation; either version 2 of the License, or
-*    (at your option) any later version.
-*
-*    This program is distributed in the hope that it will be useful,
-*    but WITHOUT ANY WARRANTY; without even the implied warranty of
-*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-*    GNU General Public License for more details.
-*
-*    You should have received a copy of the GNU General Public License
-*    along with this program; if not, write to the Free Software
-*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-*    This code is using nuts and bolts from throughout etherboot.
-*    It is a fresh implementation according to the DNS RFC, #1035
-*    
-*    REVISION HISTORY:
-*    ================
-*    2004-05-10 File created
-*    2004-05-19 First release to CVS
-*    2004-05-22 CNAME support first stage finished
-*    2004-05-24 First "stable" release to CVS
-*    2004-08-28 Improve readability, set recursion flag
-*    2005-04-30 Tidied up to the point of being a complete rewrite (mcb30)
-***************************************************************************/
-
-#include "etherboot.h"
-#include "nic.h"
-#include "resolv.h"
-#include "dns.h"
-
-/*
- *     await_dns
- *     Shall be called on any incoming packet during the resolution process
- *     (as is the case with all the other await_ functions in etherboot)
- *     Param:  as any await functions
- *
- */
-static int await_dns ( int ival, void *ptr,
-                      unsigned short ptype __unused,
-                      struct iphdr *ip __unused,
-                      struct udphdr *udp, struct tcphdr *tcp __unused ) {
-       struct dns_header **header = ptr;
-
-       if ( ! udp )
-               return 0;
-       if ( ntohs ( udp->dest ) != ival )
-               return 0;
-       *header = ( struct dns_header * ) ( udp + 1 );
-       return 1;
-}
-
-/*
- * Send a name server query and wait for a response.  Query is retried
- * up to DNS_MAX_RETRIES times.  Returns a pointer to the answer
- * packet, or NULL if no answer was received.
- *
- */
-struct dns_header * dns_query ( struct dns_query *query,
-                               unsigned int query_len, 
-                               struct sockaddr_in *nameserver ) {
-       long timeout;
-       int retry;
-       struct dns_header *reply;
-
-       for ( retry = 0 ; retry < DNS_MAX_RETRIES ; retry++ ) {
-               udp_transmit ( nameserver->sin_addr.s_addr,
-                              nameserver->sin_port, nameserver->sin_port,
-                              query_len, query );
-               timeout = rfc2131_sleep_interval ( TIMEOUT, retry );
-               if ( ! await_reply ( await_dns, nameserver->sin_port,
-                                    &reply, timeout ) )
-                       continue;
-               if ( reply->id != query->dns.id ) {
-                       DBG ( "DNS received unexpected reply ID %d "
-                             "(wanted %d)\n",
-                             ntohs ( reply->id ), ntohs ( query->dns.id ) );
-                       continue;
-               }
-               /* We have a valid reply! */
-               return reply;
-       }
-       return NULL;
-}
-
-/*
- * Compare two DNS names to see if they are the same.  Takes
- * compressed names in the reply into account (though the query name
- * must be uncompressed).  Returns 0 for a match (for consistency with
- * strcmp et al).
- *
- */
-static inline int dns_name_cmp ( const char *qname, const char *rname,
-                                struct dns_header *reply ) {
-       int i;
-       while ( 1 ) {
-               /* Obtain next section of rname */
-               while ( ( *rname ) & 0xc0 ) {
-                       rname = ( ( char * ) reply +
-                                 ( ntohs( *((uint16_t *)rname) ) & ~0xc000 ));
-               }
-               /* Check that lengths match */
-               if ( *rname != *qname )
-                       return 1;
-               /* If length is zero, we have reached the end */
-               if ( ! *qname )
-                       return 0;
-               /* Check that data matches */
-               for ( i = *qname + 1; i > 0 ; i-- ) {
-                       if ( *(rname++) != *(qname++) )
-                               return 1;
-               }
-       }
-}
-
-/*
- * Skip over a DNS name, which may be compressed
- *
- */
-static inline const char * dns_skip_name ( const char *name ) {
-       while ( 1 ) {
-               if ( ! *name ) {
-                       /* End of name */
-                       return ( name + 1);
-               }
-               if ( *name & 0xc0 ) {
-                       /* Start of a compressed name */
-                       return ( name + 2 );
-               }
-               /* Uncompressed name portion */
-               name += *name + 1;
-       }
-}
-
-/*
- * Find a Resource Record in a reply packet corresponding to our
- * query.  Returns a pointer to the RR, or NULL if no answer found.
- *
- */
-struct dns_rr_info * dns_find_rr ( struct dns_query *query,
-                                  struct dns_header *reply ) {
-       int i, cmp;
-       const char *p = ( ( char * ) reply ) + sizeof ( struct dns_header );
-
-       /* Skip over the questions section */
-       for ( i = ntohs ( reply->qdcount ) ; i > 0 ; i-- ) {
-               p = dns_skip_name ( p ) + sizeof ( struct dns_query_info );
-       }
-
-       /* Process the answers section */
-       for ( i = ntohs ( reply->ancount ) ; i > 0 ; i-- ) {
-               cmp = dns_name_cmp ( query->payload, p, reply );
-               p = dns_skip_name ( p );
-               if ( cmp == 0 )
-                       return ( ( struct dns_rr_info * ) p );
-               p += ( sizeof ( struct dns_rr_info ) +
-                      ntohs ( ( ( struct dns_rr_info * ) p )->rdlength ) );
-       }
-
-       return NULL;
-}
-
-/*
- * Convert a standard NUL-terminated string to a DNS query name,
- * consisting of "<length>element" pairs.
- *
- * Returns a pointer to the character following the constructed DNS
- * query name.
- *
- */
-static inline char * dns_make_name ( char *dest, const char *name ) {
-       char *length_byte = dest++;
-       char c;
-
-       while ( ( c = *(name++) ) ) {
-               if ( c == '.' ) {
-                       *length_byte = dest - length_byte - 1;
-                       length_byte = dest;
-               }
-               *(dest++) = c;
-       }
-       *length_byte = dest - length_byte - 1;
-       *(dest++) = '\0';
-       return dest;
-}
-
-/*
- * Produce a printable version of a DNS name.  Used only for debugging.
- *
- */
-static inline char * dns_unmake_name ( char *name ) {
-       char *p;
-       unsigned int len;
-
-       p = name;
-       while ( ( len = *p ) ) {
-               *(p++) = '.';
-               p += len;
-       }
-       
-       return name + 1;
-}
-
-/*
- * Decompress a DNS name.
- *
- * Returns a pointer to the character following the decompressed DNS
- * name.
- *
- */
-static inline char * dns_decompress_name ( char *dest, const char *name,
-                                          struct dns_header *header ) {
-       int i, len;
-
-       do {
-               /* Obtain next section of name */
-               while ( ( *name ) & 0xc0 ) {
-                       name = ( ( char * ) header +
-                                ( ntohs ( *((uint16_t *)name) ) & ~0xc000 ) );
-               }
-               /* Copy data */
-               len = *name;
-               for ( i = len + 1 ; i > 0 ; i-- ) {
-                       *(dest++) = *(name++);
-               }
-       } while ( len );
-       return dest;
-}
-
-/*
- * Resolve a name using DNS
- *
- */
-static int dns_resolv ( struct in_addr *addr, const char *name ) {
-       struct dns_query query;
-       struct dns_query_info *query_info;
-       struct dns_header *reply;
-       struct dns_rr_info *rr_info;
-       struct sockaddr_in nameserver;
-       uint16_t qtype;
-       unsigned int recursion = 0;
-       unsigned int id = 1;
-
-       /* Fail immediately if we have no name server */
-       if ( ! arptable[ARP_NAMESERVER].ipaddr.s_addr ) {
-               DBG ( "DNS has no nameserver\n" );
-               return 0;
-       }
-
-       DBG ( "DNS resolving %s\n", name );
-
-       /* Set up the query data */
-       nameserver.sin_addr = arptable[ARP_NAMESERVER].ipaddr;
-       nameserver.sin_port = DNS_UDP_PORT;
-       memset ( &query, 0, sizeof ( query ) );
-       query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
-                                 DNS_FLAG_RD );
-       query.dns.qdcount = htons ( 1 );
-       query_info = ( void * ) dns_make_name ( query.payload, name );
-       query_info->qtype = htons ( DNS_TYPE_A );
-       query_info->qclass = htons ( DNS_CLASS_IN );
-
-       while ( 1 ) {
-               /* Transmit current query, wait for reply */
-               query.dns.id = htons ( id++ );
-               qtype = ntohs ( query_info->qtype );
-               reply = dns_query ( &query,
-                                   ( ( ( char * ) query_info )
-                                     + sizeof ( *query_info )
-                                     - ( ( char * ) &query ) ),
-                                   &nameserver );
-               if ( ! reply ) {
-                       DBG ( "DNS got no response from server %@ (port %d)\n",
-                             nameserver.sin_addr.s_addr,
-                             nameserver.sin_port );
-                       return 0;
-               }
-
-               /* Search through response for useful answers.  Do
-                * this multiple times, to take advantage of useful
-                * nameservers which send us e.g. the CNAME *and* the
-                * A record for the pointed-to name.
-                */
-               while ( ( rr_info = dns_find_rr ( &query, reply ) ) ) {
-                       switch ( ntohs ( rr_info->type ) ) {
-                       case DNS_TYPE_A: {
-                               /* Found the target A record */
-                               struct dns_rr_info_a *rr_info_a =
-                                       ( struct dns_rr_info_a * ) rr_info;
-                               *addr = rr_info_a->in_addr;
-                               DBG ( "DNS found address %@\n", addr->s_addr );
-                               return 1; }
-                       case DNS_TYPE_CNAME: {
-                               /* Found a CNAME record - update the query */
-                               struct dns_rr_info_cname *rr_info_cname =
-                                       ( struct dns_rr_info_cname * ) rr_info;
-                               char *cname = rr_info_cname->cname;
-
-                               query_info = ( void * )
-                                       dns_decompress_name ( query.payload,
-                                                             cname, reply );
-                               DBG ( "DNS found CNAME %s\n",
-                                     dns_unmake_name ( query.payload ) );
-                               DBG ( "", /* Reconstruct name */
-                                     dns_make_name ( query.payload,
-                                                     query.payload + 1 ) );
-                               
-                               query_info->qtype = htons ( DNS_TYPE_A );
-                               query_info->qclass = htons ( DNS_CLASS_IN );
-
-                               if ( ++recursion > DNS_MAX_CNAME_RECURSION ) {
-                                       DBG ( "DNS recursion exceeded\n" );
-                                       return 0;
-                               }
-                               break; }
-                       default:
-                               DBG ( "DNS got unknown record type %d\n",
-                                     ntohs ( rr_info->type ) );
-                               return 0;
-                       }
-               }
-               
-               /* Determine what to do next based on the type of
-                * query we issued and the reponse we received
-                */
-               switch ( qtype ) {
-               case DNS_TYPE_A :
-                       /* We asked for an A record and got nothing;
-                        * try the CNAME.
-                        */
-                       DBG ( "DNS found no A record; trying CNAME\n" );
-                       query_info->qtype = htons ( DNS_TYPE_CNAME );
-                       break;
-               case DNS_TYPE_CNAME :
-                       /* We asked for a CNAME record.  If we didn't
-                        * get any response (i.e. the next A query
-                        * isn't already set up), then abort.
-                        */
-                       if ( query_info->qtype != htons ( DNS_TYPE_A ) ) {
-                               DBG ( "DNS found no CNAME record\n" );
-                               return 0;
-                       }
-                       break;
-               default:
-                       DBG ( "DNS internal error - inconsistent state\n" );
-               }
-       }
-}
-
-struct resolver dns_resolver __resolver = {
-       .name = "DNS",
-       .resolv = dns_resolv,
-};
index d294403..e1fc911 100644 (file)
@@ -1,6 +1,8 @@
+#if 0
+
 #include "resolv.h"
 #include "string.h"
-#include "dns.h"
+#include <gpxe/dns.h>
 #include "nic.h"
 #include "nmb.h"
 
@@ -104,3 +106,5 @@ struct resolver nmb_resolver __resolver = {
        .name = "NMB",
        .resolv = nmb_resolv,
 };
+
+#endif