aboutsummaryrefslogtreecommitdiff
path: root/pickdns.c
diff options
context:
space:
mode:
Diffstat (limited to 'pickdns.c')
-rw-r--r--pickdns.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/pickdns.c b/pickdns.c
new file mode 100644
index 0000000..28c4ba5
--- /dev/null
+++ b/pickdns.c
@@ -0,0 +1,101 @@
+#include <unistd.h>
+#include "byte.h"
+#include "case.h"
+#include "dns.h"
+#include "open.h"
+#include "cdb.h"
+#include "response.h"
+
+const char *fatal = "pickdns: fatal: ";
+const char *starting = "starting pickdns\n";
+
+static char seed[128];
+
+void initialize(void)
+{
+ dns_random_init(seed);
+}
+
+static struct cdb c;
+static char key[258];
+static char data[512];
+
+static int doit(char *q,char qtype[2],char ip[4])
+{
+ int r;
+ uint32 dlen;
+ unsigned int qlen;
+ int flaga;
+ int flagmx;
+
+ qlen = dns_domain_length(q);
+ if (qlen > 255) return 0; /* impossible */
+
+ flaga = byte_equal(qtype,2,DNS_T_A);
+ flagmx = byte_equal(qtype,2,DNS_T_MX);
+ if (byte_equal(qtype,2,DNS_T_ANY)) flaga = flagmx = 1;
+ if (!flaga && !flagmx) goto REFUSE;
+
+ key[0] = '%';
+ byte_copy(key + 1,4,ip);
+
+ r = cdb_find(&c,key,5);
+ if (!r) r = cdb_find(&c,key,4);
+ if (!r) r = cdb_find(&c,key,3);
+ if (!r) r = cdb_find(&c,key,2);
+ if (r == -1) return 0;
+
+ key[0] = '+';
+ byte_zero(key + 1,2);
+ if (r && (cdb_datalen(&c) == 2))
+ if (cdb_read(&c,key + 1,2,cdb_datapos(&c)) == -1) return 0;
+
+ byte_copy(key + 3,qlen,q);
+ case_lowerb(key + 3,qlen + 3);
+
+ r = cdb_find(&c,key,qlen + 3);
+ if (!r) {
+ byte_zero(key + 1,2);
+ r = cdb_find(&c,key,qlen + 3);
+ }
+ if (!r) goto REFUSE;
+ if (r == -1) return 0;
+ dlen = cdb_datalen(&c);
+
+ if (dlen > 512) dlen = 512;
+ if (cdb_read(&c,data,dlen,cdb_datapos(&c)) == -1) return 0;
+
+ if (flaga) {
+ dns_sortip(data,dlen);
+ if (dlen > 12) dlen = 12;
+ while (dlen >= 4) {
+ dlen -= 4;
+ if (!response_rstart(q,DNS_T_A,5)) return 0;
+ if (!response_addbytes(data + dlen,4)) return 0;
+ response_rfinish(RESPONSE_ANSWER);
+ }
+ }
+
+ return 1;
+
+
+ REFUSE:
+ response[2] &= ~4;
+ response[3] &= ~15;
+ response[3] |= 5;
+ return 1;
+}
+
+int respond(char *q,char qtype[2],char ip[4])
+{
+ int fd;
+ int result;
+
+ fd = open_read("data.cdb");
+ if (fd == -1) return 0;
+ cdb_init(&c,fd);
+ result = doit(q,qtype,ip);
+ cdb_free(&c);
+ close(fd);
+ return result;
+}