diff --git a/dns.c b/dns.c index 4e45d50..e87f3f2 100644 --- a/dns.c +++ b/dns.c @@ -26,32 +26,51 @@ typedef enum { } dns_type; int port = 53; -char *host = "seedbeta.bitcoin.sipa.be"; +int datattl = 60; +char *host = "seedtest.bitcoin.sipa.be"; +char *ns = "vps.sipa.be"; // 0: ok -// -1: premature end of input -// -2: unsufficient space in output -int parse_name(const unsigned char **inpos, const unsigned char *inend, char *buf, size_t bufsize) { +// -1: premature end of input, forward reference, component > 63 char +// -2: insufficient space in output +int parse_name(const unsigned char **inpos, const unsigned char *inend, const unsigned char *inbuf, char *buf, size_t bufsize) { size_t bufused = 0; + int init = 1; do { if (*inpos == inend) return -1; - int octet = *(inpos++); + // read length of next component + int octet = *((*inpos)++); if (octet == 0) { buf[bufused] = 0; return 0; } + // add dot in output + if (!init) { + if (bufused == bufsize-1) + return -2; + buf[bufused++] = '.'; + } else + init = 0; + // handle references + if ((octet & 0xC0) == 0xC0) { + if (*inpos == inend) + return -1; + int ref = ((octet - 0xC0) << 8) + *((*inpos)++); + if (ref < 0 || ref >= (*inpos)-inbuf) return -1; + const unsigned char *newbuf = inbuf + ref; + return parse_name(&newbuf, *inpos, inbuf, buf+bufused, bufsize-bufused); + } + if (octet > 63) return -1; + // copy data while (octet) { if (*inpos == inend) return -1; if (bufused == bufsize-1) return -2; octet--; - buf[bufused++] = *(inpos++); + buf[bufused++] = *((*inpos)++); } - if (bufused == bufsize-1) - return -2; - buf[bufused++] = '.'; } while(1); } @@ -59,7 +78,7 @@ int parse_name(const unsigned char **inpos, const unsigned char *inend, char *bu // -1: component > 63 characters // -2: insufficent space in output // -3: two subsequent dots -int write_name(unsigned char** outpos, unsigned char *outend, char *name) { +int write_name(unsigned char** outpos, unsigned char *outend, char *name, int offset) { while (*name != 0) { char *dot = strchr(name, '.'); char *fin = dot; @@ -67,36 +86,76 @@ int write_name(unsigned char** outpos, unsigned char *outend, char *name) { if (fin - name > 63) return -1; if (fin == name) return -3; if (outend - *outpos < fin - name + 2) return -2; - *(outpos++) = fin - name; + *((*outpos)++) = fin - name; memcpy(*outpos, name, fin - name); - outpos += fin - name; + *outpos += fin - name; if (!dot) break; name = dot + 1; } - if (outend == *outpos) return -2; - *(outpos++) = 0; + if (offset < 0) { + // no reference + if (outend == *outpos) return -2; + *((*outpos)++) = 0; + } else { + if (outend - *outpos < 2) return -2; + *((*outpos)++) = (offset >> 8) | 0xC0; + *((*outpos)++) = offset & 0xFF; + } return 0; } -int write_record_a(unsigned char** outpos, unsigned char *outend, char *name, int cls, int ttl, uint32_t ip) { +int write_record(unsigned char** outpos, unsigned char *outend, char *name, int offset, int typ, int cls, int ttl) { unsigned char *oldpos = *outpos; + int error = 0; // name - if (write_name(outpos, outend, name)) goto error; - if (outend - *outpos < 14) goto error; + int ret = write_name(outpos, outend, name, offset); + if (ret) { error = ret; goto error; } + if (outend - *outpos < 8) { error = -4; goto error; } // type - *(outpos++) = TYPE_A >> 8; *(outpos++) = TYPE_A & 0xFF; + *((*outpos)++) = typ >> 8; *((*outpos)++) = typ & 0xFF; // class - *(outpos++) = cls >> 8; *(outpos++) = cls & 0xFF; + *((*outpos)++) = cls >> 8; *((*outpos)++) = cls & 0xFF; // ttl - *(outpos++) = (ttl >> 24) & 0xFF; *(outpos++) = (ttl >> 16) & 0xFF; *(outpos++) = (ttl >> 8) & 0xFF; *(outpos++) = ttl & 0xFF; + *((*outpos)++) = (ttl >> 24) & 0xFF; *((*outpos)++) = (ttl >> 16) & 0xFF; *((*outpos)++) = (ttl >> 8) & 0xFF; *((*outpos)++) = ttl & 0xFF; + return 0; +error: + *outpos = oldpos; + return error; +} + + +int write_record_a(unsigned char** outpos, unsigned char *outend, char *name, int offset, int cls, int ttl, uint32_t ip) { + unsigned char *oldpos = *outpos; + int error = 0; + int ret = write_record(outpos, outend, name, offset, TYPE_A, cls, ttl); + if (ret) return ret; + if (outend - *outpos < 6) { error = -5; goto error; } // rdlength - *(outpos++) = 0; *(outpos++) = 4; + *((*outpos)++) = 0; *((*outpos)++) = 4; // rdata - *(outpos++) = (ip >> 24) & 0xFF; *(outpos++) = (ip >> 16) & 0xFF; *(outpos++) = (ip >> 8) & 0xFF; *(outpos++) = ttl & 0xFF; + *((*outpos)++) = (ip >> 24) & 0xFF; *((*outpos)++) = (ip >> 16) & 0xFF; *((*outpos)++) = (ip >> 8) & 0xFF; *((*outpos)++) = ttl & 0xFF; + return 0; +error: + *outpos = oldpos; + return error; +} + +int write_record_ns(unsigned char** outpos, unsigned char *outend, char *name, int offset, int cls, int ttl, char *ns) { + unsigned char *oldpos = *outpos; + int ret = write_record(outpos, outend, name, offset, TYPE_NS, cls, ttl); + if (ret) return ret; + int error = 0; + if (outend - *outpos < 2) { error = -5; goto error; } + (*outpos) += 2; + unsigned char *curpos = *outpos; + ret = write_name(outpos, outend, ns, -1); + if (ret) { error = ret; goto error; } + curpos[-2] = (*outpos - curpos) >> 8; + curpos[-1] = (*outpos - curpos) & 0xFF; return 0; error: *outpos = oldpos; - return -1; + return error; } ssize_t dnshandle(const unsigned char *inbuf, size_t insize, unsigned char* outbuf) { @@ -110,28 +169,31 @@ ssize_t dnshandle(const unsigned char *inbuf, size_t insize, unsigned char* outb outbuf[2] = inbuf[2]; outbuf[3] = inbuf[3]; // clear error - outbuf[3] &= ~240; + outbuf[3] &= ~15; // check qr - if (inbuf[2] & 1) { error = 1; goto error; } + if (inbuf[2] & 128) { printf("Got response?\n"); error = 1; goto error; } // check opcode - if (((inbuf[2] & 30) >> 1) != 0) { error = 4; goto error; } + if (((inbuf[2] & 120) >> 3) != 0) { printf("Opcode nonzero?\n"); error = 4; goto error; } // check Z - if (((inbuf[3] & 14) >> 1) != 0) { error = 1; goto error; } + if (((inbuf[3] & 112) >> 4) != 0) { printf("Z nonzero?\n"); error = 1; goto error; } // unset TC - outbuf[2] &= ~64; + outbuf[2] &= ~2; // unset RA - outbuf[3] &= ~1; + outbuf[3] &= ~128; // check questions - int nquestion = inbuf[4] << 8 + inbuf[5]; - if (nquestion == 0) { error = 0; goto error; } - if (nquestion > 0) { error = 4; goto error; } + int nquestion = (inbuf[4] << 8) + inbuf[5]; + if (nquestion == 0) { printf("No questions?\n"); error = 0; goto error; } + if (nquestion > 1) { printf("Multiple questions %i?\n", nquestion); error = 4; goto error; } const unsigned char *inpos = inbuf + 12; const unsigned char *inend = inbuf + insize; char name[256]; - int ret = parse_name(&inpos, inend, name, 256)) + int offset = inpos - inbuf; + int ret = parse_name(&inpos, inend, inbuf, name, 256); + printf("got request for host='%s'\n", name); if (ret == -1) { error = 1; goto error; } if (ret == -2) { error = 5; goto error; } - if (strcmp(name, host)) { error = 0; goto error; } + int namel = strlen(name), hostl = strlen(host); + if (strcmp(name, host) && (namel 0) { ssize_t ret = dnshandle(inbuf, insize, outbuf); if (ret > 0) - sendto(s, outbuf, ret, &si_other, &slen); + sendto(s, outbuf, ret, 0, (struct sockaddr*)&si_other, slen); } } while(1); return 0;