summaryrefslogtreecommitdiff
path: root/dnsstub/dns_packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'dnsstub/dns_packet.c')
-rw-r--r--dnsstub/dns_packet.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/dnsstub/dns_packet.c b/dnsstub/dns_packet.c
new file mode 100644
index 0000000..ce322ea
--- /dev/null
+++ b/dnsstub/dns_packet.c
@@ -0,0 +1,85 @@
+#include "error.h"
+#include "dnsresolv.h"
+
+/**
+ @file dns_packet.c
+ @author djb
+ @source ucspi-tcp
+ @brief DNS low level packet routine
+ @brief DNS should have used LZ77 instead of its own sophomoric compression algorithm.
+*/
+
+unsigned int dns_packet_copy(const char *buf,unsigned int len,unsigned int pos,char *out,unsigned int outlen)
+{
+ while (outlen) {
+ if (pos >= len) { errno = EPROTO; return 0; }
+ *out = buf[pos++];
+ ++out; --outlen;
+ }
+ return pos;
+}
+
+unsigned int dns_packet_skipname(const char *buf,unsigned int len,unsigned int pos)
+{
+ unsigned char ch;
+
+ for (;;) {
+ if (pos >= len) break;
+ ch = buf[pos++];
+ if (ch >= 192) return pos + 1;
+ if (ch >= 64) break;
+ if (!ch) return pos;
+ pos += ch;
+ }
+
+ errno = EPROTO;
+ return 0;
+}
+
+unsigned int dns_packet_getname(const char *buf,unsigned int len,unsigned int pos,char **d)
+{
+ unsigned int loop = 0;
+ unsigned int state = 0;
+ unsigned int firstcompress = 0;
+ unsigned int where;
+ unsigned char ch;
+ char name[255];
+ unsigned int namelen = 0;
+
+ for (;;) {
+ if (pos >= len) goto PROTO;
+ ch = buf[pos++];
+ if (++loop >= 1000) goto PROTO;
+
+ if (state) {
+ if (namelen + 1 > sizeof(name)) goto PROTO;
+ name[namelen++] = ch;
+ --state;
+ } else {
+ while (ch >= 192) {
+ where = ch; where -= 192; where <<= 8;
+ if (pos >= len) goto PROTO;
+ ch = buf[pos++];
+ if (!firstcompress) firstcompress = pos;
+ pos = where + ch;
+ if (pos >= len) goto PROTO;
+ ch = buf[pos++];
+ if (++loop >= 1000) goto PROTO;
+ }
+ if (ch >= 64) goto PROTO;
+ if (namelen + 1 > sizeof(name)) goto PROTO;
+ name[namelen++] = ch;
+ if (!ch) break;
+ state = ch;
+ }
+ }
+
+ if (!dns_domain_copy(d,name)) return 0;
+
+ if (firstcompress) return firstcompress;
+ return pos;
+
+ PROTO:
+ errno = EPROTO;
+ return 0;
+}