#include #include #include #include #include "netbios.h" void nbnsmessagequestionfree(NbnsMessageQuestion **qp) { NbnsMessageQuestion *q = *qp; if (q) { free(q); *qp = nil; } } void nbnsmessageresourcefree(NbnsMessageResource **rp) { NbnsMessageResource *r = *rp; if (r) { free(r->rdata); free(r); *rp = nil; } } static void questionfree(NbnsMessageQuestion **qp) { while (*qp) { NbnsMessageQuestion *next = (*qp)->next; nbnsmessagequestionfree(qp); *qp = next; } } static void resourcefree(NbnsMessageResource **rp) { while (*rp) { NbnsMessageResource *next = (*rp)->next; nbnsmessageresourcefree(rp); *rp = next; } } void nbnsmessagefree(NbnsMessage **sp) { NbnsMessage *s = *sp; if (s) { questionfree(&s->q); resourcefree(&s->an); resourcefree(&s->ns); resourcefree(&s->ar); free(s); *sp = nil; } } void nbnsmessageaddquestion(NbnsMessage *s, NbnsMessageQuestion *q) { NbnsMessageQuestion **qp; for (qp = &s->q; *qp; qp = &(*qp)->next) ; *qp = q; } NbnsMessageQuestion * nbnsmessagequestionnew(NbName name, ushort type, ushort class) { NbnsMessageQuestion *q; q = mallocz(sizeof(*q), 1); if (q == nil) return nil; nbnamecpy(q->name, name); q->type = type; q->class = class; return q; } NbnsMessageResource * nbnsmessageresourcenew(NbName name, ushort type, ushort class, ulong ttl, int rdlength, uchar *rdata) { NbnsMessageResource *r; r= mallocz(sizeof(*r), 1); if (r == nil) return nil; nbnamecpy(r->name, name); r->type = type; r->class = class; r->ttl = ttl; r->rdlength = rdlength; if (rdlength) { r->rdata = malloc(rdlength); if (r->rdata == nil) { free(r); return nil; } memcpy(r->rdata, rdata, rdlength); } return r; } void nbnsmessageaddresource(NbnsMessageResource **rp, NbnsMessageResource *r) { for (; *rp; rp = &(*rp)->next) ; *rp = r; } NbnsMessage * nbnsmessagenew(void) { return mallocz(sizeof(NbnsMessage), 1); } static int resourcedecode(NbnsMessageResource **headp, int count, uchar *ap, uchar *pp, uchar *ep) { uchar *p = pp; int i; for (i = 0; i < count; i++) { int n; NbnsMessageResource *r, **rp; r = mallocz(sizeof(NbnsMessageResource), 1); if (r == nil) return -1; for (rp = headp; *rp; rp = &(*rp)->next) ; *rp = r; n = nbnamedecode(ap, p, ep, r->name); if (n == 0) return -1; p += n; if (p + 10 > ep) return -1; r->type = nhgets(p); p += 2; r->class = nhgets(p); p += 2; r->ttl = nhgetl(p); p += 4; r->rdlength = nhgets(p); p += 2; //print("rdlength %d\n", r->rdlength); if (r->rdlength) { if (p + r->rdlength > ep) return -1; r->rdata = malloc(r->rdlength); if (r == nil) return -1; memcpy(r->rdata, p, r->rdlength); p += r->rdlength; } } return p - pp; } NbnsMessage * nbnsconvM2S(uchar *ap, int nap) { uchar *p, *ep; ushort qdcount, ancount, nscount, arcount, ctrl; int i; NbnsMessage *s; int n; if (nap < 12) return nil; p = ap; ep = ap + nap; s = nbnsmessagenew(); if (s == nil) return nil; s->id = nhgets(p); p+= 2; ctrl = nhgets(p); p += 2; qdcount = nhgets(p); p += 2; ancount = nhgets(p); p += 2; nscount = nhgets(p); p += 2; arcount = nhgets(p); p += 2; s->response = (ctrl & NbnsResponse) != 0; s->opcode = (ctrl >> NbnsOpShift) & NbnsOpMask; s->broadcast = (ctrl & NbnsFlagBroadcast) != 0; s->recursionavailable = (ctrl & NbnsFlagRecursionAvailable) != 0; s->recursiondesired = (ctrl & NbnsFlagRecursionDesired) != 0; s->truncation = (ctrl & NbnsFlagTruncation) != 0; s->authoritativeanswer = (ctrl & NbnsFlagAuthoritativeAnswer) != 0; s->rcode = s->response ? (ctrl & NbnsRcodeMask) : 0; for (i = 0; i < qdcount; i++) { int n; NbName nbname; NbnsMessageQuestion *q; ushort type, class; n = nbnamedecode(ap, p, ep, nbname); if (n == 0) goto fail; p += n; if (p + 4 > ep) goto fail; type = nhgets(p); p += 2; class = nhgets(p); p += 2; q = nbnsmessagequestionnew(nbname, type, class); if (q == nil) goto fail; nbnsmessageaddquestion(s, q); } n = resourcedecode(&s->an, ancount, ap, p, ep); if (n < 0) goto fail; p += n; n = resourcedecode(&s->ns, nscount, ap, p, ep); if (n < 0) goto fail; p += n; n = resourcedecode(&s->ar, arcount, ap, p, ep); if (n < 0) goto fail; //print("arcount %d\n", arcount); return s; fail: nbnsmessagefree(&s); return nil; } static int resourceencode(NbnsMessageResource *r, uchar *ap, uchar *ep) { uchar *p = ap; for (; r; r = r->next) { int n = nbnameencode(p, ep, r->name); if (n == 0) return -1; p += n; if (p + 10 > ep) return -1; hnputs(p, r->type); p += 2; hnputs(p, r->class); p += 2; hnputl(p, r->ttl); p += 4; hnputs(p, r->rdlength); p += 2; if (p + r->rdlength > ep) return -1; memcpy(p, r->rdata, r->rdlength); p += r->rdlength; } return p - ap; } int nbnsconvS2M(NbnsMessage *s, uchar *ap, int nap) { uchar *p = ap; uchar *ep = ap + nap; ushort ctrl; NbnsMessageQuestion *q; NbnsMessageResource *r; int k; int n; if (p + 12 > ep) return 0; hnputs(p, s->id); p+= 2; ctrl = (s->opcode & NbnsOpMask) << NbnsOpShift; if (s->response) { ctrl |= s->rcode & NbnsRcodeMask; ctrl |= NbnsResponse; } if (s->broadcast) ctrl |= NbnsFlagBroadcast; if (s->recursionavailable) ctrl |= NbnsFlagRecursionAvailable; if (s->recursiondesired) ctrl |= NbnsFlagRecursionDesired; if (s->truncation) ctrl |= NbnsFlagTruncation; if (s->authoritativeanswer) ctrl |= NbnsFlagAuthoritativeAnswer; hnputs(p, ctrl); p += 2; for (q = s->q, k = 0; q; k++, q = q->next) ; hnputs(p, k); p += 2; for (r = s->an, k = 0; r; k++, r = r->next) ; hnputs(p, k); p += 2; for (r = s->ns, k = 0; r; k++, r = r->next) ; hnputs(p, k); p += 2; for (r = s->ar, k = 0; r; k++, r = r->next) ; hnputs(p, k); p += 2; for (q = s->q; q; q = q->next) { int n = nbnameencode(p, ep, q->name); if (n == 0) return 0; p += n; if (p + 4 > ep) return 0; hnputs(p, q->type); p += 2; hnputs(p, q->class); p += 2; } n = resourceencode(s->an, p, ep); if (n < 0) return 0; p += n; n = resourceencode(s->ns, p, ep); if (n < 0) return 0; p += n; n = resourceencode(s->ar, p, ep); if (n < 0) return 0; p += n; return p - ap; }