#include <port_before.h>
#include <arpa/nameser.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <port_after.h>
static int rdcpy(ns_newmsg *, ns_type, const u_char *, size_t);
int
ns_newmsg_init(u_char *buffer, size_t bufsiz, ns_newmsg *handle) {
ns_msg *msg = &handle->msg;
memset(handle, 0, sizeof *handle);
msg->_msg = buffer;
msg->_eom = buffer + bufsiz;
msg->_sect = ns_s_qd;
msg->_rrnum = 0;
msg->_msg_ptr = buffer + NS_HFIXEDSZ;
handle->dnptrs[0] = msg->_msg;
handle->dnptrs[1] = NULL;
handle->lastdnptr = &handle->dnptrs[sizeof handle->dnptrs /
sizeof handle->dnptrs[0] - 1];
return (0);
}
int
ns_newmsg_copy(ns_newmsg *handle, ns_msg *msg) {
ns_flag flag;
ns_sect sect;
ns_newmsg_id(handle, ns_msg_id(*msg));
for (flag = ns_f_qr; flag < ns_f_max; flag++)
ns_newmsg_flag(handle, flag, ns_msg_getflag(*msg, flag));
for (sect = ns_s_qd; sect < ns_s_max; sect++) {
int i, count;
count = ns_msg_count(*msg, sect);
for (i = 0; i < count; i++) {
ns_rr2 rr;
int x;
if (ns_parserr2(msg, sect, i, &rr) < 0)
return (-1);
if (sect == ns_s_qd)
x = ns_newmsg_q(handle,
ns_rr_nname(rr),
ns_rr_type(rr),
ns_rr_class(rr));
else
x = ns_newmsg_rr(handle, sect,
ns_rr_nname(rr),
ns_rr_type(rr),
ns_rr_class(rr),
ns_rr_ttl(rr),
ns_rr_rdlen(rr),
ns_rr_rdata(rr));
if (x < 0)
return (-1);
}
}
return (0);
}
void
ns_newmsg_id(ns_newmsg *handle, u_int16_t id) {
ns_msg *msg = &handle->msg;
msg->_id = id;
}
void
ns_newmsg_flag(ns_newmsg *handle, ns_flag flag, u_int value) {
extern struct _ns_flagdata _ns_flagdata[16];
struct _ns_flagdata *fd = &_ns_flagdata[flag];
ns_msg *msg = &handle->msg;
assert(flag < ns_f_max);
msg->_flags &= (~fd->mask);
msg->_flags |= (value << fd->shift);
}
int
ns_newmsg_q(ns_newmsg *handle, ns_nname_ct qname,
ns_type qtype, ns_class qclass)
{
ns_msg *msg = &handle->msg;
u_char *t;
int n;
if (msg->_sect != ns_s_qd) {
errno = ENODEV;
return (-1);
}
t = (u_char *) (unsigned long) msg->_msg_ptr;
if (msg->_rrnum == 0)
msg->_sections[ns_s_qd] = t;
n = ns_name_pack(qname, t, msg->_eom - t,
handle->dnptrs, handle->lastdnptr);
if (n < 0)
return (-1);
t += n;
if (t + QFIXEDSZ >= msg->_eom) {
errno = EMSGSIZE;
return (-1);
}
NS_PUT16(qtype, t);
NS_PUT16(qclass, t);
msg->_msg_ptr = t;
msg->_counts[ns_s_qd] = ++msg->_rrnum;
return (0);
}
int
ns_newmsg_rr(ns_newmsg *handle, ns_sect sect,
ns_nname_ct name, ns_type type,
ns_class rr_class, u_int32_t ttl,
u_int16_t rdlen, const u_char *rdata)
{
ns_msg *msg = &handle->msg;
u_char *t;
int n;
if (sect < msg->_sect) {
errno = ENODEV;
return (-1);
}
t = (u_char *) (unsigned long) msg->_msg_ptr;
if (sect > msg->_sect) {
msg->_sect = sect;
msg->_sections[sect] = t;
msg->_rrnum = 0;
}
n = ns_name_pack(name, t, msg->_eom - t,
handle->dnptrs, handle->lastdnptr);
if (n < 0)
return (-1);
t += n;
if (t + RRFIXEDSZ + rdlen >= msg->_eom) {
errno = EMSGSIZE;
return (-1);
}
NS_PUT16(type, t);
NS_PUT16(rr_class, t);
NS_PUT32(ttl, t);
msg->_msg_ptr = t;
if (rdcpy(handle, type, rdata, rdlen) < 0)
return (-1);
msg->_counts[sect] = ++msg->_rrnum;
return (0);
}
size_t
ns_newmsg_done(ns_newmsg *handle) {
ns_msg *msg = &handle->msg;
ns_sect sect;
u_char *t;
t = (u_char *) (unsigned long) msg->_msg;
NS_PUT16(msg->_id, t);
NS_PUT16(msg->_flags, t);
for (sect = 0; sect < ns_s_max; sect++)
NS_PUT16(msg->_counts[sect], t);
msg->_eom = msg->_msg_ptr;
msg->_sect = ns_s_max;
msg->_rrnum = -1;
msg->_msg_ptr = NULL;
return (msg->_eom - msg->_msg);
}
static int
rdcpy(ns_newmsg *handle, ns_type type, const u_char *rdata, size_t rdlen) {
ns_msg *msg = &handle->msg;
u_char *p = (u_char *) (unsigned long) msg->_msg_ptr;
u_char *t = p + NS_INT16SZ;
u_char *s = t;
int n;
switch (type) {
case ns_t_soa:
n = ns_name_pack(rdata, t, msg->_eom - t,
handle->dnptrs, handle->lastdnptr);
if (n < 0)
return (-1);
t += n;
if (ns_name_skip(&rdata, msg->_eom) < 0)
return (-1);
n = ns_name_pack(rdata, t, msg->_eom - t,
handle->dnptrs, handle->lastdnptr);
if (n < 0)
return (-1);
t += n;
if (ns_name_skip(&rdata, msg->_eom) < 0)
return (-1);
if ((msg->_eom - t) < (NS_INT32SZ * 5)) {
errno = EMSGSIZE;
return (-1);
}
memcpy(t, rdata, NS_INT32SZ * 5);
t += (NS_INT32SZ * 5);
break;
case ns_t_ptr:
case ns_t_cname:
case ns_t_ns:
n = ns_name_pack(rdata, t, msg->_eom - t,
handle->dnptrs, handle->lastdnptr);
if (n < 0)
return (-1);
t += n;
break;
default:
memcpy(t, rdata, rdlen);
t += rdlen;
}
NS_PUT16(t - s, p);
msg->_msg_ptr = t;
return (0);
}