david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Updated DNS to use not-yet-implemented UDP data-xfer API.

This commit is contained in:
Michael Brown 2007-06-11 23:30:44 +01:00
parent a74ecf3057
commit f87bc837f4
3 changed files with 123 additions and 128 deletions

View File

@ -9,8 +9,6 @@
#include <stdint.h> #include <stdint.h>
#include <gpxe/in.h> #include <gpxe/in.h>
#include <gpxe/async.h>
#include <gpxe/retry.h>
/* /*
* Constants * Constants
@ -89,29 +87,6 @@ union dns_rr_info {
struct dns_rr_info_cname cname; struct dns_rr_info_cname cname;
}; };
/** A DNS request */ extern struct sockaddr_tcpip nameserver;
struct dns_request {
/** Socket address to fill in with resolved address */
struct sockaddr *sa;
/** Current query packet */
struct dns_query query;
/** Length of current query packet */
struct dns_query_info *qinfo;
/** Recursion counter */
unsigned int recursion;
/** Asynchronous operation */
struct async async;
/** UDP connection */
struct udp_connection udp;
/** Retry timer */
struct retry_timer timer;
};
extern struct in_addr nameserver;
extern int dns_resolv ( const char *name, struct sockaddr *sa,
struct async *parent );
#endif /* _GPXE_DNS_H */ #endif /* _GPXE_DNS_H */

View File

@ -153,6 +153,13 @@ struct resolver {
#define __resolver( resolv_order ) \ #define __resolver( resolv_order ) \
__table ( struct resolver, resolvers, resolv_order ) __table ( struct resolver, resolvers, resolv_order )
extern void resolv_done ( struct resolv_interface *resolv,
struct sockaddr *sa, int rc );
extern void ignore_resolv_done ( struct resolv_interface *resolv,
struct sockaddr *sa, int rc );
extern struct resolv_interface_operations null_resolv_ops;
struct resolv_interface null_resolv;
extern int resolv ( struct resolv_interface *resolv, const char *name, extern int resolv ( struct resolv_interface *resolv, const char *name,
struct sockaddr *sa ); struct sockaddr *sa );

View File

@ -24,9 +24,12 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <byteswap.h> #include <byteswap.h>
#include <gpxe/async.h> #include <gpxe/refcnt.h>
#include <gpxe/udp.h> #include <gpxe/xfer.h>
#include <gpxe/open.h>
#include <gpxe/resolv.h> #include <gpxe/resolv.h>
#include <gpxe/retry.h>
#include <gpxe/tcpip.h>
#include <gpxe/dns.h> #include <gpxe/dns.h>
/** @file /** @file
@ -35,8 +38,54 @@
* *
*/ */
/* The DNS server */ /** The DNS server */
struct in_addr nameserver = { INADDR_NONE }; struct sockaddr_tcpip nameserver = {
.st_port = htons ( DNS_PORT ),
};
/** A DNS request */
struct dns_request {
/** Reference counter */
struct refcnt refcnt;
/** Name resolution interface */
struct resolv_interface resolv;
/** Data transfer interface */
struct xfer_interface socket;
/** Retry timer */
struct retry_timer timer;
/** Socket address to fill in with resolved address */
struct sockaddr sa;
/** Current query packet */
struct dns_query query;
/** Location of query info structure within current packet
*
* The query info structure is located immediately after the
* compressed name.
*/
struct dns_query_info *qinfo;
/** Recursion counter */
unsigned int recursion;
};
/**
* 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 data transfer interface */
xfer_nullify ( &dns->socket );
xfer_close ( &dns->socket, rc );
/* Mark name resolution as complete */
resolv_done ( &dns->resolv, &dns->sa, rc );
}
/** /**
* Compare DNS reply name against the query name from the original request * Compare DNS reply name against the query name from the original request
@ -47,7 +96,8 @@ struct in_addr nameserver = { INADDR_NONE };
* @ret zero Names match * @ret zero Names match
* @ret non-zero Names do not match * @ret non-zero Names do not match
*/ */
static int dns_name_cmp ( struct dns_request *dns, struct dns_header *reply, static int dns_name_cmp ( struct dns_request *dns,
const struct dns_header *reply,
const char *rname ) { const char *rname ) {
const char *qname = dns->query.payload; const char *qname = dns->query.payload;
int i; int i;
@ -101,7 +151,7 @@ static const char * dns_skip_name ( const char *name ) {
* @ret rr DNS RR, or NULL if not found * @ret rr DNS RR, or NULL if not found
*/ */
static union dns_rr_info * dns_find_rr ( struct dns_request *dns, static union dns_rr_info * dns_find_rr ( struct dns_request *dns,
struct dns_header *reply ) { const struct dns_header *reply ) {
int i, cmp; int i, cmp;
const char *p = ( ( char * ) reply ) + sizeof ( struct dns_header ); const char *p = ( ( char * ) reply ) + sizeof ( struct dns_header );
union dns_rr_info *rr_info; union dns_rr_info *rr_info;
@ -179,7 +229,7 @@ static inline char * dns_unmake_name ( char *name ) {
* @v buf Buffer into which to decompress DNS name * @v buf Buffer into which to decompress DNS name
* @ret next Byte following decompressed DNS name * @ret next Byte following decompressed DNS name
*/ */
static char * dns_decompress_name ( struct dns_header *reply, static char * dns_decompress_name ( const struct dns_header *reply,
const char *name, char *buf ) { const char *name, char *buf ) {
int i, len; int i, len;
@ -198,31 +248,14 @@ static char * dns_decompress_name ( struct dns_header *reply,
return buf; 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 * Send next packet in DNS request
* *
* @v dns DNS request * @v dns DNS request
*/ */
static void dns_send_packet ( struct dns_request *dns ) { static int dns_send_packet ( struct dns_request *dns ) {
static unsigned int qid = 0; static unsigned int qid = 0;
size_t qlen;
/* Increment query ID */ /* Increment query ID */
dns->query.dns.id = htons ( ++qid ); dns->query.dns.id = htons ( ++qid );
@ -233,9 +266,9 @@ static void dns_send_packet ( struct dns_request *dns ) {
start_timer ( &dns->timer ); start_timer ( &dns->timer );
/* Send the data */ /* Send the data */
udp_send ( &dns->udp, &dns->query, qlen = ( ( ( void * ) dns->qinfo ) - ( ( void * ) &dns->query )
( ( ( void * ) dns->qinfo ) - ( ( void * ) &dns->query ) + sizeof ( dns->qinfo ) );
+ sizeof ( dns->qinfo ) ) ); return xfer_deliver_raw ( &dns->socket, &dns->query, qlen );
} }
/** /**
@ -258,18 +291,16 @@ static void dns_timer_expired ( struct retry_timer *timer, int fail ) {
/** /**
* Receive new data * Receive new data
* *
* @v udp UDP connection * @v socket UDP socket
* @v data Received data * @v data DNS reply
* @v len Length of received data * @v len Length of DNS reply
* @v st_src Partially-filled source address * @ret rc Return status code
* @v st_dest Partially-filled destination address
*/ */
static int dns_newdata ( struct udp_connection *conn, void *data, size_t len, static int dns_xfer_deliver_raw ( struct xfer_interface *socket,
struct sockaddr_tcpip *st_src __unused, const void *data, size_t len ) {
struct sockaddr_tcpip *st_dest __unused ) {
struct dns_request *dns = struct dns_request *dns =
container_of ( conn, struct dns_request, udp ); container_of ( socket, struct dns_request, socket );
struct dns_header *reply = data; const struct dns_header *reply = data;
union dns_rr_info *rr_info; union dns_rr_info *rr_info;
struct sockaddr_in *sin; struct sockaddr_in *sin;
unsigned int qtype = dns->qinfo->qtype; unsigned int qtype = dns->qinfo->qtype;
@ -311,7 +342,7 @@ static int dns_newdata ( struct udp_connection *conn, void *data, size_t len,
/* Found the target A record */ /* Found the target A record */
DBGC ( dns, "DNS %p found address %s\n", DBGC ( dns, "DNS %p found address %s\n",
dns, inet_ntoa ( rr_info->a.in_addr ) ); dns, inet_ntoa ( rr_info->a.in_addr ) );
sin = ( struct sockaddr_in * ) dns->sa; sin = ( struct sockaddr_in * ) &dns->sa;
sin->sin_family = AF_INET; sin->sin_family = AF_INET;
sin->sin_addr = rr_info->a.in_addr; sin->sin_addr = rr_info->a.in_addr;
@ -380,71 +411,62 @@ static int dns_newdata ( struct udp_connection *conn, void *data, size_t len,
} }
} }
/** DNS UDP operations */
struct udp_operations dns_udp_operations = {
.newdata = dns_newdata,
};
/** /**
* Reap asynchronous operation * Receive new data
* *
* @v async Asynchronous operation * @v socket UDP socket
* @v rc Reason for close
*/ */
static void dns_reap ( struct async *async ) { static void dns_xfer_close ( struct xfer_interface *socket, int rc ) {
struct dns_request *dns = struct dns_request *dns =
container_of ( async, struct dns_request, async ); container_of ( socket, struct dns_request, socket );
free ( dns ); if ( ! rc )
rc = -ECONNABORTED;
dns_done ( dns, rc );
} }
/** /** DNS socket operations */
* Handle SIGKILL static struct xfer_interface_operations dns_socket_operations = {
* .close = dns_xfer_close,
* @v async Asynchronous operation .vredirect = xfer_vopen,
*/ .request = ignore_xfer_request,
static void dns_sigkill ( struct async *async, enum signal signal __unused ) { .seek = ignore_xfer_seek,
struct dns_request *dns = .alloc_iob = default_xfer_alloc_iob,
container_of ( async, struct dns_request, async ); .deliver_iob = xfer_deliver_as_raw,
.deliver_raw = dns_xfer_deliver_raw,
dns_done ( dns, -ECANCELED );
}
/** DNS asynchronous operations */
static struct async_operations dns_async_operations = {
.reap = dns_reap,
.signal = {
[SIGKILL] = dns_sigkill,
},
}; };
/** /**
* Resolve name using DNS * Resolve name using DNS
* *
* @v name Host name to resolve * @v resolv Name resolution interface
* @v name Name to resolve
* @v sa Socket address to fill in * @v sa Socket address to fill in
* @v parent Parent asynchronous operation
* @ret rc Return status code * @ret rc Return status code
*/ */
int dns_resolv ( const char *name, struct sockaddr *sa, static int dns_resolv ( struct resolv_interface *resolv,
struct async *parent ) { const char *name, struct sockaddr *sa ) {
struct dns_request *dns; struct dns_request *dns;
union {
struct sockaddr_tcpip st;
struct sockaddr_in sin;
} server;
int rc; int rc;
/* Fail immediately if no DNS servers */
if ( ! nameserver.st_family ) {
DBG ( "DNS not attempting to resolve \"%s\": "
"no DNS servers\n", name );
return -ENXIO;
}
/* Allocate DNS structure */ /* Allocate DNS structure */
dns = malloc ( sizeof ( *dns ) ); dns = malloc ( sizeof ( *dns ) );
if ( ! dns ) { if ( ! dns )
rc = -ENOMEM; return -ENOMEM;
goto err;
}
memset ( dns, 0, sizeof ( *dns ) ); memset ( dns, 0, sizeof ( *dns ) );
dns->sa = sa; resolv_init ( &dns->resolv, &null_resolv_ops, &dns->refcnt );
xfer_init ( &dns->socket, &dns_socket_operations, &dns->refcnt );
dns->timer.expired = dns_timer_expired; dns->timer.expired = dns_timer_expired;
dns->udp.udp_op = &dns_udp_operations; memcpy ( &dns->sa, sa, sizeof ( dns->sa ) );
async_init ( &dns->async, &dns_async_operations, parent );
/* Create query */ /* Create query */
dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY | 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,
dns->qinfo->qtype = htons ( DNS_TYPE_A ); dns->qinfo->qtype = htons ( DNS_TYPE_A );
dns->qinfo->qclass = htons ( DNS_CLASS_IN ); dns->qinfo->qclass = htons ( DNS_CLASS_IN );
/* Identify nameserver */ /* Open UDP connection */
memset ( &server, 0, sizeof ( server ) ); if ( ( rc = xfer_open_socket ( &dns->socket, SOCK_DGRAM,
server.sin.sin_family = AF_INET; ( struct sockaddr * ) &nameserver,
server.sin.sin_port = htons ( DNS_PORT ); NULL ) ) != 0 ) {
server.sin.sin_addr = nameserver; DBGC ( dns, "DNS %p could not open socket: %s\n",
if ( server.sin.sin_addr.s_addr == INADDR_NONE ) { dns, strerror ( rc ) );
DBGC ( dns, "DNS %p no name servers\n", dns );
rc = -ENXIO;
goto err; goto err;
} }
/* Open UDP connection */
DBGC ( dns, "DNS %p using nameserver %s\n", dns,
inet_ntoa ( server.sin.sin_addr ) );
udp_connect ( &dns->udp, &server.st );
if ( ( rc = udp_open ( &dns->udp, 0 ) ) != 0 )
goto err;
/* Send first DNS packet */ /* Send first DNS packet */
dns_send_packet ( dns ); dns_send_packet ( dns );
/* Attach parent interface, mortalise self, and return */
resolv_plug_plug ( &dns->resolv, resolv );
ref_put ( &dns->refcnt );
return 0; return 0;
err: err:
DBGC ( dns, "DNS %p could not create request: %s\n", ref_put ( &dns->refcnt );
dns, strerror ( rc ) );
async_uninit ( &dns->async );
free ( dns );
return rc; return rc;
} }