acl/lib_acl/samples/dgate/rfc1035.cpp

839 lines
21 KiB
C++
Raw Normal View History

#include "stdafx.h"
#include <stdio.h> /* for snprintf */
#ifdef ACL_BCB_COMPILER
#pragma hdrstop
#endif
#include "rfc1035.h"
#define RFC1035_MAXLABELSZ 63
#define rfc1035_unpack_error 15
int rfc1035_errno;
const char *rfc1035_error_message;
#if 0
#define RFC1035_UNPACK_DEBUG acl_msg_error("unpack error at %s:%d", __FILE__,__LINE__)
#else
#define RFC1035_UNPACK_DEBUG (void)0
#endif
/*
* rfc1035HeaderPack()
*
* Packs a rfc1035_header structure into a buffer.
* Returns number of octets packed (should always be 12)
*/
static int rfc1035HeaderPack(char *buf, size_t sz, rfc1035_message * hdr)
{
const char *myname = "rfc1035HeaderPack";
int off = 0;
unsigned short s;
unsigned short t;
if (sz < 12)
acl_msg_fatal("%s: sz(%d) < 12", myname, sz);
s = htons(hdr->id);
memcpy(buf + off, &s, sizeof(s));
off += sizeof(s);
t = 0;
t |= hdr->qr << 15;
t |= (hdr->opcode << 11);
t |= (hdr->aa << 10);
t |= (hdr->tc << 9);
t |= (hdr->rd << 8);
t |= (hdr->ra << 7);
t |= hdr->rcode;
s = htons(t);
memcpy(buf + off, &s, sizeof(s));
off += sizeof(s);
s = htons(hdr->qdcount);
memcpy(buf + off, &s, sizeof(s));
off += sizeof(s);
s = htons(hdr->ancount);
memcpy(buf + off, &s, sizeof(s));
off += sizeof(s);
s = htons(hdr->nscount);
memcpy(buf + off, &s, sizeof(s));
off += sizeof(s);
s = htons(hdr->arcount);
memcpy(buf + off, &s, sizeof(s));
off += sizeof(s);
if (off != 12)
acl_msg_fatal("%s: off(%d) != 12", myname, off);
return off;
}
/*
* rfc1035LabelPack()
*
* Packs a label into a buffer. The format of
* a label is one octet specifying the number of character
* bytes to follow. Labels must be smaller than 64 octets.
* Returns number of octets packed.
*/
static int rfc1035LabelPack(char *buf, size_t sz, const char *label)
{
const char *myname = "rfc1035LabelPack";
int off = 0;
size_t len = label ? strlen(label) : 0;
if (label) {
if (strchr(label, '.') != NULL)
acl_msg_fatal("%s: '.' exist in label(%s)", myname, label);
}
if (len > RFC1035_MAXLABELSZ)
len = RFC1035_MAXLABELSZ;
if (sz < len + 1)
acl_msg_fatal("%s: sz(%d) < len(%d) + 1", myname, sz, len);
*(buf + off) = (char) len;
off++;
memcpy(buf + off, label, len);
off += (int) len;
return off;
}
/*
* rfc1035NamePack()
*
* Packs a name into a buffer. Names are packed as a
* sequence of labels, terminated with NULL label.
* Note message compression is not supported here.
* Returns number of octets packed.
*/
static int rfc1035NamePack(char *buf, size_t sz, const char *name)
{
const char *myname = "rfc1035NamePack";
int off = 0;
char *copy, *ptr;
char *t;
copy = acl_mystrdup(name);
/*
* NOTE: use of strtok here makes names like foo....com valid.
*/
ptr = copy;
for (t = acl_mystrtok(&ptr, "."); t; t = acl_mystrtok(&ptr, "."))
off += rfc1035LabelPack(buf + off, sz - off, t);
acl_myfree(copy);
off += rfc1035LabelPack(buf + off, sz - off, NULL);
if (off > (int) sz)
acl_msg_fatal("%s: off(%d) > sz(%d)", myname, off, sz);
return off;
}
/*
* rfc1035QuestionPack()
*
* Packs a QUESTION section of a message.
* Returns number of octets packed.
*/
static int rfc1035QuestionPack(char *buf, size_t sz, const char *name,
unsigned short type, unsigned short tclass)
{
const char *myname = "rfc1035QuestionPack";
int off = 0;
unsigned short s;
off += rfc1035NamePack(buf + off, sz - off, name);
s = htons(type);
memcpy(buf + off, &s, sizeof(s));
off += sizeof(s);
s = htons(tclass);
memcpy(buf + off, &s, sizeof(s));
off += sizeof(s);
if (off > (int) sz)
acl_msg_fatal("%s: off(%d) > sz(%d)", myname, off, sz);
return off;
}
/*
* rfc1035HeaderUnpack()
*
* Unpacks a RFC1035 message header buffer into the header fields
* of the rfc1035_message structure.
*
* Updates the buffer offset, which is the same as number of
* octects unpacked since the header starts at offset 0.
*
* Returns 0 (success) or 1 (error)
*/
static int rfc1035HeaderUnpack(const char *buf, size_t sz, int *off,
rfc1035_message * h)
{
const char *myname = "rfc1035HeaderUnpack";
unsigned short s;
unsigned short t;
if (*off != 0)
acl_msg_fatal("%s: *off(%d) != 0", myname, *off);
/*
* The header is 12 octets. This is a bogus message if the size
* is less than that.
*/
if (sz < 12)
return 1;
memcpy(&s, buf + (*off), sizeof(s));
(*off) += sizeof(s);
h->id = ntohs(s);
memcpy(&s, buf + (*off), sizeof(s));
(*off) += sizeof(s);
t = ntohs(s);
h->qr = (t >> 15) & 0x01;
h->opcode = (t >> 11) & 0x0F;
h->aa = (t >> 10) & 0x01;
h->tc = (t >> 9) & 0x01;
h->rd = (t >> 8) & 0x01;
h->ra = (t >> 7) & 0x01;
/*
* We might want to check that the reserved 'Z' bits (6-4) are
* all zero as per RFC 1035. If not the message should be
* rejected.
*/
h->rcode = t & 0x0F;
memcpy(&s, buf + (*off), sizeof(s));
(*off) += sizeof(s);
h->qdcount = ntohs(s);
memcpy(&s, buf + (*off), sizeof(s));
(*off) += sizeof(s);
h->ancount = ntohs(s);
memcpy(&s, buf + (*off), sizeof(s));
(*off) += sizeof(s);
h->nscount = ntohs(s);
memcpy(&s, buf + (*off), sizeof(s));
(*off) += sizeof(s);
h->arcount = ntohs(s);
if (*off != 12)
acl_msg_fatal("%s: *off(%d) != 12", myname, *off);
return 0;
}
/*
* rfc1035NameUnpack()
*
* Unpacks a Name in a message buffer into a char*.
* Note 'buf' points to the beginning of the whole message,
* 'off' points to the spot where the Name begins, and 'sz'
* is the size of the whole message. 'name' must be allocated
* by the caller.
*
* Supports the RFC1035 message compression through recursion.
*
* Updates the new buffer offset.
*
* Returns 0 (success) or 1 (error)
*/
static int rfc1035NameUnpack(const char *buf, size_t sz, int *off,
unsigned short *rdlength, char *name, size_t ns, int rdepth)
{
const char *myname = "rfc1035NameUnpack";
int no = 0;
unsigned char c;
size_t len;
if (ns <= 0)
acl_msg_fatal("%s: ns(%d) <= 0", myname, ns);
do {
if (*off >= (int) sz)
acl_msg_fatal("%s: *off(%d) >= sz(%d)", myname, *off, sz);
c = *(buf + (*off));
if (c > 191) {
/* blasted compression */
unsigned short s;
int ptr;
if (rdepth > 64) /* infinite pointer loop */
return 1;
memcpy(&s, buf + (*off), sizeof(s));
s = ntohs(s);
(*off) += sizeof(s);
/* Sanity check */
if ((*off) >= (int) sz)
return 1;
ptr = s & 0x3FFF;
/* Make sure the pointer is inside this message */
if (ptr >= (int) sz)
return 1;
return rfc1035NameUnpack(buf, sz, &ptr, rdlength, name + no,
ns - no, rdepth + 1);
} else if (c > RFC1035_MAXLABELSZ) {
/*
* "(The 10 and 01 combinations are reserved for future use.)"
*/
return 1;
} else {
(*off)++;
len = (size_t) c;
if (len == 0)
break;
if (len > (ns - no - 1)) /* label won't fit */
return 1;
if ((*off) + len >= sz) /* message is too short */
return 1;
memcpy(name + no, buf + (*off), len);
(*off) += (int) len;
no += (int) len;
*(name + (no++)) = '.';
if (rdlength)
*rdlength += (unsigned short) len + 1;
}
} while (c > 0 && no < (int) ns);
if (no)
*(name + no - 1) = '\0';
else
*name = '\0';
/* make sure we didn't allow someone to overflow the name buffer */
if (no > (int) ns)
acl_msg_fatal("%s: no(%d) > ns(%d)", myname, no, ns);
return 0;
}
/*
* rfc1035RRUnpack()
*
* Unpacks a RFC1035 Resource Record into 'RR' from a message buffer.
* The caller must free RR->rdata!
*
* Updates the new message buffer offset.
*
* Returns 0 (success) or 1 (error)
*/
static int rfc1035RRUnpack(const char *buf, size_t sz, int *off, rfc1035_rr * RR)
{
const char *myname = "rfc1035RRUnpack";
unsigned short s;
unsigned int i;
unsigned short rdlength;
int rdata_off;
if (rfc1035NameUnpack(buf, sz, off, NULL, RR->name, RFC1035_MAXHOSTNAMESZ, 0)) {
RFC1035_UNPACK_DEBUG;
memset(RR, '\0', sizeof(*RR));
return 1;
}
/*
* Make sure the remaining message has enough octets for the
* rest of the RR fields.
*/
if ((*off) + 10 > (int) sz) {
RFC1035_UNPACK_DEBUG;
memset(RR, '\0', sizeof(*RR));
return 1;
}
memcpy(&s, buf + (*off), sizeof(s));
(*off) += sizeof(s);
RR->type = ntohs(s);
memcpy(&s, buf + (*off), sizeof(s));
(*off) += sizeof(s);
RR->tclass = ntohs(s);
memcpy(&i, buf + (*off), sizeof(i));
(*off) += sizeof(i);
RR->ttl = ntohl(i);
memcpy(&s, buf + (*off), sizeof(s));
(*off) += sizeof(s);
rdlength = ntohs(s);
if ((*off) + rdlength > (int) sz) {
/*
* We got a truncated packet. 'dnscache' truncates UDP
* replies at 512 octets, as per RFC 1035.
*/
RFC1035_UNPACK_DEBUG;
memset(RR, '\0', sizeof(*RR));
return 1;
}
RR->rdlength = rdlength;
switch (RR->type) {
case RFC1035_TYPE_PTR:
RR->rdata = (char*) acl_mymalloc(RFC1035_MAXHOSTNAMESZ);
rdata_off = *off;
RR->rdlength = 0; /* Filled in by rfc1035NameUnpack */
if (rfc1035NameUnpack(buf, sz, &rdata_off, &RR->rdlength,
RR->rdata, RFC1035_MAXHOSTNAMESZ, 0))
return 1;
if (rdata_off > ((*off) + rdlength)) {
/*
* This probably doesn't happen for valid packets, but
* I want to make sure that NameUnpack doesn't go beyond
* the RDATA area.
*/
RFC1035_UNPACK_DEBUG;
acl_myfree(RR->rdata);
memset(RR, '\0', sizeof(*RR));
return 1;
}
break;
case RFC1035_TYPE_A:
default:
RR->rdata = (char*) acl_mymalloc(rdlength);
memcpy(RR->rdata, buf + (*off), rdlength);
break;
}
(*off) += rdlength;
if (*off > (int) sz)
acl_msg_fatal("%s: *off(%d) > sz(%d)", myname, *off, sz);
return 0;
}
const char *rfc1035Strerror(int errnum)
{
struct __ERRMSG{
int errnum;
const char *msg;
};
static const struct __ERRMSG errmsg[] = {
{ 0, "No error condition" },
{ 1, "Format Error: The name server was unable to "
"interpret the query." },
{ 2, "Server Failure: The name server was "
"unable to process this query." },
{ 3, "Name Error: The domain name does not exist." },
{ 4, "Not Implemented: The name server does "
"not support the requested kind of query." },
{ 5, "Refused: The name server refuses to "
"perform the specified operation." },
{ rfc1035_unpack_error, "The DNS reply message is corrupt or could "
"not be safely parsed." },
{ -1, NULL },
};
const char *unknown = "Unknown Error";
int i;
for (i = 0; errmsg[i].msg != NULL; i++) {
if (errmsg[i].errnum == -errnum)
return (errmsg[i].msg);
}
return (unknown);
}
static void rfc1035SetErrno(int n)
{
switch (rfc1035_errno = n) {
case 0:
rfc1035_error_message = "No error condition";
break;
case 1:
rfc1035_error_message = "Format Error: The name server was "
"unable to interpret the query.";
break;
case 2:
rfc1035_error_message = "Server Failure: The name server was "
"unable to process this query.";
break;
case 3:
rfc1035_error_message = "Name Error: The domain name does "
"not exist.";
break;
case 4:
rfc1035_error_message = "Not Implemented: The name server does "
"not support the requested kind of query.";
break;
case 5:
rfc1035_error_message = "Refused: The name server refuses to "
"perform the specified operation.";
break;
case rfc1035_unpack_error:
rfc1035_error_message = "The DNS reply message is corrupt or could "
"not be safely parsed.";
break;
default:
rfc1035_error_message = "Unknown Error";
break;
}
}
static void rfc1035RRDestroy(rfc1035_rr * rr, int n)
{
const char *myname = "rfc1035RRDestroy";
if (rr == NULL)
return;
if (n <= 0)
acl_msg_fatal("%s: n(%d) <= 0", myname, n);
while (n--) {
if (rr[n].rdata)
acl_myfree(rr[n].rdata);
}
acl_myfree(rr);
}
/*
* rfc1035QueryUnpack()
*
* Unpacks a RFC1035 Query Record into 'query' from a message buffer.
*
* Updates the new message buffer offset.
*
* Returns 0 (success) or 1 (error)
*/
static int rfc1035QueryUnpack(const char *buf, size_t sz, int *off,
rfc1035_query * query)
{
unsigned short s;
if (rfc1035NameUnpack(buf, sz, off, NULL, query->name, RFC1035_MAXHOSTNAMESZ, 0)) {
RFC1035_UNPACK_DEBUG;
memset(query, '\0', sizeof(*query));
return 1;
}
if (*off + 4 > (int) sz) {
RFC1035_UNPACK_DEBUG;
memset(query, '\0', sizeof(*query));
return 1;
}
memcpy(&s, buf + *off, 2);
*off += 2;
query->qtype = ntohs(s);
memcpy(&s, buf + *off, 2);
*off += 2;
query->qclass = ntohs(s);
return 0;
}
void rfc1035MessageDestroy(rfc1035_message * msg)
{
if (!msg)
return;
if (msg->query)
acl_myfree(msg->query);
if (msg->answer)
rfc1035RRDestroy(msg->answer, msg->ancount);
acl_myfree(msg);
}
/*
* rfc1035QueryCompare()
*
* Compares two rfc1035_query entries
*
* Returns 0 (equal) or !=0 (different)
*/
int rfc1035QueryCompare(const rfc1035_query * a, const rfc1035_query * b)
{
size_t la, lb;
if (a->qtype != b->qtype)
return 1;
if (a->qclass != b->qclass)
return 1;
la = strlen(a->name);
lb = strlen(b->name);
if (la != lb) {
/* Trim root label(s) */
while (la > 0 && a->name[la - 1] == '.')
la--;
while (lb > 0 && b->name[lb - 1] == '.')
lb--;
}
if (la != lb)
return 1;
return strncasecmp(a->name, b->name, la);
}
/*
* rfc1035MessageUnpack()
*
* Takes the contents of a DNS reply and fills in an array
* of resource record structures. The records array is allocated
* here, and should be freed by calling rfc1035RRDestroy().
*
* Returns number of records unpacked, zero if DNS reply indicates
* zero answers, or an error number < 0.
*/
int rfc1035MessageUnpack(const char *buf, size_t sz, rfc1035_message ** answer)
{
int off = 0;
int i;
int nr = 0;
rfc1035_message *msg;
rfc1035_rr *recs;
rfc1035_query *querys;
msg = (rfc1035_message*) acl_mycalloc(1, sizeof(*msg));
if (rfc1035HeaderUnpack(buf + off, sz - off, &off, msg)) {
RFC1035_UNPACK_DEBUG;
rfc1035SetErrno(rfc1035_unpack_error);
acl_myfree(msg);
return -rfc1035_unpack_error;
}
rfc1035_errno = 0;
rfc1035_error_message = NULL;
i = (int) msg->qdcount;
if (i != 1) {
/* This can not be an answer to our queries.. */
RFC1035_UNPACK_DEBUG;
rfc1035SetErrno(rfc1035_unpack_error);
acl_myfree(msg);
return -rfc1035_unpack_error;
}
querys = msg->query = (rfc1035_query*) acl_mycalloc((int) msg->qdcount, sizeof(*querys));
for (i = 0; i < (int) msg->qdcount; i++) {
if (rfc1035QueryUnpack(buf, sz, &off, &querys[i])) {
RFC1035_UNPACK_DEBUG;
rfc1035SetErrno(rfc1035_unpack_error);
rfc1035MessageDestroy(msg);
return -rfc1035_unpack_error;
}
}
*answer = msg;
if (msg->rcode) {
RFC1035_UNPACK_DEBUG;
rfc1035SetErrno((int) msg->rcode);
return -((int) msg->rcode);
}
if (msg->ancount == 0)
return 0;
recs = msg->answer = (rfc1035_rr*) acl_mycalloc((int) msg->ancount, sizeof(*recs));
for (i = 0; i < (int) msg->ancount; i++) {
if (off >= (int) sz) { /* corrupt packet */
RFC1035_UNPACK_DEBUG;
break;
}
if (rfc1035RRUnpack(buf, sz, &off, &recs[i])) { /* corrupt RR */
RFC1035_UNPACK_DEBUG;
break;
}
nr++;
}
if (nr == 0) {
/*
* we expected to unpack some answers (ancount != 0), but
* didn't actually get any.
*/
rfc1035MessageDestroy(msg);
*answer = NULL;
rfc1035SetErrno(rfc1035_unpack_error);
return -rfc1035_unpack_error;
}
if (msg->nscount > 0) {
//rfc1035NSUnpack(buf, sz, &off);
}
if (msg->arcount > 0) {
//rfc1035ARUnpack(buf, sz, &off);
}
return nr;
}
/*
* rfc1035RRPack()
*
* Unpacks a RFC1035 Resource Record into 'RR' from a message buffer.
* The caller must free RR->rdata!
*
* Updates the new message buffer offset.
*
* Returns > 0 (success) or 0 (error)
*/
static int rfc1035RRPack(const rfc1035_rr *RR, char *buf, size_t sz)
{
const char *myname = "rfc1035RRPack";
unsigned short s;
unsigned int i;
int off = 0, off_saved;
off = rfc1035NamePack(buf + off, sz, RR->name);
s = htons(RR->type);
memcpy(buf + off, &s,sizeof(s));
off += sizeof(s);
s = htons(RR->tclass);
memcpy(buf + off, &s ,sizeof(s));
off += sizeof(s);
i = htonl(RR->ttl);
memcpy(buf + off, &i ,sizeof(i));
off += sizeof(i);
switch (RR->type) {
case RFC1035_TYPE_PTR:
case RFC1035_TYPE_NS:
if (strlen(RR->rdata) > RFC1035_MAXHOSTNAMESZ)
return (0);
off_saved = off;
off += sizeof(s);
off += rfc1035NamePack(buf + off, sz, RR->rdata);
s = off - off_saved - (unsigned short) sizeof(s);
s = htons(s);
memcpy(buf + off_saved, &s ,sizeof(s));
break;
default:
s = htons(RR->rdlength);
memcpy(buf + off, &s ,sizeof(s));
off += sizeof(s);
memcpy(buf + off, RR->rdata, RR->rdlength);
off += RR->rdlength;
break;
}
if ((unsigned) off > sz)
acl_msg_fatal("%s: off(%d) > sz(%d)", myname, off, sz);
return (off);
}
ssize_t rfc1035BuildAReply(const char *hostname, const ACL_ARGV *ip_argv,
const char *dnsname, const char *dns_ip,
unsigned short qid, char *buf, size_t sz)
{
rfc1035_message h;
rfc1035_rr rr;
size_t offset = 0;
unsigned int nip;
int i;
memset(&h, '\0', sizeof(h));
h.id = qid;
h.qr = 1;
h.opcode = 0; /* QUERY */
h.aa = 0;
h.tc = 0;
h.rd = 1;
h.ra = 0;
h.rcode = 0;
h.qdcount = 1;
h.ancount = ip_argv->argc;
h.nscount = (dnsname && *dnsname) ? 1 : 0;
h.arcount = (h.nscount && dns_ip && *dns_ip) ? 1 : 0;
offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
offset += rfc1035QuestionPack(buf + offset, sz - offset, hostname,
RFC1035_TYPE_A, RFC1035_CLASS_IN);
for (i = 0; i < ip_argv->argc; i++) {
memset(&rr, 0, sizeof(rr));
snprintf(rr.name, sizeof(rr.name), "%s", hostname);
rr.type = RFC1035_TYPE_A;
rr.tclass = RFC1035_CLASS_IN;
rr.ttl = 5;
rr.rdlength = 4;
nip = inet_addr(ip_argv->argv[i]);
rr.rdata = (char*) acl_mycalloc(1, rr.rdlength);
memcpy(rr.rdata, &nip, rr.rdlength);
offset += rfc1035RRPack(&rr, buf + offset, sz - offset);
acl_myfree(rr.rdata);
}
if (h.nscount) {
memset(&rr, 0, sizeof(rr));
snprintf(rr.name, sizeof(rr.name), "%s", dnsname);
rr.type = RFC1035_TYPE_NS;
rr.tclass = RFC1035_CLASS_IN;
rr.ttl = 5;
rr.rdlength = (unsigned short) strlen(dnsname);
rr.rdata = acl_mystrdup(dnsname);
offset += rfc1035RRPack(&rr, buf + offset, sz - offset);
acl_myfree(rr.rdata);
}
if (h.arcount) {
memset(&rr, 0, sizeof(rr));
snprintf(rr.name, sizeof(rr.name), "%s", dnsname);
rr.type = RFC1035_TYPE_NS;
rr.tclass = RFC1035_CLASS_IN;
rr.ttl = 5;
rr.rdlength = (unsigned short) strlen(dns_ip);
rr.rdata = acl_mystrdup(dns_ip);
offset += rfc1035RRPack(&rr, buf + offset, sz - offset);
acl_myfree(rr.rdata);
}
return ((int) offset);
}
/*
* rfc1035BuildAQuery()
*
* Builds a message buffer with a QUESTION to lookup A records
* for a hostname. Caller must allocate 'buf' which should
* probably be at least 512 octets. The 'szp' initially
* specifies the size of the buffer, on return it contains
* the size of the message (i.e. how much to write).
* Returns the size of the query
*/
ssize_t rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz,
unsigned short qid, rfc1035_query * query)
{
const char *myname = "rfc1035BuildAQuery";
rfc1035_message h;
size_t offset = 0;
memset(&h, '\0', sizeof(h));
h.id = qid;
h.qr = 0;
h.rd = 1;
h.opcode = 0; /* QUERY */
h.qdcount = (unsigned int) 1;
offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
offset += rfc1035QuestionPack(buf + offset, sz - offset, hostname,
RFC1035_TYPE_A, RFC1035_CLASS_IN);
if (query) {
query->qtype = RFC1035_TYPE_A;
query->qclass = RFC1035_CLASS_IN;
ACL_SAFE_STRNCPY(query->name, hostname, sizeof(query->name));
}
if (offset > sz)
acl_msg_fatal("%s: offset(%d) > sz(%d)", myname, offset, sz);
return (ssize_t) offset;
}
/*
* rfc1035BuildPTRQuery()
*
* Builds a message buffer with a QUESTION to lookup PTR records
* for an address. Caller must allocate 'buf' which should
* probably be at least 512 octets. The 'szp' initially
* specifies the size of the buffer, on return it contains
* the size of the message (i.e. how much to write).
* Returns the size of the query
*/
ssize_t rfc1035BuildPTRQuery(const struct in_addr addr, char *buf,
size_t sz, unsigned short qid, rfc1035_query * query)
{
const char *myname = "rfc1035BuildPTRQuery";
rfc1035_message h;
size_t offset = 0;
static char rev[32];
unsigned int i;
memset(&h, '\0', sizeof(h));
i = (unsigned int) ntohl(addr.s_addr);
snprintf(rev, 32, "%u.%u.%u.%u.in-addr.arpa.",
i & 255, (i >> 8) & 255, (i >> 16) & 255, (i >> 24) & 255);
h.id = qid;
h.qr = 0;
h.rd = 1;
h.opcode = 0; /* QUERY */
h.qdcount = (unsigned int) 1;
offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
offset += rfc1035QuestionPack(buf + offset, sz - offset, rev,
RFC1035_TYPE_PTR, RFC1035_CLASS_IN);
if (query) {
query->qtype = RFC1035_TYPE_PTR;
query->qclass = RFC1035_CLASS_IN;
ACL_SAFE_STRNCPY(query->name, rev, sizeof(query->name));
}
if (offset > sz)
acl_msg_fatal("%s: offset(%d) > sz(%d)", myname, offset, sz);
return (ssize_t) offset;
}
/*
* We're going to retry a former query, but we
* just need a new ID for it. Lucky for us ID
* is the first field in the message buffer.
*/
void rfc1035SetQueryID(char *buf, unsigned short qid)
{
unsigned short s = htons(qid);
memcpy(buf, &s, sizeof(s));
}