3 #include "dns-transp-common.h"
5 #define MAX_DATA_LABELS 4
8 // *#define DPRINTF printf
10 static const char out_table[32]="0123456789abcdefghijklmnopqrstuv";
12 static void dump_enc(struct dnsdomainenc *be, const char *what) {
13 DPRINTF("ENC p=%08"PRIx32"/%-2d o=[%02d]|%02x %s\n",
14 be->pending, be->npending,
15 (int)(be->out - be->bufstop), *be->out,
19 static inline int enoughinput(struct dnsdomainenc *be) {
20 return be->npending >= 5;
22 static inline void startlabel(struct dnsdomainenc *be) {
25 static inline void outputchar(struct dnsdomainenc *be) {
26 /* there must be enough input and enough space */
30 dump_enc(be,"outputchar labelfull");
32 *--(be->out) = out_table[be->pending & 0x1f];
36 dump_enc(be,"outputchar");
39 int dnsdomainenc_start(struct dnsdomainenc *be, uint8_t *buf, int buflen,
40 int mydompathlen, const char *const mydompath[]) {
48 for (i=mydompathlen-1; i>=0; i--) {
49 const char *lab=mydompath[i];
51 if (ll>63) return FAKERCODE_MYDOMAINLABELTOOLONG;
52 if (be->out <= be->bufstop+ll+1) return FAKERCODE_MYDOMAINTOOLONG;
54 memcpy(be->out, lab, ll);
56 dump_enc(be,"start mydompath");
63 void dnsdomainenc_addbits(struct dnsdomainenc *be, uint32_t val, int nbits) {
64 assert(nbits<=28); /* otherwise pending might overflow */
65 assert(!(val & ~(((uint32_t)1 << nbits)-1)));
66 be->pending |= val << be->npending;
67 be->npending += nbits;
68 dump_enc(be,"addbits 1");
69 while (enoughinput(be)) {
70 assert(be->out > be->bufstop);
73 dump_enc(be,"addbits 2");
76 void dnsdomainenc_addu32(struct dnsdomainenc *be, uint32_t val) {
77 dnsdomainenc_addbits(be, val & 0xffff, 16);
78 dnsdomainenc_addbits(be, val >> 16, 16);
81 int dnsdomainenc_restbytes(struct dnsdomainenc *be,
82 const uint8_t *bytes, int avail) {
84 if (be->out == be->bufstop) {
85 dump_enc(be,"restbytes bufstop");
86 return avail + ((be->npending + 7) / 8);
90 be->pending |= (*bytes++) << be->npending;
93 dump_enc(be,"restbytes moreavail");
94 } else if (be->npending <= 0) {
95 dump_enc(be,"restbytes nopending");
100 dump_enc(be,"restbytes outputchar");
104 uint8_t *dnsdomainenc_getresult(struct dnsdomainenc *be) {
105 if (be->labremain != 63)
106 *--(be->out) = 63 - be->labremain; /* finish the last label */
107 dump_enc(be,"getresult");
113 static uint8_t in_table[256];
115 void dnsdomaindec_globalinit(void) {
117 memset(in_table,0xff,sizeof(in_table));
118 for (i=0; i<32; i++) {
119 in_table[(uint8_t)out_table[i]]=i;
120 in_table[toupper((unsigned char)out_table[i])]=i;
125 static void dump_dec(struct dnsdomaindec *bd, const char *what) {
126 int remain=bd->in - bd->databuf;
127 DPRINTF("DEC4 i=[%02d]|%02x p=%08"PRIx32"/%-2d %s\n",
128 remain, remain ? *(bd->in-1) : 0,
129 bd->pending, bd->npending,
133 struct labelinpacket {
134 const uint8_t *bytes;
138 static void setafter(const uint8_t *domain, const uint8_t **domain_end_r) {
139 if (domain_end_r && !*domain_end_r)
140 *domain_end_r=domain;
143 int dnsdomaindec_start(struct dnsdomaindec *bd, const uint8_t *packet,
144 const uint8_t *endpacket, const uint8_t *domain,
145 int mydompathlen, const char *const mydompath[],
146 const uint8_t **domain_end_r) {
147 int maxlabels=mydompathlen+MAX_DATA_LABELS;
148 struct labelinpacket labels[maxlabels];
149 int nlabels=0, totallen=0, i, j;
156 if (domain==endpacket)
157 return RCODE_FORMERR;
158 DPRINTF("DEC1 dom=|[%02d]|%02x[%02d]\n", domain-packet,
159 *domain, endpacket-domain);
160 unsigned b=*domain++;
163 setafter(domain,domain_end_r);
166 if ((b & 0xc0) == 0xc0) {
167 if (domain==endpacket)
168 return RCODE_FORMERR;
169 unsigned b2=*domain++;
170 setafter(domain,domain_end_r);
171 int off= ((b & 0x3f)<<8) | b2;
172 if (off >= endpacket - packet)
173 return RCODE_FORMERR;
176 if (!b) return RCODE_FORMERR;
177 /* now fall through to code expecting a literal */
179 if ((b & 0xc0) != 0x00)
180 return RCODE_FORMERR;
181 if (nlabels>=maxlabels)
182 return FAKERCODE_NOTAUTH;
184 if (totallen >= MAX_DOMAIN_BYTES) /* we still need a nul label */
185 return RCODE_FORMERR;
186 labels[nlabels].bytes=domain;
187 labels[nlabels].len=b;
188 DPRINTF("DEC1 labels[%d]=%.*s\n", nlabels,
189 labels[nlabels].len, labels[nlabels].bytes);
193 if (nlabels <= mydompathlen)
194 return FAKERCODE_NOTAUTH;
195 for (i=0; i<mydompathlen; i++) {
196 int l=strlen(mydompath[i]);
197 const struct labelinpacket *got=&labels[nlabels-mydompathlen+i];
198 DPRINTF("DEC2 [%d] %s ?= %.*s\n", i, mydompath[i],
199 got->len, got->bytes);
200 if (got->len != l || memcmp(got->bytes, mydompath[i], l))
201 return FAKERCODE_NOTAUTH;
203 /* OK, it's our domain and it has some data and a good
204 * number of labels. Wow. */
205 uint8_t *copyto=bd->databuf;
207 for (i=nlabels-mydompathlen-1; i>=0; i--) {
208 const uint8_t *p=labels[i].bytes;
209 for (j=0; j<labels[i].len; j++) {
210 int val=in_table[*p++];
212 return RCODE_NXDOMAIN;
219 assert(copyto <= bd->databuf+sizeof(bd->databuf));
224 static void inputchar(struct dnsdomaindec *bd) {
225 /* must be enough input and enough space in pending */
226 dump_dec(bd,"inputchar 1");
228 bd->pending |= (ch << bd->npending); /* already decoded */
230 dump_dec(bd,"inputchar 2");
232 uint32_t dnsdomaindec_getbits(struct dnsdomaindec *bd, int nbits)
236 while (bd->npending < nbits)
238 uint32_t rv = bd->pending & (((uint32_t)1 << nbits)-1);
239 bd->pending >>= nbits;
240 bd->npending -= nbits;
243 uint32_t dnsdomaindec_getu32(struct dnsdomaindec *bd)
245 uint32_t lsw=dnsdomaindec_getbits(bd,16);
246 uint32_t msw=dnsdomaindec_getbits(bd,16);
247 return (msw << 16) | lsw;
249 int dnsdomaindec_restbytes(struct dnsdomaindec *bd,
250 uint8_t outbuf[MAX_DOMAIN_BYTES])
252 uint8_t *out = outbuf;
254 if (bd->npending >= 8) {
255 *out++ = bd->pending;
259 if (bd->in == bd->databuf) {
260 /* that's all the input */