Skip to content

Commit

Permalink
local implementation of ns_parser functions
Browse files Browse the repository at this point in the history
For optware/entware which uclibc version < 0.9.33
  • Loading branch information
ownhere committed Apr 11, 2015
1 parent a423ccb commit 7dd6643
Showing 1 changed file with 256 additions and 8 deletions.
264 changes: 256 additions & 8 deletions src/chinadns.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#define _GNU_SOURCE
#define __USE_GNU

#include <fcntl.h>
#include <netdb.h>
#include <resolv.h>
Expand All @@ -29,6 +32,8 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
//add by ownhere
#include <errno.h>

#include "config.h"

Expand Down Expand Up @@ -132,6 +137,17 @@ static int remote_sock;

static void usage(void);

//add by ownhere
static int my_ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle);
static int my_ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr);
static void my_setsection(ns_msg *msg, ns_sect sect);
static int my_ns_skiprr(const unsigned char *ptr, const unsigned char *eom, ns_sect section, int count);
static int my_dn_skipname(const unsigned char *ptr, const unsigned char *eom);
static int my_ns_name_skip(const unsigned char **ptrptr, const unsigned char *eom);
static int my_labellen(const unsigned char *lp);
#define MY_NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
#define MY_DNS_LABELTYPE_BITSTRING 0x41

#define __LOG(o, t, v, s...) do { \
time_t now; \
time(&now); \
Expand Down Expand Up @@ -564,8 +580,8 @@ static void dns_handle_local() {
ns_msg msg;
len = recvfrom(local_sock, global_buf, BUF_SIZE, 0, src_addr, &src_addrlen);
if (len > 0) {
if (ns_initparse((const u_char *)global_buf, len, &msg) < 0) {
ERR("ns_initparse");
if (my_ns_initparse((const u_char *)global_buf, len, &msg) < 0) {
ERR("my_ns_initparse");
free(src_addr);
return;
}
Expand Down Expand Up @@ -652,8 +668,8 @@ static void dns_handle_remote() {
ns_msg msg;
len = recvfrom(remote_sock, global_buf, BUF_SIZE, 0, src_addr, &src_len);
if (len > 0) {
if (ns_initparse((const u_char *)global_buf, len, &msg) < 0) {
ERR("ns_initparse");
if (my_ns_initparse((const u_char *)global_buf, len, &msg) < 0) {
ERR("my_ns_initparse");
free(src_addr);
return;
}
Expand Down Expand Up @@ -724,8 +740,8 @@ static const char *hostname_from_question(ns_msg msg) {
if (rrmax == 0)
return NULL;
for (rrnum = 0; rrnum < rrmax; rrnum++) {
if (ns_parserr(&msg, ns_s_qd, rrnum, &rr)) {
ERR("ns_parserr");
if (my_ns_parserr(&msg, ns_s_qd, rrnum, &rr)) {
ERR("my_ns_parserr");
return NULL;
}
result = ns_rr_name(rr);
Expand Down Expand Up @@ -764,8 +780,8 @@ static int should_filter_query(ns_msg msg, struct in_addr dns_addr) {
return -1;
}
for (rrnum = 0; rrnum < rrmax; rrnum++) {
if (ns_parserr(&msg, ns_s_an, rrnum, &rr)) {
ERR("ns_parserr");
if (my_ns_parserr(&msg, ns_s_an, rrnum, &rr)) {
ERR("my_ns_parserr");
return 0;
}
u_int type;
Expand Down Expand Up @@ -907,3 +923,235 @@ Online help: <https://github.com/clowwindy/ChinaDNS>\n");
}


//add by ownhere
static int my_ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle)
{
const u_char *eom = msg + msglen;
int i;

handle->_msg = msg;
handle->_eom = eom;
if (msg + NS_INT16SZ > eom) {
errno = EMSGSIZE;
return -1;
}

NS_GET16(handle->_id, msg);
if (msg + NS_INT16SZ > eom) {
errno = EMSGSIZE;
return -1;
}

NS_GET16(handle->_flags, msg);
for (i = 0; i < ns_s_max; i++) {
if (msg + NS_INT16SZ > eom) {
errno = EMSGSIZE;
return -1;
}

NS_GET16(handle->_counts[i], msg);
}
for (i = 0; i < ns_s_max; i++)
if (handle->_counts[i] == 0)
handle->_sections[i] = NULL;
else {
int b = my_ns_skiprr(msg, eom, (ns_sect)i,
handle->_counts[i]);

if (b < 0)
return -1;
handle->_sections[i] = msg;
msg += b;
}

if (msg != eom) {
errno = EMSGSIZE;
return -1;
}

my_setsection(handle, ns_s_max);
return 0;
}
static int my_ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr)
{
int b;
int tmp;

/* Make section right. */
tmp = section;
if (tmp < 0 || section >= ns_s_max) {
errno = ENODEV;
return -1;
}

if (section != handle->_sect)
my_setsection(handle, section);

/* Make rrnum right. */
if (rrnum == -1)
rrnum = handle->_rrnum;
if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) {
errno = ENODEV;
return -1;
}
if (rrnum < handle->_rrnum)
my_setsection(handle, section);
if (rrnum > handle->_rrnum) {
b = my_ns_skiprr(handle->_ptr, handle->_eom, section,
rrnum - handle->_rrnum);

if (b < 0)
return (-1);
handle->_ptr += b;
handle->_rrnum = rrnum;
}

/* Do the parse. */
b = dn_expand(handle->_msg, handle->_eom,
handle->_ptr, rr->name, NS_MAXDNAME);
if (b < 0)
return (-1);
handle->_ptr += b;
if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) {
errno = EMSGSIZE;
return -1;
}
NS_GET16(rr->type, handle->_ptr);
NS_GET16(rr->rr_class, handle->_ptr);
if (section == ns_s_qd) {
rr->ttl = 0;
rr->rdlength = 0;
rr->rdata = NULL;
} else {
if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) {
errno = EMSGSIZE;
return -1;
}
NS_GET32(rr->ttl, handle->_ptr);
NS_GET16(rr->rdlength, handle->_ptr);
if (handle->_ptr + rr->rdlength > handle->_eom) {
errno = EMSGSIZE;
return -1;
}
rr->rdata = handle->_ptr;
handle->_ptr += rr->rdlength;
}
if (++handle->_rrnum > handle->_counts[(int)section])
my_setsection(handle, (ns_sect)((int)section + 1));

return 0;
}
static void my_setsection(ns_msg *msg, ns_sect sect)
{
msg->_sect = sect;
if (sect == ns_s_max) {
msg->_rrnum = -1;
msg->_ptr = NULL;
} else {
msg->_rrnum = 0;
msg->_ptr = msg->_sections[(int)sect];
}
}
static int my_ns_skiprr(const unsigned char *ptr, const unsigned char *eom, ns_sect section, int count)
{
const u_char *optr = ptr;

for (; count > 0; count--) {
int b, rdlength;

b = my_dn_skipname(ptr, eom);
if (b < 0) {
errno = EMSGSIZE;
return -1;
}
ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
if (section != ns_s_qd) {
if (ptr + NS_INT32SZ + NS_INT16SZ > eom) {
errno = EMSGSIZE;
return -1;
}

ptr += NS_INT32SZ/*TTL*/;
NS_GET16(rdlength, ptr);
ptr += rdlength/*RData*/;
}
}

if (ptr > eom) {
errno = EMSGSIZE;
return -1;
}

return ptr - optr;
}
static int my_dn_skipname(const unsigned char *ptr, const unsigned char *eom)
{
const unsigned char *saveptr = ptr;

if (my_ns_name_skip(&ptr, eom) == -1)
return -1;

return ptr - saveptr;
}
static int my_ns_name_skip(const unsigned char **ptrptr, const unsigned char *eom)
{
const unsigned char *cp;
u_int n;
int l;

cp = *ptrptr;
while (cp < eom && (n = *cp++) != 0) {
/* Check for indirection. */
switch (n & NS_CMPRSFLGS) {
case 0: /*%< normal case, n == len */
cp += n;
continue;
case MY_NS_TYPE_ELT: /*%< EDNS0 extended label */
if ((l = my_labellen(cp - 1)) < 0) {
errno = EMSGSIZE; /*%< XXX */
return -1;
}
cp += l;
continue;
case NS_CMPRSFLGS: /*%< indirection */
cp++;
break;
default: /*%< illegal type */
errno = EMSGSIZE;
return -1;
}

break;
}

if (cp > eom) {
errno = EMSGSIZE;
return -1;
}

*ptrptr = cp;

return 0;
}
static int my_labellen(const unsigned char *lp)
{
int bitlen;
unsigned char l = *lp;

if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
/* should be avoided by the caller */
return -1;
}

if ((l & NS_CMPRSFLGS) == MY_NS_TYPE_ELT) {
if (l == MY_DNS_LABELTYPE_BITSTRING) {
if ((bitlen = *(lp + 1)) == 0)
bitlen = 256;
return ((bitlen + 7 ) / 8 + 1);
}

return -1; /*%< unknwon ELT */
}

return l;
}

0 comments on commit 7dd6643

Please sign in to comment.