public void DoCall(string netbiosname) { lock (this) // This entire method needs to be synchronized { // int retry_count = 0; int port = SSN_SRVC_TCP_PORT; InetAddress = NbtNameResolver.Resolve(netbiosname); // Get the real NetBIOS name & Workgroup from an IP NBTNameService ns = new NBTNameService(); NbInfo info = ns.queryStatus(InetAddress); NetBiosName = info.Name; WorkgroupName = info.Workgroup; // If we couldn't resolve the name, then the host either doesn't // exist or does not support CIFS. if (NetBiosName == null) { throw new CifsIoException("CM2", InetAddress.ToString()); } DoConnect(InetAddress, port); byte[] packet = MakeRequestPacket(NetBiosName); if (Debug.DebugOn && Debug.DebugLevel >= Debug.Info) { Debug.WriteLine(Debug.Info, "NetBIOS: doCall"); Debug.WriteLine(Debug.Info, "Called name=" + NetBiosName); Debug.WriteLine(Debug.Info, "Calling name=" + fCallingName); Debug.WriteLine(Debug.Info, "Called addr=" + InetAddress.ToString()); if (Debug.DebugLevel >= Debug.Buffer) { Debug.WriteLine(Debug.Buffer, "Packet to send:"); Debug.WriteLine(Debug.Buffer, packet, 0, packet.Length); } } try { fOutput.Write(packet, 0, packet.Length); fOutput.Flush(); } catch (IOException e) { DoHangup(); throw new CifsIoException("NB500").setDetail(e); } // read header try { int count = Read(packet, 0, HDR_SIZE); if (Debug.DebugOn && Debug.DebugLevel >= Debug.Buffer) { Debug.WriteLine(Debug.Buffer, "Recieved packet:"); Debug.WriteLine(Debug.Buffer, packet, 0, packet.Length); } if (count < HDR_SIZE) { DoHangup(); throw new CifsIoException("NB501"); } byte type = packet[HDR_TYPE_1]; switch (type) { case SPT_POS_RESPONSE: /* * POSITIVE SESSION RESPONSE PACKET * * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | TYPE | FLAGS | LENGTH | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ break; case SPT_NEG_RESPONSE: /* * NEGATIVE SESSION RESPONSE PACKET * * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | TYPE | FLAGS | LENGTH | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ERROR_CODE | +-+-+-+-+-+-+-+-+ */ int rc = fInput.ReadByte(); Debug.WriteLine(Debug.Error, "NetBIOS: Negative response: " + rc); DoHangup(); throw CifsIoException.getNBException(rc & 0xff); case SPT_RTG_RESPONSE: /* * SESSION RETARGET RESPONSE PACKET * * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | TYPE | FLAGS | LENGTH | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | RETARGET_IP_ADDRESS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | PORT | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ count = Read(packet, 0, RT_SIZE); DoHangup(); throw new CifsIoException("NB502"); default: DoHangup(); throw new CifsRuntimeException("NB503", (Int32)type); } } catch (IOException e) { DoHangup(); throw new CifsIoException("NB501").setDetail(e); } } }
/// <summary> /// This does a NB Status Request to a given host. /// </summary> /// <param name="hostIP">IPAddress of the host to query</param> /// <returns>The NetBIOS name, or null if unreachable/non SMB</returns> public NbInfo queryStatus(IPAddress hostIP) { fSocket = new UDPCli(); byte[] encodedname = buildSecondLevelEncodedName(NBT_STAT_QNAME, false); int trid = nextTRID(); clearHeader(); int pos = HDR_NAME_TRN_ID_2; setShortAt(pos, fData, trid); int opcode; int rcode; int nmflags = RECURSIVE_DESIRED; int flags = (nmflags << NM_FLAGS_SHIFT); pos = HDR_FLAGS_2; setShortAt(pos, fData, (flags & 0xffff)); pos = HDR_QDCOUNT_2; setShortAt(pos, fData, 1); pos = QUESTION_NAME_OFF; for (int i = 0; i < encodedname.Length; i++) { fData[pos++] = encodedname[i]; } setShortAt(pos, fData, QUESTION_TYPE_NBSTAT); pos += 2; setShortAt(pos, fData, QUESTION_CLASS_IN); pos += 2; //byte[] packet = new byte[fData.Length]; if (Debug.DebugOn && Debug.DebugLevel >= Debug.Buffer) { Debug.WriteLine(Debug.Buffer, "NBNS name query request:"); Debug.WriteLine(Debug.Buffer, fData, 0, pos); } IPEndPoint ip = new IPEndPoint(hostIP, NAME_SERVICE_UDP_PORT); int sent = fSocket.Send(fData, pos, ip); while (true) { bool bSuccess = fSocket.DoReceive(ref ip, ref fData); if (!bSuccess) { break; } if (Debug.DebugOn && Debug.DebugLevel >= Debug.Buffer) { Debug.WriteLine(Debug.Buffer, "NBNS response:"); Debug.WriteLine(Debug.Buffer, fData, 0, fData.Length); } if (trid != getShortAt(0, fData)) { continue; } flags = getShortAt(2, fData); rcode = flags & RCODE_MASK; if ((flags & RESPONSE_PACKET) == 0) { break; // not a response } opcode = ((flags & OPCODE_MASK) >> OPCODE_SHIFT) & 0xf; nmflags = ((flags & NM_FLAGS_MASK) >> NM_FLAGS_SHIFT) & 0x7f; if (rcode == 0) { /* * NODE STATUS RESPONSE * * * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | NAME_TRN_ID |1| 0x0 |1|0|0|0|0 0|0| 0x0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x0000 | 0x0001 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x0000 | 0x0000 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | / RR_NAME / | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | NBSTAT (0x0021) | IN (0x0001) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x00000000 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | RDLENGTH | NUM_NAMES | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + + + / NODE_NAME ARRAY / + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + + / STATISTICS / + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | The NODE_NAME ARRAY is an array of zero or more NUM_NAMES entries | of NODE_NAME records. Each NODE_NAME entry represents an active | name in the same NetBIOS scope as the requesting name in the | local name table of the responder. RR_NAME is the requesting | name. | | NODE_NAME Entry: | | 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | +--- ---+ | | +--- NETBIOS FORMAT NAME ---+ | | +--- ---+ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | NAME_FLAGS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | */ // Read machine name; string NBTname = Encoding.UTF8.GetString(fData, NBT_STAT_COMP_OFF, 15); // Get the NetBIOS name NBTname = NBTname.Trim(); // remove the whitespace // Read workgroup/domain string NBTgroup = Encoding.UTF8.GetString(fData, NBT_STAT_WORKGRP_OFF1, 15); // Get the NetBIOS group NBTgroup = NBTgroup.Trim(); // remove the whitespaces if (NBTname == NBTgroup) // Try the alternate location { NBTgroup = Encoding.UTF8.GetString(fData, NBT_STAT_WORKGRP_OFF2, 15); NBTgroup = NBTgroup.Trim(); } NbInfo info = new NbInfo(); info.Name = (string)NBTname.Clone(); info.Workgroup = (string)NBTgroup.Clone(); fSocket = null; return(info); } else { // NEGATIVE NAME QUERY RESPONSE if (Debug.DebugOn && Debug.DebugLevel >= Debug.Error) { Debug.WriteLine(Debug.Error, "WINS error: " + rcode); } fSocket = null; return(new NbInfo()); } } fSocket = null; return(new NbInfo()); }
/// <summary> /// This does a NB Status Request to a given host. /// </summary> /// <param name="hostIP">IPAddress of the host to query</param> /// <returns>The NetBIOS name, or null if unreachable/non SMB</returns> public NbInfo queryStatus(IPAddress hostIP) { fSocket = new UDPCli(); byte[] encodedname = buildSecondLevelEncodedName(NBT_STAT_QNAME, false); int trid = nextTRID(); clearHeader(); int pos = HDR_NAME_TRN_ID_2; setShortAt(pos, fData, trid); int opcode; int rcode; int nmflags = RECURSIVE_DESIRED; int flags = (nmflags << NM_FLAGS_SHIFT); pos = HDR_FLAGS_2; setShortAt(pos, fData, (flags & 0xffff)); pos = HDR_QDCOUNT_2; setShortAt(pos, fData, 1); pos = QUESTION_NAME_OFF; for(int i=0; i<encodedname.Length; i++) fData[pos++] = encodedname[i]; setShortAt(pos, fData, QUESTION_TYPE_NBSTAT); pos += 2; setShortAt(pos, fData, QUESTION_CLASS_IN); pos += 2; //byte[] packet = new byte[fData.Length]; if(Debug.DebugOn && Debug.DebugLevel >= Debug.Buffer) { Debug.WriteLine(Debug.Buffer, "NBNS name query request:"); Debug.WriteLine(Debug.Buffer, fData, 0, pos); } IPEndPoint ip = new IPEndPoint(hostIP, NAME_SERVICE_UDP_PORT); int sent = fSocket.Send(fData, pos, ip); while(true) { bool bSuccess = fSocket.DoReceive(ref ip, ref fData); if(!bSuccess) break; if(Debug.DebugOn && Debug.DebugLevel >= Debug.Buffer) { Debug.WriteLine(Debug.Buffer, "NBNS response:"); Debug.WriteLine(Debug.Buffer, fData, 0, fData.Length); } if(trid != getShortAt(0, fData)) continue; flags = getShortAt(2, fData); rcode = flags & RCODE_MASK; if ((flags & RESPONSE_PACKET) == 0) break; // not a response opcode = ((flags & OPCODE_MASK) >> OPCODE_SHIFT) & 0xf; nmflags = ((flags & NM_FLAGS_MASK) >> NM_FLAGS_SHIFT) & 0x7f; if (rcode == 0) { /* NODE STATUS RESPONSE 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | NAME_TRN_ID |1| 0x0 |1|0|0|0|0 0|0| 0x0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x0000 | 0x0001 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x0000 | 0x0000 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | / RR_NAME / | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | NBSTAT (0x0021) | IN (0x0001) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x00000000 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | RDLENGTH | NUM_NAMES | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + + / NODE_NAME ARRAY / + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + / STATISTICS / + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ The NODE_NAME ARRAY is an array of zero or more NUM_NAMES entries of NODE_NAME records. Each NODE_NAME entry represents an active name in the same NetBIOS scope as the requesting name in the local name table of the responder. RR_NAME is the requesting name. NODE_NAME Entry: 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | +--- ---+ | | +--- NETBIOS FORMAT NAME ---+ | | +--- ---+ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | NAME_FLAGS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ // Read machine name; string NBTname = Encoding.UTF8.GetString(fData, NBT_STAT_COMP_OFF, 15); // Get the NetBIOS name NBTname = NBTname.Trim(); // remove the whitespace // Read workgroup/domain string NBTgroup = Encoding.UTF8.GetString(fData, NBT_STAT_WORKGRP_OFF1, 15); // Get the NetBIOS group NBTgroup = NBTgroup.Trim(); // remove the whitespaces if(NBTname == NBTgroup) // Try the alternate location { NBTgroup = Encoding.UTF8.GetString(fData, NBT_STAT_WORKGRP_OFF2, 15); NBTgroup = NBTgroup.Trim(); } NbInfo info = new NbInfo(); info.Name = (string)NBTname.Clone(); info.Workgroup = (string)NBTgroup.Clone(); fSocket = null; return info; } else { // NEGATIVE NAME QUERY RESPONSE if(Debug.DebugOn && Debug.DebugLevel >= Debug.Error) Debug.WriteLine(Debug.Error, "WINS error: " + rcode); fSocket = null; return new NbInfo(); } } fSocket = null; return new NbInfo(); }