#include "bin.h"
#include "ldapdns.h"
#include "dns.h"
#include "str.h"
#include "ht.h"
#include <netinet/in.h>
#include <string.h>
int response_rstart(dns_ctx *c, char *dnsenc, char rr[2], unsigned int ttl)
{
if (!response_addname(c, dnsenc)) return 0;
if (!response_addbytes(c, rr, 2)) return 0;
if (!response_addbytes(c, DNS_C_IN, 2)) return 0;
if (!response_addulong(c, ttl)) return 0;
if (!response_addbytes(c, "\0\0", 2)) return 0;
c->response_dpos = clen(c->response);
return 1;
}
static unsigned long __hash_dns(const void *str, unsigned len)
{
const char *h;
unsigned long d;
unsigned i;
d = 5431;
for (i = 0, h = str; i < len; i++) {
/* Clib */
d += (d << 5) ^ (tolower((int)h[i]));
}
return d;
}
void response_axfr(dns_ctx *c)
{
c->response->used = 0; /* Internal */
}
int response_axstart(dns_ctx *c, int soa, char *q, char qt[2], char qc[2], unsigned int ttl)
{
int flushed = 0;
char buf[10];
if (c->response->used > 0) {
tp_write(c);
flushed = 1;
}
c->answers = 0;
c->response_ls = 0;
ht_die(&c->response_names);
c->response->used = 0; /* Internal */
ht_init(&c->response_names, 7, __hash_dns);
if (!response_addbytes(c, c->dns_message_id, 2)) return 0;
memcpy(buf, "\204\000\0\0\0\1\0\0\0\0", 10);
if (!soa) buf[0] &= ~4;
if (!flushed) {
buf[3] = 1;
if (!response_addbytes(c, buf, 10)) return 0;
if (!response_addname(c, q)) return 0;
/* we only support AXFR over internet */
if (!response_addbytes(c, DNS_T_AXFR, 2)) return 0;
if (!response_addbytes(c, DNS_C_IN, 2)) return 0;
} else {
if (!response_addbytes(c, buf, 10)) return 0;
}
if (!response_addname(c, q)) return 0;
if (!response_addbytes(c, qt, 2)) return 0;
if (!response_addbytes(c, qc, 2)) return 0;
if (!response_addulong(c, ttl)) return 0;
if (!response_addbytes(c, "\0\0", 2)) return 0;
c->response_dpos = clen(c->response);
return 1;
}
void response_axfinish(dns_ctx *c)
{
unsigned short n;
/* Clib */
n = htons(clen(c->response) - c->response_dpos);
memcpy(c->response->buf + (c->response_dpos - 2), &n, 2);
}
int response_query(dns_ctx *c, char *q, char qt[2], char qc[2])
{
c->answers = 0;
c->response_ls = 0;
ht_die(&c->response_names);
c->response->used = 0; /* Internal */
ht_init(&c->response_names, 7, __hash_dns);
if (!response_addbytes(c, "\0\0\201\200\0\1\0\0\0\0\0\0", 12)) return 0;
if (!response_addname(c, q)) return 0;
if (!response_addbytes(c, qt, 2)) return 0;
if (!response_addbytes(c, qc, 2)) return 0;
c->response_tc = clen(c->response);
return 1;
}
int response_notify(dns_ctx *c, char *q, char qt[2], char qc[2])
{
c->response->used = 0; /* Internal */
if (!response_addbytes(c, "\0\0\204\200\0\1\0\0\0\0\0\0", 12)) return 0;
if (!response_addname(c, q)) return 0;
if (!response_addbytes(c, qt, 2)) return 0;
if (!response_addbytes(c, qc, 2)) return 0;
return 1;
}
int response_adddns(dns_ctx *c, char *dnsenc)
{
register int dlen, i;
unsigned short j;
/* ALWAYS: convert dnsenc to upper case */
for (i = 0; dnsenc[i]; i++) {
dnsenc[i] = tolower(dnsenc[i]);
}
dlen = i;
/* safe IF dnsenc is a valid dns name */
while (*dnsenc) {
i = ht_fetchint(&c->response_names, dnsenc, dlen);
if (i > -1) {
return response_addnameptr(c, i);
}
if (dlen <= 128) {
j = clen(c->response);
ht_storeint(&c->response_names, dnsenc, dlen, j);
}
i = ((unsigned char) *dnsenc) + 1;
if (!response_addbytes(c, dnsenc, i))
return 0;
dnsenc += i;
dlen -= i;
}
return response_addbytes(c, "\0", 1);
}
int response_addnetbios(dns_ctx *c, char *dnsenc)
{
/* translates a name to netbios format */
char buf[34];
register int i, j, x;
/* not a netbios name */
if (dns_domain_length(dnsenc) > 16)
return response_adddns(c, dnsenc);
for (i = 0, j = 1; i < dnsenc[0]; i++) {
x = toupper((unsigned int)(dnsenc[i+1]));
buf[j] = (0x41 + ((x & 0xF0) >> 4));
j++;
buf[j] = (0x41 + ((x & 0x0F)));
j++;
}
while (j < 31) {
buf[j] = 0x43; j++; /* ca == whitespace */
buf[j] = 0x41; j++;
}
buf[31] = 0x41; buf[32] = 0x41;
buf[33] = 0;
buf[0] = 32;
return response_adddns(c, buf);
}
int response_addname(dns_ctx *c, char *dnsenc)
{
if (c->protnum == PROT_NETBIOS)
return response_addnetbios(c, dnsenc);
return response_adddns(c, dnsenc);
}
int response_addbytes(dns_ctx *c, unsigned char *b, int l)
{
bin_cat(c->response, b, l);
return 1;
}
int response_addulong(dns_ctx *c, unsigned long n)
{
char buf[4];
/* Clib */
n = htonl(n);
memcpy(buf, &n, 4);
return response_addbytes(c, buf, 4);
}
int response_addnameptr(dns_ctx *c, unsigned int u)
{
char buf[2];
u += 49152;
buf[1] = u & 255;
buf[0] = u >> 8;
return response_addbytes(c, buf, 2);
}
int response_addushort(dns_ctx *c, unsigned short n)
{
char buf[2];
/* Clib */
n = htons(n);
memcpy(buf, &n, 2);
return response_addbytes(c, buf, 2);
}
void response_id(dns_ctx *c, const char id[2])
{
bin_need(c->response, 12);
c->dns_message_id[0] = c->response->buf[0] = id[0];
c->dns_message_id[1] = c->response->buf[1] = id[1];
}
void response_rcode(dns_ctx *c, int code)
{
bin_need(c->response, 12);
c->response->buf[3] &= ~15;
c->response->buf[3] |= (code & 15);
}
void response_aa(dns_ctx *c, int setting)
{
bin_need(c->response, 12);
if (setting) {
c->response->buf[2] |= 4; /* set 'aa' flag */
} else {
c->response->buf[2] &= (~4); /* clear 'aa' flag */
}
}
void response_tc(dns_ctx *c)
{
bin_need(c->response, 12);
c->response->buf[2] |= 2;
c->response->used = c->response_tc; /* Internal */
}
void response_nxdomain(dns_ctx *c)
{
bin_need(c->response, 12);
c->response->buf[3] |= 3;
c->response->buf[2] |= 4;
}
void response_servfail(dns_ctx *c)
{
bin_need(c->response, 12);
c->response->buf[3] |= 2;
}
void response_refuse(dns_ctx *c)
{
bin_need(c->response, 12);
if (c->axfr) {
c->response->buf[2] &= ~4;
c->response->buf[3] &= ~128;
c->response->buf[3] &= ~15;
c->response->buf[3] |= 5;
} else {
c->response->buf[2] &= ~4;
c->response->buf[3] &= ~15;
c->response->buf[3] |= 5;
}
}
int response_rfinish(dns_ctx *c, int section)
{
unsigned short n;
bin_need(c->response, 12);
/* increment answers... */
/* Clib */
memcpy(&n, c->response->buf + section, 2);
/* Clib */
n = htons(ntohs(n) + 1);
memcpy(c->response->buf + section, &n, 2);
/* set length of this response (rr) data */
/* Clib */
n = htons(clen(c->response) - c->response_dpos);
memcpy(c->response->buf + (c->response_dpos - 2), &n, 2);
if (c->response_ls != section) {
/* change of section */
c->response_tc = clen(c->response);
c->response_ls = section;
}
if (section == RESPONSE_ANSWER)
c->answers++;
return 1;
}
syntax highlighted by Code2HTML, v. 0.9.1