Commit Diff
Diff:
/dev/null
c45084eaeb5abd393561d940a00730926706d812
Commit:
c45084eaeb5abd393561d940a00730926706d812
Tree:
460323a2fc5b536d375def106be7c26a0b7cd602
Author:
pbug <pbug@delphinusdns.org>
Committer:
pbug <pbug@delphinusdns.org>
Date:
Tue Nov 29 17:00:02 2005 UTC
Message:
* initial import
blob - /dev/null
blob + 460f5d5dbb52a3ce9e14f8a94c8d6eca0af662c6 (mode 644)
--- /dev/null
+++ Makefile
@@ -0,0 +1,12 @@
+PROG=wildcarddnsd
+SRCS=main.c parse.c reply.c additional.c
+
+#CFLAGS= -DDEBUG -g -Wall
+CFLAGS= -Wall -g
+
+OBJDIR=.
+BINDIR=/usr/local/sbin
+
+MAN= wildcarddnsd.8
+
+.include <bsd.prog.mk>
blob - /dev/null
blob + ffa9b491393f5bc2342eac3ddced1c67f8bfde6d (mode 644)
--- /dev/null
+++ README
@@ -0,0 +1,15 @@
+README
+
+To install type make, followed by make install.
+
+By default installation the configuration file is not installed you need to
+do this manually. Also by default the config file is specified as
+/etc/wildcarddns.conf this can be changed by adding the -f option to
+wildcarddnsd.
+
+A sample config file exists with the sources, the comments should be pretty
+straight forward.
+
+Enjoy using Wildcard DNS.
+
+-peter
blob - /dev/null
blob + 467587e7381d9faadb5de5b96bb0aeff7622523b (mode 644)
--- /dev/null
+++ TODO
@@ -0,0 +1,14 @@
+Here are a few things left to do (until beta):
+
+* CNAME needs to include answers to the RR type originally requested. [done]
+* NXDOMAIN should include an AUTHORITY SOA.
+* AAAA and A RR's when there is more than 1 need to be rotated every answer in
+ order to make use of load sharing.
+* TXT RR support
+* TCP support
+
+Here are a few things nice to have but not necessarily needed:
+
+* recursing and caching support
+* access lists
+* DNSSEC
blob - /dev/null
blob + f0fe836dd6401c155d6090d6098de619bb946203 (mode 644)
--- /dev/null
+++ additional.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2005 Peter Philipp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "include.h"
+#include "dns.h"
+#include "db.h"
+
+int additional_a(char *, int, struct domain *, char *, int, int, int *);
+int additional_aaaa(char *, int, struct domain *, char *, int, int, int *);
+int additional_mx(char *, int, struct domain *, char *, int, int, int *);
+int additional_ptr(char *, int, struct domain *, char *, int, int, int *);
+
+extern int compress_label(char *, int, int);
+
+
+/*
+ * ADDITIONAL_A - tag on an additional set of A records to packet
+ */
+
+int
+additional_a(char *name, int namelen, struct domain *sd, char *reply, int replylen, int offset, int *retcount)
+{
+ int a_count;
+ int tmplen;
+ int rroffset = offset;
+
+ struct answer {
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl;
+ u_int16_t rdlength; /* 12 */
+ in_addr_t rdata; /* 16 */
+ } __attribute__((packed));
+
+ struct answer *answer;
+
+ *retcount = 0;
+
+ /*
+ * We loop through our sd->a entries starting at the ptr offset
+ * first in the first loop and at the beginning until the ptr
+ * in the last loop. This will shift answers based on a_ptr.
+ */
+
+ for (a_count = sd->a_ptr; a_count < sd->a_count; a_count++) {
+ rroffset = offset;
+ if ((offset + namelen) > replylen)
+ goto out;
+
+ memcpy(&reply[offset], name, namelen);
+ offset += namelen;
+ tmplen = compress_label(reply, offset, namelen);
+
+ if (tmplen != 0) {
+ offset = tmplen;
+ }
+ if ((offset + sizeof(struct answer)) > replylen) {
+ offset = rroffset;
+ goto out;
+ }
+
+ answer = (struct answer *)&reply[offset];
+
+ answer->type = htons(DNS_TYPE_A);
+ answer->class = htons(DNS_CLASS_IN);
+ answer->ttl = htonl(sd->ttl);
+
+ answer->rdlength = htons(sizeof(in_addr_t));
+
+ memcpy((char *)&answer->rdata, (char *)&sd->a[a_count], sizeof(in_addr_t));
+ offset += sizeof(struct answer);
+ (*retcount)++;
+
+ }
+
+ for (a_count = 0; a_count < sd->a_ptr; a_count++) {
+ rroffset = offset;
+ if ((offset + namelen) > replylen)
+ goto out;
+
+ memcpy(&reply[offset], name, namelen);
+ offset += namelen;
+ tmplen = compress_label(reply, offset, namelen);
+
+ if (tmplen != 0) {
+ offset = tmplen;
+ }
+ if ((offset + sizeof(struct answer)) > replylen) {
+ offset = rroffset;
+ goto out;
+ }
+
+ answer = (struct answer *)&reply[offset];
+
+ answer->type = htons(DNS_TYPE_A);
+ answer->class = htons(DNS_CLASS_IN);
+ answer->ttl = htonl(sd->ttl);
+
+ answer->rdlength = htons(sizeof(in_addr_t));
+
+ memcpy((char *)&answer->rdata, (char *)&sd->a[a_count], sizeof(in_addr_t));
+ offset += sizeof(struct answer);
+ (*retcount)++;
+ }
+
+
+out:
+ return (offset);
+
+}
+
+/*
+ * ADDITIONAL_AAAA - tag on an additional set of AAAA records to packet
+ */
+
+int
+additional_aaaa(char *name, int namelen, struct domain *sd, char *reply, int replylen, int offset, int *retcount)
+{
+ int aaaa_count;
+ int tmplen;
+ int rroffset = offset;
+
+ struct answer {
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl;
+ u_int16_t rdlength;
+ struct in6_addr rdata;
+ } __attribute__((packed));
+
+ struct answer *answer;
+
+ *retcount = 0;
+
+ /*
+ * We loop through our sd->aaaa entries starting at the ptr offset
+ * first in the first loop and at the beginning until the ptr
+ * in the last loop. This will shift answers based on a_ptr.
+ */
+
+ for (aaaa_count = sd->aaaa_ptr; aaaa_count < sd->aaaa_count; aaaa_count++) {
+ rroffset = offset;
+ if ((offset + namelen) > replylen)
+ goto out;
+
+ memcpy(&reply[offset], name, namelen);
+ offset += namelen;
+ tmplen = compress_label(reply, offset, namelen);
+
+ if (tmplen != 0) {
+ offset = tmplen;
+ }
+
+ if ((offset + sizeof(struct answer)) > replylen) {
+ offset = rroffset;
+ goto out;
+ }
+
+ answer = (struct answer *)&reply[offset];
+
+ answer->type = htons(DNS_TYPE_AAAA);
+ answer->class = htons(DNS_CLASS_IN);
+ answer->ttl = htonl(sd->ttl);
+
+ answer->rdlength = htons(sizeof(struct in6_addr));
+
+ memcpy((char *)&answer->rdata, (char *)&sd->aaaa[aaaa_count], sizeof(struct in6_addr));
+ offset += sizeof(struct answer);
+ (*retcount)++;
+
+ }
+
+ for (aaaa_count = 0; aaaa_count < sd->aaaa_ptr; aaaa_count++) {
+ rroffset = offset;
+ if ((offset + namelen) > replylen)
+ goto out;
+
+
+ memcpy(&reply[offset], name, namelen);
+ offset += namelen;
+ tmplen = compress_label(reply, offset, namelen);
+
+ if (tmplen != 0) {
+ offset = tmplen;
+ }
+ if ((offset + sizeof(struct answer)) > replylen) {
+ offset = rroffset;
+ goto out;
+ }
+
+ answer = (struct answer *)&reply[offset];
+
+ answer->type = htons(DNS_TYPE_AAAA);
+ answer->class = htons(DNS_CLASS_IN);
+ answer->ttl = htonl(sd->ttl);
+
+ answer->rdlength = htons(sizeof(struct in6_addr));
+
+
+ memcpy((char *)&answer->rdata, (char *)&sd->aaaa[aaaa_count], sizeof(struct in6_addr));
+ offset += sizeof(struct answer);
+ (*retcount)++;
+ }
+
+
+out:
+ return (offset);
+
+}
+
+/*
+ * ADDITIONAL_MX() - replies a DNS question (*q) on socket (so)
+ *
+ */
+
+int
+additional_mx(char *name, int namelen, struct domain *sd, char *reply, int replylen, int offset, int *retcount)
+{
+ int mx_count;
+ int tmplen;
+ int rroffset = offset;
+
+ struct answer {
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl;
+ u_int16_t rdlength;
+ u_int16_t mx_priority;
+ } __attribute__((packed));
+
+ struct answer *answer;
+
+ *retcount = 0;
+
+ /*
+ * We loop through our sd->mx entries starting at the ptr offset
+ * first in the first loop and at the beginning until the ptr
+ * in the last loop. This will shift answers based on mx_ptr.
+ */
+
+ for (mx_count = sd->mx_ptr; mx_count < sd->mx_count; mx_count++) {
+ rroffset = offset;
+
+ if ((offset + namelen) > replylen)
+ goto out;
+
+ memcpy(&reply[offset], name, namelen);
+ offset += namelen;
+ tmplen = compress_label(reply, offset, namelen);
+
+ if (tmplen != 0) {
+ offset = tmplen;
+ }
+
+ if ((offset + sizeof(struct answer)) > replylen) {
+ offset = rroffset;
+ goto out;
+ }
+
+ answer = (struct answer *)&reply[offset];
+
+ answer->type = htons(DNS_TYPE_MX);
+ answer->class = htons(DNS_CLASS_IN);
+ answer->ttl = htonl(sd->ttl);
+ answer->mx_priority = htons(sd->mx[mx_count].preference);
+
+ offset += sizeof(struct answer);
+
+ if ((offset + sd->mx[mx_count].exchangelen) > replylen) {
+ offset = rroffset;
+ goto out;
+ }
+
+ memcpy((char *)&reply[offset], (char *)&sd->mx[mx_count].exchange, sd->mx[mx_count].exchangelen);
+
+ offset += sd->mx[mx_count].exchangelen;
+ tmplen = compress_label(reply, offset, sd->mx[mx_count].exchangelen);
+
+ if (tmplen != 0) {
+ answer->rdlength = htons((sd->mx[mx_count].exchangelen - (offset - tmplen)) + sizeof(u_int16_t));
+ offset = tmplen;
+ } else
+ answer->rdlength = htons(sd->mx[mx_count].exchangelen + sizeof(u_int16_t));
+
+
+ (*retcount)++;
+
+ }
+
+ for (mx_count = 0; mx_count < sd->mx_ptr; mx_count++) {
+ rroffset = offset;
+
+ if ((offset + namelen) > replylen)
+ goto out;
+
+
+ memcpy(&reply[offset], name, namelen);
+ offset += namelen;
+ tmplen = compress_label(reply, offset, namelen);
+
+ if (tmplen != 0) {
+ offset = tmplen;
+ }
+
+ if ((offset + sizeof(struct answer)) > replylen) {
+ offset = rroffset;
+ goto out;
+ }
+
+ answer = (struct answer *)&reply[offset];
+
+ answer->type = htons(DNS_TYPE_A);
+ answer->class = htons(DNS_CLASS_IN);
+ answer->ttl = htonl(sd->ttl);
+
+ offset += sizeof(struct answer);
+
+ if ((offset + sd->mx[mx_count].exchangelen) > replylen) {
+ offset = rroffset;
+ goto out;
+ }
+
+ memcpy((char *)&reply[offset], (char *)&sd->mx[mx_count].exchange, sd->mx[mx_count].exchangelen);
+
+ offset += sd->mx[mx_count].exchangelen;
+ tmplen = compress_label(reply, offset, sd->mx[mx_count].exchangelen);
+
+ if (tmplen != 0) {
+
+ answer->rdlength = htons((sd->mx[mx_count].exchangelen - (offset - tmplen)) + sizeof(u_int16_t));
+ offset = tmplen;
+ } else
+ answer->rdlength = htons(sd->mx[mx_count].exchangelen + sizeof(u_int16_t));
+
+ (*retcount)++;
+ }
+
+
+out:
+ return (offset);
+
+}
+
+/*
+ * ADDITIONAL_PTR() - replies a DNS question (*q) on socket (so)
+ *
+ */
+
+
+int
+additional_ptr(char *name, int namelen, struct domain *sd, char *reply, int replylen, int offset, int *retcount)
+{
+ int tmplen;
+ int rroffset = offset;
+
+ struct answer {
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl;
+ u_int16_t rdlength;
+ } __attribute__((packed));
+
+ struct answer *answer;
+
+ *retcount = 0;
+
+
+ if ((offset + namelen) > replylen)
+ goto out;
+
+ memcpy(&reply[offset], name, namelen);
+ offset += namelen;
+ tmplen = compress_label(reply, offset, namelen);
+
+ if (tmplen != 0) {
+ offset = tmplen;
+ }
+
+ if ((offset + sizeof(struct answer)) > replylen) {
+ offset = rroffset;
+ goto out;
+ }
+
+ answer = (struct answer *)&reply[offset];
+
+ answer->type = htons(DNS_TYPE_PTR);
+ answer->class = htons(DNS_CLASS_IN);
+ answer->ttl = htonl(sd->ttl);
+
+ offset += sizeof(struct answer);
+
+ if ((offset + sd->ptrlen) > replylen) {
+ offset = rroffset;
+ goto out;
+ }
+
+ memcpy((char *)&reply[offset], (char *)&sd->ptr, sd->ptrlen);
+
+ offset += sd->ptrlen;
+ tmplen = compress_label(reply, offset, sd->ptrlen);
+
+ if (tmplen != 0) {
+ answer->rdlength = htons(sd->ptrlen - (offset - tmplen));
+ offset = tmplen;
+ } else
+ answer->rdlength = htons(sd->ptrlen);
+
+
+ (*retcount)++;
+
+out:
+ return (offset);
+
+}
blob - /dev/null
blob + 6a955796282f21a7ceb7e1d01ffb91b65643ba1a (mode 644)
--- /dev/null
+++ db.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2005 Peter Philipp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef _DB_H
+#define _DB_H
+
+#define CONFFILE "/etc/wildcarddns.conf"
+
+#define ERR_DROP 0x1
+#define ERR_NXDOMAIN 0x2
+
+/* db stuff */
+
+struct soa {
+ char nsserver[DNS_MAXNAME];
+ u_int8_t nsserver_len;
+ char responsible_person[DNS_MAXNAME];
+ u_int8_t rp_len;
+ u_int32_t serial;
+ u_int32_t refresh;
+ u_int32_t retry;
+ u_int32_t expire;
+ u_int32_t minttl;
+} __attribute__((packed));
+
+struct smx {
+ u_int16_t preference;
+ char exchange[DNS_MAXNAME];
+ u_int8_t exchangelen;
+} __attribute__((packed));
+
+struct ns {
+ char nsserver[DNS_MAXNAME];
+ u_int8_t nslen;
+} __attribute__((packed));
+
+struct domain {
+ char zone[DNS_MAXNAME]; /* name of zone in dns name format */
+ char zonename[DNS_MAXNAME + 1]; /* name of zone in human readable */
+ u_int16_t flags; /* flags of zone */
+#define DOMAIN_HAVE_A 0x1
+#define DOMAIN_HAVE_SOA 0x2
+#define DOMAIN_HAVE_CNAME 0x4
+#define DOMAIN_HAVE_PTR 0x8
+#define DOMAIN_HAVE_MX 0x10
+#define DOMAIN_HAVE_AAAA 0x20
+#define DOMAIN_HAVE_NS 0x40
+ struct soa soa;
+ u_int32_t ttl;
+ in_addr_t a[10];
+ int a_count;
+ int a_ptr;
+ struct in6_addr aaaa[10];
+ int aaaa_count;
+ int aaaa_ptr;
+ struct smx mx[10];
+ int mx_count;
+ int mx_ptr;
+ struct ns ns[10];
+ int ns_count;
+ int ns_ptr;
+ char cname[DNS_MAXNAME];
+ u_int8_t cnamelen;
+ char ptr[DNS_MAXNAME];
+ u_int8_t ptrlen;
+} __attribute__((packed));
+
+struct sreply {
+ int so; /* socket */
+ char *buf; /* question packet */
+ int len; /* question packet length */
+ struct question *q; /* struct question */
+ struct sockaddr *sa; /* struct sockaddr of question */
+ int salen; /* length of struct sockaddr */
+ struct domain *sd1; /* first resolved domain */
+ struct domain *sd2; /* CNAME to second resolved domain */
+};
+
+/*
+ * the BUILD_REPLY macro fills struct sreply with given information,
+ * It's hoped that this will speed up things instead of a build_reply()
+ * function.
+ * (hopefully the only macro in the program !!!!)
+ */
+
+#define BUILD_REPLY(reply, so0, buf0, len0, q0, sa0, salen0, sd10, sd20) \
+ do { \
+ reply.so = so0; \
+ reply.buf = buf0; \
+ reply.len = len0; \
+ reply.q = q0; \
+ reply.sa = sa0; \
+ reply.salen = salen0; \
+ reply.sd1 = sd10; \
+ reply.sd2 = sd20; \
+ } while (0);
+
+int parse_file(DB *db, char *);
+DB * opendatabase(DB *);
+
+
+#endif /* _DB_H */
blob - /dev/null
blob + 2e4d054ff82e36255fbc3083f5dc12cad974a16c (mode 644)
--- /dev/null
+++ dns.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2002, 2003, 2005 Peter Philipp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef _DNS_H
+#define _DNS_H
+
+
+/* RFC 1035 - page 26 */
+
+struct dns_header {
+ u_int16_t id; /* ID of header */
+ u_int16_t query;
+ u_int16_t question; /* # of question entries */
+ u_int16_t answer; /* # of answer RR's */
+ u_int16_t nsrr; /* # of NS RR's */
+ u_int16_t additional; /* # additional RR's */
+};
+
+struct dns_hints {
+ int proto;
+ u_int16_t id;
+ u_int16_t query;
+ u_int16_t question;
+ u_int16_t answer;
+ u_int16_t nsrr;
+ u_int16_t additional;
+};
+
+/*
+ * resource record structure
+ * RFC 1035 - page 9
+ */
+
+struct dns_rr {
+ char *name; /* name of zone */
+ char *question; /* pointer to question */
+ u_int16_t type; /* type of RR */
+ u_int16_t class; /* class of reply */
+ u_int32_t ttl; /* ttl of record */
+ u_int16_t rdlen; /* length of record */
+ char *rdata; /* data of record */
+};
+
+/* RFC 1035 - page 28 */
+struct dns_question_hdr {
+ char *name;
+ u_int namelen;
+ u_int16_t qtype;
+ u_int16_t qclass;
+};
+
+
+
+/*
+ * flags RFC 1035, page 26
+ */
+
+#define DNS_REPLY 0x8000 /* if set response if not set query */
+#define DNS_SREQ 0x1000 /* if set a server status request (STATUS) */
+#define DNS_INV 0x800 /* if set an inverse query */
+#define DNS_AUTH 0x400 /* Authoritative Answer (AA) in replies */
+#define DNS_TRUNC 0x200 /* Truncated (TC) */
+#define DNS_RECURSE 0x100 /* if set Recursion Desired (RD) */
+#define DNS_RECAVAIL 0x80 /* if set Recursion Available (RA) */
+#define DNS_REFUSED 0x5 /* RCODE - Refused */
+#define DNS_NOTIMPL 0x4 /* RCODE - Not Implemented */
+#define DNS_NAMEERR 0x3 /* RCODE - Name Error */
+#define DNS_SERVFAIL 0x2 /* RCODE - Server Failure */
+#define DNS_FORMATERR 0x1 /* RCODE - Format Error */
+#define DNS_NOERR 0x0 /* RCODE - No error */
+
+/*
+ * macros to set flags (must be converted to network byte order after)
+ */
+
+#define SET_DNS_REPLY(x) ((x)->query |= (DNS_REPLY))
+#define SET_DNS_QUERY(x) ((x)->query &= (DNS_REPLY))
+#define SET_DNS_STATUS_REQ(x) ((x)->query |= (DNS_SREQ))
+#define SET_DNS_INVERSE_QUERY(x) ((x)->query |= (DNS_INV))
+#define SET_DNS_AUTHORITATIVE(x) ((x)->query |= (DNS_AUTH))
+#define SET_DNS_TRUNCATION(x) ((x)->query |= (DNS_TRUNC))
+#define SET_DNS_RECURSION(x) ((x)->query |= (DNS_RECURSE))
+#define SET_DNS_RECURSION_AVAIL(x) ((x)->query |= (DNS_RECAVAIL))
+#define SET_DNS_RCODE_REFUSED(x) ((x)->query |= (DNS_REFUSED))
+#define SET_DNS_RCODE_NOTIMPL(x) ((x)->query |= (DNS_NOTIMPL))
+#define SET_DNS_RCODE_NAMEERR(x) ((x)->query |= (DNS_NAMEERR))
+#define SET_DNS_RCODE_SERVFAIL(x) ((x)->query |= (DNS_SERVFAIL))
+#define SET_DNS_RCODE_NOERR(x) ((x)->query |= (DNS_NOERR))
+
+/* DNS types - RFC 1035 page 12 */
+
+#define DNS_TYPE_A 1
+#define DNS_TYPE_NS 2
+#define DNS_TYPE_CNAME 5
+#define DNS_TYPE_SOA 6
+#define DNS_TYPE_PTR 12
+#define DNS_TYPE_MX 15
+#define DNS_TYPE_TXT 16
+
+/* quad A - RFC 3596 */
+#define DNS_TYPE_AAAA 28
+
+
+/* DNS CLASSES - RFC 1035 page 13 */
+
+#define DNS_CLASS_IN 1 /* internet */
+#define DNS_CLASS_CH 3 /* chaos */
+#define DNS_CLASS_HS 4 /* hesiod */
+
+#define DNS_CLASS_ANY 255 /* any class */
+
+/* limits */
+
+#define DNS_MAXLABEL 63
+#define DNS_MAXNAME 255
+#define DNS_MAXUDP 512
+
+
+struct question {
+ struct dns_question_hdr *hdr;
+ char *converted_name;
+};
+
+#endif /* DNS_H */
blob - /dev/null
blob + a3a4f09038850f8a9dd31aa7e9940b3dbcdf7da4 (mode 644)
--- /dev/null
+++ include.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2005 Peter Philipp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef _INCLUDES_H
+#define _INCLUDES_H
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <db.h>
+#include <pwd.h>
+#include <ifaddrs.h>
+
+#endif
blob - /dev/null
blob + 7730ed669959d8ef73da14051d2b4b9e6c611fcf (mode 644)
--- /dev/null
+++ main.c
@@ -0,0 +1,1239 @@
+/*
+ * Copyright (c) 2002, 2005 Peter Philipp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "include.h"
+#include "dns.h"
+#include "db.h"
+
+/* prototypes */
+
+
+
+struct question * build_question(char *, int);
+struct question * build_fake_question(char *, int, u_int16_t);
+void mainloop(int *, int *, int, char **, DB *);
+int free_question(struct question *);
+int lookup_zone(DB *, struct question *, struct domain *, int *, char *);
+
+extern void reply_notimpl(struct sreply *);
+extern void reply_nxdomain(struct sreply *);
+extern void reply_a(struct sreply *);
+extern void reply_aaaa(struct sreply *);
+extern void reply_soa(struct sreply *);
+extern void reply_ptr(struct sreply *);
+extern void reply_cname(struct sreply *);
+extern void reply_mx(struct sreply *);
+extern void reply_ns(struct sreply *);
+char * dns_label(char *, int *);
+int compress_label(char *, int, int);
+int memcasecmp(char *, char *, int);
+
+#define DEFAULT_PRIVILEGE "named"
+#define DEFAULT_SOCKET 64
+
+extern char *__progname;
+
+/*
+ * MAIN - set up arguments, set up database, set up sockets, call mainloop
+ *
+ */
+
+int
+main(int argc, char *argv[])
+{
+ int udp[DEFAULT_SOCKET];
+ int tcp[DEFAULT_SOCKET];
+ static char *ident[DEFAULT_SOCKET];
+
+ int ch, i, j;
+ int gai_error;
+ int salen;
+ int bflag = 0, iflag = 0;
+ int bcount = 0, icount = 0;
+ int found = 0;
+ u_int16_t port = 53;
+
+
+ struct passwd *pw;
+ struct addrinfo hints, *res0, *res;
+ char *conffile = CONFFILE;
+ char buf[512];
+ struct ifaddrs *ifap, *pifap;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ char *interface_list[255];
+ char *bind_list[255];
+
+ static DB *db;
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "must be started as root\n"); /* .. dolt */
+ exit(1);
+ }
+
+ while ((ch = getopt(argc, argv, "b:i:f:p:")) != -1) {
+ switch (ch) {
+ case 'b':
+ bflag = 1;
+ if (bcount > 253) {
+ fprintf(stderr, "too man -b flags\n");
+ exit(1);
+ }
+ bind_list[bcount++] = optarg;
+ break;
+ case 'i':
+ iflag = 1;
+ if (icount > 254) {
+ fprintf(stderr, "too many -i flags\n");
+ exit(1);
+ }
+ interface_list[icount++] = optarg;
+ break;
+ case 'f':
+ conffile = optarg;
+ break;
+ case 'p':
+ port = atoi(optarg) & 0xffff;
+ break;
+ default:
+ fprintf(stderr, "usage: dnsserver [-i interface] [-b bindaddress] [-f configfile] [-p portnumber]\n");
+ exit (1);
+ }
+ }
+
+ if (bflag && iflag) {
+ fprintf(stderr, "you may specify -i or -b but not both\n");
+ exit(1);
+ }
+
+ db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL);
+
+ if (db == NULL) {
+ perror("dbopen");
+ exit(1);
+ }
+
+
+ parse_file(db, conffile);
+
+ pw = getpwnam(DEFAULT_PRIVILEGE);
+ if (pw == NULL) {
+ perror("getpwnam");
+ exit(1);
+ }
+
+ if (bcount > DEFAULT_SOCKET) {
+ fprintf(stderr, "not enough sockets available\n");
+ exit(1);
+ }
+
+ if (bflag) {
+ for (i = 0; i < bcount; i++) {
+ memset(&hints, 0, sizeof(hints));
+
+ if (strchr(bind_list[i], ':') != NULL) {
+ hints.ai_family = AF_INET6;
+ } else {
+ hints.ai_family = AF_INET;
+ }
+
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_flags = AI_NUMERICHOST;
+
+ snprintf(buf, sizeof(buf) - 1, "%u", port);
+
+ if ((gai_error = getaddrinfo(bind_list[i], buf, &hints, &res0)) != 0) {
+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(gai_error));
+ exit (1);
+ }
+
+ res = res0;
+
+ if ((udp[i] = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
+ perror("socket");
+ exit(1);
+ }
+
+ if (bind(udp[i], res->ai_addr, res->ai_addrlen) < 0) {
+ perror("bind");
+ exit(1);
+ }
+
+
+ ident[i] = bind_list[i];
+ }
+
+ } else {
+ if (getifaddrs(&ifap) < 0) {
+ perror("getifaddrs");
+ exit(1);
+ }
+
+ for (pifap = ifap, i = 0; i < DEFAULT_SOCKET && pifap; pifap = pifap->ifa_next, i++) {
+
+ found = 0;
+
+ /* we want only one interface not the rest */
+ if (icount > 0) {
+ for (j = 0; j < icount; j++) {
+ if (strcmp(pifap->ifa_name, interface_list[j]) == 0) {
+ found = 1;
+ }
+ }
+
+ if (! found) {
+ i--;
+ continue;
+ }
+
+ }
+ if ((pifap->ifa_flags & IFF_UP) != IFF_UP) {
+ printf("skipping down interface %s\n", pifap->ifa_name);
+ i--;
+ continue;
+ }
+
+ if (pifap->ifa_addr->sa_family == AF_INET) {
+ sin = (struct sockaddr_in *)pifap->ifa_addr;
+ sin->sin_port = htons(port);
+ salen = sizeof(struct sockaddr_in);
+ /* no address bound to this interface */
+ if (sin->sin_addr.s_addr == INADDR_ANY) {
+ i--;
+ continue;
+ }
+ } else if (pifap->ifa_addr->sa_family == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *)pifap->ifa_addr;
+ sin6->sin6_port = htons(53);
+ /* no address bound to this interface */
+ salen = sizeof(struct sockaddr_in6);
+
+ /*
+ if (IN6_IS_ADDR_UNSPECIFIED(*(sin6->sin6_addr))) {
+ i--;
+ continue;
+ }
+ */
+ } else {
+#ifdef DEBUG
+ fprintf(stderr, "unknown address family %d\n", pifap->ifa_addr->sa_family);
+#endif
+ i--;
+ continue;
+ }
+
+
+ if ((udp[i] = socket(pifap->ifa_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ perror("socket");
+ exit(1);
+ }
+
+ if (bind(udp[i], (struct sockaddr *)pifap->ifa_addr, salen) < 0) {
+ perror("bind");
+ exit(1);
+ }
+
+ ident[i] = pifap->ifa_name;
+
+ }
+
+ if (i >= DEFAULT_SOCKET) {
+ fprintf(stderr, "not enough sockets available\n");
+ exit(1);
+ }
+ }
+
+ /* chroot to the drop priv user home directory */
+ chroot(pw->pw_dir);
+
+ /* set groups */
+
+ if (setgroups(1, &pw->pw_gid) < 0) {
+ perror("setgroups");
+ exit(1);
+ }
+
+ if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) < 0) {
+ perror("setresgid");
+ exit(1);
+ }
+
+ if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0) {
+ perror("setresuid");
+ exit(1);
+ }
+
+#ifndef DEBUG
+ daemon(0,0);
+#endif
+
+ openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
+
+ syslog(LOG_INFO, "starting up");
+
+ mainloop((int *)&udp, (int *)&tcp, i, ident, db);
+
+ /* NOTREACHED */
+ return 0;
+}
+
+
+/*
+ * MAINLOOP - does the polling of descriptors and if ready receives the
+ * requests, builds the question and calls for replies, loops
+ *
+ */
+
+void
+mainloop(int *udp, int *tcp, int sockcount, char **ident, DB *db)
+{
+ fd_set rset;
+ int sel;
+ int len;
+ int is_ipv6;
+ int i;
+ int maxso;
+ int so;
+ int type0, type1;
+ int lzerrno;
+
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } sockaddr_large;
+
+ struct sockaddr *from = (void *)&sockaddr_large;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ int fromlen = sizeof(sockaddr_large);
+ char buf[2048];
+ char address[INET6_ADDRSTRLEN];
+ char replystring[DNS_MAXNAME + 1];
+ char fakereplystring[DNS_MAXNAME + 1];
+
+ struct dns_header *dh;
+ struct question *question, *fakequestion;
+ struct domain sd0, sd1;
+
+ struct sreply sreply;
+
+ maxso = 0;
+ for (i = 0; i < sockcount; i++) {
+ if (maxso < udp[i])
+ maxso = udp[i];
+ }
+
+ for (;;) {
+ is_ipv6 = 0;
+
+ FD_ZERO(&rset);
+ for (i = 0; i < sockcount; i++)
+ FD_SET(udp[i], &rset);
+
+ memset(&buf, 0, sizeof(buf));
+
+ sel = select(maxso + 1, &rset, NULL, NULL, NULL);
+
+ if (sel < 0) {
+ syslog(LOG_INFO, "select: %m");
+ continue;
+ }
+
+ if (sel == 0) {
+ continue;
+ }
+
+ for (i = 0; i < sockcount; i++) {
+ if (FD_ISSET(udp[i], &rset)) {
+ so = udp[i];
+ fromlen = sizeof(sockaddr_large);
+ len = recvfrom(so, buf, sizeof(buf), 0, from, &fromlen);
+ if (len < 0) {
+ syslog(LOG_INFO, "recvfrom: on descriptor %u interface \"%s\" %m", so, ident[i]);
+ continue;
+ }
+
+ if (from->sa_family == AF_INET6) {
+ is_ipv6 = 1;
+
+ fromlen = sizeof(struct sockaddr_in6);
+ sin6 = (struct sockaddr_in6 *)from;
+ inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, (char *)&address, sizeof(address));
+ } else if (from->sa_family == AF_INET) {
+ is_ipv6 = 0;
+
+ fromlen = sizeof(struct sockaddr_in);
+ sin = (struct sockaddr_in *)from;
+ inet_ntop(AF_INET, (void *)&sin->sin_addr, (char *)&address, sizeof(address));
+ } else {
+ syslog(LOG_INFO, "packet received on descriptor %u interface \"%s\" had weird address family (%u), drop", so, ident[i], from->sa_family);
+ goto drop;
+ }
+
+ /* if UDP packet check length for minimum / maximum */
+ if (len > DNS_MAXUDP || len < sizeof(struct dns_header)){
+ syslog(LOG_INFO, "on descriptor %u interface \"%s\" illegal dns packet length from %s, drop", so, ident[i], address);
+ goto drop;
+ }
+
+ dh = (struct dns_header *)&buf[0];
+
+ /* check if we're a question or reply, drop replies */
+ if ((ntohs(dh->query) & DNS_REPLY)) {
+ syslog(LOG_INFO, "on descriptor %u interface \"%s\" dns header from %s is not a question, drop", so, ident[i], address);
+ goto drop;
+ }
+
+ /*
+ * if no question entry is included drop
+ */
+
+ if (ntohs(dh->question) == 0) {
+ syslog(LOG_INFO, "on descriptor %u interface \"%s\" header from %s has no question, drop", so, ident[i], address);
+ goto drop;
+ }
+
+
+ if ((question = build_question(buf, len)) == NULL) {
+ syslog(LOG_INFO, "on descriptor %u interface \"%s\" malformed question from %s, drop", so, ident[i], address);
+ goto drop;
+ }
+
+ /* goto drop beyond this point should goto out instead */
+ fakequestion = NULL;
+
+ if ((type0 = lookup_zone(db, question, &sd0, &lzerrno, (char *)&replystring)) < 0) {
+ switch (lzerrno) {
+ default:
+ syslog(LOG_INFO, "invalid lzerrno! dropping");
+ /* FALLTHROUGH */
+ case ERR_DROP:
+ snprintf(replystring, DNS_MAXNAME, "DROP");
+ goto out;
+
+ case ERR_NXDOMAIN:
+ goto nxdomain;
+ }
+ }
+
+
+ switch (type0) {
+ case 0:
+ /*
+ * lookup_zone could not find an RR for the
+ * question at all -> nxdomain
+ */
+nxdomain:
+ snprintf(replystring, DNS_MAXNAME, "NXDOMAIN");
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, NULL, NULL);
+ reply_nxdomain(&sreply);
+ goto out;
+ case DNS_TYPE_CNAME:
+ fakequestion = build_fake_question(sd0.cname, sd0.cnamelen, question->hdr->qtype);
+ if (fakequestion == NULL) {
+ syslog(LOG_INFO, "fakequestion failed");
+ break;
+ }
+
+ type1 = lookup_zone(db, fakequestion, &sd1, &lzerrno, (char *)&fakereplystring);
+ /* break CNAMES pointing to CNAMES */
+ if (type1 == DNS_TYPE_CNAME)
+ type1 = 0;
+
+ break;
+ default:
+
+ break;
+ }
+
+
+ switch (ntohs(question->hdr->qclass)) {
+ case DNS_CLASS_IN:
+ break;
+ default:
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, NULL, NULL);
+ reply_notimpl(&sreply);
+ snprintf(replystring, DNS_MAXNAME, "NOTIMPL");
+ goto out;
+ }
+
+ switch (ntohs(question->hdr->qtype)) {
+ case DNS_TYPE_A:
+ if (type0 == DNS_TYPE_CNAME) {
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL));
+ reply_cname(&sreply);
+ } else if (type0 == DNS_TYPE_A) {
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, &sd0, NULL);
+ reply_a(&sreply);
+ break; /* must break here */
+ }
+
+ break;
+ case DNS_TYPE_AAAA:
+
+ if (type0 == DNS_TYPE_CNAME) {
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL));
+ reply_cname(&sreply);
+ } else if (type0 == DNS_TYPE_AAAA) {
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, &sd0, NULL);
+ reply_aaaa(&sreply);
+ break; /* must break here */
+ }
+
+ break;
+ case DNS_TYPE_MX:
+
+ if (type0 == DNS_TYPE_CNAME) {
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL));
+ reply_cname(&sreply);
+ } else if (type0 == DNS_TYPE_MX) {
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, &sd0, NULL);
+ reply_mx(&sreply);
+ break; /* must break here */
+ }
+
+ break;
+ case DNS_TYPE_SOA:
+ if (type0 == DNS_TYPE_SOA) {
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, &sd0, NULL);
+ reply_soa(&sreply);
+ }
+ break;
+ case DNS_TYPE_NS:
+ if (type0 == DNS_TYPE_NS) {
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, &sd0, NULL);
+ reply_ns(&sreply);
+ }
+ break;
+
+
+ case DNS_TYPE_CNAME:
+ if (type0 == DNS_TYPE_CNAME) {
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, &sd0, NULL);
+ reply_cname(&sreply);
+ }
+ break;
+
+ case DNS_TYPE_PTR:
+ if (type0 == DNS_TYPE_CNAME) {
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, &sd0, ((type1 > 0) ? &sd1 : NULL));
+ reply_cname(&sreply);
+ } else if (type0 == DNS_TYPE_PTR) {
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, &sd0, NULL);
+ reply_ptr(&sreply);
+ break; /* must break here */
+ }
+ break;
+
+ default:
+
+ /*
+ * ANY unkown RR TYPE gets a NOTIMPL
+ */
+
+ BUILD_REPLY(sreply, so, buf, len, question, from, fromlen, NULL, NULL);
+ reply_notimpl(&sreply);
+ snprintf(replystring, DNS_MAXNAME, "NOTIMPL");
+ break;
+ }
+
+ out:
+ syslog(LOG_INFO, "request on descriptor %u interface \"%s\" from %s for \"%s\" type=%u class=%u, answering \"%s\"", so, ident[i], address, question->converted_name, ntohs(question->hdr->qtype), ntohs(question->hdr->qclass), replystring);
+
+
+ if (fakequestion != NULL) {
+ free_question(fakequestion);
+ }
+
+ free_question(question);
+
+ } /* END ISSET */
+
+ } /* for */
+
+ drop:
+
+ continue;
+ }
+
+ /* NOTREACHED */
+}
+
+/*
+ * BUILD_QUESTION - fill the question structure with the DNS query.
+ */
+
+struct question *
+build_question(char *buf, int len)
+{
+ u_int i;
+ u_int namelen = 0;
+ int num_label;
+ char *p, *end_name = NULL;
+ u_int16_t *qtype, *qclass;
+
+ struct question *q;
+
+ /* find the end of name */
+ for (i = sizeof(struct dns_header); i < len; i++) {
+ if (buf[i] == NULL) {
+ end_name = &buf[i];
+ break;
+ }
+ }
+
+ /* implies i >= len */
+ if (end_name == NULL) {
+ syslog(LOG_INFO, "query name is not null terminated");
+ return NULL;
+ }
+
+ /* parse the size of the name */
+ for (i = sizeof(struct dns_header), num_label = 0; i < len && &buf[i] < end_name;) {
+ u_int labellen;
+
+ ++num_label;
+
+ labellen = (u_int)buf[i];
+
+ /*
+ * do some checks on the label, if it's 0 or over 63 it's
+ * illegal, also if it reaches beyond the entire name it's
+ * also illegal.
+ */
+ if (labellen == 0) {
+ syslog(LOG_INFO, "illegal label len (0)");
+ return NULL;
+ }
+ if (labellen > DNS_MAXLABEL) {
+ syslog(LOG_INFO, "illegal label len (> 63)");
+ return NULL;
+ }
+ if (labellen > (end_name - &buf[i])) {
+ syslog(LOG_INFO, "label len extends beyond name");
+ return NULL;
+ }
+
+ i += (labellen + 1);
+ namelen += labellen;
+ }
+
+ if (&buf[i] != end_name || i >= len) {
+ syslog(LOG_INFO, "query name is maliciously malformed");
+ return NULL;
+ }
+
+ if (i > DNS_MAXNAME) {
+ syslog(LOG_INFO, "query name is too long (%u)", i);
+ return NULL;
+ }
+
+
+ /* check if there is space for qtype and qclass */
+ if (len < ((end_name - &buf[0]) + (2 * sizeof(u_int16_t)))) {
+ syslog(LOG_INFO, "question rr is truncated");
+ return NULL;
+ }
+
+
+ q = (void *)calloc(1, sizeof(struct question));
+ if (q == NULL) {
+ syslog(LOG_INFO, "calloc: %m");
+ return NULL;
+ }
+ q->hdr = (void *)calloc(1, sizeof(struct dns_question_hdr));
+ if (q->hdr == NULL) {
+ syslog(LOG_INFO, "calloc: %m");
+ free(q);
+ return NULL;
+ }
+ q->hdr->namelen = (end_name - &buf[sizeof(struct dns_header)]) + 1; /* XXX */
+ q->hdr->name = (void *) calloc(1, q->hdr->namelen);
+ if (q->hdr->name == NULL) {
+ syslog(LOG_INFO, "calloc: %m");
+ free(q->hdr);
+ free(q);
+ return NULL;
+ }
+ q->converted_name = (void *)calloc(1, namelen + num_label + 2);
+ if (q->converted_name == NULL) {
+ syslog(LOG_INFO, "calloc: %m");
+ free(q->hdr->name);
+ free(q->hdr);
+ free(q);
+ return NULL;
+ }
+
+ p = q->converted_name;
+
+ /*
+ * parse the name again this time filling the labels
+ * XXX this is expensive going over the buffer twice
+ */
+ for (i = sizeof(struct dns_header); i < len && &buf[i] < end_name;) {
+ u_int labelend;
+
+ labelend = (u_int)buf[i] + 1 + i; /* i = offset, plus contents of buf[i], + 1 */
+
+ /* i is reused here to count every character, this is not a bug */
+ for (i++; i < labelend; i++) {
+ if ((buf[i] & 0xc0) == 0xc0) {
+ syslog(LOG_INFO, "has compressed name");
+ free_question(q);
+ return NULL; /* XXX should say error */
+ }
+ *p++ = tolower(buf[i]);
+ }
+
+ *p++ = '.';
+ }
+
+ /* XXX */
+ if (&buf[sizeof(struct dns_header)] == end_name)
+ *p++ = '.';
+
+ *p = '\0';
+
+ /* fill our name into the dns header struct */
+
+ memcpy(q->hdr->name, &buf[sizeof(struct dns_header)], q->hdr->namelen);
+
+ /* make it lower case */
+
+ for (i = 0; i < q->hdr->namelen; i++) {
+ if (isalpha(q->hdr->name[i])) {
+ q->hdr->name[i] = tolower(q->hdr->name[i]);
+ }
+ }
+
+ /* parse type and class from the question */
+
+ qtype = (u_int16_t *)(end_name + 1);
+ qclass = (u_int16_t *)(end_name + sizeof(u_int16_t) + 1);
+
+ memcpy((char *)&q->hdr->qtype, (char *)qtype, sizeof(u_int16_t));
+ memcpy((char *)&q->hdr->qclass, (char *)qclass, sizeof(u_int16_t));
+
+ return (q);
+}
+
+/*
+ * FREE_QUESTION - free a question struct
+ *
+ */
+
+int
+free_question(struct question *q)
+{
+ free(q->hdr->name);
+ free(q->hdr);
+ free(q->converted_name);
+ free(q);
+
+ return 0;
+}
+
+/*
+ * DNS_LABEL - build a DNS NAME (with labels) from a canonical name
+ *
+ */
+
+char *
+dns_label(char *name, int *returnlen)
+{
+ char tname[DNS_MAXNAME + 1]; /* 255 bytes */
+ char *pt = &tname[0];
+ int len, newlen = 0;
+ int i, lc = 0; /* lc = label count */
+ char *dnslabel, *p;
+ char *labels[255];
+ char **pl;
+
+
+ if (name == NULL)
+ return NULL;
+
+ strlcpy(tname, name, sizeof(tname));
+
+ len = strlen(tname);
+ if (tname[len - 1] == '.')
+ tname[len - 1] = '\0';
+
+ for (pl=labels;pl<&labels[254]&&(*pl=strsep(&pt,"."))!= NULL;pl++,lc++)
+ newlen += strlen(*pl);
+
+ newlen += lc; /* add label count to length */
+
+
+ /* make the buffer space, add 1 for trailing NULL */
+ if ((dnslabel = malloc(newlen + 1)) == NULL) {
+ return NULL;
+ }
+
+ *returnlen = newlen + 1;
+ dnslabel[newlen] = '\0'; /* trailing NULL */
+
+ for (i = 0, p = dnslabel; i < lc; i++) {
+ len = strlen(labels[i]);
+ *p++ = len;
+ strlcpy(p, labels[i], newlen - (p - dnslabel) + 1);
+ p += len;
+ }
+
+ /*
+ * XXX hack to make all DNS names lower case, we only preserve
+ * case on compressed answers..
+ */
+
+ for (i = 0, p = dnslabel; i < *returnlen; i++) {
+ if (isalpha(*p))
+ *p = tolower(*p);
+ p++;
+ }
+
+#ifdef DEBUG
+ printf("converting name= %s\n", name);
+#endif
+
+ return dnslabel;
+}
+
+/*
+ * COMPRESS_LABEL - compress a DNS name, must be passed an entire reply
+ * with the to be compressed name before the offset of
+ * that reply.
+ */
+
+int
+compress_label(char *buf, int offset, int labellen)
+{
+ char expandbuf[512];
+ int i, j;
+ char *p, *e;
+ char *compressmark;
+ int checklen;
+ u_int16_t *compressor;
+ u_int16_t *checkcompress;
+ int expandlen, expandoffset;
+
+ p = &buf[offset - labellen];
+ checklen = labellen;
+
+ for (;*p != NULL;) {
+
+ for (i = sizeof(struct dns_header); i < (offset - labellen); i++) {
+
+ /*
+ * fill in and expand a buffer with data from the
+ * packet
+ */
+
+ memcpy(expandbuf, &buf[i], checklen); /* XXX expensive */
+ e = &expandbuf[0];
+ /*
+ * check this entire name, expanding compression as we go
+ */
+
+ for (j = 0; j < checklen; j++) {
+ if (expandbuf[j] == NULL)
+ break; /* end of lookup */
+ checkcompress = (u_int16_t *)&expandbuf[j];
+ if ((ntohs(*checkcompress) & 0xc000) == 0xc000){
+ expandoffset = (ntohs(*checkcompress) & ~(0xc000));
+ expandlen = checklen - j;
+
+ if (offset < (expandlen + expandoffset)) {
+ /* can't expand this, it's bogus, ie beyond our buffer offset */
+ break;
+ }
+
+ memcpy((char*)&expandbuf[j], (char*)&buf[expandoffset], expandlen); /* XXX expensive */
+
+ /* check once more that our search does not terminate */
+ if (expandbuf[j] == NULL) {
+ e = &expandbuf[j];
+ break;
+ }
+ }
+
+ j += *e;
+ e = &expandbuf[j];
+ e++;
+ }
+
+ /* check packet for a matching name */
+ if (*e == NULL && memcasecmp(&expandbuf[0], p, checklen) == 0) {
+ compressmark = &buf[i];
+ goto out; /* found one */
+ }
+ }
+
+ if (*p > DNS_MAXLABEL)
+ return 0; /* totally bogus label */
+
+ checklen -= *p;
+ p += *p;
+ checklen--;
+ p++;
+
+ }
+
+ return 0; /* no compression possible */
+
+out:
+ /* take off our compress length */
+ offset -= checklen;
+ /* write compressed label */
+ compressor = (u_int16_t *)&buf[offset];
+
+ *compressor = (compressmark - &buf[0]);
+ *compressor |= 0xc000;
+
+ /* network byte order */
+ NTOHS(*compressor);
+
+ offset += sizeof(u_int16_t);
+
+ return (offset);
+}
+
+
+/*
+ * MEMCASECMP - check if buffer is identical to another buffer with
+ * one exception if a character is alphabetic it's
+ * compared to it's lower case value so that heLLo is
+ * the same as hello
+ */
+
+int
+memcasecmp(char *b1, char *b2, int len)
+{
+ int i;
+ int identical = 1;
+
+ for (i = 0; i < len; i++) {
+ if ((isalpha(b1[i]) ? tolower(b1[i]) : b1[i]) !=
+ (isalpha(b2[i]) ? tolower(b2[i]) : b2[i])) {
+ identical = 0;
+ break;
+ }
+ }
+
+ if (identical)
+ return 0;
+
+ return 1; /* XXX */
+}
+
+
+/*
+ * LOOKUP_ZONE - look up a zone filling sd and returning RR TYPE, if error
+ * occurs returns -1, and sets errno on what type of error.
+ */
+
+
+int
+lookup_zone(DB *db, struct question *question, struct domain *sd, int *lzerrno, char *replystring)
+{
+
+ char *p;
+ int plen, onemore = 0;
+ int ret = 0;
+ int returnval;
+ char *wildlookup = "*";
+
+ DBT key, data;
+
+ /*
+ * if the asked domain name is foo.bar.baz.org then
+ * lookup foo.bar.baz.org, bar.baz.org, baz.org,
+ * org and if there is a match return that.
+ */
+
+ p = question->hdr->name;
+ plen = question->hdr->namelen;
+ onemore = 0;
+
+ returnval = 0;
+
+ do {
+
+ key.data = (char *)p;
+ key.size = plen;
+
+ data.data = NULL;
+ data.size = 0;
+ ret = db->get(db, &key, &data, 0);
+
+ if (ret != 0) {
+ /* next label */
+ if (*p != NULL) {
+ plen -= (*p + 1);
+ p = (p + (*p + 1));
+ } else if (*p == NULL && ! onemore) {
+ plen = 1;
+ onemore = 1;
+ continue;
+ }
+ } else {
+ /* we have a match check if the type has an answer, if not we leave */
+ if (data.size != sizeof(struct domain)) {
+ syslog(LOG_INFO, "btree db is damaged, drop");
+ *lzerrno = ERR_DROP;
+ return -1;
+ }
+
+ memcpy((char *)sd, (char *)data.data, data.size);
+ snprintf(replystring, DNS_MAXNAME, "%s", sd->zonename);
+
+
+ switch (ntohs(question->hdr->qtype)) {
+ case DNS_TYPE_A:
+ if ((sd->flags & DOMAIN_HAVE_A) ==
+ DOMAIN_HAVE_A) {
+ returnval = DNS_TYPE_A;
+ break;
+ } else if ((sd->flags & DOMAIN_HAVE_CNAME) == DOMAIN_HAVE_CNAME) {
+ returnval = DNS_TYPE_CNAME;
+ break;
+ }
+
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+ case DNS_TYPE_AAAA:
+ if ((sd->flags & DOMAIN_HAVE_AAAA) ==
+ DOMAIN_HAVE_AAAA) {
+ returnval = DNS_TYPE_AAAA;
+ break;
+ } else if ((sd->flags & DOMAIN_HAVE_CNAME) == DOMAIN_HAVE_CNAME) {
+ returnval = DNS_TYPE_CNAME;
+ break;
+ }
+
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+ case DNS_TYPE_MX:
+ if ((sd->flags & DOMAIN_HAVE_MX) ==
+ DOMAIN_HAVE_MX) {
+ returnval = DNS_TYPE_MX;
+ break;
+ } else if ((sd->flags & DOMAIN_HAVE_CNAME) == DOMAIN_HAVE_CNAME) {
+ returnval = DNS_TYPE_CNAME;
+ break;
+ }
+
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+ case DNS_TYPE_PTR:
+ if ((sd->flags & DOMAIN_HAVE_PTR) ==
+ DOMAIN_HAVE_PTR) {
+ returnval = DNS_TYPE_PTR;
+ break;
+ } else if ((sd->flags & DOMAIN_HAVE_CNAME) == DOMAIN_HAVE_CNAME) {
+ returnval = DNS_TYPE_CNAME;
+ break;
+ }
+
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+
+ case DNS_TYPE_SOA:
+ if ((sd->flags & DOMAIN_HAVE_SOA) != DOMAIN_HAVE_SOA) {
+
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+ }
+ returnval = DNS_TYPE_SOA;
+ break;
+
+ case DNS_TYPE_CNAME:
+ if ((sd->flags & DOMAIN_HAVE_CNAME) != DOMAIN_HAVE_CNAME) {
+
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+ }
+
+ returnval = DNS_TYPE_CNAME;
+ break;
+ case DNS_TYPE_NS:
+ if ((sd->flags & DOMAIN_HAVE_NS) != DOMAIN_HAVE_NS) {
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+ }
+ returnval = DNS_TYPE_NS;
+ break;
+ }
+
+ break;
+ }
+
+
+ } while (*p != NULL && ret != 0);
+
+ if (ret != 0) {
+ key.data = wildlookup;
+ key.size = 1;
+
+ if (db->get(db, &key, &data, 0) != 0) {
+ syslog(LOG_INFO, "don't have wildcard answer");
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+
+ }
+ if (data.size != sizeof(struct domain)) {
+ syslog(LOG_INFO, "btree db is damaged, drop");
+ *lzerrno = ERR_DROP;
+ return -1;
+ }
+
+ memcpy((char *)sd, (char *)data.data, data.size);
+
+
+ switch (ntohs(question->hdr->qtype)) {
+ case DNS_TYPE_A:
+ if ((sd->flags & DOMAIN_HAVE_A) ==
+ DOMAIN_HAVE_A) {
+ returnval = DNS_TYPE_A;
+ break;
+ } else if ((sd->flags & DOMAIN_HAVE_CNAME) == DOMAIN_HAVE_CNAME) {
+ returnval = DNS_TYPE_CNAME;
+ break;
+ }
+
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+ case DNS_TYPE_AAAA:
+ if ((sd->flags & DOMAIN_HAVE_AAAA) ==
+ DOMAIN_HAVE_AAAA) {
+ returnval = DNS_TYPE_AAAA;
+ break;
+ } else if ((sd->flags & DOMAIN_HAVE_CNAME) == DOMAIN_HAVE_CNAME) {
+ returnval = DNS_TYPE_CNAME;
+ break;
+ }
+
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+ case DNS_TYPE_MX:
+ if ((sd->flags & DOMAIN_HAVE_MX) ==
+ DOMAIN_HAVE_MX) {
+ returnval = DNS_TYPE_MX;
+ break;
+ } else if ((sd->flags & DOMAIN_HAVE_CNAME) == DOMAIN_HAVE_CNAME) {
+ returnval = DNS_TYPE_CNAME;
+ break;
+ }
+
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+ case DNS_TYPE_PTR:
+ if ((sd->flags & DOMAIN_HAVE_PTR) ==
+ DOMAIN_HAVE_PTR) {
+ returnval = DNS_TYPE_PTR;
+ break;
+ } else if ((sd->flags & DOMAIN_HAVE_CNAME) == DOMAIN_HAVE_CNAME) {
+ returnval = DNS_TYPE_CNAME;
+ break;
+ }
+
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+
+ case DNS_TYPE_SOA:
+ if ((sd->flags & DOMAIN_HAVE_SOA) != DOMAIN_HAVE_SOA) {
+
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+ }
+ returnval = DNS_TYPE_SOA;
+ break;
+ case DNS_TYPE_NS:
+ if ((sd->flags & DOMAIN_HAVE_NS) != DOMAIN_HAVE_NS) {
+
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+ }
+ returnval = DNS_TYPE_NS;
+ break;
+
+ case DNS_TYPE_CNAME:
+ if ((sd->flags & DOMAIN_HAVE_CNAME) != DOMAIN_HAVE_CNAME) {
+ *lzerrno = ERR_NXDOMAIN;
+ return -1;
+ }
+ returnval = DNS_TYPE_CNAME;
+ break;
+ }
+
+ snprintf(replystring, DNS_MAXNAME, "*");
+ }
+
+ return returnval;
+}
+
+/*
+ * BUILD_FAKE_QUESTION - fill the fake question structure with the DNS query.
+ */
+
+struct question *
+build_fake_question(char *name, int namelen, u_int16_t type)
+{
+ struct question *q;
+
+ q = (void *)calloc(1, sizeof(struct question));
+ if (q == NULL) {
+ syslog(LOG_INFO, "calloc: %m");
+ return NULL;
+ }
+
+ q->hdr = (void *)calloc(1, sizeof(struct dns_question_hdr));
+ if (q->hdr == NULL) {
+ syslog(LOG_INFO, "calloc: %m");
+ free(q);
+ return NULL;
+ }
+ q->hdr->namelen = namelen;
+ q->hdr->name = (void *) calloc(1, q->hdr->namelen);
+ if (q->hdr->name == NULL) {
+ syslog(LOG_INFO, "calloc: %m");
+ free(q->hdr);
+ free(q);
+ return NULL;
+ }
+ q->converted_name = NULL;
+
+ /* fill our name into the dns header struct */
+
+ memcpy(q->hdr->name, name, q->hdr->namelen);
+
+ q->hdr->qtype = type;
+ q->hdr->qclass = htons(DNS_CLASS_IN);
+
+ return (q);
+}
blob - /dev/null
blob + a0dcd35a4ac3a96293289b23dd2af3eee8e6944f (mode 644)
--- /dev/null
+++ parse.c
@@ -0,0 +1,651 @@
+/*
+ * Copyright (c) 2005 Peter Philipp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "include.h"
+#include "dns.h"
+#include "db.h"
+
+extern char * dns_label(char *, int *);
+
+struct myrr_lookup {
+ char *name;
+ u_int16_t type;
+} mysrr_lookup[] = {
+ { "a", DNS_TYPE_A } ,
+ { "soa", DNS_TYPE_SOA },
+ { "cname", DNS_TYPE_CNAME },
+ { "ptr", DNS_TYPE_PTR },
+ { "mx", DNS_TYPE_MX },
+ { "aaaa", DNS_TYPE_AAAA },
+ { "ns", DNS_TYPE_NS },
+ { NULL, 0 },
+};
+
+/*
+ * PARSE_FILE - parse the configfile XXX rewrite me in yacc :(
+ *
+ */
+
+
+int
+parse_file(DB *db, char *file)
+{
+ FILE *f;
+
+ int len, i;
+ int tokenlen;
+ u_int16_t type;
+ u_int32_t ttl;
+ char buf[1024];
+ char domainname[DNS_MAXNAME + 1];
+ char *converted_name;
+ int converted_namelen;
+ char *p, *endline, *start, *starttoken;
+ char save;
+ int line = 0;
+
+ DBT key, data;
+
+ struct domain sdomain;
+
+ in_addr_t *ia;
+ struct in6_addr *ia6;
+
+ if ((f = fopen(file, "r")) == NULL) {
+ perror("fopen");
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), f) != NULL) {
+ converted_name = NULL;
+ len = strlen(buf);
+
+ start = &buf[0];
+ starttoken = p = start; /* XXX */
+ endline = NULL;
+ for (i = 0; i < len; i++, p++) {
+ if (*p == '\n') {
+ line++;
+ endline = p;
+ break;
+ }
+ }
+
+ if (endline == NULL) {
+ fprintf(stderr, "line too long line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ /* are we a comment? skip rest of line */
+ if (*start == '#' || *start == ';') {
+#ifdef DEBUG
+ printf("hash mark skipping line %d\n", line);
+#endif
+ goto skip;
+ }
+
+ for (p = starttoken; p < endline && *p != ','; p++);
+ if (p >= endline || *p != ',') {
+ fprintf(stderr, "(1) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ tokenlen = (p - starttoken);
+ if (tokenlen > (DNS_MAXNAME - 2)) {
+ fprintf(stderr, "domain name is too long\n");
+ fclose(f);
+ return -1;
+ }
+
+ /* write out our domain name all in lowercase and append a
+ * terminating '.' if necessary.
+ */
+
+ {
+ char *c;
+ int i;
+
+ c = starttoken;
+ for (i = 0; i < tokenlen; i++) {
+ domainname[i] = tolower(*c++);
+ }
+
+ if (domainname[tokenlen - 1] != '.' &&
+ !(tokenlen == 1 && domainname[tokenlen - 1] == '*')) {
+ domainname[tokenlen] = '.';
+ tokenlen++;
+ }
+
+ domainname[tokenlen] = '\0';
+
+ }
+
+ if (tokenlen == 1 && domainname[0] == '*') {
+ converted_name = (char *)malloc(1);
+ if (converted_name == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+ *converted_name = '*';
+ converted_namelen = 1;
+ } else {
+ converted_name = dns_label(domainname, &converted_namelen);
+ if (converted_name == NULL) {
+ fprintf(stderr, "(XXX) illegal domain name line %d\n", line);
+ exit(1);
+ }
+ }
+
+
+ key.data = (char *)converted_name;
+ key.size = converted_namelen;
+
+ data.data = NULL;
+ data.size = 0;
+
+ memset((char *)&sdomain, 0, sizeof(struct domain));
+ if (db->get(db, &key, &data, 0) == 0) {
+ if (data.size != sizeof(struct domain)) {
+ fprintf(stderr, "damaged btree database\n");
+ fclose(f);
+ return -1;
+ }
+
+ memcpy((char *)&sdomain, (char *)data.data, data.size);
+ } else {
+#if 0
+ perror("db->get");
+#endif
+ }
+
+ strlcpy((char *)&sdomain.zonename[0], (char *)&domainname[0], sizeof(sdomain.zonename));
+
+ if (++p >= endline) {
+ fprintf(stderr, "(2) malformed line %d", line);
+ fclose(f);
+ return -1;
+ }
+
+ starttoken = p;
+
+ for (p = starttoken; p < endline && *p != ','; p++);
+ if (p >= endline || *p != ',') {
+ fprintf(stderr, "(3) malformed line %d", line);
+ fclose(f);
+ return -1;
+ }
+
+ tokenlen = (p - starttoken);
+ save = *p;
+ *p = NULL;
+
+ type = 0;
+ for (i = 0; mysrr_lookup[i].name != NULL; i++) {
+ if (strncasecmp(starttoken, mysrr_lookup[i].name, tokenlen) == 0) {
+ type = mysrr_lookup[i].type;
+ break;
+ }
+ }
+
+ if (type == 0) {
+ fprintf(stderr, "unknown rr line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ *p = save;
+
+ if (++p >= endline) {
+ fprintf(stderr, "(4) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ starttoken = p;
+
+ for (p = starttoken; p < endline && *p != ','; p++);
+ if (p >= endline || *p != ',') {
+ fprintf(stderr, "(5) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ tokenlen = (p - starttoken);
+ save = *p;
+ *p = NULL;
+
+ ttl = atoi(starttoken);
+
+ sdomain.ttl = ttl;
+
+ *p = save;
+
+ if (++p >= endline) {
+ fprintf(stderr, "(6) malformed line %d\n", line );
+ fclose(f);
+ return -1;
+ }
+
+ starttoken = p;
+
+
+ switch (type) {
+ case DNS_TYPE_A:
+ p = endline;
+ save = *p;
+ *p = '\0';
+ if (sdomain.a_count < 10) {
+ ia = (in_addr_t *) &sdomain.a[sdomain.a_count];
+ sdomain.a_count++;
+ } else {
+ fprintf(stderr, "too many a records for zone \"%s\", skipping line %d\n", domainname, line);
+ break;
+ }
+
+ /* don't allow 0.0.0.0 skip take this entry back */
+ if ((*ia = inet_addr(starttoken)) == INADDR_ANY)
+ sdomain.a_count--;
+
+ *p = save;
+
+ sdomain.flags |= DOMAIN_HAVE_A;
+ break;
+ case DNS_TYPE_AAAA:
+ p = endline;
+ save = *p;
+ *p = NULL;
+ if (sdomain.aaaa_count < 10) {
+ ia6 = (struct in6_addr *) &sdomain.aaaa[sdomain.aaaa_count];
+ sdomain.aaaa_count++;
+ } else {
+ fprintf(stderr, "too many aaaa records for zone \"%s\", skipping line %d\n", domainname, line);
+ break;
+ }
+
+#ifdef DEBUG
+ printf("starttoken = %s\n", starttoken);
+#endif
+
+ if (inet_pton(AF_INET6, (char *)starttoken, (char *)ia6) != 1) {
+ sdomain.aaaa_count--;
+ fprintf(stderr, "aaaa \"%s\" unparseable line %d\n", starttoken, line);
+ }
+
+ *p = save;
+
+ sdomain.flags |= DOMAIN_HAVE_AAAA;
+ break;
+ case DNS_TYPE_MX:
+
+ for (p = starttoken; p < endline && *p != ','; p++);
+ if (p >= endline || *p != ',') {
+ fprintf(stderr, "(7) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ tokenlen = (p - starttoken);
+ save = *p;
+ *p = NULL;
+
+ if (sdomain.mx_count < 10) {
+ sdomain.mx[sdomain.mx_count].preference = atoi(starttoken);
+ } else {
+ fprintf(stderr, "too many mx records for zone \"%s\", skipping line %d\n", domainname, line);
+ break;
+ }
+
+ *p = save;
+
+ if (++p >= endline) {
+ fprintf(stderr, "(XX) malformed line %d", line);
+ break;
+ }
+
+ starttoken = p;
+
+ p = endline;
+ save = *p;
+ *p = NULL;
+
+
+ {
+ char *name;
+ char *n;
+
+ if ((name = dns_label(starttoken, (int *)&sdomain.mx[sdomain.mx_count].exchangelen)) == NULL) {
+ fprintf(stderr, "illegal mx server, skipping line %d\n", line);
+ goto skip;
+ }
+ n = (char *)sdomain.mx[sdomain.mx_count].exchange;
+
+ memcpy((char *)n, name, sdomain.mx[sdomain.mx_count].exchangelen);
+ free (name);
+ }
+
+ sdomain.mx_count++;
+ *p = save;
+
+ sdomain.flags |= DOMAIN_HAVE_MX;
+ break;
+ case DNS_TYPE_SOA:
+ for (p = starttoken; p < endline && *p != ','; p++);
+ if (p >= endline || *p != ',') {
+ fprintf(stderr, "(7) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ tokenlen = (p - starttoken);
+ save = *p;
+ *p = NULL;
+
+ {
+ char *name;
+
+ if ((name = dns_label(starttoken, (int *)&sdomain.soa.nsserver_len)) == NULL) {
+ fprintf(stderr, "illegal nameserver, skipping line %d\n", line);
+ goto skip;
+ }
+
+ memcpy((char *)&sdomain.soa.nsserver[0], name, sdomain.soa.nsserver_len);
+ free (name);
+ }
+
+ *p = save;
+
+ if (++p >= endline) {
+ fprintf(stderr, "(8) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ starttoken = p;
+
+ for (p = starttoken; p < endline && *p != ','; p++);
+ if (p >= endline || *p != ',') {
+ fprintf(stderr, "(9) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ tokenlen = (p - starttoken);
+ save = *p;
+ *p = NULL;
+
+ {
+ char *name;
+
+ if ((name = dns_label(starttoken, (int *)&sdomain.soa.rp_len)) == NULL) {
+ fprintf(stderr, "illegal nameserver, skipping line %d\n", line);
+ goto skip;
+ }
+
+ memcpy((char *)&sdomain.soa.responsible_person[0], name, sdomain.soa.rp_len);
+ free (name);
+ }
+
+ *p = save;
+
+ if (++p >= endline) {
+ fprintf(stderr, "(10) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ starttoken = p;
+
+ for (p = starttoken; p < endline && *p != ','; p++);
+ if (p >= endline || *p != ',') {
+ fprintf(stderr, "(11) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ tokenlen = (p - starttoken);
+ save = *p;
+ *p = NULL;
+
+ sdomain.soa.serial = atoi(starttoken);
+
+ *p = save;
+
+ if (++p >= endline) {
+ fprintf(stderr, "(12) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ starttoken = p;
+
+ for (p = starttoken; p < endline && *p != ','; p++);
+ if (p >= endline || *p != ',') {
+ fprintf(stderr, "(13) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ tokenlen = (p - starttoken);
+ save = *p;
+ *p = NULL;
+
+ sdomain.soa.refresh = atoi(starttoken);
+
+ *p = save;
+
+ if (++p >= endline) {
+ fprintf(stderr, "(14) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ starttoken = p;
+
+ for (p = starttoken; p < endline && *p != ','; p++);
+ if (p >= endline || *p != ',') {
+ fprintf(stderr, "(15) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ tokenlen = (p - starttoken);
+ save = *p;
+ *p = NULL;
+
+ sdomain.soa.retry = atoi(starttoken);
+
+ *p = save;
+
+ if (++p >= endline) {
+ fprintf(stderr, "(16) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ starttoken = p;
+
+ for (p = starttoken; p < endline && *p != ','; p++);
+ if (p >= endline || *p != ',') {
+ fprintf(stderr, "(17) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ tokenlen = (p - starttoken);
+ save = *p;
+ *p = NULL;
+
+ sdomain.soa.expire = atoi(starttoken);
+
+ *p = save;
+
+ if (++p >= endline) {
+ fprintf(stderr, "(18) malformed line %d\n", line);
+ fclose(f);
+ return -1;
+ }
+
+ starttoken = p;
+ p = endline;
+
+ tokenlen = (p - starttoken);
+ save = *p;
+ *p = NULL;
+
+ sdomain.soa.minttl = atoi(starttoken);
+ *p = save;
+
+ sdomain.flags |= DOMAIN_HAVE_SOA;
+
+ break;
+ case DNS_TYPE_PTR:
+ p = endline;
+ save = *p;
+ *p = NULL;
+
+ {
+ char *name;
+
+ if ((name = dns_label(starttoken, (int *)&sdomain.ptrlen)) == NULL) {
+ fprintf(stderr, "illegal nameserver, skipping line %d\n", line);
+ goto skip;
+ }
+
+ memcpy((char *)&sdomain.ptr[0], name, sdomain.ptrlen);
+ free (name);
+ }
+
+ *p = save;
+
+ sdomain.flags |= DOMAIN_HAVE_PTR;
+ break;
+
+ case DNS_TYPE_NS:
+ p = endline;
+ save = *p;
+ *p = NULL;
+
+ {
+ char *name;
+ char *n;
+
+ if ((name = dns_label(starttoken, (int *)&sdomain.ns[sdomain.ns_count].nslen)) == NULL) {
+ fprintf(stderr, "illegal mx server, skipping line %d\n", line);
+ goto skip;
+ }
+ n = (char *)sdomain.ns[sdomain.ns_count].nsserver;
+
+ memcpy((char *)n, name, sdomain.ns[sdomain.ns_count].nslen);
+ free (name);
+ }
+
+ sdomain.ns_count++;
+
+ *p = save;
+
+ sdomain.flags |= DOMAIN_HAVE_NS;
+ break;
+
+ case DNS_TYPE_CNAME:
+
+ p = endline;
+ save = *p;
+ *p = NULL;
+
+ {
+ char *name;
+
+ if ((name = dns_label(starttoken, (int *)&sdomain.cnamelen)) == NULL) {
+ fprintf(stderr, "illegal nameserver, skipping line %d\n", line);
+ goto skip;
+ }
+
+ memcpy((char *)&sdomain.cname[0], name, sdomain.cnamelen);
+ free (name);
+ }
+
+ *p = save;
+
+ sdomain.flags |= DOMAIN_HAVE_CNAME;
+ break;
+
+ default:
+ break;
+ }
+
+ /* write new record into btree database */
+
+ key.data = (char *)converted_name;
+ key.size = converted_namelen;
+
+ data.data = (void *)&sdomain;
+ data.size = sizeof(struct domain);
+
+ if (db->put(db, &key, &data, 0) < 0) {
+ perror("db->put");
+ fclose(f);
+ return -1;
+ }
+
+skip:
+#ifdef DEBUG
+ save = *endline;
+ *endline = NULL;
+
+ printf("line %d: \"%s\"\n", line, start);
+
+ *endline = save;
+#endif
+
+ if (converted_name)
+ free (converted_name);
+
+ /* next line */
+ endline++;
+
+ }
+
+ fclose(f);
+ return 0;
+}
+
+
+
+/* open a memory btree */
+
+DB *
+opendatabase(DB *ret)
+{
+ ret = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL);
+
+ return (ret);
+
+}
+
+
blob - /dev/null
blob + d66dae1521a364f0e97c75135073fe2591f1a123 (mode 644)
--- /dev/null
+++ reply.c
@@ -0,0 +1,1027 @@
+/*
+ * Copyright (c) 2005 Peter Philipp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "include.h"
+#include "dns.h"
+#include "db.h"
+
+void reply_a(struct sreply *);
+void reply_aaaa(struct sreply *);
+void reply_mx(struct sreply *);
+void reply_ns(struct sreply *);
+void reply_notimpl(struct sreply *);
+void reply_nxdomain(struct sreply *);
+void reply_soa(struct sreply *);
+void reply_ptr(struct sreply *);
+void reply_cname(struct sreply *);
+
+extern int compress_label(char *, int, int);
+extern int additional_a(char *, int, struct domain *, char *, int, int, int *);
+extern int additional_aaaa(char *, int, struct domain *, char *, int, int, int *);
+extern int additional_mx(char *, int, struct domain *, char *, int, int, int *);
+extern int additional_ptr(char *, int, struct domain *, char *, int, int, int *);
+
+
+/*
+ * REPLY_A() - replies a DNS question (*q) on socket (so)
+ *
+ */
+
+void
+reply_a(struct sreply *sreply)
+{
+ char reply[512];
+ struct dns_header *odh;
+ int outlen;
+ int a_count;
+
+ struct answer {
+ char name[2];
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl;
+ u_int16_t rdlength; /* 12 */
+ in_addr_t rdata; /* 16 */
+ } __attribute__((packed));
+
+ struct answer *answer;
+
+ int so = sreply->so;
+ char *buf = sreply->buf;
+ int len = sreply->len;
+ struct question *q = sreply->q;
+ struct sockaddr *sa = sreply->sa;
+ int salen = sreply->salen;
+ struct domain *sd = sreply->sd1;
+
+
+#if 0
+ memset(&reply, 0, sizeof(reply));
+#endif
+
+ odh = (struct dns_header *)&reply[0];
+ outlen = sizeof(struct dns_header);
+
+ if (len > sizeof(reply)) {
+ return;
+ }
+
+ memcpy(&reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+ memset((char *)&odh->query, 0, sizeof(u_int16_t));
+
+ outlen += (q->hdr->namelen + 4);
+
+ SET_DNS_REPLY(odh);
+ SET_DNS_AUTHORITATIVE(odh);
+
+ HTONS(odh->query);
+
+ odh->question = ntohs(1);
+ odh->answer = ntohs(sd->a_count);
+ odh->nsrr = 0;
+ odh->additional = 0;
+
+ /* skip dns header, question name, qtype and qclass */
+ answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ q->hdr->namelen + 4);
+
+ a_count = 0;
+ do {
+ answer->name[0] = 0xc0;
+ answer->name[1] = 0x0c;
+ answer->type = q->hdr->qtype;
+ answer->class = q->hdr->qclass;
+ answer->ttl = htonl(sd->ttl);
+
+ answer->rdlength = htons(sizeof(in_addr_t));
+
+ memcpy((char *)&answer->rdata, (char *)&sd->a[a_count++], sizeof(in_addr_t));
+ outlen += 16;
+
+ /* can we afford to write another header? if no truncate */
+ if (sd->a_count > 1 && outlen + 16 > DNS_MAXUDP) {
+ NTOHS(odh->query);
+ SET_DNS_TRUNCATION(odh);
+ HTONS(odh->query);
+ goto out;
+ }
+
+ /* set new offset for answer */
+ answer = (struct answer *)&reply[outlen];
+ } while (a_count < 10 && --sd->a_count);
+
+out:
+ if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
+
+ return;
+}
+
+/*
+ * REPLY_AAAA() - replies a DNS question (*q) on socket (so)
+ *
+ */
+
+void
+reply_aaaa(struct sreply *sreply)
+{
+ char reply[512];
+ struct dns_header *odh;
+ int outlen;
+ int aaaa_count;
+
+ struct answer {
+ char name[2];
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl;
+ u_int16_t rdlength; /* 12 */
+ char rdata; /* 12 + 16 */
+ } __attribute__((packed));
+
+ struct answer *answer;
+
+ int so = sreply->so;
+ char *buf = sreply->buf;
+ int len = sreply->len;
+ struct question *q = sreply->q;
+ struct sockaddr *sa = sreply->sa;
+ int salen = sreply->salen;
+ struct domain *sd = sreply->sd1;
+
+
+#if 0
+ memset(&reply, 0, sizeof(reply));
+#endif
+
+ odh = (struct dns_header *)&reply[0];
+ outlen = sizeof(struct dns_header);
+
+ if (len > sizeof(reply)) {
+ return;
+ }
+
+ memcpy(&reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+ memset((char *)&odh->query, 0, sizeof(u_int16_t));
+
+ outlen += (q->hdr->namelen + 4);
+
+ SET_DNS_REPLY(odh);
+ SET_DNS_AUTHORITATIVE(odh);
+
+ HTONS(odh->query);
+
+ odh->question = ntohs(1);
+ odh->answer = ntohs(sd->aaaa_count);
+ odh->nsrr = 0;
+ odh->additional = 0;
+
+ /* skip dns header, question name, qtype and qclass */
+ answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ q->hdr->namelen + 4);
+
+ aaaa_count = 0;
+
+ do {
+ answer->name[0] = 0xc0;
+ answer->name[1] = 0x0c;
+ answer->type = q->hdr->qtype;
+ answer->class = q->hdr->qclass;
+ answer->ttl = htonl(sd->ttl);
+
+ answer->rdlength = htons(sizeof(struct in6_addr));
+
+ memcpy((char *)&answer->rdata, (char *)&sd->aaaa[aaaa_count++], sizeof(struct in6_addr));
+ outlen += 28;
+
+ /* can we afford to write another header? if no truncate */
+ if (sd->aaaa_count > 1 && outlen + 28 > DNS_MAXUDP) {
+ NTOHS(odh->query);
+ SET_DNS_TRUNCATION(odh);
+ HTONS(odh->query);
+ goto out;
+ }
+
+ /* set new offset for answer */
+ answer = (struct answer *)&reply[outlen];
+ } while (aaaa_count < 10 && --sd->aaaa_count);
+
+out:
+ if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
+
+ return;
+}
+
+/*
+ * REPLY_MX() - replies a DNS question (*q) on socket (so)
+ *
+ */
+
+void
+reply_mx(struct sreply *sreply)
+{
+ char reply[512];
+ struct dns_header *odh;
+ int outlen;
+ int mx_count;
+
+ struct answer {
+ char name[2];
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl;
+ u_int16_t rdlength; /* 12 */
+ u_int16_t mx_priority;
+ char exchange;
+ } __attribute__((packed));
+
+ struct answer *answer;
+
+ int so = sreply->so;
+ char *buf = sreply->buf;
+ int len = sreply->len;
+ struct question *q = sreply->q;
+ struct sockaddr *sa = sreply->sa;
+ int salen = sreply->salen;
+ struct domain *sd = sreply->sd1;
+
+
+ odh = (struct dns_header *)&reply[0];
+ outlen = sizeof(struct dns_header);
+
+ if (len > sizeof(reply)) {
+ return;
+ }
+
+ memcpy(&reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+ memset((char *)&odh->query, 0, sizeof(u_int16_t));
+
+ outlen += (q->hdr->namelen + 4);
+
+ SET_DNS_REPLY(odh);
+ SET_DNS_AUTHORITATIVE(odh);
+
+ HTONS(odh->query);
+
+ odh->question = ntohs(1);
+ odh->answer = ntohs(sd->mx_count);
+ odh->nsrr = 0;
+ odh->additional = 0;
+
+ /* skip dns header, question name, qtype and qclass */
+ answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ q->hdr->namelen + 4);
+
+ mx_count = 0;
+ do {
+ answer->name[0] = 0xc0;
+ answer->name[1] = 0x0c;
+ answer->type = q->hdr->qtype;
+ answer->class = q->hdr->qclass;
+ answer->ttl = htonl(sd->ttl);
+
+ answer->rdlength = htons(sizeof(u_int16_t) + sd->mx[mx_count].exchangelen);
+
+ answer->mx_priority = htons(sd->mx[mx_count].preference);
+ memcpy((char *)&answer->exchange, (char *)&sd->mx[mx_count].exchange, sd->mx[mx_count].exchangelen);
+ outlen += (12 + 2 + sd->mx[mx_count].exchangelen);
+
+ /* can we afford to write another header? if no truncate */
+ if (sd->mx_count > 1 && (outlen + 12 + 2 + sd->mx[mx_count].exchangelen) > DNS_MAXUDP) {
+ NTOHS(odh->query);
+ SET_DNS_TRUNCATION(odh);
+ HTONS(odh->query);
+ goto out;
+ }
+
+ /* set new offset for answer */
+ answer = (struct answer *)&reply[outlen];
+ } while (++mx_count < 10 && --sd->mx_count);
+
+out:
+ if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
+
+ return;
+}
+
+/*
+ * REPLY_NS() - replies a DNS question (*q) on socket (so)
+ *
+ */
+
+void
+reply_ns(struct sreply *sreply)
+{
+ char reply[512];
+ struct dns_header *odh;
+ int outlen;
+ int ns_count;
+
+ struct answer {
+ char name[2];
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl;
+ u_int16_t rdlength; /* 12 */
+ char ns;
+ } __attribute__((packed));
+
+ struct answer *answer;
+
+ int so = sreply->so;
+ char *buf = sreply->buf;
+ int len = sreply->len;
+ struct question *q = sreply->q;
+ struct sockaddr *sa = sreply->sa;
+ int salen = sreply->salen;
+ struct domain *sd = sreply->sd1;
+
+#if 0
+ memset(&reply, 0, sizeof(reply));
+#endif
+
+ odh = (struct dns_header *)&reply[0];
+ outlen = sizeof(struct dns_header);
+
+ if (len > sizeof(reply)) {
+ return;
+ }
+
+ memcpy(&reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+ memset((char *)&odh->query, 0, sizeof(u_int16_t));
+
+ outlen += (q->hdr->namelen + 4);
+
+ SET_DNS_REPLY(odh);
+ SET_DNS_AUTHORITATIVE(odh);
+
+ HTONS(odh->query);
+
+ odh->question = ntohs(1);
+ odh->answer = ntohs(sd->ns_count);
+ odh->nsrr = 0;
+ odh->additional = 0;
+
+ /* skip dns header, question name, qtype and qclass */
+ answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ q->hdr->namelen + 4);
+
+ ns_count = 0;
+ do {
+ answer->name[0] = 0xc0;
+ answer->name[1] = 0x0c;
+ answer->type = q->hdr->qtype;
+ answer->class = q->hdr->qclass;
+ answer->ttl = htonl(sd->ttl);
+
+ answer->rdlength = htons(sd->ns[ns_count].nslen);
+
+ memcpy((char *)&answer->ns, (char *)&sd->ns[ns_count].nsserver, sd->ns[ns_count].nslen);
+ outlen += (12 + sd->ns[ns_count].nslen);
+
+ /* can we afford to write another header? if no truncate */
+ if (sd->ns_count > 1 && (outlen + 12 + sd->ns[ns_count].nslen) > DNS_MAXUDP) {
+ NTOHS(odh->query);
+ SET_DNS_TRUNCATION(odh);
+ HTONS(odh->query);
+ goto out;
+ }
+
+ /* set new offset for answer */
+ answer = (struct answer *)&reply[outlen];
+ } while (++ns_count < 10 && --sd->ns_count);
+
+out:
+ if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
+
+ return;
+}
+
+
+/*
+ * REPLY_CNAME() - replies a DNS question (*q) on socket (so)
+ *
+ */
+
+
+void
+reply_cname(struct sreply *sreply)
+{
+ char reply[512];
+ struct dns_header *odh;
+ int outlen;
+ char *p;
+ int i, tmplen;
+ int labellen;
+ char *label, *plabel;
+ int addcount;
+
+ struct answer {
+ char name[2];
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl;
+ u_int16_t rdlength; /* 12 */
+ char rdata;
+ } __attribute__((packed));
+
+ struct answer *answer;
+
+ int so = sreply->so;
+ char *buf = sreply->buf;
+ int len = sreply->len;
+ struct question *q = sreply->q;
+ struct sockaddr *sa = sreply->sa;
+ int salen = sreply->salen;
+ struct domain *sd = sreply->sd1;
+ struct domain *sd1 = sreply->sd2;
+
+
+ odh = (struct dns_header *)&reply[0];
+ outlen = sizeof(struct dns_header);
+
+ if (len > sizeof(reply)) {
+ return;
+ }
+
+ /* copy question to reply */
+ memcpy(&reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+ /* blank query */
+ memset((char *)&odh->query, 0, sizeof(u_int16_t));
+
+ outlen += (q->hdr->namelen + 4);
+
+ SET_DNS_REPLY(odh);
+ SET_DNS_AUTHORITATIVE(odh);
+
+ HTONS(odh->query);
+
+ odh->question = htons(1);
+ odh->answer = htons(1);
+ odh->nsrr = 0;
+ odh->additional = 0;
+
+ answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ q->hdr->namelen + 4);
+
+ answer->name[0] = 0xc0;
+ answer->name[1] = 0x0c;
+ answer->type = ntohs(DNS_TYPE_CNAME);
+ answer->class = q->hdr->qclass;
+ answer->ttl = htonl(sd->ttl);
+
+ outlen += 12; /* up to rdata length */
+
+ p = (char *)&answer->rdata;
+
+ label = &sd->cname[0];
+ labellen = sd->cnamelen;
+
+ plabel = label;
+
+ /* copy label to reply */
+ for (i = outlen; i < sizeof(reply); i++) {
+ if (i - outlen == labellen)
+ break;
+
+ reply[i] = *plabel++;
+ }
+
+ if (i >= sizeof(reply))
+ return ;
+
+ outlen = i;
+
+ /* compress the label if possible */
+ if ((tmplen = compress_label(reply, outlen, labellen)) > 0) {
+ /* XXX */
+ outlen = tmplen;
+ }
+
+ answer->rdlength = htons(&reply[outlen] - &answer->rdata);
+
+ if (ntohs(q->hdr->qtype) == DNS_TYPE_A && sd1 != NULL) {
+ tmplen = additional_a(sd->cname, sd->cnamelen, sd1, reply, sizeof(reply), outlen, &addcount);
+ if (tmplen > 0)
+ outlen = tmplen;
+
+ NTOHS(odh->answer);
+ odh->answer += addcount;
+ HTONS(odh->answer);
+ } else if (ntohs(q->hdr->qtype) == DNS_TYPE_AAAA && sd1 != NULL) {
+ tmplen = additional_aaaa(sd->cname, sd->cnamelen, sd1, reply, sizeof(reply), outlen, &addcount);
+ if (tmplen > 0)
+ outlen = tmplen;
+
+ NTOHS(odh->answer);
+ odh->answer += addcount;
+ HTONS(odh->answer);
+ } else if (ntohs(q->hdr->qtype) == DNS_TYPE_MX && sd1 != NULL) {
+ tmplen = additional_mx(sd->cname, sd->cnamelen, sd1, reply, sizeof(reply), outlen, &addcount);
+ if (tmplen > 0)
+ outlen = tmplen;
+
+ NTOHS(odh->answer);
+ odh->answer += addcount;
+ HTONS(odh->answer);
+ } else if (ntohs(q->hdr->qtype) == DNS_TYPE_PTR && sd1 != NULL) {
+ tmplen = additional_ptr(sd->cname, sd->cnamelen, sd1, reply, sizeof(reply), outlen, &addcount);
+ if (tmplen > 0)
+ outlen = tmplen;
+
+ NTOHS(odh->answer);
+ odh->answer += addcount;
+ HTONS(odh->answer);
+ }
+
+ if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
+
+ return;
+}
+
+/*
+ * REPLY_PTR() - replies a DNS question (*q) on socket (so)
+ *
+ */
+
+void
+reply_ptr(struct sreply *sreply)
+{
+ char reply[512];
+ struct dns_header *odh;
+ int outlen;
+ char *p;
+ int i, tmplen;
+ int labellen;
+ char *label, *plabel;
+
+ struct answer {
+ char name[2];
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl;
+ u_int16_t rdlength; /* 12 */
+ char rdata;
+ } __attribute__((packed));
+
+ struct answer *answer;
+
+ int so = sreply->so;
+ char *buf = sreply->buf;
+ int len = sreply->len;
+ struct question *q = sreply->q;
+ struct sockaddr *sa = sreply->sa;
+ int salen = sreply->salen;
+ struct domain *sd = sreply->sd1;
+
+ odh = (struct dns_header *)&reply[0];
+ outlen = sizeof(struct dns_header);
+
+
+ if (len > sizeof(reply)) {
+ return;
+ }
+
+ /* copy question to reply */
+ memcpy(&reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+ /* blank query */
+ memset((char *)&odh->query, 0, sizeof(u_int16_t));
+
+ outlen += (q->hdr->namelen + 4);
+
+ SET_DNS_REPLY(odh);
+ SET_DNS_AUTHORITATIVE(odh);
+
+ HTONS(odh->query);
+
+ odh->question = ntohs(1);
+ odh->answer = ntohs(1);
+ odh->nsrr = 0;
+ odh->additional = 0;
+
+ answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ q->hdr->namelen + 4);
+
+ answer->name[0] = 0xc0;
+ answer->name[1] = 0x0c;
+ answer->type = q->hdr->qtype;
+ answer->class = q->hdr->qclass;
+ answer->ttl = htonl(sd->ttl);
+
+ outlen += 12; /* up to rdata length */
+
+ p = (char *)&answer->rdata;
+
+ label = &sd->ptr[0];
+ labellen = sd->ptrlen;
+
+ plabel = label;
+
+ /* copy label to reply */
+ for (i = outlen; i < sizeof(reply); i++) {
+ if (i - outlen == labellen)
+ break;
+
+ reply[i] = *plabel++;
+ }
+
+ if (i >= sizeof(reply)) {
+ return ;
+ }
+
+ outlen = i;
+
+ /* compress the label if possible */
+ if ((tmplen = compress_label(reply, outlen, labellen)) > 0) {
+ outlen = tmplen;
+ }
+
+ answer->rdlength = htons(&reply[outlen] - &answer->rdata);
+
+ if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
+
+ return;
+}
+
+/*
+ * REPLY_SOA() - replies a DNS question (*q) on socket (so)
+ *
+ */
+
+
+void
+reply_soa(struct sreply *sreply)
+{
+ char reply[512];
+ struct dns_header *odh;
+ int outlen;
+ char *p;
+ u_int32_t *soa_val;
+ int i, tmplen;
+ int labellen;
+ char *label, *plabel;
+
+ struct answer {
+ char name[2];
+ u_int16_t type;
+ u_int16_t class;
+ u_int32_t ttl;
+ u_int16_t rdlength; /* 12 */
+ char rdata;
+ } __attribute__((packed));
+
+ struct soa {
+ char *nsserver;
+ char *responsible_person;
+ u_int32_t serial;
+ u_int32_t refresh;
+ u_int32_t retry;
+ u_int32_t expire;
+ u_int32_t minttl;
+ };
+
+
+ struct answer *answer;
+
+ int so = sreply->so;
+ char *buf = sreply->buf;
+ int len = sreply->len;
+ struct question *q = sreply->q;
+ struct sockaddr *sa = sreply->sa;
+ int salen = sreply->salen;
+ struct domain *sd = sreply->sd1;
+
+#if 0
+ struct soa mysoa = { "neptune.solarsail.org.", "pbug.neptune.solarsail.org", 1, 3600, 1800, (14 * 24 * 3600), 0xffffffff };
+
+#endif
+
+#if 0
+ memset(&reply, 0, sizeof(reply));
+#endif
+
+ odh = (struct dns_header *)&reply[0];
+ outlen = sizeof(struct dns_header);
+
+ if (len > sizeof(reply)) {
+ return;
+ }
+
+ /* copy question to reply */
+ memcpy(&reply, buf, sizeof(struct dns_header) + q->hdr->namelen + 4);
+ /* blank query */
+ memset((char *)&odh->query, 0, sizeof(u_int16_t));
+
+ outlen += (q->hdr->namelen + 4);
+
+ SET_DNS_REPLY(odh);
+ SET_DNS_AUTHORITATIVE(odh);
+
+ NTOHS(odh->query);
+
+ odh->question = ntohs(1);
+ odh->answer = ntohs(1);
+ odh->nsrr = 0;
+ odh->additional = 0;
+
+ answer = (struct answer *)(&reply[0] + sizeof(struct dns_header) +
+ q->hdr->namelen + 4);
+
+ answer->name[0] = 0xc0;
+ answer->name[1] = 0x0c;
+ answer->type = q->hdr->qtype;
+ answer->class = q->hdr->qclass;
+ answer->ttl = htonl(sd->ttl);
+
+ outlen += 12; /* up to rdata length */
+
+ p = (char *)&answer->rdata;
+
+#if 0
+ label = dns_label((char *)mysoa.nsserver, &labellen);
+ if (label == NULL)
+ return;
+#endif
+
+ label = &sd->soa.nsserver[0];
+ labellen = sd->soa.nsserver_len;
+
+ plabel = label;
+
+ /* copy label to reply */
+ for (i = outlen; i < sizeof(reply); i++) {
+ if (i - outlen == labellen)
+ break;
+
+ reply[i] = *plabel++;
+ }
+
+ if (i >= sizeof(reply)) {
+#if 0
+ free(label);
+#endif
+ return ;
+ }
+
+ outlen = i;
+#if 0
+ free(label);
+#endif
+
+ /* compress the label if possible */
+ if ((tmplen = compress_label(reply, outlen, labellen)) > 0) {
+ outlen = tmplen;
+ }
+
+#if 0
+ label = dns_label((char *)mysoa.responsible_person, &labellen);
+ if (label == NULL)
+ return;
+#endif
+
+ label = &sd->soa.responsible_person[0];
+ labellen = sd->soa.rp_len;
+ plabel = label;
+
+ for (i = outlen; i < sizeof(reply); i++) {
+ if (i - outlen == labellen)
+ break;
+
+ reply[i] = *plabel++;
+ }
+
+ if (i >= sizeof(reply)) {
+#if 0
+ free(label);
+#endif
+ return ;
+ }
+
+ outlen = i;
+
+#if 0
+ free(label);
+#endif
+
+ /* 2 compress the label if possible */
+
+ if ((tmplen = compress_label(reply, outlen, labellen)) > 0) {
+ outlen = tmplen;
+ }
+
+
+#if 0
+ if ((outlen + sizeof(mysoa.serial)) > sizeof(reply)) {
+ /* XXX server error reply? */
+ return;
+ }
+ soa_val = (u_int32_t *)&reply[outlen];
+ *soa_val = htonl(mysoa.serial);
+ outlen += sizeof(mysoa.serial);
+#else
+ if ((outlen + sizeof(sd->soa.serial)) > sizeof(reply)) {
+ /* XXX server error reply? */
+ return;
+ }
+ soa_val = (u_int32_t *)&reply[outlen];
+ *soa_val = htonl(sd->soa.serial);
+ outlen += sizeof(sd->soa.serial);
+#endif
+
+#if 0
+ if ((outlen + sizeof(mysoa.refresh)) > sizeof(reply)) {
+ return;
+ }
+ soa_val = (u_int32_t *)&reply[outlen];
+ *soa_val = htonl(mysoa.refresh);
+ outlen += sizeof(mysoa.refresh);
+#else
+ if ((outlen + sizeof(sd->soa.refresh)) > sizeof(reply)) {
+ return;
+ }
+ soa_val = (u_int32_t *)&reply[outlen];
+ *soa_val = htonl(sd->soa.refresh);
+ outlen += sizeof(sd->soa.refresh);
+#endif
+
+#if 0
+ if ((outlen + sizeof(mysoa.retry)) > sizeof(reply)) {
+ return;
+ }
+ soa_val = (u_int32_t *)&reply[outlen];
+ *soa_val = htonl(mysoa.retry);
+ outlen += sizeof(mysoa.retry);
+#else
+ if ((outlen + sizeof(sd->soa.retry)) > sizeof(reply)) {
+ return;
+ }
+ soa_val = (u_int32_t *)&reply[outlen];
+ *soa_val = htonl(sd->soa.retry);
+ outlen += sizeof(sd->soa.retry);
+#endif
+
+#if 0
+ if ((outlen + sizeof(mysoa.expire)) > sizeof(reply)) {
+ return;
+ }
+ soa_val = (u_int32_t *)&reply[outlen];
+ *soa_val = htonl(mysoa.expire);
+ outlen += sizeof(mysoa.expire);
+#else
+ if ((outlen + sizeof(sd->soa.expire)) > sizeof(reply)) {
+ return;
+ }
+ soa_val = (u_int32_t *)&reply[outlen];
+ *soa_val = htonl(sd->soa.expire);
+ outlen += sizeof(sd->soa.expire);
+#endif
+
+#if 0
+ if ((outlen + sizeof(mysoa.minttl)) > sizeof(reply)) {
+ return;
+ }
+ soa_val = (u_int32_t *)&reply[outlen];
+ *soa_val = htonl(mysoa.minttl);
+ outlen += sizeof(mysoa.minttl);
+#else
+ if ((outlen + sizeof(sd->soa.minttl)) > sizeof(reply)) {
+ return;
+ }
+ soa_val = (u_int32_t *)&reply[outlen];
+ *soa_val = htonl(sd->soa.minttl);
+ outlen += sizeof(sd->soa.minttl);
+#endif
+
+ answer->rdlength = htons(&reply[outlen] - &answer->rdata);
+
+ if (sendto(so, reply, outlen, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
+
+ return;
+}
+
+/*
+ * REPLY_NOTIMPL - reply "Not Implemented"
+ *
+ */
+
+void
+reply_notimpl(struct sreply *sreply)
+{
+ char reply[512];
+ struct dns_header *odh;
+ int outlen;
+
+ int so = sreply->so;
+ char *buf = sreply->buf;
+ int len = sreply->len;
+ struct sockaddr *sa = sreply->sa;
+ int salen = sreply->salen;
+
+#if 0
+ struct domain *sd = sreply->sd1;
+ struct question *q = sreply->q;
+#endif
+
+ odh = (struct dns_header *)&reply[0];
+ outlen = sizeof(struct dns_header);
+
+ if (len > sizeof(reply)) {
+ return;
+ }
+
+ memcpy(&reply, buf, len);
+ memset((char *)&odh->query, 0, sizeof(u_int16_t));
+
+ SET_DNS_REPLY(odh);
+ SET_DNS_RCODE_NOTIMPL(odh);
+
+ HTONS(odh->query);
+
+ if (sendto(so, reply, len, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
+
+ return;
+}
+
+/*
+ * REPLY_NXDOMAIN() - replies a DNS question (*q) on socket (so)
+ *
+ */
+
+void
+reply_nxdomain(struct sreply *sreply)
+{
+ char reply[512];
+ struct dns_header *odh;
+ int outlen;
+
+ int so = sreply->so;
+ char *buf = sreply->buf;
+ int len = sreply->len;
+ struct sockaddr *sa = sreply->sa;
+ int salen = sreply->salen;
+
+#if 0
+ struct question *q = sreply->q;
+ struct domain *sd = sreply->sd1;
+#endif
+
+ odh = (struct dns_header *)&reply[0];
+ outlen = sizeof(struct dns_header);
+
+ if (len > sizeof(reply)) {
+ return;
+ }
+
+ memcpy(&reply, buf, len);
+ memset((char *)&odh->query, 0, sizeof(u_int16_t));
+
+ SET_DNS_REPLY(odh);
+ SET_DNS_RCODE_NAMEERR(odh);
+
+ HTONS(odh->query);
+
+ if (sendto(so, reply, len, 0, sa, salen) < 0) {
+ syslog(LOG_INFO, "sendto: %m");
+ }
+
+ return;
+}
blob - /dev/null
blob + 9bb786d07893eb4183028dce3adfbeaf63905b82 (mode 644)
--- /dev/null
+++ wildcarddns.conf
@@ -0,0 +1,58 @@
+#
+#
+# wildcarddns - RR configuration file
+#
+#
+;
+; comments must be at the beginning of a new line, # and ; is allowed
+;
+;
+; ALL RR's begine with: zone,RR,time to live, ...
+;
+; names can be expressed with no trailing . or with trailing dot either way
+; they'll be modified to have a trailing dot.
+; example: www.google.com or www.google.com. becomes www.google.com.
+;
+# soa RR consists of: zone, SOA, ttl of RR, nameserver, responsible person,
+# serial, refresh, retry, expire, zone time to live (no spaces)
+;
+*,soa,3600,neptune.ATLAS.,pbug.neptune.ATLAS,1,3600,1800,7200,3600
+;
+# a RR consists of: zone, A, ttl of RR, IP (no spaces)
+# up to 10 addresses allowed
+;
+*,a,3600,10.0.0.2
+*,a,3600,10.0.0.1
+;
+# MX RR consists of: zone, MX, ttl of RR, priority, name of MX (no spaces)
+# up to 10 addresses allowed
+;
+*,mx,3600,1,atlas.local
+*,mx,3600,1,neptune.local
+;
+# AAAA RR consists of: zone, AAAA, ttl of RR, IPv6 address (no spaces)
+# up to 10 addresses allowed
+;
+*,aaaa,3600,::1
+*,aaaa,3600,3ffe:b00:1022::
+;
+# all of *.com looks like this:
+;
+com,soa,3600,a.com,b.com,1,3600,1800,300000,3600
+;
+# CNAME RR consists of: zone, CNAME, ttl of RR, name (no spaces)
+; CNAME support is currently not complete since a CNAME must attach the
+; records it is pointing to... something to be done in the future I guess..
+;
+*,cname,3600,neptune.local
+;
+#
+# PTR RR consists of: zone, PTR, ttl of RR, name (no spaces)
+;
+arpa.,ptr,3600,neptune.local.
+;
+# NS RR consists of: zone, NS, ttl of RR, name (no spaces)
+;
+*,ns,3600,ns.neptune.local.
+;
+; Got it? good.
blob - /dev/null
blob + d9fde24c7d4c0c7e321b3eb5605ee75de13ec160 (mode 644)
--- /dev/null
+++ wildcarddnsd.8
@@ -0,0 +1,103 @@
+.\" Copyright (c) 2005 Peter Philipp
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd November 27, 2005
+.Dt WILDCARDDNSD 8
+.Os
+.Sh NAME
+.Nm wildcarddnsd
+.Nd the Wildcard DNS daemon
+.Sh SYNOPSIS
+.Nm wildcarddnsd
+.Oo
+.Op Fl b Ar address
+.Op ...
+.Oc
+.Op Fl f Ar file
+.Oo
+.Op Fl i Ar interface
+.Op ...
+.Oc
+.Op Fl p Ar port
+.Sh DESCRIPTION
+.Nm
+is the daemon that runs Wildcard DNS.
+.Pp
+The options are as follows:
+.Pp
+.Bl -tag -width Ds
+.It Xo
+.Fl b
+.Ar address
+.Xc
+Adds an
+.Ar address
+that
+.Nm
+should
+.Xr bind 2
+to. This option can be repeated multiple times to add more. May
+not be used in conjunction with
+.Fl i .
+.It Xo
+.Fl f
+.Ar file
+.Xc
+The configuration file to be used is found at
+.Ar file .
+.It Xo
+.Fl i
+.Ar interface
+.Xc
+The particular
+.Ar interface
+that
+.Nm
+should listen on. This option can be specified multiple times. May not be
+used in conjunction with
+.Fl b .
+.It Xo
+.Fl p
+.Ar port
+.Xc
+Specifies the
+.Ar port
+that
+.Nm
+should listen on. This can be useful when using
+.Nm
+with
+.Xr pf 4 .
+.El
+.Sh FILES
+.Pa /etc/wildcarddns.conf
+.Sh SEE ALSO
+.Xr bind 2 ,
+.Xr daemon 3 ,
+.Xr pf 4 ,
+.Sh AUTHORS
+This software was written by
+.An Peter Philipp Aq peter_philipp@freenet.de
+
blob - /dev/null
blob + 014bf43e0a9ac4a1450ac57fb340a34cd8b55444 (mode 644)
--- /dev/null
+++ wildcarddnsd.cat8
@@ -0,0 +1,42 @@
+WILDCARDDNSD(8) OpenBSD System Manager's Manual WILDCARDDNSD(8)
+
+NNAAMMEE
+ wwiillddccaarrddddnnssdd - the Wildcard DNS daemon
+
+SSYYNNOOPPSSIISS
+ wwiillddccaarrddddnnssdd [[--bb _a_d_d_r_e_s_s] [...]] [--ff _f_i_l_e] [[--ii _i_n_t_e_r_f_a_c_e] [...]] [--pp
+ _p_o_r_t]
+
+DDEESSCCRRIIPPTTIIOONN
+ wwiillddccaarrddddnnssdd is the daemon that runs Wildcard DNS.
+
+ The options are as follows:
+
+ --bb _a_d_d_r_e_s_s
+ Adds an _a_d_d_r_e_s_s that wwiillddccaarrddddnnssdd should bind(2) to. This option
+ can be repeated multiple times to add more. May not be used in
+ conjunction with --ii.
+
+ --ff _f_i_l_e
+ The configuration file to be used is found at _f_i_l_e.
+
+ --ii _i_n_t_e_r_f_a_c_e
+ The particular _i_n_t_e_r_f_a_c_e that wwiillddccaarrddddnnssdd should listen on.
+ This option can be specified multiple times. May not be used in
+ conjunction with --bb.
+
+ --pp _p_o_r_t
+ Specifies the _p_o_r_t that wwiillddccaarrddddnnssdd should listen on. This can
+ be useful when using wwiillddccaarrddddnnssdd with pf(4).
+
+FFIILLEESS
+ _/_e_t_c_/_w_i_l_d_c_a_r_d_d_n_s_._c_o_n_f
+
+SSEEEE AALLSSOO
+ bind(2), daemon(3), pf(4),
+
+AAUUTTHHOORRSS
+ This software was written by Peter Philipp <peter_philipp@freenet.de>
+
+
+OpenBSD 3.8 November 27, 2005 1
repomaster@centroid.eu