+/*
+ * Simple test program
+ */
+
+#include "dns-transp-common.h"
+
+#include <stdio.h>
+#include <inttypes.h>
+
#define NMYLABELS 3
static const char *const mylabels[NMYLABELS]={"z","example","com"};
static const char prefix[]="PREFIX ";
static const char suffix[]=" SUFFIX";
static uint8_t packet[100];
-static struct dnsbitenc enc;
+static struct dnsdomainenc enc;
+static struct dnsdomaindec dec;
int main(int argc, const char **argv) {
- const char **argv_save=
+ dnsdomaindec_globalinit();
+
+ const char **argv_save=argv;
memcpy(packet+sizeof(packet)-sizeof(suffix), suffix, sizeof(suffix));
- dnsbitenc_start(&enc, packet+sizeof(prefix),
- sizeof(packet)-sizeof(prefix)-sizeof(suffix));
+ dnsdomainenc_start(&enc, packet+sizeof(prefix),
+ sizeof(packet)-sizeof(prefix)-sizeof(suffix),
+ NMYLABELS,mylabels);
for (;;) {
const char *arg = *++argv;
if (!strcmp(arg,"b")) {
- uint32_t val=strtoul(*++argv,0,0);
int bits=atoi(*++argv);
- dnsbitenc_addbits(&enc,val,bits);
+ uint32_t val=strtoul(*++argv,0,0);
+ dnsdomainenc_addbits(&enc,val,bits);
} else if (!strcmp(arg,"w")) {
uint32_t val=strtoul(*++argv,0,0);
- dnsbitenc_addu32(&enc,val);
+ dnsdomainenc_addu32(&enc,val);
} else if (!strcmp(arg,"r")) {
const char *rest=*++argv;
int l=strlen(rest);
- int nofit=dnsbitenc_restbytes(&enc,rest,l);
+ int nofit=dnsdomainenc_restbytes(&enc,(const uint8_t*)rest,l);
printf("FIT %.*s|%.*s\n",l-nofit,rest,nofit,rest+l-nofit);
break;
} else {
abort();
}
}
- const uint8_t *encoded=dnsbitenc_getresult(&enc);
- const uint8_t *pktbegin=encoded-sizeof(prefix);
+ uint8_t *encoded=dnsdomainenc_getresult(&enc);
+ uint8_t *pktbegin=encoded-sizeof(prefix);
memcpy(pktbegin,prefix,sizeof(prefix));
const uint8_t *pr;
printf("%02x",*pr);
printf("\n");
- uint8_t domainend;
- int r=dnsbitdec_start(&dec, pktbegin, packet+sizeof(packet),
- pktbegin+sizeof(prefix), NMYLABELS,mylabels,
- &domainend);
+ const uint8_t *domainend;
+ int r=dnsdomaindec_start(&dec, pktbegin, packet+sizeof(packet),
+ pktbegin+sizeof(prefix), NMYLABELS,mylabels,
+ &domainend);
if (r) {
printf("DEC ERROR %d\n",r);
return 0;
for (;;) {
const char *arg = *++argv;
if (!strcmp(arg,"b")) {
- ++argv;
int bits=atoi(*++argv);
- uint32_t
-
- if (nofit)
-
- } else
-
- const int c0=*arg++;
- switch (c0) {
- case 'b':
-
+ ++argv;
+ uint32_t val=dnsdomaindec_getbits(&dec,bits);
+ printf("b %d 0x%"PRIx32, bits, val);
+ } else if (!strcmp(arg,"w")) {
+ uint32_t val=dnsdomaindec_getu32(&dec);
+ printf("w 0x%"PRIx32, val);
+ } else if (!strcmp(arg,"r")) {
+ uint8_t rbuf[MAX_DOMAIN_BYTES];
+ int l=dnsdomaindec_restbytes(&dec,rbuf);
+ printf("r %.*s",l,rbuf);
+ } else {
+ abort();
+ }
+ }
+}
+/**/
+
+#include "dns-transp-common.h"
+
+#define MAX_DATA_LABELS 4
static const char out_table[32]="0123456789abcdefghijklmnopqrstuv";
-static inline int enoughinput(struct dnsbitenc *be) {
+static inline int enoughinput(struct dnsdomainenc *be) {
return be->npending >= 5;
}
-static inline void startlabel(struct dnsbitenc *be) {
+static inline void startlabel(struct dnsdomainenc *be) {
be->labremain=63;
}
-static inline void outputchar(struct dnsbitenc *be) {
+static inline void outputchar(struct dnsdomainenc *be) {
/* there must be enough input and enough space */
if (!be->labremain) {
*--(be->out) = 63;
be->npending -= 5;
}
-void dnsbitenc_start(struct dnsbitenc *be, uint8_t *buf, int buflen) {
+int dnsdomainenc_start(struct dnsdomainenc *be, uint8_t *buf, int buflen,
+ int mydompathlen, const char *const mydompath[]) {
+ int i;
assert(buflen>0);
be->pending=0;
be->npending=0;
be->bufstop=buf+1;
be->out=buf+buflen;
+ for (i=mydompathlen-1; i>=0; i++) {
+ const char *lab=mydompath[i];
+ int ll=strlen(lab);
+ if (ll>63) return FAKERCODE_MYDOMAINLABELTOOLONG;
+ if (be->out <= be->bufstop+ll+1) return FAKERCODE_MYDOMAINTOOLONG;
+ be->out -= ll;
+ memcpy(be->out, lab, ll);
+ *be->out -= ll;
+ }
startlabel(be);
+ return 0;
}
-void dnsbitenc_addbits(struct dnsbitenc *be, uint32_t val, int nbits) {
+void dnsdomainenc_addbits(struct dnsdomainenc *be, uint32_t val, int nbits) {
assert(nbits<=28); /* otherwise pending might overflow */
assert(!(val & ~(((uint32_t)1 << nbits)-1)));
be->pending |= val << be->npending;
}
}
-void dnsbitenc_addu32(struct dnsbitenc *be, uint32_t val) {
- dnsbitenc_addbits(be, val & 0xffff, 16);
- dnsbitenc_addbits(be, val >> 16, 16);
+void dnsdomainenc_addu32(struct dnsdomainenc *be, uint32_t val) {
+ dnsdomainenc_addbits(be, val & 0xffff, 16);
+ dnsdomainenc_addbits(be, val >> 16, 16);
}
-int dnsbitenc_restbytes(struct dnsbitenc *be, uint8_t *bytes, int qty) {
+int dnsdomainenc_restbytes(struct dnsdomainenc *be,
+ const uint8_t *bytes, int avail) {
for (;;) {
- if (buf==bufstop) {
- return qty + ((be->npending + 7) / 8);
+ if (be->out == be->bufstop) {
+ return avail + ((be->npending + 7) / 8);
}
if (be->npending<5) {
- if (qty) {
+ if (avail) {
be->pending |= (*bytes++) << be->npending;
be->npending += 8;
} else if (be->npending <= 0) {
}
}
-uint8_t *dnsbitenc_getresult(struct dnsbitenc *be) {
+uint8_t *dnsdomainenc_getresult(struct dnsdomainenc *be) {
*--(be->out) = 63 - be->labremain; /* finish the last label */
return be->out;
}
+static uint8_t in_table[256];
+
+void dnsdomaindec_globalinit(void) {
+ int i;
+ memset(in_table,0xff,sizeof(in_table));
+ for (i=0; i<32; i++) {
+ in_table[(uint8_t)out_table[i]]=i;
+ in_table[toupper((unsigned char)out_table[i])]=i;
+ }
+}
-#define MAX_DATA_LABELS
struct labelinpacket {
const uint8_t *bytes;
int len;
};
-struct dnsbitdec {
- /* private for dnsbitdec_... functions; do not access direcctly */
- const databuf[MAX_DOMAIN_BYTES];
- const uint8_t *in;
-};
-
static void setafter(const uint8_t *domain, const uint8_t **domain_end_r) {
if (domain_end_r && !*domain_end_r)
*domain_end_r=domain;
}
-int dnsdomaindec_start(struct dnsbitdec *bd, const uint8_t *packet,
+int dnsdomaindec_start(struct dnsdomaindec *bd, const uint8_t *packet,
const uint8_t *endpacket, const uint8_t *domain,
- int mydompathlen, const char *mydompath[],
+ int mydompathlen, const char *const mydompath[],
const uint8_t **domain_end_r) {
- int maxlabels=mydompath+MAX_DATA_LABELS;
- const strut labelinpacket labels[maxlabels];
- int nlabels=0, totallen=0;
+ int maxlabels=mydompathlen+MAX_DATA_LABELS;
+ struct labelinpacket labels[maxlabels];
+ int nlabels=0, totallen=0, i, j;
+
+ bd->pending=0;
+ bd->npending=0;
*domain_end_r=0;
for (;;) {
if (domain==endpacket)
- return FORMERR;
+ return RCODE_FORMERR;
unsigned b=*domain++;
if (!b) {
totallen++;
}
if ((b & 0xc0) == 0xc0) {
if (domain==endpacket)
- return FORMERR;
+ return RCODE_FORMERR;
unsigned b2=*domain++;
setafter(domain,domain_end_r);
- unsigned off= ((b & 0x3f)<<8) | b2;
+ int off= ((b & 0x3f)<<8) | b2;
if (off >= endpacket - packet)
- return False;
+ return RCODE_FORMERR;
domain=packet+off;
b=*domain++;
- if (!b) return FORMERR
+ if (!b) return RCODE_FORMERR;
/* now fall through to code expecting a literal */
}
if ((b & 0xc0) != 0x00)
- return FORMERR;
+ return RCODE_FORMERR;
if (nlabels>=maxlabels)
- return NOTAUTH;
+ return FAKERCODE_NOTAUTH;
totallen+=b+1;
if (totallen >= MAX_DOMAIN_BYTES) /* we still need a nul label */
- return FORMERR;
+ return RCODE_FORMERR;
labels[nlabels].bytes=domain;
labels[nlabels].len=b;
nlabels++;
domain += b;
}
if (nlabels <= mydompathlen)
- return NOTAUTH;
+ return FAKERCODE_NOTAUTH;
for (i=0; i<mydompathlen; i++) {
int l=strlen(mydompath[i]);
const struct labelinpacket *got=&labels[nlabels-mydompathlen];
- if (got->len != l || memcmp(got->bytes,mydompath[i]))
- return NOTAUTH;
+ if (got->len != l || memcmp(got->bytes, mydompath[i], l))
+ return FAKERCODE_NOTAUTH;
}
/* OK, it's our domain and it has some data and a good
* number of labels. Wow. */
- uint8_t *copyto=&bd->databuf;
+ uint8_t *copyto=bd->databuf;
for (i=0; i<nlabels-mydompathlen; i++) {
const uint8_t *p=labels[i].bytes;
for (j=0; j<labels[i].len; j++) {
int val=in_table[*p++];
if (val & 0x80)
- return NXDOMAIN;
+ return RCODE_NXDOMAIN;
*copyto++=val;
}
}
return 0;
}
-static uint8_t in_table[256];
-
-static void dnsdomaindec_globalinit(void) {
- memset(in_table,0xff,sizeof(in_table));
- for (i=0; i<32; i++) {
- in_table[out_table[i]]=i;
- in_table[toupper((unsigned char)out_table[i])]=i;
- }
-}
-
-static void inputchar(struct dnsbitdec *bd) {
+static void inputchar(struct dnsdomaindec *bd) {
/* must be enough input and enough space in pending */
int ch=*--(bd->in);
bd->pending <<= 8;
bd->pending |= ch; /* already decoded */
bd->npending += 5;
}
-uint32_t dnsdomaindec_getbits(struct dnsbitdec *bd, int nbits)
+uint32_t dnsdomaindec_getbits(struct dnsdomaindec *bd, int nbits)
{
/* must be enough */
assert(nbits<=28);
- while (bd->pending < nbits)
- inputchar();
+ while (bd->npending < nbits)
+ inputchar(bd);
int newnpending = bd->pending - nbits;
uint32_t rv = bd->pending >> newnpending;
bd->pending &= ((uint32_t)1 << newnpending)-1;
bd->npending = newnpending;
+ return rv;
}
-uint32_t dnsdomaindec_getu32(struct dnsbitdec *bd)
+uint32_t dnsdomaindec_getu32(struct dnsdomaindec *bd)
{
uint32_t lsw=dnsdomaindec_getbits(bd,16);
uint32_t msw=dnsdomaindec_getbits(bd,16);
return (msw << 16) | lsw;
}
-int dnsbitdec_restbytes(struct dnsbitdec *bd, uint8_t outbuf[MAX_DOMAIN_BYTES])
+int dnsdomaindec_restbytes(struct dnsdomaindec *bd, uint8_t outbuf[MAX_DOMAIN_BYTES])
{
- uint8_t *out;
+ uint8_t *out = outbuf;
for (;;) {
if (bd->npending >= 8) {
*out++ = bd->pending;
-struct dnsbitenc {
- /* private for dnsbitenc_... functions; do not access direcctly */
+#ifndef dns_transp_common_h
+#define dns_transp_common_h
+
+#define MAX_DOMAIN_BYTES 255
+
+
+#define RCODE_NOERROR 0
+#define RCODE_FORMERR 1
+#define RCODE_SERVFAIL 2
+#define RCODE_NXDOMAIN 3
+#define RCODE_REFUSED 5
+
+#define FAKERCODE_NOTAUTH -1
+#define FAKERCODE_MYDOMAINTOOLONG -2
+#define FAKERCODE_MYDOMAINLABELTOOLONG -3
+
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+
+void dnsdomaindec_globalinit(void);
+
+
+struct dnsdomainenc {
+ /* private for dnsdomainenc_... functions; do not access direcctly */
uint32_t pending;
int npending; /* never more than 4 unless we're in the middle */
uint8_t *out, *bufstop; /* counts backwards */
* getresult
*/
-void dnsbitenc_start(struct dnsbitenc *be, uint8_t *buf, int buflen);
+int dnsdomainenc_start(struct dnsdomainenc *be, uint8_t *buf, int buflen,
+ int mydompathlen, const char *const mydompath[]);
+ /* returns -1 if mydompath is too long somehow */
-void dnsbitenc_addbits(struct dnsbitenc *be, uint32_t val, int nbits);
+void dnsdomainenc_addbits(struct dnsdomainenc *be, uint32_t val, int nbits);
/* adds the bottom nbits bits of val; must be enough space; nbits<=28 */
-void dnsbitenc_addu32(struct dnsbitenc *be, uint32_t val);
+void dnsdomainenc_addu32(struct dnsdomainenc *be, uint32_t val);
/* must be enough space */
-int dnsbitenc_restbytes(struct dnsbitenc *be, uint8_t *bytes, int qty);
+int dnsdomainenc_restbytes(struct dnsdomainenc *be,
+ const uint8_t *bytes, int avail);
/* returns number of bytes which did not fit */
-uint8_t *dnsbitenc_getresult(struct dnsbitenc *be);
+uint8_t *dnsdomainenc_getresult(struct dnsdomainenc *be);
/* returns pointer into caller-supplied buffer; we have used
* bytes from the result to the end (so the caller needs to remember
* the buffer len to know what the encoded length is */
-fixme needs to add mylabels too
+
+
+struct dnsdomaindec {
+ /* private for dnsbitdec_... functions; do not access direcctly */
+ uint8_t databuf[MAX_DOMAIN_BYTES];
+ const uint8_t *in;
+ uint32_t pending;
+ int npending;
+};
+
+int dnsdomaindec_start(struct dnsdomaindec *bd, const uint8_t *packet,
+ const uint8_t *endpacket, const uint8_t *domain,
+ int mydompathlen, const char *const mydompath[],
+ const uint8_t **domain_end_r);
+
+uint32_t dnsdomaindec_getbits(struct dnsdomaindec *bd, int nbits);
+
+uint32_t dnsdomaindec_getu32(struct dnsdomaindec *bd);
+
+int dnsdomaindec_restbytes(struct dnsdomaindec *bd,
+ uint8_t outbuf[MAX_DOMAIN_BYTES]);
+
+
+#endif /* dns_transp_common_h */