001: /* jcifs smb client library in Java
002: * Copyright (C) 2000 "Michael B. Allen" <jcifs at samba dot org>
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package com.knowgate.jcifs.netbios;
020:
021: import java.net.InetAddress;
022:
023: import com.knowgate.misc.Gadgets;
024:
025: abstract class NameServicePacket {
026:
027: private static final int LOOKUP_RESP_LIMIT = com.knowgate.jcifs.Config
028: .getInt("jcifs.netbios.lookupRespLimit", 5);
029:
030: private static int addrIndex = 0;
031:
032: // opcode
033: static final int QUERY = 0;
034: static final int WACK = 7;
035:
036: // rcode
037: static final int FMT_ERR = 0x1;
038: static final int SRV_ERR = 0x2;
039: static final int IMP_ERR = 0x4;
040: static final int RFS_ERR = 0x5;
041: static final int ACT_ERR = 0x6;
042: static final int CFT_ERR = 0x7;
043:
044: // type/class
045: static final int NB_IN = 0x00200001;
046: static final int NBSTAT_IN = 0x00210001;
047: static final int NB = 0x0020;
048: static final int NBSTAT = 0x0021;
049: static final int IN = 0x0001;
050: static final int A = 0x0001;
051: static final int NS = 0x0002;
052: static final int NULL = 0x000a;
053:
054: static final int HEADER_LENGTH = 12;
055:
056: // header field offsets
057: static final int OPCODE_OFFSET = 2;
058: static final int QUESTION_OFFSET = 4;
059: static final int ANSWER_OFFSET = 6;
060: static final int AUTHORITY_OFFSET = 8;
061: static final int ADDITIONAL_OFFSET = 10;
062:
063: static void writeInt2(int val, byte[] dst, int dstIndex) {
064: dst[dstIndex++] = (byte) ((val >> 8) & 0xFF);
065: dst[dstIndex] = (byte) (val & 0xFF);
066: }
067:
068: static void writeInt4(int val, byte[] dst, int dstIndex) {
069: dst[dstIndex++] = (byte) ((val >> 24) & 0xFF);
070: dst[dstIndex++] = (byte) ((val >> 16) & 0xFF);
071: dst[dstIndex++] = (byte) ((val >> 8) & 0xFF);
072: dst[dstIndex] = (byte) (val & 0xFF);
073: }
074:
075: static int readInt2(byte[] src, int srcIndex) {
076: return ((src[srcIndex] & 0xFF) << 8)
077: + (src[srcIndex + 1] & 0xFF);
078: }
079:
080: static int readInt4(byte[] src, int srcIndex) {
081: return ((src[srcIndex] & 0xFF) << 24)
082: + ((src[srcIndex + 1] & 0xFF) << 16)
083: + ((src[srcIndex + 2] & 0xFF) << 8)
084: + (src[srcIndex + 3] & 0xFF);
085: }
086:
087: static int readNameTrnId(byte[] src, int srcIndex) {
088: return readInt2(src, srcIndex);
089: }
090:
091: int nameTrnId;
092:
093: int opCode, resultCode, questionCount, answerCount, authorityCount,
094: additionalCount;
095: boolean received, isResponse, isAuthAnswer, isTruncated,
096: isRecurDesired, isRecurAvailable, isBroadcast;
097:
098: Name questionName;
099: Name recordName;
100:
101: int questionType, questionClass, recordType, recordClass, ttl,
102: rDataLength;
103:
104: InetAddress addr;
105:
106: NameServicePacket() {
107: isRecurDesired = true;
108: isBroadcast = true;
109: questionCount = 1;
110: questionClass = IN;
111: }
112:
113: int writeWireFormat(byte[] dst, int dstIndex) {
114: int start = dstIndex;
115: dstIndex += writeHeaderWireFormat(dst, dstIndex);
116: dstIndex += writeBodyWireFormat(dst, dstIndex);
117: return dstIndex - start;
118: }
119:
120: int readWireFormat(byte[] src, int srcIndex) {
121: int start = srcIndex;
122: srcIndex += readHeaderWireFormat(src, srcIndex);
123: srcIndex += readBodyWireFormat(src, srcIndex);
124: return srcIndex - start;
125: }
126:
127: int writeHeaderWireFormat(byte[] dst, int dstIndex) {
128: int start = dstIndex;
129: writeInt2(nameTrnId, dst, dstIndex);
130: dst[dstIndex + OPCODE_OFFSET] = (byte) ((isResponse ? 0x80
131: : 0x00)
132: + ((opCode << 3) & 0x78)
133: + (isAuthAnswer ? 0x04 : 0x00)
134: + (isTruncated ? 0x02 : 0x00) + (isRecurDesired ? 0x01
135: : 0x00));
136: dst[dstIndex + OPCODE_OFFSET + 1] = (byte) ((isRecurAvailable ? 0x80
137: : 0x00)
138: + (isBroadcast ? 0x10 : 0x00) + (resultCode & 0x0F));
139: writeInt2(questionCount, dst, start + QUESTION_OFFSET);
140: writeInt2(answerCount, dst, start + ANSWER_OFFSET);
141: writeInt2(authorityCount, dst, start + AUTHORITY_OFFSET);
142: writeInt2(additionalCount, dst, start + ADDITIONAL_OFFSET);
143: return HEADER_LENGTH;
144: }
145:
146: int readHeaderWireFormat(byte[] src, int srcIndex) {
147: nameTrnId = readInt2(src, srcIndex);
148: isResponse = ((src[srcIndex + OPCODE_OFFSET] & 0x80) == 0) ? false
149: : true;
150: opCode = (src[srcIndex + OPCODE_OFFSET] & 0x78) >> 3;
151: isAuthAnswer = ((src[srcIndex + OPCODE_OFFSET] & 0x04) == 0) ? false
152: : true;
153: isTruncated = ((src[srcIndex + OPCODE_OFFSET] & 0x02) == 0) ? false
154: : true;
155: isRecurDesired = ((src[srcIndex + OPCODE_OFFSET] & 0x01) == 0) ? false
156: : true;
157: isRecurAvailable = ((src[srcIndex + OPCODE_OFFSET + 1] & 0x80) == 0) ? false
158: : true;
159: isBroadcast = ((src[srcIndex + OPCODE_OFFSET + 1] & 0x10) == 0) ? false
160: : true;
161: resultCode = src[srcIndex + OPCODE_OFFSET + 1] & 0x0F;
162: questionCount = readInt2(src, srcIndex + QUESTION_OFFSET);
163: answerCount = readInt2(src, srcIndex + ANSWER_OFFSET);
164: authorityCount = readInt2(src, srcIndex + AUTHORITY_OFFSET);
165: additionalCount = readInt2(src, srcIndex + ADDITIONAL_OFFSET);
166: return HEADER_LENGTH;
167: }
168:
169: int writeQuestionSectionWireFormat(byte[] dst, int dstIndex) {
170: int start = dstIndex;
171: dstIndex += questionName.writeWireFormat(dst, dstIndex);
172: writeInt2(questionType, dst, dstIndex);
173: dstIndex += 2;
174: writeInt2(questionClass, dst, dstIndex);
175: dstIndex += 2;
176: return dstIndex - start;
177: }
178:
179: int readQuestionSectionWireFormat(byte[] src, int srcIndex) {
180: int start = srcIndex;
181: srcIndex += questionName.readWireFormat(src, srcIndex);
182: questionType = readInt2(src, srcIndex);
183: srcIndex += 2;
184: questionClass = readInt2(src, srcIndex);
185: srcIndex += 2;
186: return srcIndex - start;
187: }
188:
189: int writeResourceRecordWireFormat(byte[] dst, int dstIndex) {
190: int start = dstIndex;
191: if (recordName == questionName) {
192: dst[dstIndex++] = (byte) 0xC0; // label string pointer to
193: dst[dstIndex++] = (byte) 0x0C; // questionName (offset 12)
194: } else {
195: dstIndex += recordName.writeWireFormat(dst, dstIndex);
196: }
197: writeInt2(recordType, dst, dstIndex);
198: dstIndex += 2;
199: writeInt2(recordClass, dst, dstIndex);
200: dstIndex += 2;
201: writeInt4(ttl, dst, dstIndex);
202: dstIndex += 4;
203: rDataLength = writeRDataWireFormat(dst, dstIndex + 2);
204: writeInt2(rDataLength, dst, dstIndex);
205: dstIndex += 2 + rDataLength;
206: return dstIndex - start;
207: }
208:
209: int readResourceRecordWireFormat(byte[] src, int srcIndex) {
210: int start = srcIndex;
211: int end;
212:
213: if ((src[srcIndex] & 0xC0) == 0xC0) {
214: recordName = questionName; // label string pointer to questionName
215: srcIndex += 2;
216: } else {
217: srcIndex += recordName.readWireFormat(src, srcIndex);
218: }
219: recordType = readInt2(src, srcIndex);
220: srcIndex += 2;
221: recordClass = readInt2(src, srcIndex);
222: srcIndex += 2;
223: ttl = readInt4(src, srcIndex);
224: srcIndex += 4;
225: rDataLength = readInt2(src, srcIndex);
226: srcIndex += 2;
227:
228: end = srcIndex + rDataLength;
229: for (int i = 0; srcIndex < end; i++) {
230: srcIndex += readRDataWireFormat(src, srcIndex);
231: if (i == addrIndex) {
232: addrIndex++;
233: if (addrIndex == LOOKUP_RESP_LIMIT) {
234: addrIndex = 0;
235: }
236: return end - start;
237: }
238: }
239: addrIndex = 0;
240:
241: return srcIndex - start;
242: }
243:
244: abstract int writeBodyWireFormat(byte[] dst, int dstIndex);
245:
246: abstract int readBodyWireFormat(byte[] src, int srcIndex);
247:
248: abstract int writeRDataWireFormat(byte[] dst, int dstIndex);
249:
250: abstract int readRDataWireFormat(byte[] src, int srcIndex);
251:
252: public String toString() {
253: String opCodeString, resultCodeString, questionTypeString, questionClassString, recordTypeString, recordClassString;
254:
255: switch (opCode) {
256: case QUERY:
257: opCodeString = "QUERY";
258: break;
259: case WACK:
260: opCodeString = "WACK";
261: break;
262: default:
263: opCodeString = Integer.toString(opCode);
264: }
265: switch (resultCode) {
266: case FMT_ERR:
267: resultCodeString = "FMT_ERR";
268: break;
269: case SRV_ERR:
270: resultCodeString = "SRV_ERR";
271: break;
272: case IMP_ERR:
273: resultCodeString = "IMP_ERR";
274: break;
275: case RFS_ERR:
276: resultCodeString = "RFS_ERR";
277: break;
278: case ACT_ERR:
279: resultCodeString = "ACT_ERR";
280: break;
281: case CFT_ERR:
282: resultCodeString = "CFT_ERR";
283: break;
284: default:
285: resultCodeString = "0x"
286: + Gadgets.toHexString(resultCode, 1);
287: }
288: switch (questionType) {
289: case NB:
290: questionTypeString = "NB";
291: case NBSTAT:
292: questionTypeString = "NBSTAT";
293: default:
294: questionTypeString = "0x"
295: + Gadgets.toHexString(questionType, 4);
296: }
297: switch (recordType) {
298: case A:
299: recordTypeString = "A";
300: break;
301: case NS:
302: recordTypeString = "NS";
303: break;
304: case NULL:
305: recordTypeString = "NULL";
306: break;
307: case NB:
308: recordTypeString = "NB";
309: case NBSTAT:
310: recordTypeString = "NBSTAT";
311: default:
312: recordTypeString = "0x"
313: + Gadgets.toHexString(recordType, 4);
314: }
315:
316: return new String("nameTrnId="
317: + nameTrnId
318: + ",isResponse="
319: + isResponse
320: + ",opCode="
321: + opCodeString
322: + ",isAuthAnswer="
323: + isAuthAnswer
324: + ",isTruncated="
325: + isTruncated
326: + ",isRecurAvailable="
327: + isRecurAvailable
328: + ",isRecurDesired="
329: + isRecurDesired
330: + ",isBroadcast="
331: + isBroadcast
332: + ",resultCode="
333: + resultCode
334: + ",questionCount="
335: + questionCount
336: + ",answerCount="
337: + answerCount
338: + ",authorityCount="
339: + authorityCount
340: + ",additionalCount="
341: + additionalCount
342: + ",questionName="
343: + questionName
344: + ",questionType="
345: + questionTypeString
346: + ",questionClass="
347: + (questionClass == IN ? "IN" : "0x"
348: + Gadgets.toHexString(questionClass, 4))
349: + ",recordName="
350: + recordName
351: + ",recordType="
352: + recordTypeString
353: + ",recordClass="
354: + (recordClass == IN ? "IN" : "0x"
355: + Gadgets.toHexString(recordClass, 4))
356: + ",ttl=" + ttl + ",rDataLength=" + rDataLength);
357: }
358: }
|