sheerdns/ 0040755 0000000 0000000 00000000000 10202743037 011371 5 ustar root root sheerdns/Makefile 0100644 0001236 0000012 00000001074 07645744231 012302 0 ustar wheel
CFLAGS=-Wall -g -O0 -ansi -pedantic
SRCS=$(wildcard *.c)
all: sheerdns sheerdnshash sheerdns.ps
OBJECTS=$(SRCS:.c=.o)
sheerdns: $(OBJECTS)
gcc -o sheerdns $(OBJECTS)
sheerdnshash: hash.c
gcc $(CFLAGS) -o sheerdnshash hash.c -DSTANDALONE -Wall
.c.o: $(SRCS)
gcc $(CFLAGS) -c $<
clean:
rm -f sheerdns sheerdnshash *.o
distclean: clean
rm -f core *~ sheerdns.ps *.diss
sheerdns.ps:
groff -Tps -mandoc sheerdns.8 > sheerdns.ps
install: all
install sheerdnshash sheerdns /usr/sbin/
install sheerdns.8 /usr/share/man/man8/
install sheerdns.8 /usr/man/man8/
sheerdns/dir.c 0100644 0000000 0000000 00000007336 10202740245 012317 0 ustar root root #include
#include
#include
#include
#include
#include
#include
#include
#include "strutil.h"
#include "dir.h"
#include "hash.h"
const char *qtype_name[] = {
NULL, "A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG", "MR", "NULL", "WKS", "PTR", "HINFO",
"MINFO", "MX", "TXT", "RP", "AFSDB", "X25", "ISDN", "RT", "NSAP", "NSAP_PTR", "SIG", "KEY", "PX",
"GPOS", "AAAA", "LOC", "NXT", "EID", "NIMLOC", "SRV", "ATMA", "NAPTR", "KX", "CERT", "A6", "DNAME",
"SINK", "OPT",
};
/* special reformatting of ptr address - reverse the name:
"2.1.168.192.in-addr.arpa\0" becomes "192.168.1.2\0" */
static char *
try_reverse_in_arpa (char *query) {
int k, c;
char new_query[16] = "";
char *t;
if (strlen (query) < 12)
return (char *) strdup (query);
if (!(t = strstr ((char *) query, "in-addr.arpa")))
return (char *) strdup (query);
k = c = (t - query) - 1;
if (k > 16)
return (char *) strdup (query);
for (; k >= 0; k--)
if (k == 0 || query[k - 1] == '.') {
strncat ((char *) new_query, (char *) query + k, c - k);
k && strcat ((char *) new_query, ".");
c = --k; }
return (char *) strdup (new_query); }
static int
get_file_name (char *buf, int len, int qtype, unsigned char *s) {
if (qtype < 1 || qtype > 41)
return 1;
s = (unsigned char *) try_reverse_in_arpa ((char *) s);
if (*s)
snprintf (buf, len, SHEERDNS_DIR "/%s/%s/%s", hex_hash (s), s, qtype_name[qtype]);
else
snprintf (buf, len, SHEERDNS_DIR "/%s", qtype_name[qtype]);
free (s);
return 0; }
static void
round_robin (char **s) {
int n, i;
char *t;
for (n = 0; s[n]; n++);
for (i = 0; i < n * 2; i++) {
int e;
e = (long) random () % n;
t = s[i % n];
s[i % n] = s[e];
s[e] = t; }}
char **
directory_lookup (int qtype, unsigned char *s) {
int fd = -1, c, i;
char buf[1024];
char **r, *q = (char *) s;
/* if this is an SOA or NS lookup, we descend through the
domains for any that we are an authority for. this allows
the user to create one NS entry for say test.com and have
that returned as the NS for www.test.com,
ftp.henry.test.com, user1.lab.chemsitry.test.com, etc. :
*/
while (!get_file_name (buf, sizeof (buf), qtype, (unsigned char *) q)
&& (fd = open (buf, O_RDONLY)) == -1 && (q = strchr (q, '.')) && q++ && (qtype == REQ_SOA
|| qtype == REQ_NS));
if (fd == -1) {
/* try lookup "*.example.com" where asking for "nonexistant.example.com": */
char *t;
if (qtype == REQ_SOA || qtype == REQ_NS) /* probably a bad idea to wildcard these, so return */
return NULL;
q = t = (char *) strdup (s);
while (*t && *t != '.')
t++;
if (!*t || t == q || !(*--t = '*') || get_file_name (buf, sizeof (buf), qtype, (unsigned char *) t)
|| (fd = open (buf, O_RDONLY)) == -1) {
free (q);
return NULL; }
free (q); }
/* done finding and opening the file, now read the contents: */
c = read (fd, buf, sizeof (buf));
close (fd);
if (c <= 0 || c == sizeof (buf))
return NULL;
buf[c] = '\0';
if (!(r = string_split (buf, '\n', 1000, 1)))
return NULL;
if (!r[0]) { /* is this possible? */
free (r);
return NULL; }
for (i = 0; r[i]; i++) {
string_chomp ((unsigned char *) r[i]);
if (qtype == REQ_TXT)
string_wash ((unsigned char *) r[i]);
else
string_purify ((unsigned char *) r[i]);
if (!*(r[i])) {
free (r);
return NULL; }}
if (qtype == REQ_A || qtype == REQ_NS)
round_robin (r);
return r; }
time_t
get_mtime (int qtype, unsigned char *s) {
struct stat st;
char buf[1024];
if (get_file_name (buf, sizeof (buf), qtype, s))
abort ();
if (stat (buf, &st))
return (time_t) 1000000000UL;
return st.st_mtime; }
sheerdns/dir.h 0100644 0000000 0000000 00000000425 07645744253 012340 0 ustar root root
#define REQ_A 1
#define REQ_NS 2
#define REQ_CNAME 5
#define REQ_SOA 6
#define REQ_PTR 12
#define REQ_MX 15
#define REQ_TXT 16
char **directory_lookup (int qtype, unsigned char *s);
time_t get_mtime (int qtype, unsigned char *s);
#define SHEERDNS_DIR "/var/sheerdns"
sheerdns/strutil.c 0100644 0000000 0000000 00000003232 07646272605 013260 0 ustar root root #include
#include
#include
#include
#include "strutil.h"
void
string_wash (unsigned char *p) {
unsigned char *q;
int n;
assert (p);
for (n = 0, q = p; *q && n < MAX_RECORD_LEN; q++, n++)
if (!issuspect (*q))
*p++ = *q;
*p = '\0'; }
void
string_purify (unsigned char *p) {
unsigned char *q;
int n;
assert (p);
for (n = 0, q = p; *q && n < MAX_RECORD_LEN; q++, n++)
if (!isevil (*q))
*p++ = *q;
*p = '\0'; }
void
string_chomp (unsigned char *p) {
unsigned char *q, *t;
assert (p);
/* skip over leading spaces */
for (q = p; *q; q++)
if (!isspace (*q))
break;
/* skip over non-space */
for (t = p; *q;)
if (!isspace (*p++ = *q++))
t = p;
/* truncate trailing space */
*t = '\0'; }
/* this is quite possibly my favorite function in the whole world */
char **
string_split (const char *s, char c, size_t max, int multi) {
char *p, **a;
int n;
for (n = 0, p = (char *) s; *p && n < max; n++) {
while (*p && *p != c)
p++;
if (multi) {
while (*p && *p == c)
p++; }
else if (*p)
p++; }
if (!(a = malloc ((n + 1) * sizeof (char *) + strlen (s) + 1)))
return 0;
p = (char *) (&(a[n + 1]));
for (n = 0; *s && n < max; n++) {
a[n] = p;
while (*s && *s != c)
*p++ = *s++;
if (multi) {
*p = '\0';
while (*s && *s == c) {
*p++ = '\0';
s++; }}
else if (*s) {
*p++ = '\0';
if (*s == c)
s++; }
else {
*p = '\0'; }}
a[n] = 0;
return a; }
int
string_present (char *s, char **a) {
int i;
for (i = 0; a[i]; i++)
if (!strcmp (a[i], s))
return 1;
return 0; }
sheerdns/strutil.h 0100644 0000000 0000000 00000001032 07646272442 013260 0 ustar root root
void string_purify (unsigned char *s);
void string_chomp (unsigned char *s);
char **string_split (const char *s, char c, size_t max, int multi);
int string_present (char *s, char **a);
/* See section 2.3.1, "Preferred name syntax", of RFC-1035 : */
#define MAX_RECORD_LEN 255
#define isevil(c) \
(!( \
((c) >= 'a' && (c) <= 'z') \
|| ((c) >= 'A' && (c) <= 'Z') \
|| ((c) >= '0' && (c) <= '9') \
|| (c) == '.' \
|| (c) == '-' \
))
#define issuspect(c) ((c) < ' ' || (c) > '~' || (c) == '/')
sheerdns/hash.c 0100644 0000000 0000000 00000001274 07645744253 012503 0 ustar root root #include
#include
#include
#include
#include
#include
#include "hash.h"
#include "dir.h"
char *
hex_hash (unsigned char *s) {
static char h[4];
unsigned long r = 0;
for (; *s; s++)
r += *s;
snprintf (h, sizeof (h), "%2.2X", (unsigned int) (r & 0xFFUL));
return h; }
#ifdef STANDALONE
int
main (int argc, char **argv) {
if (argc > 1) {
char buf[1024];
int l;
unsigned char *s;
s = (unsigned char *) hex_hash ((unsigned char *) argv[1]);
snprintf (buf, sizeof (buf), SHEERDNS_DIR "/%s/%s", s, argv[1]);
mkdir (buf);
l = strlen ((char *) s);
write (1, s, l);
write (1, "\n", 1); }
return 0; }
#endif
sheerdns/hash.h 0100644 0000000 0000000 00000000045 07610627044 012471 0 ustar root root
char *hex_hash (unsigned char *s);
sheerdns/ChangeLog 0100644 0000000 0000000 00000000227 10202742254 013141 0 ustar root root Thu 10 Feb 2005 10:31:26 PM SAST
* dir.c: added wildcard support
Sun 13 Apr 2003 04:39:49 PM SAST
* touchdns.c, strutil.c, dir.c: security fixes
sheerdns/sockutil.c 0100644 0000000 0000000 00000002142 07645744652 013413 0 ustar root root #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int
listen_socket (char *iface_addr, int listen_port, char *type) {
struct sockaddr_in a;
int s;
if ((s = socket (AF_INET, *type == 'T' ? SOCK_STREAM : SOCK_DGRAM, 0)) < 0) {
perror ("socket() failed");
return -1; }
#ifdef SO_REUSEADDR
{
int yes = 1;
if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof (yes)) < 0) {
perror ("setsockopt() failed");
close (s);
return -1; }}
#endif
memset (&a, 0, sizeof (a));
a.sin_port = htons (listen_port);
a.sin_family = AF_INET;
if (!inet_aton (iface_addr, &a.sin_addr)) {
perror ("bad iface address");
close (s);
return -1; }
if (bind (s, (struct sockaddr *) &a, sizeof (a)) < 0) {
perror ("bind() failed");
close (s);
return -1; }
listen (s, 50);
printf ("accepting %s packets on addr:port %s:%d\n", *type == 'T' ? "TCP" : "UDP", iface_addr, (int) listen_port);
return s; }
sheerdns/sockutil.h 0100644 0000000 0000000 00000000104 07610627057 013403 0 ustar root root
int listen_socket (char *iface_addr, int listen_port, char *type);
sheerdns/sheerdns.c 0100644 0000000 0000000 00000046702 10202743037 013356 0 ustar root root #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "sockutil.h"
#include "strutil.h"
#include "dir.h"
#define xfree(x) do { if ((x) && ((char *) (x)) != (char *) extra_results) free(x); (x) = NULL; } while (0)
#define max(a,b) ((a) > (b) ? (a) : (b))
typedef unsigned char u1;
typedef unsigned short u2;
typedef unsigned int u4;
static void make_directories (void);
static int process_packet (int s, u1 * in_buf, int packet_len, char *how, struct sockaddr *from, int fromlen);
enum {
ANSWERS = 0,
SERVERS = 1,
EXTRAS = 2,
ANS_BLOCKS = 3
};
#define ONE_DAY (24 * 60 * 60)
#define THREE_DAYS (3 * 24 * 60 * 60)
static u4 short_time = ONE_DAY;
#define TTL_POLICY(q) (((q) == REQ_SOA || (q) == REQ_NS) ? THREE_DAYS : short_time)
/* the following values are meaningless, since they all apply to
secondary DNS servers, and we are not using them: */
#define REFRESH (10 * 60)
#define RETRY (10 * 60)
#define EXPIRE (THREE_DAYS)
#define MINTTL short_time
static int
put_name (u1 * buf, u1 ** here, u1 * name) {
unsigned int c;
int i, k, n, offset;
offset = *here - buf;
k = 0;
while ((c = name[k]) != 0) {
n = 0;
while ((c = name[k + n]) != 0 && c != '.')
n++;
if (n == 0)
break;
*(*here)++ = (unsigned char) (n & ~0xc0);
for (i = 0; i < n; i++)
*(*here)++ = name[k++];
if (name[k] == '.')
k++; }
*(*here)++ = 0;
return offset; }
#define lower_case(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) | 0x20) : (c))
static int
get_name (u1 * msg, u1 ** here, u1 * end, unsigned char *string, int string_len, int k) {
unsigned int len;
int i;
if (*here >= end)
return -1;
while ((len = **here) != 0) {
*here += 1;
if ((len & 0xc0) == 0xc0) {
unsigned int offset;
u1 *p;
if (*here >= end)
return -1;
offset = ((len & ~0xc0) << 8) + **here;
p = &msg[offset];
k = get_name (msg, &p, end, string, string_len, k);
if (k == -1)
return k;
break; }
else if ((len & 0xc0)) {
return -1; }
else {
for (i = 0; i < len; i++) {
if (*here >= end)
return -1;
if (k < string_len - 1) {
if (isevil (**here))
return -1;
string[k++] = lower_case (**here);
}
*here += 1; }
if (k < string_len - 1)
string[k++] = '.'; }}
*here += 1;
string[k] = '\0';
return k; }
void
interrupt (int x) {
write (2, "exiting\n", 8);
exit (2); }
struct connection {
struct connection *next;
u1 *buf;
int fd;
u2 last_activity, len, alloced; };
static struct connection connections = { NULL, (u1 *) "first list item not used" };
int
main (int argc, char **argv) {
int s, t, fork_twice = 0;
u2 port = 53;
u1 in_buf[1536]; /* cannot get packets bigger than this on ethernet */
char *listen_interface = "0.0.0.0";
if (argc > 1) {
int k;
for (k = 1; k < argc; k++) {
if (!strncmp (argv[k], "-d", 2)) {
fork_twice = 1;
continue; }
if (argv[k][0] == '-' && k > argc - 2)
goto usage;
if (!strncmp (argv[k], "-ttl", 4))
short_time = (u4) atol (argv[++k]);
else if (!strncmp (argv[k], "-p", 2))
port = (u2) atol (argv[++k]);
else if (!strncmp (argv[k], "-i", 2))
listen_interface = argv[++k];
else if (argv[k][0] == '-') {
usage:
fprintf (stderr, "Usage:\n\tsheerdns [-ttl ] [-p ] [-i ] [-d]\n\n");
exit (1); }}}
make_directories ();
signal (SIGINT, interrupt);
signal (SIGPIPE, SIG_IGN);
signal (SIGHUP, SIG_IGN);
#ifdef SIGTSTP
signal (SIGTSTP, SIG_IGN);
#endif
#ifdef SIGURG
signal (SIGURG, SIG_IGN);
#endif
s = listen_socket (listen_interface, port, "UDP");
if (s < 0)
exit (1);
t = listen_socket (listen_interface, port, "TCP");
if (t < 0)
exit (1);
if (fork_twice) {
if (fork () > 0)
exit (0);
if (fork () > 0)
exit (0); }
while (1) {
struct connection *c, *d;
fd_set fdset;
int r, f_max;
time_t current_time_time_t;
u2 current_time;
FD_ZERO (&fdset);
FD_SET (s, &fdset);
FD_SET (t, &fdset);
f_max = max (s, t);
#define killtcp(c) \
do { \
struct connection *tmp; \
shutdown ((c)->fd, 2), close ((c)->fd); \
tmp = (c)->next, free (c->buf), free (c), (c) = tmp;\
} while (0)
for (c = &connections; c->next;) {
d = c->next;
if ((u2) current_time - d->last_activity > (u2) 30) { /* idle to long ? */
killtcp (c->next);
continue; }
else {
f_max = max (f_max, d->fd);
FD_SET (d->fd, &fdset); }
c = c->next; }
r = select (f_max + 1, &fdset, NULL, NULL, NULL);
if (r < 0) {
perror ("select");
exit (1); }
if (r == 0) { /* should not be possible */
FD_ZERO (&fdset); }
time (¤t_time_time_t);
current_time = (u2) (current_time_time_t & 0xFFFF);
/* check to add a new TCP connection: */
if (FD_ISSET (t, &fdset)) {
struct sockaddr_in from;
int fromlen = sizeof (from);
int fd;
memset (&from, 0, fromlen);
fd = accept (t, (struct sockaddr *) &from, (void *) &fromlen);
if (fd < 0) {
perror ("accept"); }
else {
c = (struct connection *) malloc (sizeof (struct connection));
c->fd = fd, c->last_activity = current_time;
c->len = 0, c->alloced = 2, c->buf = malloc (c->alloced);
c->next = connections.next;
connections.next = c; }}
/* check all current TCP connections */
for (c = &connections; c->next;) {
d = c->next;
if (FD_ISSET (d->fd, &fdset)) { /* got data? */
r = read (d->fd, d->buf + d->len, d->alloced - d->len);
if (r <= 0 || (!d->len && r != 2 /* first read must be exactly 2 bytes */ )) {
killtcp (c->next);
continue; }
d->len += r;
d->last_activity = current_time;
if (d->len == 2) { /* first process the packet size bytes */
u2 l;
l = (((u2) d->buf[0] << 8) | d->buf[1]);
if (l > 1024) {
killtcp (c->next);
continue; }
d->alloced = l + 2; /* add two bytes for the packet length */
d->buf = realloc (d->buf, d->alloced); }
else if (d->len == d->alloced) {
if (process_packet (d->fd, d->buf + 2, d->len - 2, "TCP", NULL, 0) < d->len) {
killtcp (c->next);
continue; }
d->len = 0, d->alloced = 2;
d->buf = realloc (d->buf, d->alloced); }} /* ready for next packet */
c = c->next; }
if (FD_ISSET (s, &fdset)) {
struct sockaddr_in from;
int fromlen = sizeof (from);
r = recvfrom (s, in_buf, sizeof (in_buf), 0, (struct sockaddr *) &from, (void *) &fromlen);
if (r > 0) {
memset (in_buf + r, 0, sizeof (in_buf) - r);
process_packet (s, in_buf, r, "UDP", (struct sockaddr *) &from, fromlen); }}}}
#define er(s) do { fprintf (stderr, "%s\n", #s); return -1; } while (0)
#define MAX_EXTRA_RESULTS 64
static int
process_packet (int s, u1 * in_buf, int packet_len, char *how, struct sockaddr *from, int fromlen) {
u1 _out_buf[1536 + 2]; /* cannot get packets bigger than this on ethernet */
u1 *out_buf = &_out_buf[2];
u1 query[MAX_RECORD_LEN + 1];
char *extra_results[MAX_EXTRA_RESULTS];
char *extra_queries[MAX_EXTRA_RESULTS];
u4 extra_ttls[MAX_EXTRA_RESULTS];
int query_len, name_pointer, i, j, extra_results_len = 0;
u2 id, flags, nqueries, nanswers, nservers, nextras, qtype = 0, orig_qtype = 0, qclass = 0, name_len, *p2;
u1 *p1, *len_pointer;
/* RFC-1035 says size limit of 512 - we make ours 1024 for both UDP and TCP */
if (packet_len < 12 || packet_len > 1024)
er (invalid packet size);
p2 = (u2 *) in_buf;
id = ntohs (p2[0]);
flags = ntohs (p2[1]);
/* get number of queries */
if (!(nqueries = ntohs (p2[2])))
er (no queries);
/* get the query string */
p1 = in_buf + 12;
memset (query, 0, sizeof (query));
if (get_name (in_buf, &p1, in_buf + packet_len, query, sizeof (query), 0) == -1)
er (bad query format);
query_len = strlen ((char *) query);
if (*query && query[query_len - 1] == '.')
query[query_len - 1] = '\0';
/* get the query type */
qtype = (qtype << 8) | *p1++;
qtype = (qtype << 8) | *p1++;
orig_qtype = qtype;
qclass = (qclass << 8) | *p1++;
qclass = (qclass << 8) | *p1++;
nqueries = 1;
nanswers = 0;
nservers = 0;
nextras = 0;
memset (_out_buf, 0, sizeof (_out_buf));
p1 = out_buf + 12;
/* query section starts here ----> */
name_pointer = put_name (out_buf, &p1, query);
*p1++ = qtype >> 8;
*p1++ = qtype & 0xFF;
*p1++ = qclass >> 8;
*p1++ = qclass & 0xFF;
if ((flags & 0x8000)) /* response packet - ignoring */
er (ignoring response packet);
/* now check for valid flags. if not valid, jump over the
part where we fill in the packet: */
flags &= 0x7900; /* copy recursive-query-bit, copy opcode-bits */
flags |= 0x8000; /* response-bit */
if (!(qtype == REQ_A || qtype == REQ_PTR || qtype == REQ_MX
|| qtype == REQ_CNAME || qtype == REQ_NS || qtype == REQ_SOA || qtype == REQ_TXT)) {
goto empty_packet; } /* we have none of these records */
if (qclass != 1 /* class INET */ ) {
flags |= 4; /* not supported */
goto empty_packet; }
if ((flags & 0x7800) == 1) { /* inverse query */
flags |= 4; /* who supports this ?? */
goto empty_packet; }
if ((flags & 0x7800) == 2) /* status request */
goto empty_packet;
if ((flags & 0x7800) != 0) /* standard query */
goto empty_packet;
/* answer section starts here ----> */
extra_results[0] = NULL;
extra_queries[0] = NULL;
for (j = 0; j < ANS_BLOCKS; j++) { /* there are three answer blocks */
char **lookup_results = NULL;
u2 *to_incr = NULL;
switch (j) {
case ANSWERS: /* section 1 */
to_incr = &nanswers;
lookup_results = directory_lookup (qtype, query);
/* a missing a record may be a CNAME - try find it and
then proceed as though we had a CNAME lookup: */
if (!lookup_results) {
qtype = REQ_CNAME;
xfree (lookup_results);
lookup_results = directory_lookup (REQ_CNAME, query); }
/* CNAME requires a directly adjacent A record within the
answer section (as per RFC-1034, §3.6.2). This is a
special case, and breaks the elegance of this algorithm.
So we prepend the CNAME answer, and then proceed as though
it were a regular A record (or other record) by replacing
the query with a new query of the canonical name: */
if (qtype == REQ_CNAME) {
if (lookup_results) {
nanswers++;
put_name (out_buf, &p1, (u1 *) query);
*p1++ = qtype >> 8;
*p1++ = qtype & 0xFF;
*p1++ = qclass >> 8;
*p1++ = qclass & 0xFF;
*p1++ = (short_time >> 24) & 0xFF;
*p1++ = (short_time >> 16) & 0xFF;
*p1++ = (short_time >> 8) & 0xFF;
*p1++ = (short_time >> 0) & 0xFF;
len_pointer = p1; /* store length of string here */
p1 += 2;
name_pointer = put_name (out_buf, &p1, (u1 *) lookup_results[0]); /* <--- replacement of query string with cname (2) */
name_len = (p1 - len_pointer) - 2;
*len_pointer++ = name_len >> 8; /* back insert the length */
*len_pointer++ = name_len & 0xFF;
/* now proceed as though this were a regular query: */
qtype = orig_qtype;
strcpy ((char *) query, lookup_results[0]); /* <--- replacement of query string with cname (2) */
xfree (lookup_results);
lookup_results = directory_lookup (orig_qtype, query); }}
break;
case SERVERS: /* section 2 */
to_incr = &nservers;
/* append any SOA records possibly present in the
database, but not if the original query was an SOA query,
in which case it would already appear in the section 1: */
if (orig_qtype != REQ_SOA) {
qtype = REQ_SOA;
lookup_results = directory_lookup (REQ_SOA, query);
/* if we know we are the authority, then we want to be
explicit that the domain really does not exist: */
if (!nanswers && lookup_results)
flags = (flags & ~0xf) | 3; } /* authoritatively no such domain */
/* append any NS records possibly present in the database,
but not if the original query was an NS query (in which
case it would already appear in the section 1), or if we
have already added SOA records (because its not really
necessary to add NS records along with NS records): */
if (!lookup_results && (orig_qtype != REQ_NS /* don't repeat stuff */ )) {
xfree (lookup_results);
qtype = REQ_NS;
lookup_results = directory_lookup (REQ_NS, query); }
break;
case EXTRAS: /* section 3 */
to_incr = &nextras;
/* any hostnames referenced in the previous two sections
are appended with their proper IP addresses to a list for
inclusion in the last section: */
qtype = REQ_A;
lookup_results = extra_results;
break; }
/* loop through each found record: */
for (i = 0; lookup_results && lookup_results[i] && i < 256; i++, (*to_incr)++) {
u1 *p1_within_512_bytes;
u4 ttl;
p1_within_512_bytes = p1; /* psuh the offset in case we overrun */
if (j == EXTRAS) {
ttl = extra_ttls[i]; /* extra section has myriad TTLs */
put_name (out_buf, &p1, (u1 *) extra_queries[i]); } /* as well as myriad names */
else {
ttl = TTL_POLICY (qtype); /* other sections have stock TTLs */
/* pointer to original query string or CNAME result (2), as the case may be: */
*p1++ = 0xc0 | ((name_pointer >> 8) & ~0xc0);
*p1++ = (name_pointer & 0xFF); }
*p1++ = qtype >> 8;
*p1++ = qtype & 0xFF;
*p1++ = qclass >> 8;
*p1++ = qclass & 0xFF;
*p1++ = (ttl >> 24) & 0xFF;
*p1++ = (ttl >> 16) & 0xFF;
*p1++ = (ttl >> 8) & 0xFF;
*p1++ = (ttl >> 0) & 0xFF;
len_pointer = p1; /* store length of string here */
p1 += 2;
if (qtype == REQ_MX) { /* for mail servers, prefix with priority number */
*p1++ = (10 + i * 10) >> 8;
*p1++ = (10 + i * 10) & 0xFF; }
if (qtype == REQ_A) { /* for A records just store the IP */
struct in_addr a;
u1 *q;
a.s_addr = 0;
if (!inet_aton (lookup_results[i], &a))
flags = (flags & ~0xf) | 1; /* Format error */
q = (u1 *) & a.s_addr;
*p1++ = *q++; /* already in network byte order */
*p1++ = *q++;
*p1++ = *q++;
*p1++ = *q++; }
else if (qtype == REQ_TXT) { /* for TXT records just store plain text */
int y;
for (y = 0; y < 64 && lookup_results[i][y]; y++)
p1[y + 1] = (u1) lookup_results[i][y];
*p1 = y, p1 += y + 1; }
else {
put_name (out_buf, &p1, (u1 *) lookup_results[i]); /* store string result */
if (j != EXTRAS) {
char **t_results = NULL;
if (qtype != REQ_CNAME) /* CNAMEs IPs are specially appended in the answer section */
if (!string_present (lookup_results[i], extra_queries)) /* did we already look this one up? */
t_results = directory_lookup (REQ_A, (u1 *) lookup_results[i]); /* lookup any A records available */
if (t_results && extra_results_len < MAX_EXTRA_RESULTS - 1) {
extra_results[extra_results_len] = (char *) strdup ((char *) t_results[0]);
extra_queries[extra_results_len] = (char *) strdup ((char *) lookup_results[i]);
/* now we need to calculate the ttl's of the extra
section. Our extra section contains only A records of
either an NS, PTR, CNAME, MX, or SOA lookup. NS records
have fixed IP address, and CNAME and SOA records are
fixed. Its only "A" records of REQ_MX, REQ_CNAME, and
REQ_PTR that need a short TTL. This is not exactly
correct, because a CNAME or PTR could actually be a
nameserver, but hay: */
extra_ttls[extra_results_len] = TTL_POLICY (qtype);
extra_results_len++;
extra_results[extra_results_len] = NULL;
extra_queries[extra_results_len] = NULL; }
xfree (t_results); }}
/* for soa records servers we suffix the entry with: mailbox,
serial, refresh, retry, expire, min-ttl: */
if (qtype == REQ_SOA) {
u4 serial;
time_t tm;
struct tm *lt;
lookup_results[i + 1] = NULL; /* force only one SOA record */
strcpy ((char *) p1, "\012hostmaster");
p1 += 11;
put_name (out_buf, &p1, (u1 *) lookup_results[i]); /* store string result */
tm = (time_t) get_mtime (REQ_SOA, (unsigned char *) query);
lt = localtime (&tm);
/* hack a serial number from the modified time of the file - this
has a resolution of 32 seconds and looks like YYYYppnnnn where
pp.nnnn is the percentage of the year passed: */
serial =
((u4) lt->tm_year + 1900) * 1000000 + ((u4) ((u4) lt->tm_yday * 24 * 3600 +
lt->tm_hour * 3600 + lt->tm_min * 60 +
lt->tm_sec) >> 5);
*p1++ = (serial >> 24) & 0xFF;
*p1++ = (serial >> 16) & 0xFF;
*p1++ = (serial >> 8) & 0xFF;
*p1++ = (serial >> 0) & 0xFF;
*p1++ = (REFRESH >> 24) & 0xFF;
*p1++ = (REFRESH >> 16) & 0xFF;
*p1++ = (REFRESH >> 8) & 0xFF;
*p1++ = (REFRESH >> 0) & 0xFF;
*p1++ = (RETRY >> 24) & 0xFF;
*p1++ = (RETRY >> 16) & 0xFF;
*p1++ = (RETRY >> 8) & 0xFF;
*p1++ = (RETRY >> 0) & 0xFF;
*p1++ = (EXPIRE >> 24) & 0xFF;
*p1++ = (EXPIRE >> 16) & 0xFF;
*p1++ = (EXPIRE >> 8) & 0xFF;
*p1++ = (EXPIRE >> 0) & 0xFF;
*p1++ = (MINTTL >> 24) & 0xFF;
*p1++ = (MINTTL >> 16) & 0xFF;
*p1++ = (MINTTL >> 8) & 0xFF;
*p1++ = (MINTTL >> 0) & 0xFF; }
name_len = (p1 - len_pointer) - 2;
*len_pointer++ = name_len >> 8; /* back insert the length */
*len_pointer++ = name_len & 0xFF;
if ((p1 - out_buf) > (*how == 'T' ? 1024 : 512)) { /* limit to 1024 bytes for TCP, 512 for UDP */
p1 = p1_within_512_bytes;
*how == 'U' && (flags |= 0x0200 /* truncation bit */ ); /* for TCP we are silent about the truncation */
/* do not increment (*to_incr), and then */
xfree (lookup_results);
goto break_2; }}
xfree (lookup_results); }
break_2:
while (--extra_results_len >= 0) {
assert (extra_results[extra_results_len]);
assert (extra_queries[extra_results_len]);
free (extra_results[extra_results_len]);
free (extra_queries[extra_results_len]);
extra_results[extra_results_len] = NULL;
extra_queries[extra_results_len] = NULL; }
packet_len = (p1 - out_buf);
if (nanswers || nservers) {
flags |= 0x0400; } /* authority-bit 0x0400 */
empty_packet:
p1 = out_buf; /* goto start of packet to fill in total counts */
*p1++ = id >> 8;
*p1++ = id & 0xFF;
*p1++ = flags >> 8;
*p1++ = flags & 0xFF;
*p1++ = nqueries >> 8;
*p1++ = nqueries & 0xFF;
*p1++ = nanswers >> 8;
*p1++ = nanswers & 0xFF;
*p1++ = nservers >> 8;
*p1++ = nservers & 0xFF;
*p1++ = nextras >> 8;
*p1++ = nextras & 0xFF;
/* finally... */
if (*how == 'T' /* TCP */ ) {
out_buf -= 2;
out_buf[0] = (packet_len >> 8);
out_buf[1] = (packet_len & 0xFF);
/* this assumes the OS queue can hold our data without
blocking. for 1026 bytes or less, we are pretty sure it
can. */
return send (s, out_buf, packet_len + 2, 0); }
else { /* UDP */
return sendto (s, out_buf, packet_len, 0, from, fromlen); }}
static void
make_directories (void) {
const char *hex = "0123456789ABCDEF";
char path[256];
int j, fd, l;
mkdir (SHEERDNS_DIR, 0700);
strcpy (path, SHEERDNS_DIR);
mkdir (path, 0700);
l = strlen (path);
for (j = 0; j < 256; j++) {
path[l] = '/';
path[l + 1] = hex[j >> 4];
path[l + 2] = hex[j & 0xF];
path[l + 3] = '\0';
mkdir (path, 0700); }
mkdir (SHEERDNS_DIR "/C9/localhost", 0700);
fd = open (SHEERDNS_DIR "/C9/localhost/A", O_WRONLY | O_CREAT | O_TRUNC, 0700);
write (fd, "127.0.0.1", 9);
close (fd);
mkdir (SHEERDNS_DIR "/7A/localhost.localdomain", 0700);
fd = open (SHEERDNS_DIR "/7A/localhost.localdomain/A", O_WRONLY | O_CREAT | O_TRUNC, 0700);
write (fd, "127.0.0.1", 9);
close (fd);
mkdir (SHEERDNS_DIR "/B5/127.0.0.1", 0700);
fd = open (SHEERDNS_DIR "/B5/127.0.0.1/PTR", O_WRONLY | O_CREAT | O_TRUNC, 0700);
write (fd, "localhost", 9);
close (fd); }
sheerdns/sheerdns.ps 0100644 0000000 0000000 00000053407 10202742330 013551 0 ustar root root %!PS-Adobe-3.0
%%Creator: groff version 1.18
%%CreationDate: Thu Feb 10 22:32:24 2005
%%DocumentNeededResources: font Times-Roman
%%+ font Times-Bold
%%+ font Times-Italic
%%DocumentSuppliedResources: procset grops 1.18 0
%%Pages: 4
%%PageOrder: Ascend
%%Orientation: Portrait
%%EndComments
%%BeginProlog
%%BeginResource: procset grops 1.18 0
/setpacking where{
pop
currentpacking
true setpacking
}if
/grops 120 dict dup begin
/SC 32 def
/A/show load def
/B{0 SC 3 -1 roll widthshow}bind def
/C{0 exch ashow}bind def
/D{0 exch 0 SC 5 2 roll awidthshow}bind def
/E{0 rmoveto show}bind def
/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
/G{0 rmoveto 0 exch ashow}bind def
/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
/I{0 exch rmoveto show}bind def
/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
/K{0 exch rmoveto 0 exch ashow}bind def
/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
/M{rmoveto show}bind def
/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
/O{rmoveto 0 exch ashow}bind def
/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
/Q{moveto show}bind def
/R{moveto 0 SC 3 -1 roll widthshow}bind def
/S{moveto 0 exch ashow}bind def
/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
/SF{
findfont exch
[exch dup 0 exch 0 exch neg 0 0]makefont
dup setfont
[exch/setfont cvx]cvx bind def
}bind def
/MF{
findfont
[5 2 roll
0 3 1 roll
neg 0 0]makefont
dup setfont
[exch/setfont cvx]cvx bind def
}bind def
/level0 0 def
/RES 0 def
/PL 0 def
/LS 0 def
/MANUAL{
statusdict begin/manualfeed true store end
}bind def
/PLG{
gsave newpath clippath pathbbox grestore
exch pop add exch pop
}bind def
/BP{
/level0 save def
1 setlinecap
1 setlinejoin
72 RES div dup scale
LS{
90 rotate
}{
0 PL translate
}ifelse
1 -1 scale
}bind def
/EP{
level0 restore
showpage
}bind def
/DA{
newpath arcn stroke
}bind def
/SN{
transform
.25 sub exch .25 sub exch
round .25 add exch round .25 add exch
itransform
}bind def
/DL{
SN
moveto
SN
lineto stroke
}bind def
/DC{
newpath 0 360 arc closepath
}bind def
/TM matrix def
/DE{
TM currentmatrix pop
translate scale newpath 0 0 .5 0 360 arc closepath
TM setmatrix
}bind def
/RC/rcurveto load def
/RL/rlineto load def
/ST/stroke load def
/MT/moveto load def
/CL/closepath load def
/Fr{
setrgbcolor fill
}bind def
/Fk{
setcmykcolor fill
}bind def
/Fg{
setgray fill
}bind def
/FL/fill load def
/LW/setlinewidth load def
/Cr/setrgbcolor load def
/Ck/setcmykcolor load def
/Cg/setgray load def
/RE{
findfont
dup maxlength 1 index/FontName known not{1 add}if dict begin
{
1 index/FID ne{def}{pop pop}ifelse
}forall
/Encoding exch def
dup/FontName exch def
currentdict end definefont pop
}bind def
/DEFS 0 def
/EBEGIN{
moveto
DEFS begin
}bind def
/EEND/end load def
/CNT 0 def
/level1 0 def
/PBEGIN{
/level1 save def
translate
div 3 1 roll div exch scale
neg exch neg exch translate
0 setgray
0 setlinecap
1 setlinewidth
0 setlinejoin
10 setmiterlimit
[]0 setdash
/setstrokeadjust where{
pop
false setstrokeadjust
}if
/setoverprint where{
pop
false setoverprint
}if
newpath
/CNT countdictstack def
userdict begin
/showpage{}def
}bind def
/PEND{
clear
countdictstack CNT sub{end}repeat
level1 restore
}bind def
end def
/setpacking where{
pop
setpacking
}if
%%EndResource
%%IncludeResource: font Times-Roman
%%IncludeResource: font Times-Bold
%%IncludeResource: font Times-Italic
grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72
def/PL 841.89 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron
/Zcaron/scaron/zcaron/Ydieresis/trademark/quotesingle/Euro/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent
/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen
/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon
/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O
/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex
/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y
/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft
/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl
/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen
/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft
/logicalnot/minus/registered/macron/degree/plusminus/twosuperior
/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior
/ordmasculine/guilsinglright/onequarter/onehalf/threequarters
/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE
/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex
/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn
/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla
/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis
/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash
/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def
/Times-Italic@0 ENC0/Times-Italic RE/Times-Bold@0 ENC0/Times-Bold RE
/Times-Roman@0 ENC0/Times-Roman RE
%%EndProlog
%%Page: 1 1
%%BeginPageSetup
BP
%%EndPageSetup
/F0 10/Times-Roman@0 SF 372.2(sheerdns\(1\) sheerdns\(1\))72 48 R/F1
10.95/Times-Bold@0 SF -.219(NA)72 84 S(ME).219 E F0
(sheerdns - master DNS serv)108 96 Q(er)-.15 E F1(SYNOPSIS)72 112.8 Q/F2
10/Times-Bold@0 SF(sheerdns)108 124.8 Q F0([)2.5 E F2(-ttl)A/F3 10
/Times-Italic@0 SF(seconds)2.5 E F0 2.5(][)C F2(-p)-2.5 E F3(port)2.5 E
F0 2.5(][)C F2(-i)-2.5 E F3(iface-ip)2.5 E F0 2.5(][)C F2(-d)-2.5 E F0
(])A F2(sheerdnshash)108 141.6 Q F3(string)2.5 E F1(DESCRIPTION)72 168 Q
F2(sheerdns)108 180 Q F0 .535(is a master DNS serv)3.035 F .535
(er whose zone records are stored on a One-Record-Per)-.15 F .534
(-File bases. Because)-.2 F .654(of this,)108 192 R F2(sheerdns)3.154 E
F0 .654(is the simplest of an)3.154 F 3.154(yD)-.15 G .654
(NS to con\214gure, the easiest to update, and the most ef)-3.154 F .655
(\214cient for)-.25 F(netw)108 204 Q .427(orks that e)-.1 F .426
(xperience a lot of updates \(for e)-.15 F .426(xample master serv)-.15
F .426(ers for dynamic IP address ranges\). Y)-.15 F(ou)-1.1 E F3(ne)108
216 Q(ver)-.15 E F0(ha)5.279 E 3.079 -.15(ve t)-.2 H 5.279(or).15 G
(estart)-5.279 E F2(sheerdns)5.279 E F0 5.279(;a)C 3.079 -.15(ny u)
-5.279 H 2.779(pdates are a).15 F -.25(va)-.2 G 2.779
(ilable immediately without ha).25 F 2.78(ving to notify the)-.2 F F2
(sheerdns)108 228 Q F0(process.)2.5 E F2(sheerdns)108 244.8 Q F0
(is secure.)2.5 E F2(sheerdns)2.5 E F0(is f)2.5 E
(ast because Unix operating systems cache small \214les in memory)-.1 E
(.)-.65 E F2(sheerdns)108 261.6 Q F0(is written in strict ANSI C.)2.5 E
F2(sheerdnshash)108 278.4 Q F0 .788(creates a directory)3.288 F F2(/v)
3.287 E(ar/sheerdns/)-.1 E F3(XX)A F2(/)A F3(string)A F2(/)A F0 3.287
(,w)C(here)-3.287 E F3(XX)3.287 E F0 .787
(is a hash of the string, and outputs)3.287 F F3(XX)108 290.4 Q F0
(to stdout.)2.5 E .702(Note that)108 307.2 R F2(sheerdns)3.202 E F0(is)
3.202 E F3(not)3.202 E F0 3.202(ac)3.202 G .702(aching nameserv)-3.202 F
.702(er for resolving queries about the rest of the Internet. It is a)
-.15 F .86(master serv)108 319.2 R .86(er for telling the rest of Inter\
net about the zones you are responsible for)-.15 F 3.36(.N)-.55 G 3.36
(oc)-3.36 G .86(lients an)-3.36 F(ywhere)-.15 E(should ha)108 331.2 Q .3
-.15(ve a)-.2 H F2(/etc/r)2.65 E(esolv)-.18 E(.conf)-.7 E F0("nameserv)
2.5 E(er" entry that points to a)-.15 E F2(sheerdns)2.5 E F0(serv)2.5 E
(er)-.15 E(.)-.55 E F2(sheerdns)108 348 Q F0 -.1(wo)2.5 G
(rks by looking up queries from \214les of the name:).1 E F2(/v)144
364.8 Q(ar/sheerdns/)-.1 E F3(XX)A F2(/)A F3(full.doma.in)A F2(/)A F3
(query-type)A F0(.)A 1.181(These \214les are created by the administrat\
or \(or one of his/her sh/perl/p)108 381.6 R 1.182
(ython/php scripts\). Y)-.1 F 1.182(ou can write)-1.1 F(an)108 393.6 Q
1.198(ything to these \214les --)-.15 F F2(sheerdns)3.698 E F0 1.197
(will answer with their contents e)3.698 F -.15(ve)-.25 G 3.697(ni).15 G
3.697(ft)-3.697 G(he)-3.697 E 3.697(ya)-.15 G 1.197(re bogus. The)-3.697
F F3(XX)3.697 E F0 1.197(is an)3.697 F(upper)108 405.6 Q(-case tw)-.2 E
2.5(oc)-.1 G(haracter he)-2.5 E 2.5(xn)-.15 G(umber of the range)-2.5 E
F2(00)2.5 E F0(to)2.5 E F2(FF)2.5 E F0(.)A .925
(Each of these \214les contains one or more ne)108 422.4 R .925
(wline separated strings. There should be no leading ne)-.25 F(wlines,)
-.25 E 2.13(and zero or one trailing ne)108 434.4 R 2.13
(wline. In the case of A records, the strings are IP addresses, for e)
-.25 F(xample)-.15 E F2(192.0.2.1)108 446.4 Q F0 2.5(.I)C 2.5(ft)-2.5 G
(here are se)-2.5 E -.15(ve)-.25 G(ral IP addresses in the \214le, the)
.15 E 2.5(ya)-.15 G(re order)-2.5 E(-randomized before return.)-.2 E .43
(In the case of PTR, MX, NS, SO)108 463.2 R .43(A, and CN)-.35 F .431
(AME records, the strings are host-names. F)-.35 F .431
(or MX and NS you)-.15 F 1.113(can ha)108 475.2 R 1.413 -.15(ve m)-.2 H
1.113(ultiple hostnames per \214le, b).15 F 1.113(ut for PTR, SO)-.2 F
1.113(A, and CN)-.35 F 1.113(AME records, you must ha)-.35 F 1.413 -.15
(ve o)-.2 H 1.112(nly one).15 F .419
(entry in each \214le. TXT records can contain an)108 487.2 R .419
(ything---one record is returned for each line in the \214le \(TXT)-.15
F(is not discussed ag)108 499.2 Q(ain\).)-.05 E -.15(Fo)108 516 S 2.5
(rM).15 G 2.5(Xr)-2.5 G(ecords, the \214rst entry in the \214le is gi)
-2.5 E -.15(ve)-.25 G 2.5(nap).15 G
(riority of 10, the second 20, and so on.)-2.5 E -.15(Fo)108 532.8 S
3.004(rS).15 G 1.204 -.35(OA r)-3.004 H .504
(ecords, the modi\214ed time of the \214le counts as the Serial-Number)
.35 F 3.004(,a)-.4 G .504(nd the contents as the name-)-3.004 F(serv)108
544.8 Q(er)-.15 E 5.88(.T)-.55 G .88
(he administrator email address returned is just the name-serv)-5.88 F
.88(er prepended with "hostmaster", so)-.15 F .692(you should mak)108
556.8 R 3.192(es)-.1 G .692(ure this email address e)-3.192 F .692
(xists for that domain and is reachable. The remaining \214elds are)-.15
F .328(hardcoded to reasonable def)108 568.8 R .328(ault v)-.1 F .328
(alues. Note that time \214elds for SO)-.25 F 2.828(Ar)-.35 G .329
(ecords are only used for zone trans-)-2.828 F(fers hence are irrele)108
580.8 Q -.25(va)-.25 G(nt here.).25 E -.15(Fo)108 597.6 S 2.581(rN).15 G
2.581(Sa)-2.581 G .081(nd SO)-2.581 F 2.581(Ar)-.35 G .081
(ecords, an entry for a domain is v)-2.581 F .081
(alid for all domains belo)-.25 F 2.581(wi)-.25 G .081(t. F)-2.581 F
.081(or e)-.15 F .081(xample, if you create)-.15 F 1.962
(an NS record for the domain)108 609.6 R F2(test.edu)4.462 E F0 4.462
(,t)C 1.962(hen that NS record is returned for the domain)-4.462 F F2
(www)4.462 E(.test.edu)-.7 E F0(,)A F2(ftp.henry)108 621.6 Q(.test.edu)
-.7 E F0 2.64(,a)C 2.64(sw)-2.64 G .14(ell as)-2.64 F F2(user1.lab)2.64
E(.chemistry)-.4 E(.test.edu)-.7 E F0 2.639(.O)C 2.639(nt)-2.639 G .139
(he other hand a separate NS record can be)-2.639 F 3.845(created for)
108 633.6 R F2(lab)6.345 E(.chemistry)-.4 E(.test.edu)-.7 E F0 6.345(,a)
C 3.845(pplying to all domains)-6.345 F F2(*.lab)6.345 E(.chemistry)-.4
E(.test.edu)-.7 E F0(,)A F2(*.*.lab)6.345 E(.chem-)-.4 E(istry)108 645.6
Q(.test.edu)-.7 E F0 2.822(etc. This)2.822 F -.1(wo)2.822 G .322
(rks because).1 F F2(sheerdns)2.822 E F0 .321
(searches for NS records by iterati)2.821 F -.15(ve)-.25 G .321
(ly deleting the te).15 F .321(xt up)-.15 F
(to the front most dot until a nameserv)108 657.6 Q
(er is found. This gi)-.15 E -.15(ve)-.25 G 2.5(st).15 G(he intuiti)-2.5
E -.15(ve)-.25 G(ly e).15 E(xpected beha)-.15 E(vior)-.2 E(.)-.55 E
(There is a special case for using)108 674.4 Q F2(sheerdns)2.5 E F0
(as a root nameserv)2.5 E(er)-.15 E 2.5(.S)-.55 G(ee the e)-2.5 E
(xample belo)-.15 E -.65(w.)-.25 G F2(sheerdns)108 691.2 Q F0 .296
(does lookups in lo)2.796 F .296
(wer case. All \214lenames and \214le contents must be in lo)-.25 F .297
(wer case.)-.25 F F2(sheerdns)2.797 E F0(does)2.797 E .06
(no interpretation of an)108 703.2 R 2.56(yo)-.15 G 2.56(ft)-2.56 G .06
(he \214le contents e)-2.56 F .059
(xcept for the characters \\f\\n\\r\\t\\v and the dot character)-.15 F
2.559(,s)-.4 G 2.559(oi)-2.559 G 2.559(tc)-2.559 G(an)-2.559 E
(probably manage UTF-8 domain names without a problem.)108 715.2 Q
(Jan 11 2000)281.835 768 Q(1)204.835 E 0 Cg EP
%%Page: 2 2
%%BeginPageSetup
BP
%%EndPageSetup
/F0 10/Times-Roman@0 SF 372.2(sheerdns\(1\) sheerdns\(1\))72 48 R/F1 10
/Times-Bold@0 SF(sheerdns)108 84 Q F0 .779(does not send TCP results lo\
nger than 1024 bytes, neither does it set the TC bit if the response)
3.278 F 1.033(ought to be longer)108 96 R 3.533(.I)-.55 G 3.533(ft)
-3.533 G 1.033(here are too man)-3.533 F 3.533(yr)-.15 G 1.032
(ecords to \214t in the pack)-3.533 F 1.032
(et, then trailing records are omitted to)-.1 F -.1(ke)108 108 S 1.883
(ep within the 1024 byte limit. The pack).1 F 1.884(et format will be v)
-.1 F 1.884(alid none-the-less. Administrators should)-.25 F
(ensure that their site is not so comple)108 120 Q 2.5(xt)-.15 G
(hat lar)-2.5 E(ge pack)-.18 E(ets need to be sent.)-.1 E/F2 10.95
/Times-Bold@0 SF(OPTIONS)72 141.6 Q F1(-ttl)108 153.6 Q/F3 10
/Times-Italic@0 SF(seconds)2.5 E F0 1.4(The T)144 165.6 R(ime-T)-.35 E
(o-Li)-.8 E 1.7 -.15(ve \214)-.25 H 1.4(eld to be set on outgoing pack)
.15 F 3.899(ets. Records)-.1 F 1.399(that are lik)3.899 F 1.399
(ely to be \214x)-.1 F 1.399(ed \(not)-.15 F .859(dynamic\) are gi)144
177.6 R -.15(ve)-.25 G 3.359(na3).15 G .86
(-day ttl. Examples are the IP address of the NS record, and the CN)
-3.359 F(AME,)-.35 E .423(MX, NS, and SO)144 189.6 R 2.923(Ar)-.35 G
.422(ecords. All other records are gi)-2.923 F -.15(ve)-.25 G 2.922(nt)
.15 G .422(he ttl speci\214ed in this option. The def)-2.922 F(ault)-.1
E 1.853(is 86400 seconds \(one day\). This option should be set to 10 s\
econds for dynamic IP address)144 201.6 R(ranges.)144 213.6 Q F1(-p)108
230.4 Q F3(port)2.5 E F0(Listen port. Def)7.94 E(ault is 53.)-.1 E F1
(-i)108 247.2 Q F3(iface-ip)2.5 E(inface-ip)144 259.2 Q F0 .781
(is the netw)3.281 F .781(ork card you w)-.1 F .781(ant to listen on.)
-.1 F .78(If omitted, it def)5.781 F .78(aults to 0.0.0.0 meaning)-.1 F
F3(all)3.28 E F0(interf)144 271.2 Q(aces.)-.1 E F1(-d)108 288 Q F0 -.15
(Fo)27.11 G .145
(rk twice into the background \(to run as a daemon process\); otherwise)
.15 F F1(sheerdns)2.646 E F0 .146(runs in the fore-)2.646 F(ground.)144
300 Q F2(WILDCARDS)72 321.6 Q F0(An entry such as)108 333.6 Q F1
(*.test.com)2.5 E F0(will return results as e)2.5 E
(xpected. This means you should)-.15 E(echo 192.0.2.1 > /v)144 350.4 Q
(ar/sheerdns/`sheerdnshash '*'.test.com`/'*'.test.com/A)-.25 E
(dig @localhost A lsdjkfhalsdfkjh.test.com)144 362.4 Q .89(Note that qu\
otes around the asterisk. This means the \214lename has an asterisk in \
it which is ne)108 379.2 R -.15(ve)-.25 G 3.389(rag).15 G(ood)-3.389 E
(idea on Unix systems.)108 391.2 Q F2(EXAMPLES)72 412.8 Q F0 .758
(These e)108 424.8 R .758(xamples assume that you ha)-.15 F 1.059 -.15
(ve a)-.2 H .759(lready in).15 F -.2(vo)-.4 G -.1(ke).2 G(d).1 E F1
(sheerdns)3.259 E F0 3.259(,t)C .759(hat you kno)-3.259 F 3.259(ww)-.25
G .759(hat kind of records are)-3.259 F .91(appropriate to create, that\
you do not guess, and that you realize that the e)108 436.8 R .91
(xamples are merely sho)-.15 F .91(wn for)-.25 F(demonstration and not \
as a recommendation for the kinds of records really required.)108 448.8
Q(Add mutiple A records for)108 465.6 Q F1(test.com)2.5 E F0
(for round robin sharing:)2.5 E(echo 192.0.2.1 > /v)144 482.4 Q
(ar/sheerdns/`sheerdnshash test.com`/test.com/A)-.25 E
(echo 192.0.2.2 >> /v)144 494.4 Q
(ar/sheerdns/`sheerdnshash test.com`/test.com/A)-.25 E
(echo 192.0.2.3 >> /v)144 506.4 Q
(ar/sheerdns/`sheerdnshash test.com`/test.com/A)-.25 E
(dig @localhost A test.com)144 518.4 Q(dig @localhost A test.com)144
530.4 Q(dig @localhost A test.com)144 542.4 Q(Add a PTR records for)108
559.2 Q F1(test.com)2.5 E F0(:)A(echo test.com > /v)144 576 Q
(ar/sheerdns/`sheerdnshash 192.0.2.1`/192.0.2.1/PTR)-.25 E
(echo test.com > /v)144 588 Q
(ar/sheerdns/`sheerdnshash 192.0.2.2`/192.0.2.2/PTR)-.25 E
(echo test.com > /v)144 600 Q
(ar/sheerdns/`sheerdnshash 192.0.2.3`/192.0.2.3/PTR)-.25 E
(echo ns.ispfortest.net > /v)144 612 Q
(ar/sheerdns/`sheerdnshash 192.0.2`/192.0.2/NS)-.25 E
(dig @localhost PTR 1.2.0.192.in-addr)144 624 Q(.arpa)-.55 E
(Add an MX record for)108 640.8 Q F1(test.com)2.5 E F0(with \(IMPOR)2.5
E -.93(TA)-.6 G(NT\)).93 E F3(both)2.5 E F0(its forw)2.5 E(ard, re)-.1 E
-.15(ve)-.25 G(rse,).15 E F3(and)2.5 E F0(nameserv)2.5 E(er lookups:)
-.15 E(echo mail.test.com > /v)144 657.6 Q
(ar/sheerdns/`sheerdnshash test.com`/test.com/MX)-.25 E
(echo 192.0.3.99 > /v)144 669.6 Q
(ar/sheerdns/`sheerdnshash mail.test.com`/mail.test.com/A)-.25 E
(echo mail.test.com > /v)144 681.6 Q
(ar/sheerdns/`sheerdnshash 192.0.3.99`/192.0.3.99/PTR)-.25 E
(echo ns.ispfortest.net > /v)144 693.6 Q
(ar/sheerdns/`sheerdnshash test.com`/test.com/NS)-.25 E
(dig @localhost MX test.com)144 705.6 Q 1.339(Add an SO)108 722.4 R
3.839(Ar)-.35 G 1.339(ecord for)-3.839 F F1(test.com)3.839 E F0 3.839
(.N)C 1.339(ote that although SO)-3.839 F 3.839(Ar)-.35 G 1.34
(ecords are only required for zone transfers,)-3.839 F(Jan 11 2000)
281.835 768 Q(2)204.835 E 0 Cg EP
%%Page: 3 3
%%BeginPageSetup
BP
%%EndPageSetup
/F0 10/Times-Roman@0 SF 372.2(sheerdns\(1\) sheerdns\(1\))72 48 R .191(\
some institutions may demand them. The only con\214gurable data item in\
the SO)108 84 R 2.691(Ar)-.35 G .191(ecord is the authoritati)-2.691 F
-.15(ve)-.25 G(nameserv)108 96 Q(er which is inserted as follo)-.15 E
(ws:)-.25 E(echo ns.ispfortest.net > /v)144 112.8 Q
(ar/sheerdns/`sheerdnshash test.com`/test.com/SO)-.25 E(A)-.35 E
(dig @localhost SO)144 124.8 Q 2.5(At)-.35 G(est.com)-2.5 E 1.169
(Add an CN)108 141.6 R 1.169(AME record for)-.35 F/F1 10/Times-Bold@0 SF
(www)3.669 E(.test.com)-.7 E F0 3.669(.I)C 3.669(fy)-3.669 G 1.169
(ou use a CN)-3.669 F 1.17(AME, you should only ha)-.35 F 1.47 -.15
(ve o)-.2 H 1.17(ne line in the).15 F(CN)108 153.6 Q .774
(AME \214le, and it should be the only \214le in the domain')-.35 F
3.274(sd)-.55 G(irectory)-3.274 E 3.274(,a)-.65 G .774(nd the CN)-3.274
F .773(AME should not appear)-.35 F(an)108 165.6 Q .296
(ywhere as the te)-.15 F .296(xt of an)-.15 F 2.796(yo)-.15 G .297
(ther records. I repeat: ")-2.796 F/F2 10/Times-Italic@0 SF .297
(If you use a CN)B .297(AME, you should only have one line in)-.27 F
.107(the CN)108 177.6 R .107(AME \214le)-.27 F 2.607(,a)-.1 G .107
(nd it should be the only \214le in the domain')-2.607 F 2.607(sd)-.4 G
(ir)-2.607 E(ectory)-.37 E 2.607(,a)-.55 G .107(nd the CN)-2.607 F .106
(AME should not appear)-.27 F(anywher)108 189.6 Q 2.5(ea)-.37 G 2.5(st)
-2.5 G(he te)-2.5 E(xt of any other r)-.2 E(ecor)-.37 E(ds.)-.37 E F0
(". Do I need to say it a third time?)A(echo "I will not lea)144 206.4 Q
.3 -.15(ve o)-.2 H(ut the ne).15 E(xt command")-.15 E(rm -f /v)144 218.4
Q(ar/sheerdns/`sheerdnshash www)-.25 E(.test.com`/www)-.65 E
(.test.com/*)-.65 E(grep -w 'www[.]test[.]com' `\214nd /v)144 230.4 Q
(ar/sheerdns/ -type f` && \\)-.25 E(echo "This DNS setup is brok)154
242.4 Q(en")-.1 E(echo "I will not lea)144 254.4 Q .3 -.15(ve o)-.2 H
(ut the pre).15 E(vious command")-.25 E(echo test.com > /v)144 266.4 Q
(ar/sheerdns/`sheerdnshash www)-.25 E(.test.com`/www)-.65 E
(.test.com/CN)-.65 E(AME)-.35 E(dig @localhost A www)144 278.4 Q
(.test.com)-.65 E(Using)108 295.2 Q F1(sheerdns)2.5 E F0
(as a root nameserv)2.5 E(er)-.15 E 2.5(.N)-.55 G
(ote that for root domains, the hash is especially omitted:)-2.5 E 2.5
(>/)144 312 S -.25(va)-2.5 G(r/sheerdns/NS).25 E 2.5(>/)144 324 S -.25
(va)-2.5 G(r/sheerdns/SO).25 E(A)-.35 E(for i in)144 336 Q(\\)5 E 10
(a:198.41.0.4 h:128.63.2.53 c:192.33.4.12 g:192.112.36.4)146.5 348 R(\\)
10 E 7.5(f:192.5.5.241 b:128.9.0.107)146.5 360 R 5
(j:192.58.128.30 k:193.0.14.129)12.5 F(\\)10 E 5
(l:198.32.64.12 m:202.12.27.33)146.5 372 R 5
(i:192.36.148.17 e:192.203.230.10)10 F 2.5(;d)5 G(o)-2.5 E
(N=`echo $i | cut -f1 -d:`.root-serv)154 384 Q(ers.net)-.15 E
(echo $i | cut -f2 -d: > /v)154 396 Q
(ar/sheerdns/`sheerdnshash $N`/$N/A)-.25 E(echo $N >> /v)154 408 Q
(ar/sheerdns/NS)-.25 E(echo $N >> /v)154 420 Q(ar/sheerdns/SO)-.25 E(A)
-.35 E(done)144 432 Q(dig @localhost SO)144 444 Q 2.5(A.)-.35 G
(dig @localhost NS .)144 456 Q/F3 10.95/Times-Bold@0 SF(ENVIR)72 477.6 Q
(ONMENT V)-.329 E(ARIABLES)-1.478 E F0(There are no applicable en)108
489.6 Q(vironment v)-.4 E(ariables.)-.25 E F3(CONFIGURA)72 511.2 Q
(TION FILE)-1.04 E F1(sheerdns)108 523.2 Q F0
(has no con\214guration \214le. It just w)2.5 E(orks.)-.1 E F3 -.11(BU)
72 544.8 S(GS).11 E F0(No b)108 556.8 Q(ugs are kno)-.2 E
(wn at present.)-.25 E F3(FILES)72 578.4 Q F1(sheerdns)108 590.4 Q F0
(mak)3.118 E .618(es use of the directory)-.1 F F1(/v)3.118 E
(ar/sheerdns/*/*)-.1 E F0 .619
(to lookup entries. These directories are created on)3.119 F 2.5
(startup. No)108 602.4 R
(errors are reported if the directories could not be created.)2.5 E F3
(ST)72 624 Q(AND)-.986 E(ARDS)-.383 E F0(Hmmm, more than I ha)108 636 Q
.3 -.15(ve t)-.2 H(ime to read. Start with RFC-1035.).15 E F3 -1.04
-1.588(AV A)72 657.6 T(ILABILITY)1.588 E F0
(http://freshmeat.net/ will al)108 669.6 Q -.1(wa)-.1 G(ys ha).1 E .3
-.15(ve l)-.2 H(inks to the latest sheerdns.tar).15 E
(.gz source \214le as well as this page.)-.55 E F3 -.548(AU)72 691.2 S
(THOR).548 E F0 -.15(Pa)108 703.2 S(ul Sheer ).15 E
(Jan 11 2000)281.835 768 Q(3)204.835 E 0 Cg EP
%%Page: 4 4
%%BeginPageSetup
BP
%%EndPageSetup
/F0 10/Times-Roman@0 SF 372.2(sheerdns\(1\) sheerdns\(1\))72 48 R/F1
10.95/Times-Bold@0 SF(SEE ALSO)72 84 Q/F2 10/Times-Bold@0 SF(dig)108 96
Q F0(\(1\),)A F2(nslookup)2.5 E F0(\(8\),)A F2(BIND)2.5 E F0(,)A F2
(MyDNS)2.5 E F0(,)A F2(djbdns)2.5 E F0(,)A F2(tinydns)2.5 E F0(,)A F2
(Dents)2.5 E F0(.)A(Jan 11 2000)281.835 768 Q(4)204.835 E 0 Cg EP
%%Trailer
end
%%EOF
sheerdns/sheerdns.8 0100600 0000764 0000764 00000023216 10202741044 013534 0 ustar koala koala .\" -*- nroff -*-
.TH sheerdns 1 "Jan 11 2000"
.SH NAME
sheerdns - master DNS server
.SH SYNOPSIS
\fBsheerdns\fP [\fB-ttl\fP \fIseconds\fP] [\fB-p\fP \fIport\fP] [\fB-i\fP \fIiface-ip\fP] [\fB-d\fP]
.PP
\fBsheerdnshash\fP \fIstring\fP
.PP
.PP
.SH DESCRIPTION
\fBsheerdns\fP is a master DNS server whose zone records
are stored on a One-Record-Per-File bases. Because of
this, \fBsheerdns\fP is the simplest of any DNS to
configure, the easiest to update, and the most efficient
for networks that experience a lot of updates (for example
master servers for dynamic IP address ranges). You \fInever\fP
have to restart \fBsheerdns\fP; any updates are available
immediately without having to notify the \fBsheerdns\fP
process.
.PP
\fBsheerdns\fP is secure. \fBsheerdns\fP is fast because
Unix operating systems cache small files in memory.
.PP
\fBsheerdns\fP is written in strict ANSI C.
.PP
\fBsheerdnshash\fP creates a directory
\fB/var/sheerdns/\fP\fIXX\fP\fB/\fP\fIstring\fP\fB/\fP, where \fIXX\fP
is a hash of the string, and outputs \fIXX\fP to stdout.
.PP
Note that \fBsheerdns\fP is \fInot\fP a caching nameserver
for resolving queries about the rest of the Internet. It
is a master server for telling the rest of Internet about
the zones you are responsible for. No clients anywhere
should have a \fB/etc/resolv.conf\fP "nameserver" entry
that points to a \fBsheerdns\fP server.
.PP
\fBsheerdns\fP works by looking up queries from files of
the name:
.PP
.RS
\fB/var/sheerdns/\fP\fIXX\fP\fB/\fP\fIfull.doma.in\fP\fB/\fP\fIquery-type\fP.
.RE
.PP
These files are created by the administrator (or one of
his/her sh/perl/python/php scripts). You can write
anything to these files -- \fBsheerdns\fP will answer with
their contents even if they are bogus. The \fIXX\fP is an
upper-case two character hex number of the range \fB00\fP
to \fBFF\fP.
.PP
Each of these files contains one or more newline separated
strings. There should be no leading newlines, and zero or one
trailing newline. In the case of A records, the strings are
IP addresses, for example \fB192.0.2.1\fP. If there are
several IP addresses in the file, they are
order-randomized before return.
.PP
In the case of PTR, MX, NS, SOA, and CNAME records, the
strings are host-names. For MX and NS you can have
multiple hostnames per file, but for PTR, SOA, and CNAME
records, you must have only one entry in each file. TXT
records can contain anything---one record is returned for
each line in the file (TXT is not discussed again).
.PP
For MX records, the first entry in the file is given a
priority of 10, the second 20, and so on.
.PP
For SOA records, the modified time of the file counts as
the Serial-Number, and the contents as the name-server.
The administrator email address returned is just the
name-server prepended with "hostmaster", so you should make
sure this email address exists for that domain and is
reachable. The remaining fields are hardcoded to reasonable
default values. Note that time fields for SOA records are only
used for zone transfers hence are irrelevant here.
.PP
For NS and SOA records, an entry for a domain is valid for
all domains below it. For example, if you create an NS
record for the domain \fBtest.edu\fP, then that NS record
is returned for the domain \fBwww.test.edu\fP,
\fBftp.henry.test.edu\fP, as well as
\fBuser1.lab.chemistry.test.edu\fP. On the other hand a
separate NS record can be created for
\fBlab.chemistry.test.edu\fP, applying to all
domains \fB*.lab.chemistry.test.edu\fP, \fB*.*.lab.chemistry.test.edu\fP etc.
This works because \fBsheerdns\fP searches for NS records
by iteratively deleting the text up to the front most dot
until a nameserver is found. This gives the intuitively
expected behavior.
.PP
There is a special case for using \fBsheerdns\fP as a root
nameserver. See the example below.
.PP
\fBsheerdns\fP does lookups in lower case. All filenames
and file contents must be in lower case. \fBsheerdns\fP
does no interpretation of any of the file contents except
for the characters \\f\\n\\r\\t\\v and the dot character,
so it can probably manage UTF-8 domain names without a
problem.
.PP
\fBsheerdns\fP does not send TCP results longer than 1024
bytes, neither does it set the TC bit if the response
ought to be longer. If there are too many records to fit
in the packet, then trailing records are omitted to keep
within the 1024 byte limit. The packet format will be
valid none-the-less. Administrators should ensure that
their site is not so complex that large packets need to be
sent.
.PP
.SH OPTIONS
.TP
\fB-ttl\fP \fIseconds\fP
The Time-To-Live field to be set on outgoing packets.
Records that are likely to be fixed (not dynamic) are given
a 3-day ttl. Examples are the IP address of the NS record,
and the CNAME, MX, NS, and SOA records. All other records
are given the ttl specified in this option. The default is
86400 seconds (one day). This option should be set to 10
seconds for dynamic IP address ranges.
.TP
\fB-p\fP \fIport\fP
Listen port. Default is 53.
.TP
\fB-i\fP \fIiface-ip\fP
\fIinface-ip\fP is the network card you want to listen on.
If omitted, it defaults to 0.0.0.0 meaning \fIall\fP interfaces.
.TP
\fB-d\fP
Fork twice into the background (to run as a daemon
process); otherwise \fBsheerdns\fP runs in the foreground.
.PP
.SH WILDCARDS
An entry such as \fB*.test.com\fP will return results
as expected. This means you should
.PP
.RS
.nf
echo 192.0.2.1 > /var/sheerdns/`sheerdnshash '*'.test.com`/'*'.test.com/A
dig @localhost A lsdjkfhalsdfkjh.test.com
.fi
.RE
.PP
Note that quotes around the asterisk. This means the filename
has an asterisk in it which is never a good idea on Unix systems.
.PP
.SH EXAMPLES
These examples assume that you have already invoked \fBsheerdns\fP,
that you know what kind of records are appropriate to create, that
you do not guess, and that you realize that the examples are merely
shown for demonstration and not as a recommendation for the kinds
of records really required.
.PP
Add mutiple A records for \fBtest.com\fP for round robin sharing:
.PP
.RS
.nf
echo 192.0.2.1 > /var/sheerdns/`sheerdnshash test.com`/test.com/A
echo 192.0.2.2 >> /var/sheerdns/`sheerdnshash test.com`/test.com/A
echo 192.0.2.3 >> /var/sheerdns/`sheerdnshash test.com`/test.com/A
dig @localhost A test.com
dig @localhost A test.com
dig @localhost A test.com
.fi
.RE
.PP
Add a PTR records for \fBtest.com\fP:
.PP
.RS
.nf
echo test.com > /var/sheerdns/`sheerdnshash 192.0.2.1`/192.0.2.1/PTR
echo test.com > /var/sheerdns/`sheerdnshash 192.0.2.2`/192.0.2.2/PTR
echo test.com > /var/sheerdns/`sheerdnshash 192.0.2.3`/192.0.2.3/PTR
echo ns.ispfortest.net > /var/sheerdns/`sheerdnshash 192.0.2`/192.0.2/NS
dig @localhost PTR 1.2.0.192.in-addr.arpa
.fi
.RE
.PP
Add an MX record for \fBtest.com\fP with (IMPORTANT)
\fIboth\fP its forward, reverse, \fIand\fP nameserver
lookups:
.PP
.RS
.nf
echo mail.test.com > /var/sheerdns/`sheerdnshash test.com`/test.com/MX
echo 192.0.3.99 > /var/sheerdns/`sheerdnshash mail.test.com`/mail.test.com/A
echo mail.test.com > /var/sheerdns/`sheerdnshash 192.0.3.99`/192.0.3.99/PTR
echo ns.ispfortest.net > /var/sheerdns/`sheerdnshash test.com`/test.com/NS
dig @localhost MX test.com
.fi
.RE
.PP
Add an SOA record for \fBtest.com\fP. Note that although
SOA records are only required for zone transfers, some
institutions may demand them. The only configurable data
item in the SOA record is the authoritative nameserver
which is inserted as follows:
.PP
.RS
.nf
echo ns.ispfortest.net > /var/sheerdns/`sheerdnshash test.com`/test.com/SOA
dig @localhost SOA test.com
.fi
.RE
.PP
Add an CNAME record for \fBwww.test.com\fP. If you use a
CNAME, you should only have one line in the CNAME file,
and it should be the only file in the domain's directory,
and the CNAME should not appear anywhere as the text of
any other records. I repeat: "\fIIf you use a CNAME, you
should only have one line in the CNAME file, and it should
be the only file in the domain's directory, and the CNAME
should not appear anywhere as the text of any other
records.\fP". Do I need to say it a third time?
.PP
.RS
.nf
echo "I will not leave out the next command"
rm -f /var/sheerdns/`sheerdnshash www.test.com`/www.test.com/*
grep -w 'www[.]test[.]com' `find /var/sheerdns/ -type f` && \\
echo "This DNS setup is broken"
echo "I will not leave out the previous command"
echo test.com > /var/sheerdns/`sheerdnshash www.test.com`/www.test.com/CNAME
dig @localhost A www.test.com
.fi
.RE
.PP
Using \fBsheerdns\fP as a root nameserver. Note that for
root domains, the hash is especially omitted:
.PP
.RS
.nf
> /var/sheerdns/NS
> /var/sheerdns/SOA
for i in \\
a:198.41.0.4 h:128.63.2.53 c:192.33.4.12 g:192.112.36.4 \\
f:192.5.5.241 b:128.9.0.107 j:192.58.128.30 k:193.0.14.129 \\
l:198.32.64.12 m:202.12.27.33 i:192.36.148.17 e:192.203.230.10 ; do
N=`echo $i | cut -f1 -d:`.root-servers.net
echo $i | cut -f2 -d: > /var/sheerdns/`sheerdnshash $N`/$N/A
echo $N >> /var/sheerdns/NS
echo $N >> /var/sheerdns/SOA
done
dig @localhost SOA .
dig @localhost NS .
.fi
.RE
.PP
.SH "ENVIRONMENT VARIABLES"
There are no applicable environment variables.
.PP
.SH "CONFIGURATION FILE"
\fBsheerdns\fP has no configuration file. It just works.
.PP
.SH BUGS
No bugs are known at present.
.PP
.SH FILES
\fBsheerdns\fP makes use of the directory \fB/var/sheerdns/*/*\fP
to lookup entries. These directories are created on startup.
No errors are reported if the directories could not be created.
.PP
.SH STANDARDS
Hmmm, more than I have time to read. Start with RFC-1035.
.PP
.SH AVAILABILITY
http://freshmeat.net/ will always have links to the latest
sheerdns.tar.gz source file as well as this page.
.PP
.SH AUTHOR
Paul Sheer
.PP
.SH "SEE ALSO"
\fBdig\fP(1), \fBnslookup\fP(8), \fBBIND\fP, \fBMyDNS\fP,
\fBdjbdns\fP, \fBtinydns\fP, \fBDents\fP.
sheerdns/sheerdns.html 0100644 0000000 0000000 00000046227 10202742377 014110 0 ustar root root
sheerdns
sheerdns
NAME
SYNOPSIS
DESCRIPTION
OPTIONS
WILDCARDS
EXAMPLES
ENVIRONMENT VARIABLES
CONFIGURATION FILE
BUGS
FILES
STANDARDS
AVAILABILITY
AUTHOR
SEE ALSO
NAME
|
sheerdns - master DNS server
|
SYNOPSIS
|
sheerdns [-ttl seconds] [-p
port] [-i iface-ip] [-d]
sheerdnshash string
|
DESCRIPTION
|
sheerdns is a master DNS server whose zone records
are stored on a One-Record-Per-File bases. Because of this,
sheerdns is the simplest of any DNS to configure, the
easiest to update, and the most efficient for networks that
experience a lot of updates (for example master servers for
dynamic IP address ranges). You never have to restart
sheerdns; any updates are available immediately
without having to notify the sheerdns process.
sheerdns is secure. sheerdns is fast
because Unix operating systems cache small files in
memory.
sheerdns is written in strict ANSI C.
sheerdnshash creates a directory
/var/sheerdns/XX/string/,
where XX is a hash of the string, and outputs
XX to stdout.
Note that sheerdns is not a caching
nameserver for resolving queries about the rest of the
Internet. It is a master server for telling the rest of
Internet about the zones you are responsible for. No clients
anywhere should have a /etc/resolv.conf
"nameserver" entry that points to a
sheerdns server.
sheerdns works by looking up queries from files of
the name:
|
|
/var/sheerdns/XX/full.doma.in/query-type. |
|
These files are created by the administrator (or one of
his/her sh/perl/python/php scripts). You can write anything
to these files -- sheerdns will answer with their
contents even if they are bogus. The XX is an
upper-case two character hex number of the range 00
to FF.
Each of these files contains one or more newline
separated strings. There should be no leading newlines, and
zero or one trailing newline. In the case of A records, the
strings are IP addresses, for example 192.0.2.1. If
there are several IP addresses in the file, they are
order-randomized before return.
In the case of PTR, MX, NS, SOA, and CNAME records, the
strings are host-names. For MX and NS you can have multiple
hostnames per file, but for PTR, SOA, and CNAME records, you
must have only one entry in each file. TXT records can
contain anything---one record is returned for each line in
the file (TXT is not discussed again).
For MX records, the first entry in the file is given a
priority of 10, the second 20, and so on.
For SOA records, the modified time of the file counts as
the Serial-Number, and the contents as the name-server. The
administrator email address returned is just the name-server
prepended with "hostmaster", so you should make
sure this email address exists for that domain and is
reachable. The remaining fields are hardcoded to reasonable
default values. Note that time fields for SOA records are
only used for zone transfers hence are irrelevant here.
For NS and SOA records, an entry for a domain is valid
for all domains below it. For example, if you create an NS
record for the domain test.edu, then that NS record
is returned for the domain www.test.edu,
ftp.henry.test.edu, as well as
user1.lab.chemistry.test.edu. On the other hand a
separate NS record can be created for
lab.chemistry.test.edu, applying to all domains
*.lab.chemistry.test.edu,
*.*.lab.chemistry.test.edu etc. This works because
sheerdns searches for NS records by iteratively
deleting the text up to the front most dot until a
nameserver is found. This gives the intuitively expected
behavior.
There is a special case for using sheerdns as a
root nameserver. See the example below.
sheerdns does lookups in lower case. All filenames
and file contents must be in lower case. sheerdns
does no interpretation of any of the file contents except
for the characters \f\n\r\t\v and the dot character, so it
can probably manage UTF-8 domain names without a
problem.
sheerdns does not send TCP results longer than
1024 bytes, neither does it set the TC bit if the response
ought to be longer. If there are too many records to fit in
the packet, then trailing records are omitted to keep within
the 1024 byte limit. The packet format will be valid
none-the-less. Administrators should ensure that their site
is not so complex that large packets need to be sent.
|
OPTIONS
|
The Time-To-Live field to be set on outgoing packets.
Records that are likely to be fixed (not dynamic) are given
a 3-day ttl. Examples are the IP address of the NS record,
and the CNAME, MX, NS, and SOA records. All other records
are given the ttl specified in this option. The default is
86400 seconds (one day). This option should be set to 10
seconds for dynamic IP address ranges.
|
|
Listen port. Default is 53.
|
|
inface-ip is the network card you want to listen
on. If omitted, it defaults to 0.0.0.0 meaning all
interfaces.
|
|
-d
|
|
Fork twice into the background (to run as a daemon
process); otherwise sheerdns runs in the
foreground.
|
WILDCARDS
|
An entry such as *.test.com will return results as
expected. This means you should
|
|
echo 192.0.2.1 > /var/sheerdns/‘sheerdnshash ’*’.test.com‘/’*’.test.com/A
dig @localhost A lsdjkfhalsdfkjh.test.com
|
|
Note that quotes around the asterisk. This means the
filename has an asterisk in it which is never a good idea on
Unix systems.
|
EXAMPLES
|
These examples assume that you have already invoked
sheerdns, that you know what kind of records are
appropriate to create, that you do not guess, and that you
realize that the examples are merely shown for demonstration
and not as a recommendation for the kinds of records really
required.
Add mutiple A records for test.com for round robin
sharing:
|
|
echo 192.0.2.1 > /var/sheerdns/‘sheerdnshash test.com‘/test.com/A
echo 192.0.2.2 >> /var/sheerdns/‘sheerdnshash test.com‘/test.com/A
echo 192.0.2.3 >> /var/sheerdns/‘sheerdnshash test.com‘/test.com/A
dig @localhost A test.com
dig @localhost A test.com
dig @localhost A test.com
|
|
Add a PTR records for test.com:
|
|
echo test.com > /var/sheerdns/‘sheerdnshash 192.0.2.1‘/192.0.2.1/PTR
echo test.com > /var/sheerdns/‘sheerdnshash 192.0.2.2‘/192.0.2.2/PTR
echo test.com > /var/sheerdns/‘sheerdnshash 192.0.2.3‘/192.0.2.3/PTR
echo ns.ispfortest.net > /var/sheerdns/‘sheerdnshash 192.0.2‘/192.0.2/NS
dig @localhost PTR 1.2.0.192.in-addr.arpa
|
|
Add an MX record for test.com with (IMPORTANT)
both its forward, reverse, and nameserver
lookups:
|
|
echo mail.test.com > /var/sheerdns/‘sheerdnshash test.com‘/test.com/MX
echo 192.0.3.99 > /var/sheerdns/‘sheerdnshash mail.test.com‘/mail.test.com/A
echo mail.test.com > /var/sheerdns/‘sheerdnshash 192.0.3.99‘/192.0.3.99/PTR
echo ns.ispfortest.net > /var/sheerdns/‘sheerdnshash test.com‘/test.com/NS
dig @localhost MX test.com
|
|
Add an SOA record for test.com. Note that although
SOA records are only required for zone transfers, some
institutions may demand them. The only configurable data
item in the SOA record is the authoritative nameserver which
is inserted as follows:
|
|
echo ns.ispfortest.net > /var/sheerdns/‘sheerdnshash test.com‘/test.com/SOA
dig @localhost SOA test.com
|
|
Add an CNAME record for www.test.com. If you use a
CNAME, you should only have one line in the CNAME file, and
it should be the only file in the domain’s directory,
and the CNAME should not appear anywhere as the text of any
other records. I repeat: "If you use a CNAME, you
should only have one line in the CNAME file, and it should
be the only file in the domain’s directory, and the
CNAME should not appear anywhere as the text of any other
records.". Do I need to say it a third time?
|
|
echo "I will not leave out the next command"
rm -f /var/sheerdns/‘sheerdnshash www.test.com‘/www.test.com/*
grep -w ’www[.]test[.]com’ ‘find /var/sheerdns/ -type f‘ && \
echo "This DNS setup is broken"
echo "I will not leave out the previous command"
echo test.com > /var/sheerdns/‘sheerdnshash www.test.com‘/www.test.com/CNAME
dig @localhost A www.test.com
|
|
Using sheerdns as a root nameserver. Note that for
root domains, the hash is especially omitted:
|
|
> /var/sheerdns/NS
> /var/sheerdns/SOA
for i in \
a:198.41.0.4 h:128.63.2.53 c:192.33.4.12 g:192.112.36.4 \
f:192.5.5.241 b:128.9.0.107 j:192.58.128.30 k:193.0.14.129 \
l:198.32.64.12 m:202.12.27.33 i:192.36.148.17 e:192.203.230.10 ; do
N=‘echo $i | cut -f1 -d:‘.root-servers.net
echo $i | cut -f2 -d: > /var/sheerdns/‘sheerdnshash $N‘/$N/A
echo $N >> /var/sheerdns/NS
echo $N >> /var/sheerdns/SOA
done
dig @localhost SOA .
dig @localhost NS .
|
ENVIRONMENT VARIABLES
|
There are no applicable environment variables.
|
CONFIGURATION FILE
|
sheerdns has no configuration file. It just
works.
|
BUGS
|
No bugs are known at present.
|
FILES
|
sheerdns makes use of the directory
/var/sheerdns/*/* to lookup entries. These
directories are created on startup. No errors are reported
if the directories could not be created.
|
STANDARDS
|
Hmmm, more than I have time to read. Start with
RFC-1035.
|
AVAILABILITY
|
http://freshmeat.net/ will always have links to the
latest sheerdns.tar.gz source file as well as this page.
|
AUTHOR
|
Paul Sheer <psheer@icon.co.za>
|
SEE ALSO
|
dig(1), nslookup(8), BIND,
MyDNS, djbdns, tinydns,
Dents.
|