/src/nbdgm.c

https://bitbucket.org/opexxx/lanmap2 · C · 215 lines · 166 code · 16 blank · 33 comment · 27 complexity · 661b03ee4eaf473a623d81159d0de0e8 MD5 · raw file

  1. /* ex: set ff=dos ts=2 et: */
  2. /* $Id$ */
  3. /*
  4. * Copyright 2008 Ryan Flynn
  5. * All rights reserved.
  6. */
  7. /*
  8. * NetBIOS Datagram
  9. */
  10. #include <assert.h>
  11. #include <stdio.h>
  12. #include <arpa/inet.h>
  13. #include "env.h"
  14. #include "types.h"
  15. #include "prot.h"
  16. #include "report.h"
  17. #include "util.h"
  18. #include "udp.h"
  19. #include "ipv4.h"
  20. #include "nbdgm.h"
  21. static const nb_dgm Dgm;
  22. static const nb_dgm_name DgmName;
  23. static int init (void);
  24. static size_t parse(char *, size_t, parse_frame *, const parse_status *);
  25. static size_t dump(const parse_frame *, int options, FILE *);
  26. static int test_udp(const char *, size_t, const parse_status *);
  27. static const prot_parent Test[] = {
  28. { PROT_UDP, test_udp }
  29. };
  30. /**
  31. * exported interface
  32. */
  33. const prot_iface Iface_NBDgm = {
  34. DINIT(id, PROT_NBDGM),
  35. DINIT(osi, OSI_App),
  36. DINIT(shortname, "NB-Dgm"),
  37. DINIT(propername, "NetBIOS Datagram"),
  38. DINIT(init, init),
  39. DINIT(unload, NULL),
  40. DINIT(parse, parse),
  41. DINIT(dump, dump),
  42. DINIT(addr_type, NULL),
  43. DINIT(addr_from, NULL),
  44. DINIT(addr_to, NULL),
  45. DINIT(addr_format, NULL),
  46. DINIT(addr_local, NULL),
  47. DINIT(parents, sizeof Test / sizeof Test[0]),
  48. DINIT(parent, Test)
  49. };
  50. /**
  51. * Windows NB Dgms are sent between reserved ports on both machines (TODO: Reference needed)
  52. */
  53. static int test_udp(const char *buf, size_t len, const parse_status *st)
  54. {
  55. const udp *u = (udp *)st->frame[st->frames - 1].off;
  56. return NBDGM_UDP_PORT == u->srcport &&
  57. NBDGM_UDP_PORT == u->dstport;
  58. }
  59. /**
  60. * Each octet in a NetBIOS name is split into 4-bit nibbles and stored as
  61. * an uppercase ASCII character 'A' + n
  62. * @ref #2
  63. */
  64. size_t nb_decode_name(char *wr, size_t wrlen, const char *rd, size_t rdlen)
  65. {
  66. const char *owr = wr;
  67. assert((unsigned)rdlen < 2048);
  68. assert(wrlen >= rdlen / 2);
  69. if (0 == (rdlen & 1)) {
  70. while (rdlen -= 2) {
  71. *wr++ = (u8)(((rd[0]-'A') << 4) | ((rd[1]-'A') & 0xF));
  72. rd += 2;
  73. if ('\x20' == *(wr-1)) {
  74. wr--;
  75. break;
  76. }
  77. }
  78. }
  79. return (size_t)(wr-owr);
  80. }
  81. static ptrdiff_t do_parse_names(nb_dgm *d, size_t len, parse_frame *f)
  82. {
  83. static nb_dgm_name name;
  84. char *orig = (char *)d + sizeof *d, /* byte after */
  85. *curr = orig;
  86. size_t l;
  87. /* attach and initialize */
  88. name.head = d;
  89. name.srcname = NULL;
  90. name.dstname = NULL;
  91. name.srcnamelen = 0;
  92. name.dstnamelen = 0;
  93. f->pass = &name;
  94. /* parse src name */
  95. l = memcspn(curr, len, "\0", 1);
  96. if (l >= len - 2) /* too long, no space for dest */
  97. return 0;
  98. name.srcname = curr;
  99. name.srcnamelen = l;
  100. curr += l, len -= l;
  101. /* skip \0 */
  102. l = memspn(curr, len, "\0", 1);
  103. curr += l, len -= l;
  104. /* parse dst name */
  105. l = memcspn(curr, len, "\0", 1);
  106. name.dstname = curr;
  107. name.dstnamelen = l;
  108. curr += l, len -= l;
  109. /* skip \0 */
  110. l = memspn(curr, len, "\0", 1);
  111. curr += l, len -= l;
  112. /* adjust strings */
  113. if (0 == name.srcnamelen || '\x20' != name.srcname[0] ||
  114. 0 == name.dstnamelen || '\x20' != name.dstname[0])
  115. return 0;
  116. name.srcname++;
  117. name.srcnamelen--;
  118. name.srcnamelen = nb_decode_name(name.srcname, name.srcnamelen, name.srcname, name.srcnamelen);
  119. name.dstname++;
  120. name.dstnamelen--;
  121. name.dstnamelen = nb_decode_name(name.dstname, name.dstnamelen, name.dstname, name.dstnamelen);
  122. return curr - orig;
  123. }
  124. /**
  125. * @return number of octets used by this protocol, or zero upon error
  126. */
  127. static size_t parse(char *buf, size_t len, parse_frame *f, const parse_status *st)
  128. {
  129. nb_dgm *d = (nb_dgm *)buf;
  130. size_t consumed;
  131. /* sanity check packet */
  132. if (sizeof *d > len)
  133. return 0;
  134. /* convert endianness */
  135. d->id = ntohs(d->id);
  136. d->len = ntohs(d->len);
  137. d->srcport = ntohs(d->srcport);
  138. d->off = ntohs(d->off);
  139. /* parse variable-length names off end */
  140. consumed = do_parse_names(d, len - sizeof *d, f);
  141. if (0 == consumed)
  142. return 0;
  143. consumed += sizeof *d;
  144. return consumed;
  145. }
  146. size_t dump(const parse_frame *f, int options, FILE *out)
  147. {
  148. const nb_dgm_name *n = f->pass;
  149. const nb_dgm *d = n->head;
  150. int bytes = fprintf(out,
  151. "%s "
  152. "msgtype=%u snt=%u frag(f=%u more=%u) id=0x%04x "
  153. "src=%u.%u.%u.%u:%hu "
  154. "len=%hu off=%hu srcname=\"",
  155. Iface_NBDgm.shortname,
  156. d->msgtype, d->snt, d->f, d->m, d->id,
  157. d->srcip[0], d->srcip[1], d->srcip[2], d->srcip[3], d->srcport,
  158. d->len, d->off);
  159. bytes += dump_chars((char *)n->srcname, n->srcnamelen, out);
  160. bytes += fprintf(out, "\" dstname=\"");
  161. bytes += dump_chars((char *)n->dstname, n->dstnamelen, out);
  162. bytes += fprintf(out, "\"\n");
  163. /* report */
  164. {
  165. char srcbuf[64],
  166. ipbuf[64];
  167. const parse_frame *fi = f-2;
  168. const ipv4 *ip = fi->off;
  169. assert(PROT_IPv4 == fi->id);
  170. ipv4_addr_format(ipbuf, sizeof ipbuf, ip->src);
  171. dump_chars_buf(srcbuf, sizeof srcbuf, (char *)n->srcname, n->srcnamelen);
  172. if ('\0' != srcbuf[0])
  173. rep_addr("4", ipbuf, "N", srcbuf, Iface_NBDgm.shortname, 1);
  174. }
  175. return (size_t)bytes;
  176. }
  177. static int init(void)
  178. {
  179. printf("offsetof(nb_dgm, id) -> %u\n",
  180. offsetof(nb_dgm, id));
  181. assert(2 == offsetof(nb_dgm, id));
  182. assert(4 == offsetof(nb_dgm, srcip));
  183. assert(8 == offsetof(nb_dgm, srcport));
  184. printf("offsetof(nb_dgm, srcport) -> %u\n",
  185. offsetof(nb_dgm, srcport));
  186. assert(10 == offsetof(nb_dgm, len));
  187. printf("offsetof(nb_dgm, len) -> %u\n",
  188. offsetof(nb_dgm, len));
  189. assert(12 == offsetof(nb_dgm, off));
  190. printf("sizeof Dgm -> %u\n", sizeof Dgm);
  191. assert(14 == sizeof Dgm);
  192. return 1;
  193. }
  194. #ifdef TEST
  195. int main(void)
  196. {
  197. return 0;
  198. }
  199. #endif