-typedef enum {
- rcode_noerror,
- rcode_formaterror,
- rcode_servfail,
- rcode_nxdomain,
- rcode_notimp,
- rcode_refused
-} dns_rcode;
-
-#define GETIL_B(cb) (dgram[*(cb)++])
-#define GET_B(cb,tv) ((tv)= GETIL_B((cb)))
-#define GET_W(cb,tv) ((tv)=0, (tv)|=(GETIL_B((cb))<<8), (tv)|=GETIL_B(cb), (tv))
-
-static void vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len) {
- char qbuf[10];
- int i;
-
- while (len) {
- qbuf[0]= 0;
- for (i=0; i<len; i++) {
- ch= buf[i];
- if (ch == '.' || ch == '"' || ch == '(' || ch == ')' ||
- ch == '@' || ch == ';' || ch == '$') {
- sprintf(qbuf,"\\%c",ch);
- break;
- } else if (ch <= ' ' || ch >= 127) {
- sprintf(qbuf,"\\%03o",ch);
- break;
- }
- }
- if (!adns__vbuf_append(vb,buf,i) || !adns__vbuf_append(vb,qbuf,strlen(qbuf)))
- return adns_s_nolocalmem;
- buf+= i; len-= i;
- }
-}
-
-static adns_status get_label(const byte *dgram, int dglen, int *max_io,
- int *cbyte_io, int *lablen_r, int *labstart_r,
- int *namelen_io) {
- /* If succeeds, *lablen_r may be set to -1 to indicate truncation/overrun */
- int max, cbyte, lablen, namelen;
-
- max= *max_io;
- cbyte= *cbyte_io;
-
- for (;;) {
- if (cbyte+2 > max) goto x_truncated;
- GET_W(cbyte,lablen);
- if (!(lablen & 0x0c000)) break;
- if ((lablen & 0x0c000) != 0x0c000) return adns_s_unknownreply;
- if (cbyte_io) { *cbyte_io= cbyte; cbyte_io= 0; }
- cbyte= dgram+DNS_HDR_SIZE+(lablen&0x3fff);
- *max_io= max= dglen;
- }
- if (labstart_r) *labstart_r= cbyte;
- if (lablen) {
- namelen= *namelen_io;
- if (namelen) namelen++;
- namelen+= lablen;
- if (namelen > DNS_MAXDOMAIN) return adns_s_domaintoolong;
- *namelen_io= namelen;
- cbyte+= lablen;
- if (cbyte > max) goto x_truncated;
- }
- if (cbyte_io) *cbyte_io= cbyte;
- *lablen_r= lablen;
- return adns_s_ok;
-
- x_truncated:
- *lablen_r= -1;
- return adns_s_ok;
-}
-
-static adns_status get_domain_perm(adns_state ads, adns_query qu, int serv,
- const byte *dgram, int dglen,
- int *cbyte_io, int max, char **domain_r) {
- /* Returns 0 for OK (*domain_r set) or truncated (*domain_r null)
- * or any other adns_s_* value.
- */
- int cbyte, sused, lablen, namelen;
-
- /* If we follow a pointer we set cbyte_io to 0 to indicate that
- * we've lost our original starting and ending points; we don't
- * put the end of the pointed-to thing into the original *cbyte_io.
- */
- cbyte= *cbyte_io;
- sused= qu->ans.used;
- *domain_r= 0;
- namelen= 0;
- for (;;) {
- st= get_label(dgram,dglen,&max, &cbyte,&lablen,&labstart,&namelen);
- if (st) return st;
- if (lablen<0) goto x_truncated;
- if (!lablen) break;
- if (qu->ans.used != sused)
- if (!adns__vbuf_append(&qu->ans,".",1)) return adns_s_nolocalmem;
- if (qu->flags & adns_qf_anyquote) {
- if (!vbuf__append_quoted1035(&qu->ans,dgram+labstart,lablen))
- return adns_s_nolocalmem;
- } else {
- if (!ctype_isalpha(dgram[labstart])) return adns_s_invaliddomain;
- for (i= cbyte+1; i<cbyte+lablen; i++) {
- ch= dgram[cbyte];
- if (ch != '-' && !ctype_isalpha(ch) && !ctype_isdigit(ch))
- return adns_s_invaliddomain;
- }
- if (!adns__vbuf_append(&qu->ans,dgram+labstart,lablen))
- return adns_s_nolocalmem;
- }
- }
- if (cbyte_io) *cbyte_io= cbyte;
- if (!adns__vbuf_append(&qu->ans,"",1)) return adns_s_nolocalmem;
- *domain_r= qu->ans.buf+sused;
- return adns_s_ok;
-
- x_truncated:
- return cbyte_io ? -1 : adns_s_serverfaulty;