3 #include "dns-transp-common.h"
5 #define MAX_DATA_LABELS 4
7 static const char out_table[32]="0123456789abcdefghijklmnopqrstuv";
9 static void dump_enc(struct dnsdomainenc *be, const char *what) {
10 printf("ENC p=%08"PRIx32"/%-2d o=[%02d]|%02x %s\n",
11 be->pending, be->npending,
12 (int)(be->out - be->bufstop), *be->out,
16 static inline int enoughinput(struct dnsdomainenc *be) {
17 return be->npending >= 5;
19 static inline void startlabel(struct dnsdomainenc *be) {
22 static inline void outputchar(struct dnsdomainenc *be) {
23 /* there must be enough input and enough space */
27 dump_enc(be,"outputchar labelfull");
29 *--(be->out) = out_table[be->pending & 0x1f];
33 dump_enc(be,"outputchar");
36 int dnsdomainenc_start(struct dnsdomainenc *be, uint8_t *buf, int buflen,
37 int mydompathlen, const char *const mydompath[]) {
45 for (i=mydompathlen-1; i>=0; i--) {
46 const char *lab=mydompath[i];
48 if (ll>63) return FAKERCODE_MYDOMAINLABELTOOLONG;
49 if (be->out <= be->bufstop+ll+1) return FAKERCODE_MYDOMAINTOOLONG;
51 memcpy(be->out, lab, ll);
53 dump_enc(be,"start mydompath");
60 void dnsdomainenc_addbits(struct dnsdomainenc *be, uint32_t val, int nbits) {
61 assert(nbits<=28); /* otherwise pending might overflow */
62 assert(!(val & ~(((uint32_t)1 << nbits)-1)));
63 be->pending |= val << be->npending;
64 be->npending += nbits;
65 dump_enc(be,"addbits 1");
66 while (enoughinput(be)) {
67 assert(be->out > be->bufstop);
70 dump_enc(be,"addbits 2");
73 void dnsdomainenc_addu32(struct dnsdomainenc *be, uint32_t val) {
74 dnsdomainenc_addbits(be, val & 0xffff, 16);
75 dnsdomainenc_addbits(be, val >> 16, 16);
78 int dnsdomainenc_restbytes(struct dnsdomainenc *be,
79 const uint8_t *bytes, int avail) {
81 if (be->out == be->bufstop) {
82 dump_enc(be,"restbytes bufstop");
83 return avail + ((be->npending + 7) / 8);
87 be->pending |= (*bytes++) << be->npending;
90 dump_enc(be,"restbytes moreavail");
91 } else if (be->npending <= 0) {
92 dump_enc(be,"restbytes nopending");
97 dump_enc(be,"restbytes outputchar");
101 uint8_t *dnsdomainenc_getresult(struct dnsdomainenc *be) {
102 if (be->labremain != 63)
103 *--(be->out) = 63 - be->labremain; /* finish the last label */
104 dump_enc(be,"getresult");
110 static uint8_t in_table[256];
112 void dnsdomaindec_globalinit(void) {
114 memset(in_table,0xff,sizeof(in_table));
115 for (i=0; i<32; i++) {
116 in_table[(uint8_t)out_table[i]]=i;
117 in_table[toupper((unsigned char)out_table[i])]=i;
122 static void dump_dec(struct dnsdomaindec *bd, const char *what) {
123 int remain=bd->in - bd->databuf;
124 printf("DEC4 i=[%02d]|%02x p=%08"PRIx32"/%-2d %s\n",
125 remain, remain ? *(bd->in-1) : 0,
126 bd->pending, bd->npending,
130 struct labelinpacket {
131 const uint8_t *bytes;
135 static void setafter(const uint8_t *domain, const uint8_t **domain_end_r) {
136 if (domain_end_r && !*domain_end_r)
137 *domain_end_r=domain;
140 int dnsdomaindec_start(struct dnsdomaindec *bd, const uint8_t *packet,
141 const uint8_t *endpacket, const uint8_t *domain,
142 int mydompathlen, const char *const mydompath[],
143 const uint8_t **domain_end_r) {
144 int maxlabels=mydompathlen+MAX_DATA_LABELS;
145 struct labelinpacket labels[maxlabels];
146 int nlabels=0, totallen=0, i, j;
153 if (domain==endpacket)
154 return RCODE_FORMERR;
155 printf("DEC1 dom=|[%02d]|%02x[%02d]\n", domain-packet,
156 *domain, endpacket-domain);
157 unsigned b=*domain++;
160 setafter(domain,domain_end_r);
163 if ((b & 0xc0) == 0xc0) {
164 if (domain==endpacket)
165 return RCODE_FORMERR;
166 unsigned b2=*domain++;
167 setafter(domain,domain_end_r);
168 int off= ((b & 0x3f)<<8) | b2;
169 if (off >= endpacket - packet)
170 return RCODE_FORMERR;
173 if (!b) return RCODE_FORMERR;
174 /* now fall through to code expecting a literal */
176 if ((b & 0xc0) != 0x00)
177 return RCODE_FORMERR;
178 if (nlabels>=maxlabels)
179 return FAKERCODE_NOTAUTH;
181 if (totallen >= MAX_DOMAIN_BYTES) /* we still need a nul label */
182 return RCODE_FORMERR;
183 labels[nlabels].bytes=domain;
184 labels[nlabels].len=b;
185 printf("DEC1 labels[%d]=%.*s\n", nlabels,
186 labels[nlabels].len, labels[nlabels].bytes);
190 if (nlabels <= mydompathlen)
191 return FAKERCODE_NOTAUTH;
192 for (i=0; i<mydompathlen; i++) {
193 int l=strlen(mydompath[i]);
194 const struct labelinpacket *got=&labels[nlabels-mydompathlen+i];
195 printf("DEC2 [%d] %s ?= %.*s\n", i, mydompath[i],
196 got->len, got->bytes);
197 if (got->len != l || memcmp(got->bytes, mydompath[i], l))
198 return FAKERCODE_NOTAUTH;
200 /* OK, it's our domain and it has some data and a good
201 * number of labels. Wow. */
202 uint8_t *copyto=bd->databuf;
204 for (i=nlabels-mydompathlen-1; i>=0; i--) {
205 const uint8_t *p=labels[i].bytes;
206 for (j=0; j<labels[i].len; j++) {
207 int val=in_table[*p++];
209 return RCODE_NXDOMAIN;
216 assert(copyto <= bd->databuf+sizeof(bd->databuf));
221 static void inputchar(struct dnsdomaindec *bd) {
222 /* must be enough input and enough space in pending */
223 dump_dec(bd,"inputchar 1");
225 bd->pending |= (ch << bd->npending); /* already decoded */
227 dump_dec(bd,"inputchar 2");
229 uint32_t dnsdomaindec_getbits(struct dnsdomaindec *bd, int nbits)
233 while (bd->npending < nbits)
235 int newnpending = bd->pending - nbits;
236 uint32_t rv = bd->pending >> newnpending;
237 bd->pending &= ((uint32_t)1 << newnpending)-1;
238 bd->npending = newnpending;
241 uint32_t dnsdomaindec_getu32(struct dnsdomaindec *bd)
243 uint32_t lsw=dnsdomaindec_getbits(bd,16);
244 uint32_t msw=dnsdomaindec_getbits(bd,16);
245 return (msw << 16) | lsw;
247 int dnsdomaindec_restbytes(struct dnsdomaindec *bd, uint8_t outbuf[MAX_DOMAIN_BYTES])
249 uint8_t *out = outbuf;
251 if (bd->npending >= 8) {
252 *out++ = bd->pending;
256 if (bd->in == bd->databuf) {
257 /* that's all the input */