static void test(void) { unsigned i; for (i = 0; i < sizeof TestCase / sizeof TestCase[0]; i++) { char p0fbuf[256]; parse_frame pf = { PROT_IPv4, T->iplen, T->ip, NULL }; parse_frame pf2 = { PROT_TCP, T->tcplen, T->tcp, NULL }; /* print */ printf("#%2u:\n", i); /* parse ip and tcp in order */ ipv4_parse(T->ip, T->iplen, &pf, NULL); tcp_parse(T->tcp, T->tcplen, &pf2, NULL); /* generate fingerprint */ p0f2str(p0fbuf, sizeof p0fbuf, (tcp*)T->tcp, T->tcplen, (ipv4*)T->ip, T->iplen, 0); if (0 == strcmp(p0fbuf, T->expected_p0f)) { printf("OK\n"); } else { printf("%s p0f: %s\nexpected: %s)\n", "!!", p0fbuf, T->expected_p0f); printf(" IP len=%u ", T->iplen); dump_chars(T->ip, T->iplen, stdout); fputc('\n', stdout); printf(" TCP len=%u ", T->tcplen); dump_chars(T->tcp, T->tcplen, stdout); fputc('\n', stdout); ipv4_dump(&pf, 0, stdout); tcp_dump(&pf2, 0, stdout); } T++; } }
static void test(void) { unsigned i; for (i = 0; i < sizeof TestCase / sizeof TestCase[0]; i++) { parse_frame pf = { PROT_SMB, T->smblen, T->smb, NULL }; parse_frame pf2 = { PROT_BROWSE, T->browselen, T->browse, NULL }; size_t smbbytes, browsebytes; /* print */ printf("#%2u:\n", i); printf(" SMB len=%lu ", T->smblen); dump_chars(T->smb, T->smblen, stdout); fputc('\n', stdout); printf(" BROWSE len=%lu ", T->browselen); dump_chars(T->browse, T->browselen, stdout); fputc('\n', stdout); /* parse ip and tcp in order */ smbbytes = smb_parse(T->smb, T->smblen, &pf, NULL); printf("smb parsed %u bytes: ", (unsigned)smbbytes); dump_chars((char *)T->smb, smbbytes, stdout); fputc('\n', stdout); browsebytes = parse(T->browse, T->browselen, &pf2, NULL); printf("browse parsed %u bytes: ", (unsigned)browsebytes); dump_chars((char *)T->browse, browsebytes, stdout); fputc('\n', stdout); smb_dump(&pf, 0, stdout); dump(&pf2, 0, stdout); assert(smbbytes == T->smblen); assert(browsebytes == T->browselen); T++; } }
static void test(void) { parse_frame f = { PROT_SMB, sizeof Sample - 1, Sample, NULL }; size_t bytes; printf("Sample(%u bytes):", (unsigned)f.len); dump_chars(Sample, f.len, stdout); fputc('\n', stdout); bytes = smb_parse(f.off, f.len, &f, NULL); printf("Consumed(%u bytes):", (unsigned)bytes); dump_chars(Sample, bytes, stdout); fputc('\n', stdout); dump(&f, 0, stdout); }
/** * parse a variable-length DNS name pointed at by 'buf'; do not exceed * 'len' bytes * @ref #1 S3.1 */ size_t dns_calc_len_name(const char *buf, size_t len) { const char *obuf = buf; size_t olen = len; while (len > 0) { if (0xC0 == (u8)*buf) { if (len < 2) buf += len, len = 0; else buf += 2, len -= 2; break; } else if ((u8)*buf >= len) { buf += len, len = 0; break; } else if (0 == *buf) { buf++, len--; break; } else { len -= *buf + 1; buf += *buf + 1; } } #if 0 printf("%s name(%u bytes)=", __func__, (unsigned)(buf - obuf)); dump_chars(obuf, (unsigned)(buf - obuf), stdout); fputc('\n', stdout); #endif assert((size_t)(buf - obuf) <= olen); return (size_t)(buf - obuf); }
static void test(void) { unsigned i; for (i = 0; i < sizeof TestCase / sizeof TestCase[0]; i++) { parse_frame f = { PROT_SMB, T->len, T->txt, NULL }; size_t bytes; printf("Sample(%u bytes):", (unsigned)f.len); dump_chars(f.off, f.len, stdout); fputc('\n', stdout); bytes = smb_parse(f.off, f.len, &f, NULL); printf("Consumed(%u bytes):", (unsigned)bytes); dump_chars(f.off, bytes, stdout); fputc('\n', stdout); smb_dump(&f, 0, stdout); } }
size_t dump(const parse_frame *f, int options, FILE *out) { const tivoconn *t = (tivoconn *)f->off; const tivoconn_kv *kv = f->pass; const char *ver = (char *)f->off + sizeof t->tivoconnect + 1; int bytes = fprintf(out, "%s ver=%c\n", Iface_TiVoConn.shortname, *ver); unsigned i; for (i = 1; i < kv->cnt; i++) { /* yes, start at one. skip TiVoConn header */ bytes += fprintf(out, " %-8.*s %.*s\n", kv->item[i].keystr.len, kv->item[i].keystr.start, kv->item[i].val.len, kv->item[i].val.start); if (Key_Platform == i) { char ipbuf[48]; const parse_frame *fi = f-2; const ipv4 *ip = fi->off; assert(PROT_IPv4 == fi->id); (void)ipv4_addr_format(ipbuf, sizeof ipbuf, ip->src); rep_hint("4", ipbuf, "TivoConn.Platform", kv->item[i].val.start, kv->item[i].val.len); } } #if 0 bytes += dump_chars(ver + 2, f->len - ((ver + 2) - (char *)f->off), stdout); fputc('\n', stdout); bytes++; #endif return (size_t)bytes; }
/* * NAME: dump_program() * DESCRIPTION: output the program */ static void dump_program(control *ctrl) { if (ctrl->progsize != 0) { printf("\nstatic char program[] = {\n"); size = 0; dump_chars(ctrl->prog, ctrl->progsize); printf("\n};\n"); } }
static void test(void) { unsigned i; for (i = 0; i < sizeof TestCase / sizeof TestCase[0]; i++) { parse_frame pf = { PROT_DNS, T->len, T->txt, NULL }; printf("#%2u: ", i); dump_chars(T->txt, T->len, stdout); dns_parse(T->txt, T->len, &pf, NULL); dump(&pf, 0, stdout); fputc('\n', stdout); T++; } }
size_t dns_calc_len_rr(const char *buf, size_t len) { const char *name = buf; size_t namelen = dns_calc_len_name(name, len); const dns_answer *a; size_t bytes = len; if (namelen + sizeof *a > len) return len; a = (dns_answer *)(buf + namelen); bytes = namelen + sizeof *a + ntohs(a->rrlen); #if 0 printf("name(%u byes)=", namelen); dump_chars(name, namelen, stdout); fputc('\n', stdout); printf("answer(%u byes)=", sizeof *a); dump_chars((char*)a, sizeof *a, stdout); fputc('\n', stdout); #endif if (bytes > len) bytes = len; return bytes; }
static size_t dump_resp(const parse_frame *f, int opt, FILE *out, const http *h) { const http_resp *r = &h->data.resp; int bytes = fprintf(out, "ver=%.*s code=%.*s (%.*s)\n", r->ver.len, r->ver.start, r->code.len, r->code.start, r->desc.len, r->desc.start); bytes += http_dump_headers(&r->headers, opt, out); bytes += dump_chars(r->contents.start, r->contents.len, out); fputc('\n', out); bytes++; return (size_t)bytes; }
static size_t parse_domwg(const browse *b, char *buf, size_t len, const parse_status *st) { const struct dom_wg *d = (struct dom_wg *)buf; size_t bytes, namelen; if (len < sizeof *d) return 0; namelen = memcspn((char *)d->master_name, len - sizeof *d, "\x00", 1); bytes = sizeof *d + namelen; printf("%s %s (bytes=%u):", __FILE__, __func__, (unsigned)bytes); dump_chars((char *)d, bytes, stdout); fputc('\n', stdout); return bytes; }
static void test(void) { unsigned i; for (i = 0; i < sizeof TestCase / sizeof TestCase[0]; i++) { size_t len = T->len ? T->len : strlen(T->txt); parse_frame pf = { PROT_GNUTELLA, len, T->txt, NULL }; printf("#%2u: ", i); dump_chars(T->txt, len, stdout); fputc('\n', stdout); parse(T->txt, len, &pf, NULL); dump(&pf, 0, stdout); fputc('\n', stdout); T++; } }
/** * parse host comment at the end; * NOTE: this *should* go until the end of the packet; however some instances * (i.e. BROWSER over LLC) pad the message with NUL bytes. */ static size_t parse_host(const browse *b, char *buf, size_t len, const parse_status *st) { const struct browse_hostann *h = (struct browse_hostann *)buf; size_t bytes, commentlen; if (len < sizeof *h) return 0; commentlen = memcspn((char *)h->host_comment, len - sizeof *h, "\x00", 1); bytes = sizeof *h + commentlen; if (bytes > len) bytes = len; printf("%s %s (bytes=%u):", __FILE__, __func__, (unsigned)bytes); dump_chars((char *)h, bytes, stdout); fputc('\n', stdout); return bytes; }
static size_t parse_elect(const browse *b, char *buf, size_t len, const parse_status *st) { struct electreq *e = (struct electreq *)buf; size_t bytes, namelen; if (len < sizeof *e) return 0; namelen = memcspn((char *)e->name, len - sizeof *e, "\x00", 1); bytes = sizeof *e + namelen; printf("%s %s (bytes=%u):", __FILE__, __func__, (unsigned)bytes); dump_chars((char *)e, bytes, stdout); fputc('\n', stdout); /* fix endianness */ e->uptime = ltohl(e->uptime); assert(bytes == len); return bytes; }
static void test(void) { unsigned i; for (i = 0; i < sizeof TestCase / sizeof TestCase[0]; i++) { http_headers h; size_t len, bytes; len = T->len ? T->len : strlen(T->txt); printf("#%2u: ", i); dump_chars(T->txt, len, stdout); fflush(stdout); memset(&h, 0, sizeof h); bytes = http_parse_headers(T->txt, len, &h); printf(" len=%u parsed=%u\n", (unsigned)len, (unsigned)bytes); (void)http_dump_headers(&h, 0, stdout); assert(bytes <= len); T++; } }
static size_t dump_qd(const char *buf, size_t len, FILE *out) { char namebuf[1024]; const char *name = (const char *)buf; size_t namel = memcspn(name, len, "\x00", 1); int bytes = 0; const dns_query *q = (dns_query *)(buf + namel + 1); (void)dump_chars_buf(namebuf, sizeof namebuf, buf, namel); #if 0 printf("len=%u name[namel=%u]=%s name[10]=", (unsigned)len, (unsigned)namel, namebuf); dump_chars(name, 10, stdout); fputc('\n', stdout); #endif bytes = fprintf(out, " qd name=%s type=%hu(%s) class=%hu(%s)\n", namebuf, ntohs(q->type), type2str(ntohs(q->type)), ntohs(q->class_), class2str(ntohs(q->class_))); return bytes; }
/* * NAME: dump_strings() * DESCRIPTION: output the strings */ static void dump_strings(control *ctrl) { int i; long len; if (ctrl->nstrings != 0) { printf("\nstatic dstrconst sstrings[] = {\n"); len = 0; for (i = 0; i < ctrl->nstrings; i++) { printf("{ %ld, %u },\n", len, ctrl->strings[i]->len); len += ctrl->strings[i]->len; } printf("};\n\nstatic char stext[] = {\n"); size = 0; for (i = 0; i < ctrl->nstrings; i++) { dump_chars(ctrl->strings[i]->text, ctrl->strings[i]->len); } printf("\n};\n"); } }
/** * @return number of octets used by this protocol, or zero upon error */ size_t smb_parse(char *buf, size_t len, parse_frame *f, const parse_status *st) { smb_hdr *h = (smb_hdr *)buf; size_t bytes; /* sanity check packet */ if (sizeof *h > len) return 0; /* convert endianness */ h->treeid = ntohs(h->treeid); h->procid = ntohs(h->procid); h->userid = ntohs(h->userid); bytes = do_parse(buf + sizeof *h, len - sizeof *h, h); #if 1 printf("%s %s do_parse=%u bytes: ", __FILE__, __func__, (unsigned)bytes); dump_chars(buf + sizeof *h, bytes, stdout); fputc('\n', stdout); #endif bytes += sizeof *h; return bytes; }
static size_t do_parse(char *buf, size_t len) { const char *obuf = buf; cdp_data *d = (cdp_data *)buf; while (len >= sizeof d->head) { d->head.type = ntohs(d->head.type); d->head.bytes = ntohs(d->head.bytes); if (d->head.bytes > len) break; if (d->head.type < Data_COUNT && DataHandle[d->head.type].parse) { (*DataHandle[d->head.type].parse)(d, (char *)d + sizeof d->head, d->head.bytes - sizeof d->head); printf("%s %s (len=%u) bytes=%hu contents=", __FILE__, __func__, (unsigned)len, d->head.bytes); dump_chars((char *)d, d->head.bytes, stdout); fputc('\n', stdout); } len -= d->head.bytes; d = (cdp_data *)((char *)d + d->head.bytes); } return (size_t)((char *)d - obuf); }
/** * given an already-overlayed and endian-adjusted 'dns' struct and the rest of * the packet, calculate the length of the following variable-length Response Records */ size_t dns_calc_len(const char *buf, size_t len, const dns *d) { const struct { u16 cnt; size_t (*f)(const char *, size_t); } parse[4] = { { d->qdcnt, dns_calc_len_qd }, { d->ancnt, dns_calc_len_rr }, { d->nscnt, dns_calc_len_rr }, { d->arcnt, dns_calc_len_rr } }; const char *obuf = buf; const size_t olen = len; size_t bytes; unsigned i; printf("%s:%s len=%u d=%p\n", __FILE__, __func__, (unsigned)len, (void *)d); for (i = 0; i < sizeof parse / sizeof parse[0]; i++) { u16 cnt = parse[i].cnt; if (cnt) printf("%s:%s i=%u cnt=%hu\n", __FILE__, __func__, i, cnt); while (cnt--) { size_t b = (*parse[i].f)(buf, len); printf("%s:%s i=%u cnt=%hu consumed=%hu bytes=", __FILE__, __func__, i, cnt, (unsigned)b); dump_chars(buf, b, stdout); fputc('\n', stdout); assert(b <= len); /* adjust buffer/length for next pass */ buf += b, len -= b; } } bytes = (size_t)(buf - obuf); printf("bytes=%u olen=%u\n", (unsigned)bytes, (unsigned)olen); if (bytes != olen) printf("!!! You didn't consume the whole message!\n"); return bytes; }
/** * SMB header has been parsed, parse rest of msg * @return number of bytes consumed */ static size_t do_parse(char *buf, size_t len, const smb_hdr *h) { size_t bytes = 0; printf("do_parse len=%u buf=", (unsigned)len); dump_chars(buf, len, stdout); fputc('\n', stdout); switch ((enum SMB_Cmd)h->cmd) { case SMB_Cmd_TransReq: { /* TODO: break out into own function */ size_t namelen; smb_trans_req *r = (smb_trans_req *)buf; if (sizeof *r > len) return 0; /* convert endianness */ r->totalparam = ltohs(r->totalparam); r->totaldata = ltohs(r->totaldata); r->maxparam = ltohs(r->maxparam); r->maxdata = ltohs(r->maxdata); r->param = ltohs(r->param); r->paramoffset = ltohs(r->paramoffset); r->data = ltohs(r->data); r->dataoffset = ltohs(r->dataoffset); r->mailslot.opcode = ltohs(r->mailslot.opcode); r->mailslot.priority= ltohs(r->mailslot.priority); r->mailslot.class_ = ltohs(r->mailslot.class_); r->mailslot.bytes = ltohs(r->mailslot.bytes); /* calculate length of name */ namelen = memcspn((char *)r->name, len - sizeof *r - 1, "\x00", 1); bytes = namelen + sizeof *r; /* includes trailing \0 */ } break; default: break; } return bytes; }
static size_t dump(const parse_frame *f, int options, FILE *out) { int bytes = dump_chars(f->off, f->len, stdout); return (size_t)bytes; }