#include "bin.h" #include "ldapdns.h" #include "dns.h" #include "str.h" #include "ht.h" #include #include 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; }