private static void SendMDNSNameReply() { if (Adapter.IPAddress == null || Networking.Adapter.Name == string.Empty) { return; } prefix.Overwrite(0, new byte[6] { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb }); prefix.Overwrite(6, Adapter.MacAddress); // Source MAC Address prefix.Overwrite(26, Adapter.IPAddress); // Source IP Address lock (lockObj) { // Set the all-important name and IP address -- that's the whole purpose here...! suffix.Overwrite(10, Adapter.IPAddress); var result = Utility.CombineArrays(prefix, Utility.CombineArrays(DNS.EncodeDnsName(Networking.Adapter.Name + ".local"), suffix)); result.Overwrite(16, ((ushort)(result.Length - 14)).ToBytes()); // Set IPv4 message size result.Overwrite(38, ((ushort)(result.Length - 34)).ToBytes()); // Set UDP message size result.Overwrite(24, new byte[] { 0x00, 0x00 }); // clear header checksum, so that calc excludes the checksum itself result.Overwrite(24, result.InternetChecksum(20, 14)); // header checksum result.Overwrite(40, new byte[] { 0x00, 0x00 }); // clear UDP Checksum Debug.WriteLine("Sending MDNS name message! "); Adapter.nic.SendFrame(result); // Send the packet out into the ether....! } }
/// <summary> /// Take care of a packet of Multicast DNS stuff /// </summary> /// <param name="payload"></param> internal static void HandlePacket(byte[] payload) { ushort ipHeaderLength = (ushort)((payload[14] & 0x0f) * 4); var name = DNS.DecodeDnsName(payload, 34 + ipHeaderLength); // Name from first Query if (Adapter.VerboseDebugging) { Debug.WriteLine("Local Name Request (MDNS) for " + name); } bool isQuery = (payload[24 + ipHeaderLength] & (1 << 7)) == 0; // DNS Query ? if (!isQuery) { return; } // Validate that this is MDNS address 224.0.0.251 if (payload[10 + ipHeaderLength] != 0xe0 || payload[11 + ipHeaderLength] != 0x00 || payload[12 + ipHeaderLength] != 0x00 || payload[13 + ipHeaderLength] != 0xfb) { return; } if (name != Networking.Adapter.Name + ".local") { return; // if the name requested does not match ours, exit! } // Wow, if we made it past all that, we should send a reply... SendMDNSNameReply(); }
/// <summary> /// A synchronous call to send an HTTP Request and Receive a Response -- this call will block (until the timeout) while trying to get the result /// </summary> /// <param name="timeout">Time out in seconds</param> /// <param name="RetrieveHeaderOnly">Set this to true if you don't need the content of the response (which can consume a lot of memory)</param> /// <returns>And HttpResponse object OR a null if it timeout happened</returns> public HttpResponse Send(ushort timeout = 5, bool ReturnHeaderOnly = false) { this.omitContent = ReturnHeaderOnly; // if _con is null, create and open a new connection. with a DNS lookup of host if necessary if (_con == null) { var remoteIp = DNS.Lookup(Host); _con = new Connection() { RemoteIP = remoteIp }; } var r = AssembleRequest(); _responseToSend = null; _con.OnConnectionPacketReceived += _con_OnConnectionPacketReceived; responseWaitHandle.Reset(); // This will release an Open() call waiting for the connection! _con.SendAsync(r, 0, (short)r.Length); //Wait for response or timeout responseWaitHandle.WaitOne(timeout * 1000, true); _con.OnConnectionPacketReceived -= _con_OnConnectionPacketReceived; return(_responseToSend); }
public void SendAsync() { // if _con is null, create and open a new connection. with a DNS lookup of host if necessary if (_con == null) { var remoteIp = DNS.Lookup(Host); _con = new Connection() { RemoteIP = remoteIp }; } var r = AssembleRequest(); _con.SendAsync(r, 0, (short)r.Length); }
/// <summary> /// /// </summary> private static void SendLLMNRNameReply(string name, byte[] tranID, byte[] destinationMac, byte[] destinationIP, byte[] destinationPort) { if (Adapter.IPAddress == null || Networking.Adapter.Name == string.Empty) { return; } lock (lockObj) { prefix.Overwrite(0, destinationMac); prefix.Overwrite(6, Adapter.MacAddress); // Source MAC Address prefix.Overwrite(26, Adapter.IPAddress); // Source IP Address prefix.Overwrite(30, destinationIP); prefix.Overwrite(36, destinationPort); prefix.Overwrite(42, tranID); var suffix = new byte[name.Length * 2 + 22]; var byteName = Utility.CombineArrays(DNS.EncodeDnsName(name), new byte[4] { 0x00, 0x01, 0x00, 0x01 }); suffix.Overwrite(0, Utility.CombineArrays(byteName, byteName)); suffix.Overwrite(suffix.Length - 7, new byte[1] { 0x1e }); // Time To Live (30 seconds) suffix.Overwrite(suffix.Length - 5, new byte[1] { 0x04 }); // IP Address length suffix.Overwrite(suffix.Length - 4, Adapter.IPAddress); var result = Utility.CombineArrays(prefix, suffix); result.Overwrite(16, ((ushort)(result.Length - 14)).ToBytes()); // Set IPv4 message size result.Overwrite(38, ((ushort)(result.Length - 34)).ToBytes()); // Set UDP message size result.Overwrite(24, new byte[] { 0x00, 0x00 }); // clear header checksum, so that calc excludes the checksum itself result.Overwrite(24, result.InternetChecksum(20, 14)); // header checksum result.Overwrite(40, new byte[] { 0x00, 0x00 }); // clear UDP Checksum Adapter.nic.SendFrame(result); // Send the packet out into the ether....! Debug.WriteLine("LLMNR Response sent"); } }
/// <summary> /// Take care of a packet of Linked-Local Multicast Name Resolution (LLMNR) stuff /// </summary> /// <param name="payload"></param> internal static void HandlePacket(byte[] payload) { ushort ipHeaderLength = (ushort)((payload[14] & 0x0f) * 4); var name = DNS.DecodeDnsName(payload, 34 + ipHeaderLength); // Name from first Query bool isQuery = (payload[24 + ipHeaderLength] & (1 << 7)) == 0; // DNS Query ? if (!isQuery) { return; } // This is not a good or valid way to detect the type because there could be multiple answers, but I have bigger fish to fry... bool isTypeA = payload[payload.Length - 3] == 0x01; if (!isTypeA) { return; } // Validate that this is an LLMNR address 224.0.0.252 if (payload[10 + ipHeaderLength] != 0xe0 || payload[11 + ipHeaderLength] != 0x00 || payload[12 + ipHeaderLength] != 0x00 || payload[13 + ipHeaderLength] != 0xfc) { return; } //Debug.WriteLine("Local Name Request (LLMNR, Type A) for " + name); if (name != Networking.Adapter.Name + ".local" && name != Networking.Adapter.Name) { return; // if the name requested does not match ours, exit! } if (Adapter.VerboseDebugging) { Debug.WriteLine("Local Name Request (LLMNR, Type A) for " + name); } SendLLMNRNameReply(name, Utility.ExtractRangeFromArray(payload, 42, 2), Utility.ExtractRangeFromArray(payload, 6, 6), Utility.ExtractRangeFromArray(payload, 26, 4), Utility.ExtractRangeFromArray(payload, 34, 2)); }
// event handler for new ethernet frame arrivals static void nic_OnFrameArrived(ENC28J60Driver sender, byte[] frame, DateTime timeReceived) { //if (buf[0] == 0x01) //{ // Debug.WriteLine("Probable Multicast Message Detected - " + buf.Length.ToString()); // if (buf[29] == 0x65) Debug.WriteLine("IP ending in 101"); //} //if (buf[29] == 0x65) //{ // Debug.WriteLine("IP ending in 101 - size: " + buf.Length.ToString()); // if (buf.Length == 541) // Debug.WriteLine("What is this? "); //} //var packetID = Guid.NewGuid().ToString(); if (frame == null) { return; } //Debug.WriteLine("Memory: " + Microsoft.SPOT.Debug.GC(false).ToString() + ", packetID = " + packetID + ", age = " + timeReceived.Subtract(DateTime.Now).Seconds + "s, size = " + frame.Length + ", addys = " + Utility.ExtractRangeFromArray(frame, 0, 14).ToAddress()); if (frame[13] == 0x06 && frame[12] == 0x08) // ARP Packet Type { if (IPAddress != null) { // If message request, and IP matches ours, we need to respond! if (frame[41] == IPAddress[3] && frame[40] == IPAddress[2] && frame[39] == IPAddress[1] && frame[38] == IPAddress[0]) { ARP.HandlePacket(frame); } else if (frame[21] == 0x02 && frame[31] == IPAddress[3] && frame[30] == IPAddress[2] && frame[29] == IPAddress[1] && frame[28] == IPAddress[0]) { Debug.WriteLine("Possible IP Address Conflict Detected"); Adapter.Stop(); // IP Address Conflict! //TODO: if DHCP is enabled, don't stop the networking! Just reset and get a new IP!!!! } } } else if (frame[13] == 0x00 && frame[12] == 0x08) // Handle IP packets { if (frame[23] == 0x01) // Protocol 1 -- PING { // Debug.WriteLine("Received ICMP (Ping) Packet -- " + frame.Length + " bytes"); ICMP.HandlePacket(frame); } else if (frame[23] == 0x11) // Protocol 17 -- UDP { if (frame[37] == 0x44 && !DhcpDisabled && frame[36] == 0x00) // DHCP port 68 -- Order of conditions to short-circuit earlier! { //Debug.WriteLine("Received DHCP Packet -- " + frame.Length + " bytes"); DHCP.HandlePacket(frame); } else if (frame[37] == 0x89 && frame[36] == 0x00 && Name != null && Name != string.Empty && IPAddress != null) // NetBIOS port 137 and name is set { //Debug.WriteLine("Received NBNS Packet -- " + frame.Length + " bytes"); // Uncomment the line below to enable Netbios over TCP Name resolution NetBiosNaming.HandlePacket(frame); } else if (frame[35] == 0x35 && frame[34] == 0x00) // DNS Source Port of 53 (0x35h) { //Debug.WriteLine("Received DNS Packet -- " + frame.Length + " bytes"); DNS.HandlePacket(frame); } else if (frame[37] == 0xe9 && frame[36] == 0x14 && frame[35] == 0xe9 && frame[34] == 0x14 && Name != null && Name != string.Empty && IPAddress != null) // mDNS Source and Destination Port of 5353 or LLMNR Destination Port of 5355 { //Debug.WriteLine("Received MDNS Packet -- " + frame.Length + " bytes"); MDNS.HandlePacket(frame); } else if (frame[37] == 0xeb && frame[36] == 0x14 && Name != null && Name != string.Empty && IPAddress != null) { // Debug.WriteLine("Received LLMNR Packet -- " + frame.Length + " bytes"); LLMNR.HandlePacket(frame); } else if (OnUdpReceivedPacketEvent != null && IPAddress != null) // Check Listening ports { //Debug.WriteLine("Received UDP Packet -- " + frame.Length + " bytes"); foreach (byte[] aPort in ListeningPorts.Values) { if (aPort[0] == frame[36] && aPort[1] == frame[37]) { UDP.HandlePacket(frame); } } } } else if (frame[23] == 0x06 && IPAddress != null) // Protocol 6 -- TCP { //Debug.WriteLine("Received TCP Packet -- " + frame.Length + " bytes"); foreach (byte[] aPort in ListeningPorts.Values) { if (aPort[0] == frame[36] && aPort[1] == frame[37]) { TCP.HandlePacket(frame); return; } } // Handle a response from a currently open connection ulong conID = TCP.GenerateConnectionID(frame); if (TCP.Connections.Contains(conID)) { TCP.HandlePacket(frame); } //else //TODO: Send a RST as a response to a closed port. //var port = (new byte[2] { frame[36], frame[37] }).ToShort(); //foreach (Connection aCon in TCP.Connections) //{ // if (aCon.LocalPort == port) // TCP.HandlePacket(frame); // return; //} } } // All other packets are ignored... like throwing back a fish :) //Debug.WriteLine("Memory: " + Microsoft.SPOT.Debug.GC(false).ToString() + ", packetID = " + packetID); //Microsoft.SPOT.Debug.EnableGCMessages(true); }
/// <summary> /// Seperate send method to share a lock so that we don't mix up packets... /// </summary> /// <param name="packetType"></param> internal static void SendMessage(byte[] packetType) { lock (MagicCookie) { scratch.Overwrite(0, Adapter.BroadcastMAC); // Destination MAC Address scratch.Overwrite(6, Adapter.MacAddress); // Source MAC Address scratch.Overwrite(30, Adapter.BroadcastIPAddress); // Destiantion IP Address scratch.Overwrite(54, Adapter.BlankIPAddress); // Source IP Address scratch.Overwrite(70, Adapter.MacAddress); // Source MAC Address Again inside the DHCP section scratch.Overwrite(284, packetType); byte[] options = new byte[13 + (Adapter.Name == string.Empty ? 0 : Adapter.Name.Length + 2)]; options.Overwrite(0, Adapter.MacAddress); transactionID = transactionID ?? Extensions.GetRandomBytes(4); // Make up some transaction ID if (packetType == DHCP.Discover) { // Debug.WriteLine("Composing Discover Message"); PendingIpAddress = null; //scratch.Overwrite(306, suffix); // write the Discover suffix options.Overwrite(6, new byte[6] { 0x33, 0x04, 0x00, 0x76, 0xa7, 0x00 }); // Request an IP lease time of 90 days } else if (packetType == DHCP.Request && PendingIpAddress != null && Adapter.Gateway != null) { //Debug.WriteLine("Composing Request Message"); options.Overwrite(6, new byte[2] { 0x32, 0x04 }); // Set the option prefix for IP Address options.Overwrite(8, PendingIpAddress); // Set the option Value options.Overwrite(12, new byte[2] { 0x36, 0x04 }); // Set the option prefix for Gateway options.Overwrite(14, Adapter.Gateway); // Set the option value if (Adapter.GatewayMac != null && Adapter.Gateway != null && Adapter.IPAddress != null) { // This is for the renewals //TODO: Test to make sure this works! //scratch.Overwrite(0, Adapter.GatewayMac); //scratch.Overwrite(30, Adapter.Gateway); scratch.Overwrite(54, Adapter.IPAddress); } } else { Debug.WriteLine("Odd DHCP situation... should we be concerned?"); return; } if (Adapter.Name != string.Empty) { // Add Hostname option to Discover and Request messages options.Overwrite(options.Length - (Adapter.Name.Length + 3), new byte[1] { 0x0c }); options.Overwrite(options.Length - (Adapter.Name.Length + 2), DNS.EncodeDnsName(Adapter.Name)); } options.Overwrite(options.Length - 1, new byte[1] { 0xFF }); // End of option section marker scratch.Overwrite(46, transactionID); // Write the transaction ID var result = Utility.CombineArrays(scratch, options); result.Overwrite(16, ((ushort)(result.Length - 14)).ToBytes()); // Set IPv4 message size result.Overwrite(38, ((ushort)(result.Length - 34)).ToBytes()); // Set UDP message size result.Overwrite(24, new byte[] { 0x00, 0x00 }); // clear header checksum, so that calc excludes the checksum itself result.Overwrite(24, result.InternetChecksum(20, 14)); // header checksum result.Overwrite(40, new byte[] { 0x00, 0x00 }); // clear UDP Checksum Adapter.nic.SendFrame(result); // Send the packet out into the ether....! } }