NameServicePacket.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. // This code is derived from jcifs smb client library <jcifs at samba dot org>
  2. // Ported by J. Arturo <webmaster at komodosoft dot net>
  3. //
  4. // This library is free software; you can redistribute it and/or
  5. // modify it under the terms of the GNU Lesser General Public
  6. // License as published by the Free Software Foundation; either
  7. // version 2.1 of the License, or (at your option) any later version.
  8. //
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. // Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public
  15. // License along with this library; if not, write to the Free Software
  16. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. using System.Net;
  18. using SharpCifs.Util;
  19. using SharpCifs.Util.Sharpen;
  20. namespace SharpCifs.Netbios
  21. {
  22. internal abstract class NameServicePacket
  23. {
  24. internal const int Query = 0;
  25. internal const int Wack = 7;
  26. internal const int FmtErr = 0x1;
  27. internal const int SrvErr = 0x2;
  28. internal const int ImpErr = 0x4;
  29. internal const int RfsErr = 0x5;
  30. internal const int ActErr = 0x6;
  31. internal const int CftErr = 0x7;
  32. internal const int NbIn = 0x00200001;
  33. internal const int NbstatIn = 0x00210001;
  34. internal const int Nb = 0x0020;
  35. internal const int Nbstat = 0x0021;
  36. internal const int In = 0x0001;
  37. internal const int A = 0x0001;
  38. internal const int Ns = 0x0002;
  39. internal const int Null = 0x000a;
  40. internal const int HeaderLength = 12;
  41. internal const int OpcodeOffset = 2;
  42. internal const int QuestionOffset = 4;
  43. internal const int AnswerOffset = 6;
  44. internal const int AuthorityOffset = 8;
  45. internal const int AdditionalOffset = 10;
  46. // opcode
  47. // rcode
  48. // type/class
  49. // header field offsets
  50. internal static void WriteInt2(int val, byte[] dst, int dstIndex)
  51. {
  52. dst[dstIndex++] = unchecked((byte)((val >> 8) & unchecked(0xFF)));
  53. dst[dstIndex] = unchecked((byte)(val & unchecked(0xFF)));
  54. }
  55. internal static void WriteInt4(int val, byte[] dst, int dstIndex)
  56. {
  57. dst[dstIndex++] = unchecked((byte)((val >> 24) & unchecked(0xFF)));
  58. dst[dstIndex++] = unchecked((byte)((val >> 16) & unchecked(0xFF)));
  59. dst[dstIndex++] = unchecked((byte)((val >> 8) & unchecked(0xFF)));
  60. dst[dstIndex] = unchecked((byte)(val & unchecked(0xFF)));
  61. }
  62. internal static int ReadInt2(byte[] src, int srcIndex)
  63. {
  64. return ((src[srcIndex] & unchecked(0xFF)) << 8) + (src[srcIndex + 1] & unchecked(
  65. 0xFF));
  66. }
  67. internal static int ReadInt4(byte[] src, int srcIndex)
  68. {
  69. return ((src[srcIndex] & unchecked(0xFF)) << 24)
  70. + ((src[srcIndex + 1] & unchecked(0xFF)) << 16)
  71. + ((src[srcIndex + 2] & unchecked(0xFF)) << 8)
  72. + (src[srcIndex + 3] & unchecked(0xFF));
  73. }
  74. internal static int ReadNameTrnId(byte[] src, int srcIndex)
  75. {
  76. return ReadInt2(src, srcIndex);
  77. }
  78. internal int AddrIndex;
  79. internal NbtAddress[] AddrEntry;
  80. internal int NameTrnId;
  81. internal int OpCode;
  82. internal int ResultCode;
  83. internal int QuestionCount;
  84. internal int AnswerCount;
  85. internal int AuthorityCount;
  86. internal int AdditionalCount;
  87. internal bool Received;
  88. internal bool IsResponse;
  89. internal bool IsAuthAnswer;
  90. internal bool IsTruncated;
  91. internal bool IsRecurDesired;
  92. internal bool IsRecurAvailable;
  93. internal bool IsBroadcast;
  94. internal Name QuestionName;
  95. internal Name RecordName;
  96. internal int QuestionType;
  97. internal int QuestionClass;
  98. internal int RecordType;
  99. internal int RecordClass;
  100. internal int Ttl;
  101. internal int RDataLength;
  102. internal IPAddress Addr;
  103. public NameServicePacket()
  104. {
  105. IsRecurDesired = true;
  106. IsBroadcast = true;
  107. QuestionCount = 1;
  108. QuestionClass = In;
  109. }
  110. internal virtual int WriteWireFormat(byte[] dst, int dstIndex)
  111. {
  112. int start = dstIndex;
  113. dstIndex += WriteHeaderWireFormat(dst, dstIndex);
  114. dstIndex += WriteBodyWireFormat(dst, dstIndex);
  115. return dstIndex - start;
  116. }
  117. internal virtual int ReadWireFormat(byte[] src, int srcIndex)
  118. {
  119. int start = srcIndex;
  120. srcIndex += ReadHeaderWireFormat(src, srcIndex);
  121. srcIndex += ReadBodyWireFormat(src, srcIndex);
  122. return srcIndex - start;
  123. }
  124. internal virtual int WriteHeaderWireFormat(byte[] dst, int dstIndex)
  125. {
  126. int start = dstIndex;
  127. WriteInt2(NameTrnId, dst, dstIndex);
  128. dst[dstIndex + OpcodeOffset] = unchecked(
  129. (byte)(
  130. (IsResponse
  131. ? unchecked(0x80)
  132. : unchecked(0x00))
  133. + ((OpCode << 3) & unchecked(0x78))
  134. + (IsAuthAnswer
  135. ? unchecked(0x04)
  136. : unchecked(0x00))
  137. + (IsTruncated
  138. ? unchecked(0x02)
  139. : unchecked(0x00))
  140. + (IsRecurDesired
  141. ? unchecked(0x01)
  142. : unchecked(0x00))
  143. )
  144. );
  145. dst[dstIndex + OpcodeOffset + 1] = unchecked(
  146. (byte)(
  147. (IsRecurAvailable
  148. ? unchecked(0x80)
  149. : unchecked(0x00))
  150. + (IsBroadcast
  151. ? unchecked(0x10)
  152. : unchecked(0x00))
  153. + (ResultCode & unchecked(0x0F))
  154. )
  155. );
  156. WriteInt2(QuestionCount, dst, start + QuestionOffset);
  157. WriteInt2(AnswerCount, dst, start + AnswerOffset);
  158. WriteInt2(AuthorityCount, dst, start + AuthorityOffset);
  159. WriteInt2(AdditionalCount, dst, start + AdditionalOffset);
  160. return HeaderLength;
  161. }
  162. internal virtual int ReadHeaderWireFormat(byte[] src, int srcIndex)
  163. {
  164. NameTrnId = ReadInt2(src, srcIndex);
  165. IsResponse = ((src[srcIndex + OpcodeOffset] & unchecked(0x80)) == 0)
  166. ? false
  167. : true;
  168. OpCode = (src[srcIndex + OpcodeOffset] & unchecked(0x78)) >> 3;
  169. IsAuthAnswer = ((src[srcIndex + OpcodeOffset] & unchecked(0x04)) == 0)
  170. ? false
  171. : true;
  172. IsTruncated = ((src[srcIndex + OpcodeOffset] & unchecked(0x02)) == 0)
  173. ? false
  174. : true;
  175. IsRecurDesired = ((src[srcIndex + OpcodeOffset] & unchecked(0x01)) == 0)
  176. ? false
  177. : true;
  178. IsRecurAvailable = ((src[srcIndex + OpcodeOffset + 1] & unchecked(0x80)) == 0)
  179. ? false
  180. : true;
  181. IsBroadcast = ((src[srcIndex + OpcodeOffset + 1] & unchecked(0x10)) == 0)
  182. ? false
  183. : true;
  184. ResultCode = src[srcIndex + OpcodeOffset + 1] & unchecked(0x0F);
  185. QuestionCount = ReadInt2(src, srcIndex + QuestionOffset);
  186. AnswerCount = ReadInt2(src, srcIndex + AnswerOffset);
  187. AuthorityCount = ReadInt2(src, srcIndex + AuthorityOffset);
  188. AdditionalCount = ReadInt2(src, srcIndex + AdditionalOffset);
  189. return HeaderLength;
  190. }
  191. internal virtual int WriteQuestionSectionWireFormat(byte[] dst, int dstIndex)
  192. {
  193. int start = dstIndex;
  194. dstIndex += QuestionName.WriteWireFormat(dst, dstIndex);
  195. WriteInt2(QuestionType, dst, dstIndex);
  196. dstIndex += 2;
  197. WriteInt2(QuestionClass, dst, dstIndex);
  198. dstIndex += 2;
  199. return dstIndex - start;
  200. }
  201. internal virtual int ReadQuestionSectionWireFormat(byte[] src, int srcIndex)
  202. {
  203. int start = srcIndex;
  204. srcIndex += QuestionName.ReadWireFormat(src, srcIndex);
  205. QuestionType = ReadInt2(src, srcIndex);
  206. srcIndex += 2;
  207. QuestionClass = ReadInt2(src, srcIndex);
  208. srcIndex += 2;
  209. return srcIndex - start;
  210. }
  211. internal virtual int WriteResourceRecordWireFormat(byte[] dst, int dstIndex)
  212. {
  213. int start = dstIndex;
  214. if (RecordName == QuestionName)
  215. {
  216. dst[dstIndex++] = unchecked(unchecked(0xC0));
  217. // label string pointer to
  218. dst[dstIndex++] = unchecked(unchecked(0x0C));
  219. }
  220. else
  221. {
  222. // questionName (offset 12)
  223. dstIndex += RecordName.WriteWireFormat(dst, dstIndex);
  224. }
  225. WriteInt2(RecordType, dst, dstIndex);
  226. dstIndex += 2;
  227. WriteInt2(RecordClass, dst, dstIndex);
  228. dstIndex += 2;
  229. WriteInt4(Ttl, dst, dstIndex);
  230. dstIndex += 4;
  231. RDataLength = WriteRDataWireFormat(dst, dstIndex + 2);
  232. WriteInt2(RDataLength, dst, dstIndex);
  233. dstIndex += 2 + RDataLength;
  234. return dstIndex - start;
  235. }
  236. internal virtual int ReadResourceRecordWireFormat(byte[] src, int srcIndex)
  237. {
  238. int start = srcIndex;
  239. int end;
  240. if ((src[srcIndex] & unchecked(0xC0)) == unchecked(0xC0))
  241. {
  242. RecordName = QuestionName;
  243. // label string pointer to questionName
  244. srcIndex += 2;
  245. }
  246. else
  247. {
  248. srcIndex += RecordName.ReadWireFormat(src, srcIndex);
  249. }
  250. RecordType = ReadInt2(src, srcIndex);
  251. srcIndex += 2;
  252. RecordClass = ReadInt2(src, srcIndex);
  253. srcIndex += 2;
  254. Ttl = ReadInt4(src, srcIndex);
  255. srcIndex += 4;
  256. RDataLength = ReadInt2(src, srcIndex);
  257. srcIndex += 2;
  258. AddrEntry = new NbtAddress[RDataLength / 6];
  259. end = srcIndex + RDataLength;
  260. for (AddrIndex = 0; srcIndex < end; AddrIndex++)
  261. {
  262. srcIndex += ReadRDataWireFormat(src, srcIndex);
  263. }
  264. return srcIndex - start;
  265. }
  266. internal abstract int WriteBodyWireFormat(byte[] dst, int dstIndex);
  267. internal abstract int ReadBodyWireFormat(byte[] src, int srcIndex);
  268. internal abstract int WriteRDataWireFormat(byte[] dst, int dstIndex);
  269. internal abstract int ReadRDataWireFormat(byte[] src, int srcIndex);
  270. public override string ToString()
  271. {
  272. string opCodeString;
  273. string resultCodeString;
  274. string questionTypeString;
  275. string recordTypeString;
  276. switch (OpCode)
  277. {
  278. case Query:
  279. {
  280. opCodeString = "QUERY";
  281. break;
  282. }
  283. case Wack:
  284. {
  285. opCodeString = "WACK";
  286. break;
  287. }
  288. default:
  289. {
  290. opCodeString = Extensions.ToString(OpCode);
  291. break;
  292. }
  293. }
  294. switch (ResultCode)
  295. {
  296. case FmtErr:
  297. {
  298. resultCodeString = "FMT_ERR";
  299. break;
  300. }
  301. case SrvErr:
  302. {
  303. resultCodeString = "SRV_ERR";
  304. break;
  305. }
  306. case ImpErr:
  307. {
  308. resultCodeString = "IMP_ERR";
  309. break;
  310. }
  311. case RfsErr:
  312. {
  313. resultCodeString = "RFS_ERR";
  314. break;
  315. }
  316. case ActErr:
  317. {
  318. resultCodeString = "ACT_ERR";
  319. break;
  320. }
  321. case CftErr:
  322. {
  323. resultCodeString = "CFT_ERR";
  324. break;
  325. }
  326. default:
  327. {
  328. resultCodeString = "0x" + Hexdump.ToHexString(ResultCode, 1);
  329. break;
  330. }
  331. }
  332. switch (QuestionType)
  333. {
  334. case Nb:
  335. {
  336. questionTypeString = "NB";
  337. break;
  338. }
  339. case Nbstat:
  340. {
  341. questionTypeString = "NBSTAT";
  342. break;
  343. }
  344. default:
  345. {
  346. questionTypeString = "0x" + Hexdump.ToHexString(QuestionType, 4);
  347. break;
  348. }
  349. }
  350. switch (RecordType)
  351. {
  352. case A:
  353. {
  354. recordTypeString = "A";
  355. break;
  356. }
  357. case Ns:
  358. {
  359. recordTypeString = "NS";
  360. break;
  361. }
  362. case Null:
  363. {
  364. recordTypeString = "NULL";
  365. break;
  366. }
  367. case Nb:
  368. {
  369. recordTypeString = "NB";
  370. break;
  371. }
  372. case Nbstat:
  373. {
  374. recordTypeString = "NBSTAT";
  375. break;
  376. }
  377. default:
  378. {
  379. recordTypeString = "0x" + Hexdump.ToHexString(RecordType, 4);
  380. break;
  381. }
  382. }
  383. return "nameTrnId=" + NameTrnId
  384. + ",isResponse=" + IsResponse
  385. + ",opCode=" + opCodeString
  386. + ",isAuthAnswer=" + IsAuthAnswer
  387. + ",isTruncated=" + IsTruncated
  388. + ",isRecurAvailable=" + IsRecurAvailable
  389. + ",isRecurDesired=" + IsRecurDesired
  390. + ",isBroadcast=" + IsBroadcast
  391. + ",resultCode=" + ResultCode
  392. + ",questionCount=" + QuestionCount
  393. + ",answerCount=" + AnswerCount
  394. + ",authorityCount=" + AuthorityCount
  395. + ",additionalCount=" + AdditionalCount
  396. + ",questionName=" + QuestionName
  397. + ",questionType=" + questionTypeString
  398. + ",questionClass=" + (QuestionClass == In
  399. ? "IN"
  400. : "0x" + Hexdump.ToHexString(QuestionClass, 4))
  401. + ",recordName=" + RecordName
  402. + ",recordType=" + recordTypeString
  403. + ",recordClass=" + (RecordClass == In
  404. ? "IN"
  405. : "0x" + Hexdump.ToHexString(RecordClass, 4))
  406. + ",ttl=" + Ttl
  407. + ",rDataLength=" + RDataLength;
  408. }
  409. }
  410. }