From 9c45d9ad13fdf439d44d7443ae75da15ea0223ed Mon Sep 17 00:00:00 2001 From: Sam Varshavchik Date: Mon, 19 Aug 2013 16:39:41 -0400 Subject: Initial checkin Imported from subversion report, converted to git. Updated all paths in scripts and makefiles, reflecting the new directory hierarchy. --- rfc1035/rfc1035reply.c | 479 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 479 insertions(+) create mode 100644 rfc1035/rfc1035reply.c (limited to 'rfc1035/rfc1035reply.c') diff --git a/rfc1035/rfc1035reply.c b/rfc1035/rfc1035reply.c new file mode 100644 index 0000000..98c3766 --- /dev/null +++ b/rfc1035/rfc1035reply.c @@ -0,0 +1,479 @@ +/* +** Copyright 1998 - 1999 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#include "rfc1035.h" +#include +#include +#include + + +void rfc1035_replyfree(struct rfc1035_reply *p) +{ +struct rfc1035_reply *q; + + while (p) + { + q=p->next; + if (p->mallocedbuf) free(p->mallocedbuf); + if (p->qdptr) free(p->qdptr); + if (p->anptr) free(p->anptr); + if (p->nsptr) free(p->nsptr); + if (p->arptr) free(p->arptr); + if (p->allrrs) free(p->allrrs); + free(p); + p=q; + } +} + +const char *rfc1035_replyuncompress(const char **ptr, + const struct rfc1035_reply *reply, char *namebuf) +{ +unsigned i=0; +unsigned l; +const char *end=reply->reply+reply->replylen; +const char *newptr=0; +int cnt=0; + + for (;;) + { + if ( (*ptr) == end) return (0); + l=(unsigned char)*(*ptr)++; + if (l > 63) + { + if ((l & 0xC0) != 0xC0) return (0); + if ( (*ptr) == end) return (0); + l= ((l & 63) << 8) + (unsigned char)*(*ptr)++; + if (l >= reply->replylen) return (0); + ptr= &newptr; + newptr=reply->reply+l; + if ( ++cnt > 100) return (0); + /* Detect loops */ + + continue; + } + if (l == 0) break; + if (i) + { + if (i >= RFC1035_MAXNAMESIZE) return (0); + if (namebuf) namebuf[i]='.'; + ++i; + } + if (RFC1035_MAXNAMESIZE-i < l) return (0); + + if (reply->reply + reply->replylen - (*ptr) < l) + return (0); + + if (namebuf) + memcpy(namebuf+i, *ptr, l); + i += l; + *ptr += l; + } + + if (namebuf) namebuf[i]=0; + return (namebuf ? namebuf:""); +} + +const char *rfc1035_replyhostname( const struct rfc1035_reply *r, const char *n, + char *namebuf) +{ +const char *p=rfc1035_replyuncompress(&n, r, namebuf); + + if (!p) strcpy(namebuf, "error"); + return (p); +} + +static void doparse(struct rfc1035_reply *, struct rfc1035_rr *); + +struct rfc1035_reply *rfc1035_replyparse(const char *p, unsigned l) +{ +struct rfc1035_reply *r=(struct rfc1035_reply *) + malloc(sizeof(struct rfc1035_reply)); +char c; +unsigned n; +int pass; +unsigned *lenptrs[3]; +struct rfc1035_rr *rrptrs[3]; +const char *end=p+l; +unsigned allcnt; + + if (!r) return (0); + r->next=0; + r->reply=p; + r->replylen=l; + r->mallocedbuf=0; + memset(&r->server_addr, 0, sizeof(r->server_addr)); + r->qdptr=0; + r->anptr=0; + r->nsptr=0; + r->arptr=0; + r->allrrs=0; + + if (l < 12) + { + errno=EINVAL; + rfc1035_replyfree(r); + return (0); + } + + c=p[2]; + r->rd= c & 1; + c >>= 1; + r->tc= c & 1; + c >>= 1; + r->aa= c & 1; + c >>= 1; + r->opcode= c & 15; + c >>= 4; + r->qr= c & 1; + + r->ra=(p[3] >> 7) & 1; + r->ad=(p[3] >> 5) & 1; + r->cd=(p[3] >> 4) & 1; + r->rcode=p[3] & 15; + + r->qdcount= ((unsigned)(unsigned char)p[4] << 8) | (unsigned char)p[5]; + r->ancount= ((unsigned)(unsigned char)p[6] << 8) | (unsigned char)p[7]; + r->nscount= ((unsigned)(unsigned char)p[8] << 8) | (unsigned char)p[9]; + r->arcount= ((unsigned)(unsigned char)p[10]<< 8) | (unsigned char)p[11]; + + if (r->qdcount >= l || r->ancount >= l || r->nscount >= l || + r->arcount >= l || + (n=r->qdcount + r->ancount) >= l || + (n += r->nscount) >= l || + n + r->arcount >= l) + { + errno=EINVAL; + rfc1035_replyfree(r); + return (0); + } + + if ((r->qdcount && (r->qdptr=malloc(sizeof(struct rfc1035_query) + * r->qdcount)) == 0) || + (r->ancount && (r->anptr=malloc(sizeof(struct rfc1035_rr) + * r->ancount)) == 0) || + (r->nscount && (r->nsptr=malloc(sizeof(struct rfc1035_rr) + * r->nscount)) == 0) || + (r->arcount && (r->arptr=malloc(sizeof(struct rfc1035_rr) + * r->arcount)) == 0) || + (r->ancount + r->nscount + r->arcount && + (r->allrrs=malloc(sizeof(*r->allrrs)*( + r->ancount + r->nscount + r->arcount))) == 0) + ) + { + rfc1035_replyfree(r); + return (0); + } + + p += 12; + l -= 12; + for (n=0; nqdcount; n++) + { + r->qdptr[n].name=p; + if (rfc1035_replyuncompress( &p, r, 0 ) == 0) + { + errno=EINVAL; + rfc1035_replyfree(r); + return (0); + } + + if (p > end-4) return (0); + + r->qdptr[n].qtype=((unsigned)(unsigned char)p[0] << 8) + | (unsigned char)p[1]; + p += 2; + r->qdptr[n].qclass=((unsigned)(unsigned char)p[0] << 8) + | (unsigned char)p[1]; + p += 2; + } + + lenptrs[0]= &r->ancount; + lenptrs[1]= &r->nscount; + lenptrs[2]= &r->arcount; + rrptrs[0]= r->anptr; + rrptrs[1]= r->nsptr; + rrptrs[2]= r->arptr; + + allcnt=0; + + for (pass=0; pass<3; pass++) + { + struct rfc1035_rr *rrp= rrptrs[pass]; + + for (n=0; n< *lenptrs[pass]; n++) + { + r->allrrs[allcnt++]=rrp; + rrp->rrname=p; + if (rfc1035_replyuncompress( &p, r, 0 ) + == 0) + { + errno=EINVAL; + rfc1035_replyfree(r); + return (0); + } + + if (p > end-10) return (0); + rrp->rrtype=((unsigned)(unsigned char)p[0] << 8) + | (unsigned char)p[1]; + p += 2; + rrp->rrclass=((unsigned)(unsigned char)p[0] << 8) + | (unsigned char)p[1]; + p += 2; + rrp->ttl=((RFC1035_UINT32)(unsigned char)p[0] << 24) | + ((RFC1035_UINT32)(unsigned char)p[1] << 16) | + ((RFC1035_UINT32)(unsigned char)p[2] << 8) | + (unsigned char)p[3]; + p += 4; + + rrp->rdlength=((unsigned)(unsigned char)p[0] << 8) + | (unsigned char)p[1]; + p += 2; + rrp->rdata= rrp->rdlength ? p:0; + if (end - p < rrp->rdlength) + { + errno=EINVAL; + rfc1035_replyfree(r); + return (0); + } + p += rrp->rdlength; + doparse(r, rrp); + ++rrp; + } + } + return (r); +} + +static void doparse(struct rfc1035_reply *r, struct rfc1035_rr *rr) +{ +const char *p; +static const char error[]="\005error"; + + memset(&rr->rr, '\0', sizeof(rr->rr)); + if (rr->rrclass != RFC1035_CLASS_IN) return; + + switch (rr->rrtype) { + case RFC1035_TYPE_A: + + if (rr->rdlength < 4) + rr->rr.inaddr.s_addr=0; + else + memcpy(&rr->rr.inaddr.s_addr, + rr->rdata, 4); + break; +#if RFC1035_IPV6 + case RFC1035_TYPE_AAAA: + memset(&rr->rr.in6addr, 0, sizeof(rr->rr.in6addr)); + if (rr->rdlength >= sizeof(struct in6_addr)) + memcpy(&rr->rr.in6addr, rr->rdata, + sizeof(rr->rr.in6addr)); + break; +#endif + case RFC1035_TYPE_CNAME: + case RFC1035_TYPE_MB: + case RFC1035_TYPE_MG: + case RFC1035_TYPE_MR: + case RFC1035_TYPE_MD: + case RFC1035_TYPE_MF: + case RFC1035_TYPE_NS: + case RFC1035_TYPE_PTR: + rr->rr.domainname=p=rr->rdata; + if (rfc1035_replyuncompress(&p, r, 0) == 0 || + p > rr->rdata + rr->rdlength) + rr->rr.domainname=error; + break; + + case RFC1035_TYPE_SOA: + rr->rr.soa.mname_label=p=rr->rdata; + + if (rr->rdlength < 20 || + rfc1035_replyuncompress(&p, r, 0) == 0 || + p > rr->rdata + rr->rdlength || + (rr->rr.soa.rname_label=p, rfc1035_replyuncompress(&p, + r, 0)) == 0 || + p > rr->rdata + rr->rdlength - 20) + { + rr->rr.soa.mname_label=error; + rr->rr.soa.rname_label=error; + rr->rr.soa.serial=0; + rr->rr.soa.refresh=0; + rr->rr.soa.retry=0; + rr->rr.soa.expire=0; + rr->rr.soa.minimum=0; + } + else + { + rr->rr.soa.serial= + ((RFC1035_UINT32)(unsigned char)p[0] << 24) | + ((RFC1035_UINT32)(unsigned char)p[1] << 16) | + ((RFC1035_UINT32)(unsigned char)p[2] << 8) | + (unsigned char)p[3]; + p += 4; + rr->rr.soa.refresh= + ((RFC1035_UINT32)(unsigned char)p[0] << 24) | + ((RFC1035_UINT32)(unsigned char)p[1] << 16) | + ((RFC1035_UINT32)(unsigned char)p[2] << 8) | + (unsigned char)p[3]; + p += 4; + rr->rr.soa.retry= + ((RFC1035_UINT32)(unsigned char)p[0] << 24) | + ((RFC1035_UINT32)(unsigned char)p[1] << 16) | + ((RFC1035_UINT32)(unsigned char)p[2] << 8) | + (unsigned char)p[3]; + p += 4; + rr->rr.soa.expire= + ((RFC1035_UINT32)(unsigned char)p[0] << 24) | + ((RFC1035_UINT32)(unsigned char)p[1] << 16) | + ((RFC1035_UINT32)(unsigned char)p[2] << 8) | + (unsigned char)p[3]; + p += 4; + rr->rr.soa.minimum= + ((RFC1035_UINT32)(unsigned char)p[0] << 24) | + ((RFC1035_UINT32)(unsigned char)p[1] << 16) | + ((RFC1035_UINT32)(unsigned char)p[2] << 8) | + (unsigned char)p[3]; + } + break; + case RFC1035_TYPE_MX: + p=rr->rdata; + if (rr->rdlength < 2) + { + rr->rr.mx.preference=0; + rr->rr.mx.mx_label=error; + } + else + { + rr->rr.mx.preference= + ((unsigned)(unsigned char)p[0] << 8) | + (unsigned char)p[1]; + p += 2; + rr->rr.mx.mx_label=p; + if (rfc1035_replyuncompress(&p, r, 0) == 0 + || p > rr->rdata + rr->rdlength) + { + rr->rr.mx.preference=0; + rr->rr.mx.mx_label=error; + } + } + break; + + case RFC1035_TYPE_HINFO: + p=rr->rdata; + rr->rr.hinfo.hinfo_str=error; + rr->rr.hinfo.os_str=error; + if (rr->rdlength && (unsigned char)*p < rr->rdlength) + { + const char *q=p+1+(unsigned char)*p; + + if (q < rr->rdata + rr->rdlength && + q+(unsigned char)*q < rr->rdata + rr->rdlength) + { + rr->rr.hinfo.hinfo_str=p; + rr->rr.hinfo.os_str=q; + } + } + break; + + case RFC1035_TYPE_MINFO: + rr->rr.minfo.rmailbx_label=p=rr->rdata; + if (rfc1035_replyuncompress(&p, r, 0) == 0 || + p > rr->rdata + rr->rdlength || + (rr->rr.minfo.emailbx_label=p, + rfc1035_replyuncompress(&p, r, 0)) == 0 || + p > rr->rdata + rr->rdlength) + { + rr->rr.minfo.rmailbx_label=error; + rr->rr.minfo.emailbx_label=error; + } + break; + case RFC1035_TYPE_RRSIG: + + p=rr->rdata; + + if (rr->rdlength < 18 || + + ((rr->rr.rrsig.type_covered= + ((unsigned)(unsigned char)p[0] << 8) + | (unsigned char)p[1]), + + (rr->rr.rrsig.algorithm=p[2]), + (rr->rr.rrsig.labels=p[3]), + (rr->rr.rrsig.original_ttl= + ((RFC1035_UINT32)(unsigned char)p[4] << 24) | + ((RFC1035_UINT32)(unsigned char)p[5] << 16) | + ((RFC1035_UINT32)(unsigned char)p[6] << 8) | + (unsigned char)p[7]), + (rr->rr.rrsig.signature_expiration= + ((RFC1035_UINT32)(unsigned char)p[8] << 24) | + ((RFC1035_UINT32)(unsigned char)p[9] << 16) | + ((RFC1035_UINT32)(unsigned char)p[10] << 8) | + (unsigned char)p[11]), + (rr->rr.rrsig.signature_inception= + ((RFC1035_UINT32)(unsigned char)p[12] << 24) | + ((RFC1035_UINT32)(unsigned char)p[13] << 16) | + ((RFC1035_UINT32)(unsigned char)p[14] << 8) | + (unsigned char)p[15]), + (rr->rr.rrsig.key_tag= + ((RFC1035_UINT16)(unsigned char)p[16] << 8) | + (unsigned char)p[17]), + (rr->rr.rrsig.signer_name=(p += 18)), + + rfc1035_replyuncompress(&p, r, 0) == 0) || + p > rr->rdata + rr->rdlength) + { + memset(&rr->rr.rrsig, 0, sizeof(rr->rr.rrsig)); + rr->rr.rrsig.signer_name=error; + break; + } + + rr->rr.rrsig.signature=p; + rr->rr.rrsig.signature_len=rr->rdata + rr->rdlength - p; + break; + + default: + break; + } +} + +/* +** Randomize order of resource records. +*/ + +static void rr_random(struct rfc1035_rr *p, unsigned n) +{ + unsigned i; + + for (i=0; ianptr, rr->ancount); +} + +void rfc1035_rr_rand_ns(struct rfc1035_reply *rr) +{ + rr_random(rr->nsptr, rr->nscount); +} + +void rfc1035_rr_rand_ar(struct rfc1035_reply *rr) +{ + rr_random(rr->arptr, rr->arcount); +} + +void rfc1035_rr_rand(struct rfc1035_reply *rr) +{ + rfc1035_rr_rand_an(rr); + rfc1035_rr_rand_ns(rr); + rfc1035_rr_rand_ar(rr); +} -- cgit v1.2.3