2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-09-02 15:25:48 +00:00

Preliminary rewrite of asynchronous DNS code (needs work)

This commit is contained in:
Ted Lemon
1998-01-12 01:00:09 +00:00
parent 1bf1747a17
commit eb0b66697b

View File

@@ -48,7 +48,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: dns.c,v 1.5 1997/11/29 07:51:49 mellon Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n"; "$Id: dns.c,v 1.6 1998/01/12 01:00:09 mellon Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@@ -64,6 +64,8 @@ static int nslookup PROTO ((u_int8_t, char *, int, u_int16_t, u_int16_t));
static int zonelookup PROTO ((u_int8_t, char *, int, u_int16_t)); static int zonelookup PROTO ((u_int8_t, char *, int, u_int16_t));
u_int16_t dns_port; u_int16_t dns_port;
struct dns_query *queries [65536];
/* Initialize the DNS protocol. */ /* Initialize the DNS protocol. */
void dns_startup () void dns_startup ()
@@ -151,16 +153,19 @@ static int copy_out_name (base, name, buf)
called with a null pointer. Otherwise, the callback is called with the called with a null pointer. Otherwise, the callback is called with the
address of the string returned by the name server. */ address of the string returned by the name server. */
int ns_inaddr_lookup (id, inaddr) struct dns_query *ns_inaddr_lookup (inaddr, wakeup)
u_int16_t id;
struct iaddr inaddr; struct iaddr inaddr;
struct dns_wakeup *wakeup;
{ {
unsigned char namebuf [512]; unsigned char question [512];
unsigned char *s = namebuf; unsigned char *s;
unsigned char *label; unsigned char *label;
int i; int i;
unsigned char c; unsigned char c;
s = question;
/* Copy out the digits. */
for (i = 3; i >= 0; --i) { for (i = 3; i >= 0; --i) {
label = s++; label = s++;
*label = 1; *label = 1;
@@ -178,140 +183,123 @@ int ns_inaddr_lookup (id, inaddr)
s += addlabel (s, "in-addr"); s += addlabel (s, "in-addr");
s += addlabel (s, "arpa"); s += addlabel (s, "arpa");
*s++ = 0; *s++ = 0;
/* return nslookup (id, namebuf, s - namebuf, T_PTR, C_IN); */
return zonelookup (id, namebuf, s - namebuf, C_IN); /* Set the query type. */
putUShort (s, T_PTR);
s += sizeof (u_int16_t);
/* Set the query class. */
putUShort (s, C_IN);
s += sizeof (u_int16_t);
return ns_query (question, s - question, wakeup);
} }
/* Construct and transmit a name server query. */ struct dns_query *ns_query (question, len, wakeup)
unsigned char *question;
static int nslookup (id, qname, namelen, qtype, qclass) int len;
u_int8_t id; struct dns_wakeup *wakeup;
char *qname;
int namelen;
u_int16_t qtype;
u_int16_t qclass;
{ {
HEADER *hdr; HEADER *hdr;
unsigned char query [512]; struct dns_query *query;
u_int8_t *s; unsigned char *s;
int len;
int i, status;
struct sockaddr_in *server = pick_name_server ();
if (!server) /* See if there's already a query for this name, and allocate a
return 0; query if none exists. */
query = find_dns_query (question, len, 1);
/* If we can't allocate a query, report that the query failed. */
if (!query) {
return (struct dns_query *)-1;
}
/* If the query has already been answered, return it. */
if (query -> expiry > cur_time)
return query;
/* The query hasn't yet been answered, so we have to wait, one
way or another. Put the wakeup on the list. */
if (wakeup) {
wakeup -> next = query -> wakeups;
query -> wakeups = wakeup;
}
/* If the query has already been sent, but we don't yet have
an answer, we're done. */
if (query -> sent)
return (struct dns_query *)0;
/* Construct a header... */ /* Construct a header... */
hdr = (HEADER *)query; hdr = (HEADER *)query -> buf;
memset (hdr, 0, sizeof *hdr); memset (hdr, 0, sizeof *hdr);
hdr -> id = htons (id); hdr -> id = query -> id;
hdr -> rd = 1; hdr -> rd = 1;
hdr -> opcode = QUERY; hdr -> opcode = QUERY;
hdr -> qdcount = htons (1); hdr -> qdcount = htons (1);
/* Copy in the name we're looking up. */ /* Copy the name into the buffer. */
s = (u_int8_t *)(hdr + 1); s = (unsigned char *)hdr + 1;
memcpy (s, qname, namelen); memcpy (s, question, len);
s += namelen; query -> question = s;
query -> question_len = len;
/* Set the query type. */ /* Figure out how long the whole message is */
putUShort (s, qtype); s += len;
s += sizeof (u_int16_t); query -> len = s - query -> buf;
/* Set the query class. */ /* Flag the query as having been sent. */
putUShort (s, qclass); query -> sent = 1;
s += sizeof (u_int16_t);
/* Send the query. */ /* Send the query. */
status = sendto (dns_protocol_fd, query, s - query, 0, dns_timeout (query);
(struct sockaddr *)server, sizeof *server);
/* If the send failed, report the failure. */ /* No answer yet, obviously. */
if (status < 0) return (struct dns_query *)0;
return 0;
return 1;
} }
/* Construct a query for the SOA for a specified name. /* Retransmit a DNS query. */
Try every possible SOA name starting from the name specified and going
to the root name - e.g., for
215.5.5.192.in-addr.arpa, look for SOAs matching: void dns_timeout (qv)
void *qv;
215.5.5.5.192.in-addr.arpa
5.5.192.in-addr.arpa
5.192.in-addr.arpa
192.in-addr.arpa
in-addr.arpa
arpa */
static int zonelookup (id, qname, namelen, qclass)
u_int8_t id;
char *qname;
int namelen;
u_int16_t qclass;
{ {
HEADER *hdr; struct dns_query *query = qv;
unsigned char query [512]; int status;
u_int8_t *s, *nptr;
int len;
int i, status, count;
struct sockaddr_in *server = pick_name_server ();
if (!server) /* Choose the server to send to. */
return 0; if (!query -> next_server)
query -> next_server = first_name_server ();
/* Construct a header... */
hdr = (HEADER *)query;
memset (hdr, 0, sizeof *hdr);
hdr -> id = htons (id);
hdr -> rd = 1;
hdr -> opcode = QUERY;
/* Copy in the name we're looking up. */
s = (u_int8_t *)(hdr + 1);
memcpy (s, qname, namelen);
s += namelen;
/* Set the query type. */
putUShort (s, T_SOA);
s += sizeof (u_int16_t);
/* Set the query class. */
putUShort (s, qclass);
s += sizeof (u_int16_t);
count = 1;
/* Now query up the hierarchy. */
nptr = (u_int8_t *)(hdr + 1);
while (*(nptr += *nptr + 1)) {
/* Store a compressed reference from the full name. */
putUShort (s, ntohs (htons (0xC000) |
htons (nptr - &query [0])));
s += sizeof (u_int16_t);
/* Store the query type. */
putUShort (s, T_SOA);
s += sizeof (u_int16_t);
putUShort (s, qclass);
s += sizeof (u_int16_t);
/* Increment the query count... */
++count;
break;
}
hdr -> qdcount = htons (count);
dump_raw (query, s - query);
/* Send the query. */ /* Send the query. */
status = sendto (dns_protocol_fd, query, s - query, 0, if (query -> next_server)
(struct sockaddr *)server, sizeof *server); status = sendto (dns_protocol_fd,
query -> buf, query -> len, 0,
((struct sockaddr *)&query ->
next_server -> addr),
sizeof query -> next_server -> addr);
else
status = -1;
/* If the send failed, report the failure. */ /* Look for the next server... */
if (status < 0) query -> next_server = query -> next_server -> next;
return 0;
return 1; /* If this is our first time, backoff one second. */
if (!query -> backoff)
query -> backoff = 1;
/* If the send failed, don't advance the backoff. */
else if (status < 0)
;
/* If we haven't run out of servers to try, don't backoff. */
else if (query -> next_server)
;
/* If we haven't backed off enough yet, back off some more. */
else if (query -> backoff < 30)
query -> backoff += random() % query -> backoff;
/* Set up the timeout. */
add_timeout (cur_time + query -> backoff, dns_timeout, query);
} }
/* Process a reply from a name server. */ /* Process a reply from a name server. */
@@ -321,83 +309,74 @@ void dns_packet (protocol)
{ {
HEADER *ns_header; HEADER *ns_header;
struct sockaddr_in from; struct sockaddr_in from;
int fl; struct dns_wakeup *wakeup;
unsigned char buf [4096]; unsigned char buf [512];
unsigned char nbuf [512];
unsigned char *base; unsigned char *base;
unsigned char *dptr; unsigned char *dptr, *name;
u_int16_t type; u_int16_t type;
u_int16_t class; u_int16_t class;
TIME ttl; TIME ttl;
u_int16_t rdlength; u_int16_t rdlength;
int len, status; int len, status;
int i; int i;
struct dns_query *query;
len = sizeof from; len = sizeof from;
status = recvfrom (protocol -> fd, buf, sizeof buf, 0, status = recvfrom (protocol -> fd, buf, sizeof buf, 0,
(struct sockaddr *)&from, &len); (struct sockaddr *)&from, &len);
if (status < 0) { if (status < 0) {
warn ("icmp_echoreply: %m"); warn ("dns_packet: %m");
return;
}
/* Response is too long? */
if (len > 512) {
warn ("dns_packet: dns message too long (%d)", len);
return; return;
} }
ns_header = (HEADER *)buf; ns_header = (HEADER *)buf;
base = (unsigned char *)(ns_header + 1); base = (unsigned char *)(ns_header + 1);
#if 0
/* Ignore invalid packets... */
if (ntohs (ns_header -> id) > ns_query_max) {
printf ("Out-of-range NS message; id = %d\n",
ntohs (ns_header -> id));
return;
}
#endif
/* Parse the response... */ /* Parse the response... */
dptr = base; dptr = base;
/* Skip over the queries... */ /* If this is a response to a query from us, there should have
for (i = 0; i < ntohs (ns_header -> qdcount); i++) { been only one query. */
dptr += skipname (dptr); if (ntohs (ns_header -> qdcount) != 1) {
/* Skip over the query type and query class. */ dns_bogus (buf, len);
dptr += 2 * sizeof (u_int16_t); return;
} }
/* Process the answers... */ /* Find the start of the name in the query. */
for (i = 0; i < ntohs (ns_header -> ancount); i++) { name = dptr;
/* Skip over the name we looked up. */
dptr += skipname (dptr);
/* Get the type. */ /* Skip over the name. */
type = getUShort (dptr); dptr += skipname (dptr);
dptr += sizeof type;
/* Get the class. */ /* Skip over the query type and query class. */
class = getUShort (dptr); dptr += 2 * sizeof (u_int16_t);
dptr += sizeof class;
/* Get the time-to-live. */ /* See if we asked this question. */
ttl = getULong (dptr); query = find_dns_query (name, dptr - name, 0);
dptr += sizeof ttl; if (!query) {
dns_bogus (buf, len);
return;
}
/* Get the length of the reply. */ /* Save the response. */
rdlength = getUShort (dptr); memcpy (buf, query -> buf, len);
dptr += sizeof rdlength;
switch (type) { /* Remember where the question is and how long it is. */
case T_A: query -> question = name;
note ("A record; value is %d.%d.%d.%d", query -> question_len = dptr - name;
dptr [0], dptr [1], dptr [2], dptr [3]);
break;
case T_CNAME: /* Remember where the answer is and how long it is. */
case T_PTR: query -> answer = dptr;
copy_out_name (base, dptr, nbuf); query -> answer_len = len - (dptr - buf);
note ("Domain name; value is %s\n", nbuf);
return;
default: /* Wake up everybody who's waiting. */
note ("unhandled type: %x", type); for (wakeup = query -> wakeups; wakeup; wakeup = wakeup -> next) {
} (*wakeup -> func) (query);
} }
} }