about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--include/arpa/nameser.h58
-rw-r--r--src/network/ns_parse.c171
2 files changed, 194 insertions, 35 deletions
diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h
index b9ee6659..581925a4 100644
--- a/include/arpa/nameser.h
+++ b/include/arpa/nameser.h
@@ -1,6 +1,11 @@
 #ifndef _ARPA_NAMESER_H
 #define _ARPA_NAMESER_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
 #include <stdint.h>
 
 #define __NAMESER	19991006
@@ -48,6 +53,8 @@ extern const struct _ns_flagdata _ns_flagdata[];
 #define ns_msg_end(handle) ((handle)._eom + 0)
 #define ns_msg_size(handle) ((handle)._eom - (handle)._msg)
 #define ns_msg_count(handle, section) ((handle)._counts[section] + 0)
+#define ns_msg_getflag(handle, flag) \
+	(((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift)
 
 typedef	struct __ns_rr {
 	char		name[NS_MAXDNAME];
@@ -296,43 +303,20 @@ typedef enum __ns_cert_types {
 #define NS_OPT_DNSSEC_OK        0x8000U
 #define NS_OPT_NSID		3
 
-#define NS_GET16(s, cp) do { \
-	register const unsigned char *t_cp = (const unsigned char *)(cp); \
-	(s) = ((uint16_t)t_cp[0] << 8) \
-	    | ((uint16_t)t_cp[1]) \
-	    ; \
-	(cp) += NS_INT16SZ; \
-} while (0)
-
-#define NS_GET32(l, cp) do { \
-	register const unsigned char *t_cp = (const unsigned char *)(cp); \
-	(l) = ((uint32_t)t_cp[0] << 24) \
-	    | ((uint32_t)t_cp[1] << 16) \
-	    | ((uint32_t)t_cp[2] << 8) \
-	    | ((uint32_t)t_cp[3]) \
-	    ; \
-	(cp) += NS_INT32SZ; \
-} while (0)
-
-#define NS_PUT16(s, cp) do { \
-	register uint16_t t_s = (uint16_t)(s); \
-	register unsigned char *t_cp = (unsigned char *)(cp); \
-	*t_cp++ = t_s >> 8; \
-	*t_cp   = t_s; \
-	(cp) += NS_INT16SZ; \
-} while (0)
-
-#define NS_PUT32(l, cp) do { \
-	register uint32_t t_l = (uint32_t)(l); \
-	register unsigned char *t_cp = (unsigned char *)(cp); \
-	*t_cp++ = t_l >> 24; \
-	*t_cp++ = t_l >> 16; \
-	*t_cp++ = t_l >> 8; \
-	*t_cp   = t_l; \
-	(cp) += NS_INT32SZ; \
-} while (0)
+#define NS_GET16(s, cp) (void)((s) = ns_get16(((cp)+=2)-2))
+#define NS_GET32(l, cp) (void)((l) = ns_get32(((cp)+=4)-4))
+#define NS_PUT16(s, cp) ns_put16((s), ((cp)+=2)-2)
+#define NS_PUT32(l, cp) ns_put32((l), ((cp)+=4)-4)
 
+unsigned ns_get16(const unsigned char *);
+unsigned long ns_get32(const unsigned char *);
+void ns_put16(unsigned, unsigned char *);
+void ns_put32(unsigned long, unsigned char *);
 
+int ns_initparse(const unsigned char *, int, ns_msg *);
+int ns_parserr(ns_msg *, ns_sect, int, ns_rr *);
+int ns_skiprr(const unsigned char *, const unsigned char *, ns_sect, int);
+int ns_name_uncompress(const unsigned char *, const unsigned char *, const unsigned char *, char *, size_t);
 
 
 #define	__BIND		19950621
@@ -464,4 +448,8 @@ typedef struct {
 #define	PUTSHORT		NS_PUT16
 #define	PUTLONG			NS_PUT32
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/src/network/ns_parse.c b/src/network/ns_parse.c
new file mode 100644
index 00000000..3ff33a87
--- /dev/null
+++ b/src/network/ns_parse.c
@@ -0,0 +1,171 @@
+#define _BSD_SOURCE
+#include <errno.h>
+#include <stddef.h>
+#include <resolv.h>
+#include <arpa/nameser.h>
+
+const struct _ns_flagdata _ns_flagdata[16] = {
+	{ 0x8000, 15 },
+	{ 0x7800, 11 },
+	{ 0x0400, 10 },
+	{ 0x0200, 9 },
+	{ 0x0100, 8 },
+	{ 0x0080, 7 },
+	{ 0x0040, 6 },
+	{ 0x0020, 5 },
+	{ 0x0010, 4 },
+	{ 0x000f, 0 },
+	{ 0x0000, 0 },
+	{ 0x0000, 0 },
+	{ 0x0000, 0 },
+	{ 0x0000, 0 },
+	{ 0x0000, 0 },
+	{ 0x0000, 0 },
+};
+
+unsigned ns_get16(const unsigned char *cp)
+{
+	return cp[0]<<8 | cp[1];
+}
+
+unsigned long ns_get32(const unsigned char *cp)
+{
+	return (unsigned)cp[0]<<24 | cp[1]<<16 | cp[2]<<8 | cp[3];
+}
+
+void ns_put16(unsigned s, unsigned char *cp)
+{
+	*cp++ = s>>8;
+	*cp++ = s;
+}
+
+void ns_put32(unsigned long l, unsigned char *cp)
+{
+	*cp++ = l>>24;
+	*cp++ = l>>16;
+	*cp++ = l>>8;
+	*cp++ = l;
+}
+
+int ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle)
+{
+	int i, r;
+
+	handle->_msg = msg;
+	handle->_eom = msg + msglen;
+	if (msglen < (2 + ns_s_max) * NS_INT16SZ) goto bad;
+	NS_GET16(handle->_id, msg);
+	NS_GET16(handle->_flags, msg);
+	for (i = 0; i < ns_s_max; i++) NS_GET16(handle->_counts[i], msg);
+	for (i = 0; i < ns_s_max; i++) {
+		if (handle->_counts[i]) {
+			handle->_sections[i] = msg;
+			r = ns_skiprr(msg, handle->_eom, i, handle->_counts[i]);
+			if (r < 0) return -1;
+			msg += r;
+		} else {
+			handle->_sections[i] = NULL;
+		}
+	}
+	if (msg != handle->_eom) goto bad;
+	handle->_sect = ns_s_max;
+	handle->_rrnum = -1;
+	handle->_msg_ptr = NULL;
+	return 0;
+bad:
+	errno = EMSGSIZE;
+	return -1;
+}
+
+int ns_skiprr(const unsigned char *ptr, const unsigned char *eom, ns_sect section, int count)
+{
+	const unsigned char *p = ptr;
+	int r;
+
+	while (count--) {
+		r = dn_skipname(p, eom);
+		if (r < 0) goto bad;
+		if (r + 2 * NS_INT16SZ > eom - p) goto bad;
+		p += r + 2 * NS_INT16SZ;
+		if (section != ns_s_qd) {
+			if (NS_INT32SZ + NS_INT16SZ > eom - p) goto bad;
+			p += NS_INT32SZ;
+			NS_GET16(r, p);
+			if (r > eom - p) goto bad;
+			p += r;
+		}
+	}
+	return ptr - p;
+bad:
+	errno = EMSGSIZE;
+	return -1;
+}
+
+int ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr)
+{
+	int r;
+
+	if (section < 0 || section >= ns_s_max) goto bad;
+	if (section != handle->_sect) {
+		handle->_sect = section;
+		handle->_rrnum = 0;
+		handle->_msg_ptr = handle->_sections[section];
+	}
+	if (rrnum == -1) rrnum = handle->_rrnum;
+	if (rrnum < 0 || rrnum >= handle->_counts[section]) goto bad;
+	if (rrnum < handle->_rrnum) {
+		handle->_rrnum = 0;
+		handle->_msg_ptr = handle->_sections[section];
+	}
+	if (rrnum > handle->_rrnum) {
+		r = ns_skiprr(handle->_msg_ptr, handle->_eom, section, rrnum - handle->_rrnum);
+		if (r < 0) return -1;
+		handle->_msg_ptr += r;
+		handle->_rrnum = rrnum;
+	}
+	r = ns_name_uncompress(handle->_msg, handle->_eom, handle->_msg_ptr, rr->name, NS_MAXDNAME);
+	if (r < 0) return -1;
+	handle->_msg_ptr += r;
+	if (2 * NS_INT16SZ > handle->_eom - handle->_msg_ptr) goto size;
+	NS_GET16(rr->type, handle->_msg_ptr);
+	NS_GET16(rr->rr_class, handle->_msg_ptr);
+	if (section != ns_s_qd) {
+		if (NS_INT32SZ + NS_INT16SZ > handle->_eom - handle->_msg_ptr) goto size;
+		NS_GET32(rr->ttl, handle->_msg_ptr);
+		NS_GET16(rr->rdlength, handle->_msg_ptr);
+		if (rr->rdlength > handle->_eom - handle->_msg_ptr) goto size;
+		rr->rdata = handle->_msg_ptr;
+		handle->_msg_ptr += rr->rdlength;
+	} else {
+		rr->ttl = 0;
+		rr->rdlength = 0;
+		rr->rdata = NULL;
+	}
+	handle->_rrnum++;
+	if (handle->_rrnum > handle->_counts[section]) {
+		handle->_sect = section + 1;
+		if (handle->_sect == ns_s_max) {
+			handle->_rrnum = -1;
+			handle->_msg_ptr = NULL;
+		} else {
+			handle->_rrnum = 0;
+		}
+	}
+	return 0;
+bad:
+	errno = ENODEV;
+	return -1;
+size:
+	errno = EMSGSIZE;
+	return -1;
+}
+
+int ns_name_uncompress(const unsigned char *msg, const unsigned char *eom,
+                       const unsigned char *src, char *dst, size_t dstsiz)
+{
+	int r;
+	r = dn_expand(msg, eom, src, dst, dstsiz);
+	if (r < 0) errno = EMSGSIZE;
+	return r;
+}
+