/* dns.c
- Domain Name Service subroutine. */
+ Domain Name Service subroutines. */
/*
* Copyright (C) 1992 by Ted Lemon.
* substantially modified for use in the Internet Software Consortium
* DHCP suite.
*
- * These later modifications were done on behalf of the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
+ * These later modifications were done on behalf of the Internet
+ * Software Consortium by Ted Lemon <mellon@fugue.com> in cooperation
+ * with Vixie Enterprises. To learn more about the Internet Software
+ * Consortium, see ``http://www.vix.com/isc''. To learn more about
+ * Vixie Enterprises, see ``http://www.vix.com''.
*/
#ifndef lint
static char copyright[] =
-"$Id: dns.c,v 1.1 1997/03/08 02:24:16 mellon Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n";
+"$Id: dns.c,v 1.2 1997/03/29 01:25:32 mellon Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
#include "arpa/nameser.h"
+int dns_protocol_initialized;
+int dns_protocol_fd;
+
+static int addlabel PROTO ((u_int8_t *, char *));
+static int skipname PROTO ((u_int8_t *));
+static int copy_out_name PROTO ((u_int8_t *, u_int8_t *, char *));
+
/* Initialize the DNS protocol. */
-void dns_startup (handler)
- void (*handler) PROTO ((struct iaddr, u_int8_t *, int));
+void dns_startup ()
{
- struct protoent *proto;
- int protocol = 1;
+ struct servent *srv;
+ u_int16_t dns_port = htons (53);
struct sockaddr_in from;
- int fd;
/* Only initialize icmp once. */
- if (icmp_protocol_initialized)
- error ("attempted to reinitialize icmp protocol");
- icmp_protocol_initialized = 1;
+ if (dns_protocol_initialized)
+ error ("attempted to reinitialize dns protocol");
+ dns_protocol_initialized = 1;
/* Get the protocol number (should be 1). */
- proto = getprotobyname ("icmp");
- if (proto)
- protocol = proto -> p_proto;
+ srv = getsrvbyname ("domain", "tcp");
+ if (srv)
+ port = srv -> s_port;
/* Get a raw socket for the ICMP protocol. */
- icmp_protocol_fd = socket (AF_INET, SOCK_RAW, protocol);
- if (!icmp_protocol_fd)
- error ("unable to create icmp socket: %m");
-
- if (setsockopt (icmp_protocol_fd, SOL_SOCKET, SO_DONTROUTE,
- (char *)&routep, sizeof routep))
- error ("Can't set SO_DONTROUTE on ICMP socket: %m");
+ dns_protocol_fd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (!dns_protocol_fd)
+ error ("unable to create dns socket: %m");
- add_protocol ("icmp", icmp_protocol_fd, icmp_echoreply, handler);
+ add_protocol ("dns", dns_protocol_fd, dns_packet, 0);
}
/* Label manipulation stuff; see RFC1035, page 28 section 4.1.2 and
the label in the first character, the contents of the label in subsequent
characters, and returning the length of the conglomeration. */
-addlabel (buf, label)
- unsigned char *buf;
- unsigned char *label;
+static int addlabel (buf, label)
+ u_int8_t *buf;
+ char *label;
{
- *buf = strlen (label);
- strcpy (buf + 1, label);
- return *buf + 1;
+ *buf = strlen (label);
+ memcpy (buf + 1, label, *buf);
+ return *buf + 1;
}
/* skipname skips over all of the labels in a single domain name,
returning the length of the domain name. */
-skipname (label)
- unsigned char *label;
+static int skipname (label)
+ u_int8_t *label;
{
- if (*label & INDIR_MASK)
- return 2;
- if (*label == 0)
- return 1;
- return *label + 1 + skipname (label + *label + 1);
+ if (*label & INDIR_MASK)
+ return 2;
+ if (*label == 0)
+ return 1;
+ return *label + 1 + skipname (label + *label + 1);
}
/* copy_out_name copies out the name appearing at the specified location
into a string, stored as fields seperated by dots rather than lengths
and labels. The length of the label-formatted name is returned. */
-copy_out_name (base, name, buf)
- unsigned char *base;
- unsigned char *name;
- unsigned char *buf;
+static int copy_out_name (base, name, buf)
+ u_int8_t *base;
+ u_int8_t *name;
+ char *buf;
{
- if (*name & INDIR_MASK)
- {
- int offset = (*name & ~INDIR_MASK) + (*name + 1);
- return copy_out_name (base, base + offset, buf);
- }
- if (!*name)
- {
- *buf = 0;
- return 1;
- }
- memcpy (buf, name + 1, *name);
- *(buf + *name) = '.';
- return *name + 1 + copy_out_name (base, name + *name + 1, buf + *name + 1);
+ if (*name & INDIR_MASK) {
+ int offset = (*name & ~INDIR_MASK) + (*name + 1);
+ return copy_out_name (base, base + offset, buf);
+ }
+ if (!*name) {
+ *buf = 0;
+ return 1;
+ }
+ memcpy (buf, name + 1, *name);
+ *(buf + *name) = '.';
+ return (*name + 1
+ + copy_out_name (base, name + *name + 1, buf + *name + 1));
}
/* ns_inaddr_lookup constructs a PTR lookup query for an internet address -
called with a null pointer. Otherwise, the callback is called with the
address of the string returned by the name server. */
-ns_inaddr_lookup (inaddr, timeout, callback)
- Address *inaddr;
- int timeout;
- void (*callback) (char *);
+int ns_inaddr_lookup (server, id, inaddr)
+ struct sockaddr_in *server;
+ u_int16_t id;
+ struct iaddr inaddr;
{
- unsigned char namebuf [MAXDNAME];
- unsigned char *s = namebuf;
- unsigned char *label;
- int i;
- unsigned char c;
-
- for (i = 3; i >= 0; --i)
- {
- label = s++;
- *label = 1;
- c = inaddr -> addr [i];
- if (c > 100)
- {
- ++*label;
- *s++ = '0' + c / 100;
+ unsigned char namebuf [512];
+ unsigned char *s = namebuf;
+ unsigned char *label;
+ int i;
+ unsigned char c;
+
+ for (i = 3; i >= 0; --i) {
+ label = s++;
+ *label = 1;
+ c = inaddr -> addr [i];
+ if (c > 100) {
+ ++*label;
+ *s++ = '0' + c / 100;
+ }
+ if (c > 10) {
+ ++*label;
+ *s++ = '0' + ((c / 10) % 10);
+ }
+ *s++ = '0' + (c % 10);
}
- if (c > 10)
- {
- ++*label;
- *s++ = '0' + ((c / 10) % 10);
- }
- *s++ = '0' + (c % 10);
- }
- s += addlabel (s, "in-addr");
- s += addlabel (s, "arpa");
- *s = 0;
- nslookup (namebuf, T_PTR, C_IN, timeout, callback);
+ s += addlabel (s, "in-addr");
+ s += addlabel (s, "arpa");
+ *s++ = 0;
+ return nslookup (server, id, namebuf, s - namebuf, T_PTR, C_IN);
}
-nslookup (qname, qtype, qclass, timeout, callback)
- char *qname;
- int qtype;
- int qclass;
- int timeout;
- void (*callback) (char *);
-{
- HEADER hdr;
- unsigned char buf [MTUSIZE];
- unsigned char query [PACKETSZ];
- unsigned char *s;
- int len;
- void ns_timeout ();
- int i;
-
- /* Construct a query ID... */
- do
- ns_query_id = random ();
- while (ns_query_id < 2048);
-
- memset (&hdr, 0, sizeof hdr);
- hdr.id = ns_query_id;
- hdr.rd = 1;
- hdr.opcode = QUERY;
- hdr.qdcount = 1;
- nsswap (&hdr);
-
- memcpy (query, &hdr, sizeof hdr);
- len = sizeof hdr;
-
- strcpy (&query [len], qname);
- len += strlen (qname) + 1;
-
- s = &query [len];
- PUTSHORT (qtype, s);
- len += sizeof (short);
- PUTSHORT (qclass, s);
- len += sizeof (short);
- /* Tack on an extra zero for the checksummer... */
- *s++ = 0;
-
- /* Create the packet header... */
- len = build_udp_packet (buf, sizeof buf, query, len,
- ns_query_id, NAMESERVER_PORT,
- &myiaddr, &nsiaddr);
-
- /* Save the callback vector... */
- ns_callback = callback;
-
- /* Push a packet out, retrying in an exponential decay starting
- with one second, and time out when the user specifies... */
- pushpacket (buf, len, (void (*) (char *, int))0, ns_timeout, timeout, 1);
-}
+/* Construct and transmit a name server query. */
-void ns_timeout ()
+int nslookup (server, id, qname, namelen, qtype, qclass)
+ struct sockaddr_in *server;
+ u_int8_t id;
+ char *qname;
+ int namelen;
+ u_int16_t qtype;
+ u_int16_t qclass;
{
- void (*callback) (char *) = ns_callback;
- ns_callback = (void (*) (char *))0;
- ns_query_id = 0;
- (*callback) ((char *)0);
+ HEADER *hdr;
+ unsigned char query [512];
+ unsigned char *s;
+ int len;
+ int i;
+
+ /* Construct a header... */
+ hdr = (HEADER *)query;
+ memset (&hdr, 0, sizeof hdr);
+ hdr -> id = htons (id);
+ hdr -> rd = 1;
+ hdr -> opcode = QUERY;
+ hdr -> qdcount = htons (1);
+
+ /* 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, qtype);
+ s += sizeof (u_int16_t);
+
+ /* Set the query class. */
+ putUShort (s, qclass);
+ s += sizeof (u_int16_t);
+
+ /* Send the query. */
+ status = sendto (dns_protocol_fd, query, s - query, 0,
+ (struct sockaddr *)server, sizeof *server);
+
+ /* If the send failed, report the failure. */
+ if (status < 0)
+ return 0;
+ return 1;
}
-ns_packet (ns_header, udp, ip, machine_header)
- HEADER *ns_header;
- struct udphdr *udp;
- struct ip *ip;
- unsigned char *machine_header;
+/* Process a reply from a name server. */
+
+dns_packet (protocol)
+ struct protocol *protocol;
{
- unsigned char *base = (unsigned char *)(ns_header + 1);
- unsigned char *dptr;
- void (*callback) (char *) = ns_callback;
- int type;
- int class;
- int ttl;
- int rdlength;
- char nbuf [MAXDNAME];
+ HEADER *ns_header;
+ struct sockaddr_in from;
+ int fl;
+ unsigned char buf [4096];
+ unsigned char nbuf [512];
+ unsigned char *base;
+ unsigned char *dptr;
+ int type;
+ int class;
+ int ttl;
+ int rdlength;
+ char nbuf [MAXDNAME];
+
+ len = sizeof from;
+ status = recvfrom (protocol -> fd, icbuf, sizeof icbuf, 0,
+ (struct sockaddr *)&from, &len);
+ if (status < 0) {
+ warn ("icmp_echoreply: %m");
+ return;
+ }
- nsswap (ns_header);
+ ns_header = (HEADER *)buf;
+ base = (unsigned char *)(ns_header + 1);
/* Ignore invalid packets... */
- if (ns_header -> id != ns_query_id)
- {
- printf ("Unexpected NS message; id = %d\n", ns_header -> id);
- return;
- }
-
- /* We have our response, so shut down the protocol... */
- ns_callback = (void (*) (char *))0;
- ns_query_id = 0;
- stop_pushing ();
+ if (ntohs (ns_header -> id) > ns_query_max) {
+ printf ("Out-of-range NS message; id = %d\n",
+ ntohs (ns_header -> id));
+ return;
+ }
/* Parse the response... */
- dptr = base;
+ dptr = base;
/* Skip over the query name... */
- dptr += skipname (dptr);
+ dptr += skipname (dptr);
/* Skip over the query type and the query class. */
- dptr += 2 * sizeof (short);
+ dptr += 2 * sizeof (short);
/* Skip over the reply name... */
- dptr += skipname (dptr);
+ dptr += skipname (dptr);
/* Extract the numeric fields: */
- GETSHORT (type, dptr);
- GETSHORT (class, dptr);
- GETLONG (ttl, dptr);
- GETSHORT (rdlength, dptr);
-
- switch (type)
- {
- case T_A:
- printf ("A record; value is ");
- printiaddr (dptr);
- if (callback)
- (*callback) (dptr);
- break;
-
- case T_CNAME:
- case T_PTR:
- copy_out_name (base, dptr, nbuf);
- printf ("Domain name; value is %s\n", nbuf);
- if (callback)
- (*callback) (nbuf);
- return;
-
-#ifdef T_TXT
- case T_TXT:
- printf ("Text string; value is %s\n", dptr);
- if (callback)
- (*callback) (dptr);
- break;
-#endif /* T_TXT */
-
- default:
- printf ("unhandled type: %x\n", type);
- }
-
- if (callback)
- (*callback) ((char *)1);
-}
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-nsswap (hdr)
- HEADER *hdr;
-{
- shortswap (hdr -> opcode);
- shortswap (hdr -> qdcount);
- shortswap (hdr -> ancount);
- shortswap (hdr -> nscount);
- shortswap (hdr -> arcount);
+ getUShort (dptr, (u_int8_t *)&type);
+ dptr += sizeof type;
+ getULong (dptr, (u_int8_t *)&class);
+ dptr += sizeof class;
+ getULong (dptr, (u_int8_t *)&ttl);
+ dptr += sizeof ttl;
+ getUShort (dptr, (u_int8_t *)&rdlength);
+ dptr += sizeof rdlength;
+
+ switch (type) {
+ case T_A:
+ printf ("A record; value is %d.%d.%d.%d",
+ dptr [0], dptr [1], dptr [2], dptr [3]);
+ break;
+
+ case T_CNAME:
+ case T_PTR:
+ copy_out_name (base, dptr, nbuf);
+ printf ("Domain name; value is %s\n", nbuf);
+ return;
+
+ default:
+ printf ("unhandled type: %x\n", type);
+ }
}
-#endif