mirror of https://github.com/ipxe/ipxe.git
Updated DNS to use not-yet-implemented UDP data-xfer API.
parent
a74ecf3057
commit
f87bc837f4
|
@ -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 */
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue